toolcall() ← all concepts

// concept · agents

An AI agent is just a loop.

Think, act, observe, repeat. Strip the buzzword off and an agent is a model calling tools in a loop until the job is done — here's the mechanism, and the question everyone asks second: when does it stop?

// the assumption

"Agent" sounds like a different kind of model — something with memory, autonomy, a will of its own. So when one misbehaves, the instinct is to reach for a bigger model.

# what we picture [ AGENT ] = some smarter, self-directed thing

The reality: a loop

An agent is a language model, running in a loop, with tools. It looks at the goal and everything that's happened so far. It picks one action — usually a tool call: run the tests, read a file, search the web. The tool runs, the result is appended back into its context. Then it goes again. Think, act, observe. Think, act, observe.

That's not a simplification for the video. Anthropic's own engineering write-up defines agents essentially this way: models using tools in a loop, directing their own process based on feedback from the environment. The pattern has a name in the literature too — ReAct (Reason + Act), which interleaves reasoning traces with actions and observations.

# the whole thing while not done: action = model(context) # think result = run(action) # act context += result # observe

The model is stateless

Here's the part most people miss. The model doesn't remember the last turn. Its weights don't change as it works; every call conditions only on the context you hand it. The loop and its growing context are the memory.

# where the state actually lives model stateless # same weights every call context the memory # grows one observation per lap
Nuance, not a contradiction. Providers bolt on conveniences — conversation storage, prompt caching, external memory stores. All of those live outside the model, which is exactly the point: something else is holding the state.

So when does the loop stop?

This is the question that follows about four seconds after "an agent is a loop" — and the fear behind it is always the same: what if it runs forever?

The agent decides. Every response comes back as one of two things: "I want to call a tool," or "I'm done." In the Claude API that's the stop_reason field — tool_use versus end_turn. Your code just reads the flag. Tools don't end the loop; they hand back a result and the model decides what to do with it.

while True: response = model(context) if response.stop_reason == "end_turn": # it's done break context += run(response.tool_calls) if laps > MAX_LAPS: # your guard, not a tool's break

The runaway guard belongs in your code, not in a tool's return value — a plain iteration cap around the loop. But there's a catch worth knowing: a cap like that is invisible to the model. It doesn't know it's about to be cut off, so it gets guillotined mid-thought.

Hidden cap vs. visible budget. If you want the agent to plan around a limit, you have to show it one. That's the idea behind task budgets: hand the model a token budget for the whole loop and let it watch the countdown, so it prioritises and wraps up gracefully instead of stopping mid-sentence. A hard cap protects you; a visible budget changes the agent's behaviour.

Do you even need an agent?

The related trap is over-reaching for one. If the order of steps is fixed and you already know it, that's a workflow, not an agent — write it as ordinary code. It's cheaper, deterministic, and far easier to debug. Anthropic draws exactly this line: workflows follow predefined code paths; agents direct their own process. Reach for the loop only when the path genuinely can't be specified up front.

And don't hard-code a graph of which tool follows which. What actually pays off is writing tool descriptions that say when to reach for a tool, not just what it does — that's the lever on tool choice.

fixed, known order -> workflow # just write the code path unknown upfront -> agent # let the loop figure it out

When it breaks, debug the loop

Because the model is stateless and the loop carries everything, most agent failures are loop failures. A tool returned an error the model never saw properly. The context grew until the important instruction got buried. Nothing told it when to stop. Reaching for a bigger model first skips over all of that.

# check these before blaming the model tool result # did it come back usable, or as a silent error? context # is the key instruction still findable in the pile? stop signal # is there anything telling it "done"?
Related: a loop that keeps piling observations into context runs into a second problem — the middle of a long context quietly stops getting read. See context rot, and the hard ceiling in context window limits.

Sources: Anthropic — Building effective agents · Yao et al. — ReAct: Synergizing Reasoning and Acting in Language Models (arXiv 2210.03629) · Claude API — handling stop reasons

One concept a week. Free.

The deeper, copy-paste version of each ToolCall short — in your inbox.

// total: 0.00 · spam: void · unsubscribe: one click