Why loops, and why now — a 1966 proof
Before the anti-pattern, why this became a problem now.
In the early days of computing, programming languages were multiplying and people argued over whose language could do more. In 1966 Corrado Böhm and Giuseppe Jacopini ended the argument with a proof: any computation needs only three things. Executing statements in sequence, branching on a condition, and looping.
Map that onto AI today and the picture sharpens. Firing off a prompt and getting an answer is sequence. Branching on a condition is something many people already do. But the loop was missing — feeding the answer back in, getting another, feeding it back again.
Part of why agents feel different is that models got better, but structurally it is the moment that third piece got filled in. And the new mistake that appeared the moment loops did is this anti-pattern.
A misconception to clear first — an LLM cannot execute tools

We say "the AI searched the web" or "the AI read the file" all the time, and taken literally that is not true.
An LLM cannot do anything except predict the next word probabilistically. Hand it a tool and it still cannot run it. All it can do is tell you, very intelligently, "call this tool with these values."
Your code is what actually calls it. Hitting the search API, opening the file, taking the result and handing it back to the model — all of that is on your side.
This distinction matters because it is where the fact that a model has several reasons to stop comes from. Stopping because it finished, stopping to ask for a tool, and stopping because it hit a length cap are three different events that all look like "a response arrived."
stop_reason — three branches
So when a response arrives you do not start with the body; you look at a field called stop_reason. Why the model stopped is written there.
| stop_reason | What it means | What your code does |
|---|---|---|
| tool_use | Stopped to ask for a tool call | Run the tool, append the result, loop once more |
| end_turn | Stopped because it finished | Exit the loop and use the answer |
| max_tokens | Cut off at the length cap | Not a finished answer — re-request or fail |
What the loop looks like
In code it is short. Call the model inside a while loop, branch on stop_reason, and on tool_use continue for another pass.
The line worth noticing is that running the tool sits outside the model call. The model decides what to call; your code does the calling.
while True:
resp = client.messages.create(
model="claude-opus-5",
messages=messages,
tools=tools,
)
# Look at why it stopped before using the answer
if resp.stop_reason == "tool_use":
result = run_tool(resp) # your code runs the tool
messages.append(result) # feed it back, go around again
continue
if resp.stop_reason == "max_tokens":
raise RuntimeError("truncated — do not treat this as a finished answer")
break # end_turn: exit
The third case is the dangerous one — a truncated answer does not look truncated

Miss tool_use and the agent simply stops doing anything, so you notice fast. The problem is max_tokens.
When the model stops because it ran out of tokens, a response still comes back — and as prose it reads fine. Cut off mid-way, the last sentence just ends awkwardly; no marker saying "truncated here" arrives with the body.
So without checking stop_reason you take it for a finished answer and use it. You asked for ten items, got six, and the six flow straight into the next step. This is where things go wrong quietly.
There is a version of this for people who do not write code. If a long table or list from a chatbot ends half-way, that is probably the length cap rather than the limit of what the model knew. Type "continue" and the rest comes out.
After the loop exits — where the human belongs
Exiting on end_turn is also where a human belongs.
The talk says to check confidence at that point. If the result looks good, keep it; if not, escalate. You define the end of the automation not as "fully automatic" but as "automatic plus a handoff condition."
Without that condition, the agent produces an answer even when it is unsure — because it fills the gap plausibly instead of stopping to say it does not know.
One thing to try today
If you write code, check whether you look at stop_reason where you receive the model's response. If not, add the max_tokens branch first. That one line turns a quiet failure into a loud one.
If you do not write code, think back to answers that ended half-way recently. That was probably a length cap rather than the model's limit. Next time, type "keep going" first.
The next post is the last one: why a million-token window does not mean you should fill it.
