# The Agent Loop

The agent loop is the beating heart of any harness. It's the control structure that determines how the agent thinks, acts, and adapts until it completes a task or needs human input.

## The Core Cycle

At its simplest, every agentic harness runs some variation of this loop:

```mermaid
graph TD
    A[User Input/Goal] --> B[Build Context]
    B --> C[Think/Plan]
    C --> D{Need to Act?}
    D -->|Yes| E[Select Tools]
    E --> F[Check Permissions]
    F --> G[Execute Tools]
    G --> H[Observe Results]
    H --> I[Update State]
    I --> B
    D -->|No| J[Respond to User]
    J --> K{Task Complete?}
    K -->|No| B
    K -->|Yes| L[Done]
    
    style A fill:#e1f5fe
    style C fill:#fff3e0
    style G fill:#f3e5f5
    style J fill:#e8f5e9
    style L fill:#c8e6c9
```

## Loop Phases

| Phase | Purpose | What Happens |
|---|---|---|
| **1. Input** | Receive goal/task | User message, continuation, or sub-agent callback |
| **2. Context Building** | Assemble relevant information | System prompt, history, files, memory, tools, project context |
| **3. Reasoning/Planning** | Decide next action | Model thinks about what to do next given goal and context |
| **4. Tool Selection** | Choose appropriate tools | Model returns tool calls with arguments |
| **5. Permission Check** | Validate safety | Check against allowlists, rules, and approval requirements |
| **6. Execution** | Run tools | Execute in sandbox/environment, handle errors |
| **7. Observation** | Process results | Format results, check for errors, update understanding |
| **8. Evaluation** | Decide whether to continue | Is task complete? Need more info? Blocked? |
| **9. Response** | Communicate with user | Text response, summary, or ask for clarification |

## Loop Variants

### ReAct (Reason + Act)
The most common pattern. Model alternates between reasoning and acting.

```python
while not done:
    thought = model.think(context)
    if thought.action == "tool_call":
        result = execute(thought.tool, thought.args)
        context.add_observation(result)
    elif thought.action == "respond":
        return thought.response
```

### Plan-Execute
Plan the entire approach first, then execute steps systematically.

```python
plan = model.plan(goal)  # Decompose into steps
for step in plan:
    result = execute_step(step, context)
    context.update(result)
    if needs_replan(result):
        plan = model.replan(goal, plan, results)
return summarize(results)
```

### Thought-Tool-Thought
Model can interleave multiple tool calls and reasoning in one turn.

```python
response = model.generate(context, tools=tools)
for tool_call in response.tool_calls:
    result = execute(tool_call)
    context.add(tool_call, result)
# Model sees all results and decides next step
```

## Control Flow Decisions

The harness must decide:
- **When to stop** - Task complete, error unrecoverable, user asked to stop
- **When to ask user** - Ambiguous requirements, destructive action, missing info
- **When to delegate** - Task is complex, can be parallelized, needs specialization
- **When to replan** - Approach not working, new information discovered
- **When to compact context** - Approaching token limits

## Loop Termination Conditions

| Condition | Description | Action |
|---|---|---|
| **Task Complete** | Goal achieved | Summarize and stop |
| **User Response** | Model gives final answer with no tool calls | Present response, wait for input |
| **Max Turns** | Exceeded turn limit | Stop with explanation |
| **Max Cost** | Exceeded budget | Stop with cost summary |
| **User Interrupt** | User cancels/stops | Gracefully stop |
| **Error Threshold** | Too many consecutive failures | Ask for help or stop |
| **Timeout** | Task taking too long | Warn and potentially stop |

## State Between Iterations

The harness must maintain state across loop iterations:

```typescript
interface AgentState {
  sessionId: string;
  messages: Message[];      // Conversation history
  taskList: Todo[];         // Current tasks
  toolResults: ToolResult[];
  memory: Memory[];
  filesRead: Set<string>;
  subAgents: SubAgent[];
  turnCount: number;
  tokensUsed: TokenCount;
  status: 'thinking' | 'tool_call' | 'responding' | 'done';
}
```

## Implementation Patterns

### Turn-Based Loop
```python
async def run_loop(goal, max_turns=50):
    state = initialize_state(goal)
    for turn in range(max_turns):
        context = build_context(state)
        response = await model.generate(context)
        if response.tool_calls:
            for call in response.tool_calls:
                if not has_permission(call): 
                    await ask_user(call); continue
                result = await execute_tool(call)
                state.add_tool_result(call, result)
        elif response.text:
            state.add_message(response.text)
            if is_complete(response): break
        state.turn_count += 1
    return state.summary()
```

### Event-Driven Loop
More flexible, handles streaming and interrupts better.

```python
class AgentLoop:
    async def run(self, input):
        await self.emit('start', input)
        while self.should_continue():
            await self.emit('thought')
            action = await self.decide_next_action()
            if action.type == 'tool':
                await self.execute_tool(action)
            elif action.type == 'respond':
                await self.respond(action)
                break
            elif action.type == 'delegate':
                await self.spawn_subagent(action)
            await self.check_interrupts()
        await self.emit('end')
```

## Best Practices

1. **Keep the harness in control** - The loop logic should be deterministic, not fully delegated to the model
2. **Limit turns** - Prevent infinite loops with reasonable limits
3. **Checkpoint often** - Save state after significant actions
4. **Handle interrupts** - Allow user to pause/stop/correct
5. **Log everything** - Every iteration should be traceable
6. **Compact aggressively** - Don't let context grow unbounded
7. **Parallelize safely** - Only parallelize independent tool calls
8. **Validate before acting** - Permission checks before execution

## Common Pitfalls

| Pitfall | Problem | Solution |
|---|---|---|
| **Runaway loops** | Agent keeps calling tools without progress | Track tool call history, detect loops, add circuit breaker |
| **Context bloat** | Too much history, slow and expensive | Summarize old turns, prune irrelevant files |
| **Blind execution** | Running dangerous commands without checking | Permission system, dry-run mode |
| **Lost state** | Crash loses progress | Checkpointing after each turn/tool batch |
| **Poor recovery** | One tool failure derails everything | Try alternatives, ask user, continue if possible |

## Related Notes

- [[Harness-Architecture.md]] — Overall architecture
- [[../Core-Components/Task-Management.md]] — Planning and task tracking
- [[../Execution/Error-Recovery.md]] — Handling failures
- [[../Execution/Sub-Agents.md]] — Delegation
- [[../Core-Components/Context-Builder.md]] — Building context

## Sources

* ReAct paper (Yao et al., 2022)  
* Plan-and-Solve (Wang et al.)  
* Anthropic - Building Effective Agents  
* OpenAI Agents SDK patterns  
* LangGraph agent patterns  
