Loop

The loop primitive has two modes: foreach for deterministic batch processing and react for AI agent reasoning. Both share the same type: "loop" — the mode property determines behavior.


Foreach Mode

Process an array of items with configurable concurrency and failure handling.

json
{
  "type": "loop",
  "properties": {
    "mode": "foreach",
    "items_path": "@input.customers",
    "item_variable_name": "customer",
    "actions_to_execute": [
      {
        "type": "gmail_send",
        "properties": {
          "__oauth_account__": "[email protected]",
          "to": "@customer.email",
          "subject": "Monthly Statement for {{customer.name}}",
          "body": "Dear {{customer.name}},\n\nPlease find your statement attached."
        }
      }
    ],
    "max_concurrency": 10,
    "failure_strategy": "continue_on_error",
    "collect_results": true,
    "result_key": "emailResults"
  }
}

Foreach Properties

Property Type Required Description
mode "foreach" Yes Selects foreach mode
items_path @path Yes Array of items to iterate over
item_variable_name string Yes Variable name for the current item (accessible as @{name})
actions_to_execute array Yes Steps to run for each item — same structure as workflow actions
max_concurrency number No Maximum parallel executions (default: 1)
failure_strategy string No "stop_on_error" (default) or "continue_on_error"
collect_results boolean No Whether to gather results from all iterations (default: false)
result_key string No Context key for collected results

Item Access

Inside actions_to_execute, reference the current item using the variable name:

json
{
  "item_variable_name": "order",
  "actions_to_execute": [
    {
      "type": "process_payment",
      "properties": {
        "order_id": "@order.id",
        "amount": "@order.total",
        "currency": "@order.currency"
      }
    }
  ]
}

Failure Strategies

stop_on_error (default): If any item fails, the loop stops and the run fails. Use when all items must succeed.

continue_on_error: Failed items are logged but processing continues. Use for best-effort batch operations like sending notifications.


React Mode

Run an AI agent that reasons step-by-step toward an objective. See Agents for full details.

json
{
  "type": "loop",
  "properties": {
    "mode": "react",
    "objective": "Investigate this expense report. Check policy compliance, verify receipts, recommend approval or rejection.",
    "tools": [
      { "type": "action", "name": "lookup_employee" },
      { "type": "action", "name": "check_expense_policy" },
      { "type": "action", "name": "verify_receipt" }
    ],
    "model": "gpt-4",
    "max_iterations": 15,
    "timeout_ms": 300000,
    "temperature": 0.7,
    "on_stuck": {
      "action": "escalate",
      "iterations": 3
    },
    "include_reasoning_trace": true,
    "result_key": "expenseDecision"
  }
}

React Properties

Property Type Required Description
mode "react" Yes Selects react mode
objective string Yes What the agent should accomplish. Supports {{ }} templates
tools array Yes Available tools — typed declarations or strings (action names). See Tool Declarations
model string No LLM model to use (default: configured in environment)
max_iterations number No Maximum think-act-observe cycles (default: 10)
timeout_ms number No Maximum execution time in milliseconds (default: 300000)
temperature number No LLM temperature 0–1 (default: 0.7)
on_stuck object No Recovery when agent loops without progress
on_stuck.iterations number No Repeated iterations before triggering (default: 3)
on_stuck.action string No "fail", "escalate", or "retry_with_hint"
on_stuck.hint string No Guidance text for retry_with_hint
include_reasoning_trace boolean No Store full reasoning trace (default: true)
result_key string No Context key for the agent's final answer

When to Use Which Mode

Use Foreach When Use React When
You know exactly what to do with each item The task requires judgment or reasoning
Processing is deterministic The approach depends on intermediate results
Items are independent of each other The agent needs to decide what to do next
You need parallel processing You need natural language understanding

Nested Loops: Foreach Containing React

A common pattern: iterate over a list of items, and for each item, run an AI agent:

json
{
  "type": "loop",
  "properties": {
    "mode": "foreach",
    "items_path": "@unmatched_invoices",
    "item_variable_name": "exception",
    "actions_to_execute": [
      {
        "type": "loop",
        "properties": {
          "mode": "react",
          "objective": "Investigate why invoice {{exception.invoice_id}} for ${{exception.amount}} has no matching payment. Check vendor history, look for partial payments, and recommend next steps.",
          "tools": [
            { "type": "action", "name": "search_payments" },
            { "type": "action", "name": "lookup_vendor" }
          ],
          "max_iterations": 8,
          "result_key": "investigation"
        }
      }
    ],
    "max_concurrency": 3,
    "failure_strategy": "continue_on_error",
    "collect_results": true,
    "result_key": "all_investigations"
  }
}

This processes each exception in parallel (up to 3 at a time), with an AI agent investigating each one independently. Results are collected into @all_investigations.

Concurrency for nested react loops. When running agents in parallel via foreach, keep max_concurrency moderate (3–5). Each agent makes LLM API calls, so high concurrency can hit rate limits. Use continue_on_error to ensure one failed investigation doesn't block the others.

→ Next: [Approval](/primitives/approval)