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:
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:
{
"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, objective, and available tools:
You are an AI agent. Your objective is:
{objective}
You have access to these tools:
- lookup_ticket: Look up a support ticket by ID
- analyze_sentiment: Analyze text sentiment and urgency
- slack_post: Post a message to a Slack channel
- __complete__: Signal that you have finished the task
- __pause_for_human__: Request human input
On each turn, respond with a JSON object containing:
- "thought": your reasoning about what to do next
- "action": the tool to use
- "action_input": the parameters for the tool
When you have completed the task, use __complete__ with your final answer.
Each tool's description and parameter schema are included so the agent knows what each tool does and what parameters it expects.
Iteration History
Every previous iteration is appended as context:
Iteration 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" }
Iteration 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 history, the engine asks: "Given the above, what is your next step?"
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
{
"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.