A small agent loop
Every coding agent is the same loop: send messages, run whatever tools the model asks for, append the results, repeat until it stops asking. Here is that loop with two real tools, in fifty lines. Nothing is elided.
Code
agent.py
Code
What a run looks like
Code
Then SUMMARY.md exists on disk with the bullets in it.
The parts that matter
The step limit is not optional. for step in range(10) is what stops a
confused model from looping forever and eating your monthly budget. Python's
for/else runs the else branch only if the loop never broke, which is a
clean way to detect the runaway case.
Tool errors go back to the model, not up the stack. Catching the exception
and returning f"error: {err}" as the tool result lets the model recover. Pass
it a bad path and it will notice, apologise, and try the right one. Raise
instead and the whole run dies.
The assistant turn is appended before the tool results. Order matters. The API needs the turn that requested the calls to sit immediately before the messages that answer them.
max_tokens=4000. The M-series reason before emitting a tool call. Set
this low and you get an empty response with no call in it, which reads as the
agent silently doing nothing. See
Choosing a model.
Making it real
A few changes turn this from a demo into something you would actually run:
- Sandbox the paths.
read_fileandwrite_filewill happily touch anything the process can reach. Resolve every path and reject anything outside a working directory. - Cap the context. Every turn re-sends the entire message list, so a long
run costs quadratically. Truncate old tool results once the transcript gets
long. The
[:200_000]slice onread_fileis the crude version of this. - Stream the final answer. Swap the last call for
stream=Trueso the user sees output while it generates. See Streaming chat. - Handle the cap. Wrap the
createcall in the retry-and-fall-back helper from Handling the 429 cap. - Drop to
minimax-m2.5for cheap sub-tasks like classifying a file type. Keepminimax-m3for the planning turns.
The Anthropic version
If your stack speaks Anthropic Messages, the loop is the same shape with
different block names. See
Tool calling for the
stop_reason == "tool_use" form.
Related
- Tool calling: the single round trip in detail.
- Handling the 429 cap: keep long runs alive.
- Connect your coding agent: or just use an agent someone else wrote.