İçeriğe geç
ajan.io

Belgeler menüsü

Bu sayfada

Kod

İş akışınızın içinden doğrudan JavaScript veya Python kodu yazın.

Genel bakış

Kod düğümünü, iş akışı verisini özel JavaScript veya Python koduyla doğrudan işlemek için kullanın. Standart düğümler yeterli olmadığında seçin; örneğin hesaplamalar, biçimlendirme, doğrulama, dosya işleme veya özel iş mantığı için.

Kod düğümünü ne zaman kullanmalı?

Kod düğümleri şunlar için idealdir:

  • Veri dönüşümleri ve biçimlendirme
  • Matematiksel hesaplamalar
  • Özel iş mantığı
  • JSON ayrıştırma ve manipülasyon
  • Veri doğrulama ve temizleme
  • Tarih/saat işlemleri
  • JavaScript ve Python ile dosya işleme

Kod düğümlerinin ideal olmadığı durumlar:

  • Yapay zeka analizi (Ajan düğümü kullanın)
  • Harici API çağrıları (HTTP isteği düğümü kullanın)
  • Basit koşullar (Koşul düğümü kullanın)
  • Uzun süren veya etkileşimli analiz (Veri Analizi kullanın)

Yapılandırma

Dil: Kodunuzu JavaScript mi yoksa Python mı yazacağınızı seçin.

Kod düzenleyici: Kod düğümünü seçtiğinizde açılan kod düzenleyicide seçilen dilde dönüşüm mantığınızı yazın.

Önceki düğümlere erişim: Önceki düğümlerin çıktıları Kod düğümünde değişken olarak kullanılabilir. Kullanılabilir değişken adları kod düzenleyicinin üstünde gösterilir. Yalnızca slug’ları kodunuzda geçen yukarı akış düğümleri yüklenir. data’dan okumak veya çıktıları slug yerine dinamik aramak, her yukarı akış çıktısını yükler. Kod düğümü çıktısını daha sonra kullanmak için Kod çıktısına erişme sayfasına bakın.

Örnekler

İstatistik hesaplama

javascript
  // Access data from previous nodes
  const scores = agent.output.structured.scores || [];

  // Calculate statistics
  const average = scores.reduce((a, b) => a + b, 0) / scores.length;
  const max = Math.max(...scores);
  const min = Math.min(...scores);

  // Return result
  return {
    average_score: average.toFixed(2),
    highest_score: max,
    lowest_score: min,
    grade: average >= 90 ? "A" : average >= 80 ? "B" : "C"
  };
python
  # Access data from previous nodes
  agent_output = agent.get("output", {})
  scores = agent_output.get("structured", {}).get("scores", [])

  if not scores:
      return {
          "average_score": 0,
          "highest_score": None,
          "lowest_score": None,
          "grade": "N/A"
      }

  # Calculate statistics
  average = sum(scores) / len(scores)
  print(f"Processed {len(scores)} scores")

  # Return result
  return {
      "average_score": round(average, 2),
      "highest_score": max(scores),
      "lowest_score": min(scores),
      "grade": "A" if average >= 90 else "B" if average >= 80 else "C"
  }

Veriyi doğrulama ve temizleme

javascript
  // Access form data
  const email = trigger.output.email || "";
  const amount = trigger.output.amount || 0;

  // Validate
  if (!email.includes("@")) {
    throw new Error("Invalid email format");
  }

  if (amount <= 0) {
    throw new Error("Amount must be greater than zero");
  }

  // Clean and return
  return {
    email: email.trim().toLowerCase(),
    amount: parseFloat(amount.toFixed(2)),
    validated: true
  };
python
  # Access form data
  trigger_output = trigger.get("output", {})
  email = trigger_output.get("email", "")
  amount = trigger_output.get("amount", 0)

  # Validate
  if "@" not in email:
      raise ValueError("Invalid email format")

  if amount <= 0:
      raise ValueError("Amount must be greater than zero")

  # Clean and return
  return {
      "email": email.strip().lower(),
      "amount": round(float(amount), 2),
      "validated": True
  }

Dizileri dönüştürme ve filtreleme

javascript
  // Access data from previous node
  const customers = trigger.output.customers || [];

  // Filter active customers
  const activeCustomers = customers.filter(c => c.status === "active");

  // Transform data
  const processed = activeCustomers.map(customer => ({
    id: customer.id,
    name: `${customer.firstName} ${customer.lastName}`.trim(),
    email: customer.email.toLowerCase(),
    tier: customer.totalSpent > 1000 ? "premium" : "standard"
  }));

  return {
    customers: processed,
    total: processed.length,
    premiumCount: processed.filter(c => c.tier === "premium").length
  };
python
  # Access data from previous node
  customers = trigger.get("output", {}).get("customers", [])

  # Filter active customers
  active_customers = [
      customer for customer in customers
      if customer.get("status") == "active"
  ]

  # Transform data
  processed = [
      {
          "id": customer.get("id"),
          "name": f"{customer.get('firstName', '')} {customer.get('lastName', '')}".strip(),
          "email": customer.get("email", "").lower(),
          "tier": "premium" if customer.get("totalSpent", 0) > 1000 else "standard"
      }
      for customer in active_customers
  ]

  return {
      "customers": processed,
      "total": len(processed),
      "premiumCount": len([c for c in processed if c["tier"] == "premium"])
  }

Tarih işlemleri

javascript
  // Access event data
  const events = trigger.output.events || [];
  const now = new Date();

  const processedEvents = events.map(event => {
    const eventDate = new Date(event.date);
    const daysUntil = Math.ceil((eventDate - now) / (1000 * 60 * 60 * 24));

    return {
      title: event.title,
      date: eventDate.toISOString(),
      formatted: eventDate.toLocaleDateString("en-US", {
        weekday: "long",
        year: "numeric",
        month: "long",
        day: "numeric"
      }),
      daysUntil: daysUntil,
      isUpcoming: daysUntil >= 0,
      isThisWeek: daysUntil >= 0 && daysUntil <= 7
    };
  });

  return {
    events: processedEvents,
    upcomingCount: processedEvents.filter(e => e.isUpcoming).length,
    thisWeekCount: processedEvents.filter(e => e.isThisWeek).length
  };
python
  from datetime import datetime, timezone

  # Access event data
  events = trigger.get("output", {}).get("events", [])
  now = datetime.now(timezone.utc)

  processed_events = []
  for event in events:
      event_date = datetime.fromisoformat(event["date"].replace("Z", "+00:00"))
      days_until = (event_date.date() - now.date()).days

      processed_events.append({
          "title": event.get("title"),
          "date": event_date.isoformat(),
          "formatted": event_date.strftime("%A, %B %d, %Y"),
          "daysUntil": days_until,
          "isUpcoming": days_until >= 0,
          "isThisWeek": 0 <= days_until <= 7
      })

  return {
      "events": processed_events,
      "upcomingCount": len([e for e in processed_events if e["isUpcoming"]]),
      "thisWeekCount": len([e for e in processed_events if e["isThisWeek"]])
  }

JSON işleme

javascript
  // Nested JSON from API response
  const apiResponse = http_request.output || {};

  // Extract and flatten nested data
  const users = apiResponse.data?.users || [];

  const flattened = users.map(user => ({
    id: user.id,
    name: `${user.first_name || ""} ${user.last_name || ""}`.trim(),
    email: user.contact?.email || "",
    city: user.address?.city || "Unknown",
    isActive: user.status === "active"
  }));

  return {
    users: flattened,
    total: flattened.length,
    activeCount: flattened.filter(u => u.isActive).length
  };
python
  # Nested JSON from API response
  api_response = http_request.get("output", {})

  # Extract and flatten nested data
  users = api_response.get("data", {}).get("users", [])

  flattened = [
      {
          "id": user.get("id"),
          "name": f"{user.get('first_name', '')} {user.get('last_name', '')}".strip(),
          "email": user.get("contact", {}).get("email", ""),
          "city": user.get("address", {}).get("city", "Unknown"),
          "isActive": user.get("status") == "active"
      }
      for user in users
  ]

  return {
      "users": flattened,
      "total": len(flattened),
      "activeCount": len([user for user in flattened if user["isActive"]])
  }

Birleştirme ve özetleme

javascript
  // Sales data from previous node
  const sales = http_request.output.sales || [];

  // Group by category
  const byCategory = {};
  sales.forEach(sale => {
    const cat = sale.category || "Other";
    if (!byCategory[cat]) {
      byCategory[cat] = { total: 0, count: 0, items: [] };
    }
    byCategory[cat].total += sale.amount || 0;
    byCategory[cat].count += 1;
    byCategory[cat].items.push(sale);
  });

  // Calculate summary
  const summary = Object.entries(byCategory).map(([category, data]) => ({
    category,
    totalRevenue: data.total.toFixed(2),
    orderCount: data.count,
    averageOrder: (data.total / data.count).toFixed(2)
  }));

  // Sort by revenue
  summary.sort((a, b) => parseFloat(b.totalRevenue) - parseFloat(a.totalRevenue));

  return {
    summary: summary,
    topCategory: summary[0]?.category || "None",
    grandTotal: sales.reduce((sum, s) => sum + (s.amount || 0), 0).toFixed(2)
  };
python
  # Sales data from previous node
  sales = http_request.get("output", {}).get("sales", [])

  # Group by category
  by_category = {}
  for sale in sales:
      category = sale.get("category") or "Other"
      if category not in by_category:
          by_category[category] = {"total": 0, "count": 0, "items": []}

      by_category[category]["total"] += sale.get("amount", 0)
      by_category[category]["count"] += 1
      by_category[category]["items"].append(sale)

  # Calculate summary
  summary = [
      {
          "category": category,
          "totalRevenue": f"{data['total']:.2f}",
          "orderCount": data["count"],
          "averageOrder": f"{data['total'] / data['count']:.2f}"
      }
      for category, data in by_category.items()
  ]

  # Sort by revenue
  summary.sort(key=lambda row: float(row["totalRevenue"]), reverse=True)

  return {
      "summary": summary,
      "topCategory": summary[0]["category"] if summary else "None",
      "grandTotal": f"{sum(sale.get('amount', 0) for sale in sales):.2f}"
  }

JavaScript ile dosya oluşturma

JavaScript, bir files dizisi döndürerek iş akışı dosyaları üretebilir. Her giriş fileName, mimeType ve ya text (metin/CSV/JSON içerik) ya da base64 (ikili içerik) içermelidir. Çalışma zamanı dosyaları yükler ve düğüm çıktısına _files altında ekler.

javascript
const customers = trigger.output.customers || [];
const activeCustomers = customers.filter((c) => c.status === "active");

const csv = [
  ["id", "email"],
  ...activeCustomers.map((c) => [c.id, (c.email || "").toLowerCase()]),
]
  .map((row) => row.map((cell) => `"${String(cell).replaceAll('"', '""')}"`).join(","))
  .join("\n");

return {
  active_count: activeCustomers.length,
  files: [
    {
      fileName: "active_customers.csv",
      mimeType: "text/csv",
      text: csv,
    },
  ],
};

Önceki düğümlerden dosya okuma {#read-files-from-previous-nodes}

Form yüklemeleri veya aksiyon çıktıları gibi önceki düğümlerden geçen dosyalar Python çalışma dizininde kullanılabilir. Her dosya nesnesi doğrudan open()’a iletebileceğiniz bir path ve _metadata.name altında orijinal dosya adını taşır.

python
# File upload fields contain a list of file objects
files = trigger.get("output", {}).get("resume", [])

processed = []
for file in files:
    with open(file["path"], "rb") as f:
        content = f.read()

    processed.append({
        "name": file["_metadata"]["name"],
        "size_bytes": len(content)
    })

return {"files_processed": processed}

Python ile dosya oluşturma

Python’un çalışma dizininde oluşturduğu dosyalar düğüm çıktısına _files altında eklenir.

python
import csv

customers = trigger.get("output", {}).get("customers", [])
active_customers = [c for c in customers if c.get("status") == "active"]

with open("active_customers.csv", "w", newline="") as file:
    writer = csv.DictWriter(file, fieldnames=["id", "email"])
    writer.writeheader()

    for customer in active_customers:
        writer.writerow({
            "id": customer.get("id"),
            "email": customer.get("email", "").lower()
        })

print(f"Created CSV with {len(active_customers)} customers")

return {
    "active_count": len(active_customers),
    "file_name": "active_customers.csv"
}

Kod çıktısına erişme {#accessing-code-output}

Sonraki düğümlerde JavaScript veya Python’dan dönen değerlere erişmek için Kod düğümü adını kullanın:

handlebars
{{code_node_name.output.customer}}
{{code_node_name.output.total}}
{{code_node_name.output.formatted_date}}
{{code_node_name.output.processed_items[0].name}}

JavaScript’in döndürdüğü veya Python’un çalışma dizininde oluşturduğu dosyalar _files altında kullanılabilir:

handlebars
{{code_node_name.output._files[0]._metadata.name}}

Dil yetenekleri

Kod düğümü yetenekleri seçilen dile bağlıdır.

JavaScript

JavaScript, yerleşik yardımcı işlevlerle güvenli bir sandbox ortamında çalışır:

  • ld.request(): HTTP istekleri yapın
  • ld.log(): Ayıklama bilgisi çıktılayın
  • Veri dönüşümleri: CSV, Parquet, Arrow biçim dönüşümleri
  • Dosya oluşturma: Üretilen dosyaları _files altında göstermek için bir files dizisi döndürün
  • Standart JavaScript: JSON, Date, Math, Array, Object yöntemleri
  • Tam yardımcılar referansı — Veri dönüşümleri, SQL doğrulama, kriptografi ve daha fazlası dahil tüm kullanılabilir sandbox yardımcılarını görüntüleyin.

Python

Python, internet erişimi olmayan bir sandbox ortamında çalışır.

  • Düğüm çıktısını ayarlamak için üst düzey return kullanın
  • Günlük yazmak için print() kullanın
  • pandas, numpy, openpyxl ve pypdf gibi önceden yüklü veri ve belge kitaplıklarını kullanın
  • Slug’ları kodunuzda geçiyorsa ve geçerli Python tanımlayıcılarıysa yukarı akış çıktılarına değişken olarak erişin
  • file["path"]’i open()’a ileterek önceki düğümlerden dosya okuyun
  • _files altında göstermek için çalışma dizinine dosya kaydedin
  • İnternet erişimi olmadan çalışır

JavaScript ld.* yardımcıları Python’da kullanılamaz.

En iyi uygulamalar

Sonraki düğümlerde kolay erişim için veriyi nesne olarak döndürün. Bu, nokta notasyonuyla belirli değerlere başvurmayı basit kılar.

Veri tanımsız veya null olduğunda varsayılan değer sağlamak ve hataları önlemek için ||, isteğe bağlı zincirleme (?.) veya Python .get() kullanın.

Riskli işlemleri JavaScript için try/catch, Python için try/except ile sarın. Bu, iş akışı başarısızlıklarını önlemeye ve anlamlı hata mesajları sağlamaya yardımcı olur.

Karmaşık mantık bir Ajan düğümünde daha iyi olabilir. Kod düğümlerini basit dönüşümler ve hesaplamalar için kullanın; zekâ veya bağlam anlayışı gerektiren görevler için değil.

Kod düğümleri, yüklenen yukarı akış çıktıları 5 MiB’ı aştığında başarısız olur. Yalnızca ihtiyacınız olan slug’lara başvurun; çünkü data ve diğer dinamik çıktı aramaları her yukarı akış çıktısını yükler.

Kodunuzun ne yaptığını gelecekte başvurmak için belgeleyin. Net yorumlar, iş akışına daha sonra döndüğünüzde sizin ve ekibinizin mantığı anlamasına yardımcı olur.

Limitler {#limits}

Girdi boyutu

Her Kod düğümünün önceki düğümlerden aldığı birleşik girdi için 5 MiB limiti vardır. Kodunuz çalışmadan önce ajan, kodunuzun slug ile başvurduğu yukarı akış çıktılarının boyutunu ölçer. 5 MiB’ı aşarlarsa düğüm bir hatayla başarısız olur ve kodunuz hiç yürütülmez. data’dan okumak veya çıktıları slug yerine dinamik aramak her yukarı akış çıktısını yükler; bu nedenle tam birleşik boyut limite karşı ölçülür.

Yaygın nedenler:

  • Birçok yinelemeden çıktıları tek bir diziye toplayan bir Döngü düğümü.
  • Çok büyük bir API yanıtı, dosya içeriği veya veri kümesi döndüren önceki bir düğüm.
  • Güvenle ölçülemeyen derin iç içe nesneler.

Bu limite takılırsanız şunlardan birini yapın:

  • Yalnızca ihtiyacınız olan alanları filtreleyerek, özetleyerek veya seçerek yukarı akış düğüm çıktısının boyutunu azaltın.
  • Önceki herhangi bir Döngü düğümünde yineleme başına daha az öğe işleyin.
  • Birleştirilmiş sonuçlarını okumanız gerekmiyorsa önceki Döngü düğümünde çıktı toplamayı kapatın.

Sonuç boyutu

Kod düğümleri dahil her iş akışı düğümü çıktısı 25 MB ile sınırlıdır. Kodunuzun döndürdüğü sonuç 25 MB’ı aşarsa düğüm Node output exceeded the maximum size of 25 MB. Reduce the amount of data the node returns (e.g. filter or paginate results). hatasıyla başarısız olur ve aşırı büyük sonuç saklanmaz. Bu JavaScript ve Python için geçerlidir. Bir files dizisinde döndürdüğünüz veya Python çalışma dizininde oluşturduğunuz dosyalar çıktı ölçülmeden önce yüklenir; bu nedenle içerikleri limite sayılmaz.

JavaScript sonuçları ayrıca kod yürütme hizmetinden geçer; bu hizmet satır içi döndürülen dosyalar dahil tam yanıtını 150 MB ile sınırlar. Ayrıntılar için Sandbox yardımcı işlevleri sayfasına bakın.

Her iki limite de takılırsanız yalnızca sonraki düğümlerin ihtiyaç duyduğu alanları döndürün ve büyük veri kümelerini döndürmeden önce filtreleyin veya sayfalayın.

Sonraki adımlar