ReAct Loop

ReAct stands for Reasoning + Acting. The agent thinks about its current state, chooses an action, observes the result, and repeats until it completes the objective or hits a limit.


Iteration Lifecycle

Each iteration follows a strict cycle:

sequenceDiagram participant Engine participant LLM participant Tool Engine->>LLM: System prompt + history + "What next?" LLM->>Engine: { thought, action, action_input } Engine->>Engine: Validate action is in tool allowlist Engine->>Tool: Execute action with action_input Tool->>Engine: Observation (result) Engine->>Engine: Append to history, check limits Note over Engine: Repeat until __complete__<br/>or max_iterations reached

Step 1 — Prompt. The engine constructs a prompt containing the objective, available tools, and the history of all previous iterations.

Step 2 — Think + Decide. The LLM responds with a structured JSON object: what it's thinking, what action to take, and with what parameters.

Step 3 — Validate. The engine checks that the chosen action is in the declared tool list. Undeclared actions are rejected.

Step 4 — Execute. The engine runs the tool and captures the result as an observation.

Step 5 — Accumulate. The thought, action, and observation are appended to the iteration history. The engine checks whether to continue, stop, or trigger stuck detection.


LLM Response Format

The agent must respond with this JSON structure on every iteration:

json
{
  "thought": "I need to look up the customer's order history before I can assess the refund request.",
  "action": "get_order_history",
  "action_input": {
    "customer_id": "cust-12345",
    "limit": 10
  }
}
Field Type Description
thought string The agent's reasoning — what it's considering, what it knows, what it needs
action string The tool to call — must be in the declared tools list
action_input object Parameters for the tool call

The thought field is critical for auditability. It captures why the agent chose this action, not just what it did. Every thought is stored in the reasoning trace.


Prompt Construction

The engine constructs the LLM prompt from three parts:

System Prompt

Sets the agent's role, available tools, and response format requirements. The prompt includes the objective, each tool's description and parameter schema, and instructions for the agent to respond with structured JSON containing thought, action, and action_input fields. Security hardening rules are appended to help the model resist prompt injection from untrusted input data.

Iteration History

Every previous step is appended as context, giving the agent full visibility into what it has already done:

text
Step 1:
  Thought: "I need to look up ticket #12345 to understand the issue."
  Action: lookup_ticket
  Input: { "ticket_id": "12345" }
  Observation: { "subject": "Billing Error", "status": "open", "priority": "high" }

Step 2:
  Thought: "The ticket is about a billing error. Let me analyze the sentiment."
  Action: analyze_sentiment
  Input: { "text": "I've been charged twice for my subscription..." }
  Observation: { "sentiment": "negative", "urgency": "high" }

Current Turn Prompt

After the objective, tools, and history, the engine asks the model to determine its next action based on what it has learned so far.


Context Accumulation

As iterations progress, the agent builds up knowledge:

Iteration What the Agent Knows
1 Objective only
2 Objective + first tool result
3 Objective + two tool results + its own reasoning about them
N Full history of thoughts, actions, and observations

Each observation becomes available for the agent to reference in subsequent reasoning. The agent effectively has a growing "working memory" of everything it has done and learned.


Token Management

The iteration history grows with each cycle. For long-running agents, this can approach the LLM's context window limit. Hyphen manages this by:

  • Including the full history up to the context window limit
  • Summarizing older iterations when the history exceeds available tokens
  • Prioritizing recent iterations and the original objective

Set max_iterations conservatively to prevent excessive token consumption. Most tasks complete in 5–10 iterations. Complex orchestration tasks may need 15–20.


Termination Conditions

The loop ends when any of these occur:

Condition Result
Agent calls __complete__ Success — the agent's answer is stored in context
max_iterations reached Failure — timeout, no answer produced
timeout_ms exceeded Failure — execution time limit
Agent calls __pause_for_human__ Paused — waiting for human input
Stuck detection triggers with action: "fail" Failure — agent was looping
Stuck detection triggers with action: "escalate" Paused — routed to human

Configuration Reference

json
{
  "type": "loop",
  "properties": {
    "mode": "react",
    "objective": "Your task description here",
    "tools": [
      { "type": "action", "name": "tool_a" },
      { "type": "action", "name": "tool_b" }
    ],
    "model": "gpt-4",
    "max_iterations": 10,
    "timeout_ms": 300000,
    "temperature": 0.7,
    "on_stuck": {
      "iterations": 3,
      "action": "escalate"
    },
    "include_reasoning_trace": true,
    "result_key": "agentResult"
  }
}

Implicit tools are auto-injected. Built-in tools like __complete__, __pause_for_human__, __store_memory__, __retrieve_memory__, and __log_progress__ are always available — you don't need to declare them. Only declare your custom action and workflow tools. See Tool Declarations for the full format reference.

→ Next: [Built-in Tools](/agents/built-in-tools)