Agentic Loop

Patterns

Definition

The core pattern for AI agents: call Claude, check `stop_reason`, if `"tool_use"` execute the requested tools and append results, then call Claude again. Repeat until `stop_reason` is `"end_turn"`. The number of loop iterations is determined dynamically by task complexity.

Example Usage

while response.stop_reason == 'tool_use': execute tools, append tool_result blocks, call Claude again.

Why It Matters for the CCA-F Exam

The agentic loop is the single most-tested pattern in Domain 1 (Agentic Architecture) of the CCA-F exam. Expect scenario questions that present a broken loop implementation and ask you to identify which `stop_reason` branch is being mishandled or which tool-result format is incorrect. Memorise the full `stop_reason` value set — see [stop_reason](/glossary/stop-reason) — including `pause_turn`, `refusal`, and `model_context_window_exceeded`; partial lists are a common exam trap.

In Depth

The Heartbeat of Every Agent

Every Claude-based agent, no matter how complex, reduces to one repeating cycle: call Claude → inspect stop_reason → if tool use was requested, execute tools and return results → repeat. This loop runs until the model signals it has finished by returning stop_reason: "end_turn".

Understanding the loop is not optional for the CCA-F exam — virtually every agent architecture question builds on it.

Loop Control: The stop_reason Branch Table

After each API call, the stop_reason value dictates what the loop does next. This branch table is the loop's decision engine:

ValueMeaningLoop action
end_turnModel is doneExtract content, exit loop
tool_useModel wants a toolExecute all tool blocks, append tool_result blocks, continue
max_tokensHit output capIncrease max_tokens or summarise context, retry or abort
stop_sequenceHit a configured stop stringDecision point — handle as done or re-prompt
pause_turnServer-side tool loop pausedRe-send the messages array as-is to resume
refusalModel declined (safety)Surface to user; do not blindly retry
model_context_window_exceededInput context window fullCompact or split; distinct from max_tokens

For definitions of each value, see stop_reason.

Appending Tool Results Correctly

All tool_result blocks for a given turn must be collected into one user message. Sending them as separate messages breaks the loop because the model does not receive a properly paired response.

Why the Loop Count Is Dynamic

You cannot predict how many iterations an agent will take before it starts. The model decides how many tools to call, and each call may produce information that triggers further tool calls. This is fundamentally different from a fixed pipeline with a known number of steps. The practical implication: always set a max-iterations guard to prevent runaway loops from exhausting your context window or budget.

MAX_ITERATIONS = 20
iterations = 0

while response.stop_reason == "tool_use":
    if iterations >= MAX_ITERATIONS:
        raise RuntimeError("Agent exceeded max iterations — aborting")
    # execute tools, collect results, call Claude again
    iterations += 1

What Makes the Loop Fail Silently

The most common bugs that corrupt the loop without raising an exception:

  • Ignoring stop_reason and always reading content: When stop_reason is tool_use, the content block contains a tool call, not a final answer. Reading it as a final answer produces garbled output.
  • Sending tool results as separate messages: The model expects all results for a turn in one user message.
  • Not handling refusal: The model may decline mid-loop for safety reasons. Code that only handles end_turn will spin forever.
  • Forgetting pause_turn: Introduced for server-side tool loops; if your code does not handle it, the agent silently stalls.

For a deep dive on execution mechanics see the Agentic Loop Lifecycle concept page. The tool_use glossary entry covers parallel tool call mechanics.

Frequently Asked Questions

When `stop_reason` is `tool_use`, can there be multiple tool calls in one response?

Yes. Claude can return multiple `tool_use` content blocks in a single response (parallel tool calls). Your code must execute all of them and return all the corresponding `tool_result` blocks in a single user message. Sending them one at a time across multiple messages will cause the model to receive incomplete context and produce incorrect follow-up calls.

What is the difference between `max_tokens` and `model_context_window_exceeded` as stop reasons?

`max_tokens` fires when the *output* reaches the `max_tokens` limit you set in the request — the response was cut off mid-generation. `model_context_window_exceeded` fires when the *input* context (messages + tools + system prompt) is too large for the model to accept — the request was rejected before generation started. The fix for `max_tokens` is raising the output cap or splitting the task; the fix for `model_context_window_exceeded` is compressing or summarising the conversation history.

How do I prevent an agentic loop from running indefinitely?

Wrap the loop in a counter: track iterations and break (or raise an error) after a reasonable maximum — commonly 10–20 steps for most tasks. You can also implement a `task_budget` (beta) on newer models for a hard cap on total reasoning cost across the entire loop. Never rely on the model naturally terminating — adversarial inputs or tool errors can push models into repetitive cycles.