Multi-step reasoning with chained tool calls

A single tool call is the simple case. The interesting behaviour is when the model uses one tool's output to plan the next call. That is what makes the loop feel like an agent rather than a function.

terminal
bash
make 04-tools-agent-loop

# you> Read the file 01-simplest-bot/bot.py and tell me how many functions it defines.
#
# [tool] read_file({"path": "01-simplest-bot/bot.py"})
# [tool] (model parses content, no more tools needed)
# bot> The file defines 4 functions: ask, handle_message, run_telegram, run_cli.

Ask the agent to do something it cannot answer in one tool call. Watch which tools it picks, in what order.

Each iteration of the while-loop is one round trip with the model. The history grows: user turn, assistant turn with tool_calls, tool result, assistant turn with more tool_calls, tool result, ... eventually an assistant turn with no tool_calls.

sessions/cli-user.jsonl (excerpt)
json
{"role": "user", "content": "How many functions does 01-simplest-bot/bot.py define?"}
{"role": "assistant", "content": "", "tool_calls": [{"id": "call_a1", "type": "function", "function": {"name": "read_file", "arguments": "{\"path\": \"01-simplest-bot/bot.py\"}"}}]}
{"role": "tool", "tool_call_id": "call_a1", "content": "import os\nimport sys\n... (full file contents) ..."}
{"role": "assistant", "content": "The file defines 4 functions: ask, handle_message, run_telegram, run_cli."}

After one chained turn, this is what the session log looks like. Notice the pairing of tool_call ids with tool_call_id on the tool message.

Ordering exercise: Order the steps of a single agent-loop iteration

Loading practice…

In practice modern coding models are good at stopping when they have the answer. In production you add a max-iterations cap (say, 20) and break out if you hit it. Past that, you also want a timeout on the whole turn. The permission system coming up next incidentally makes runaway turns much less scary.

AI prompt: Try it: a real chained task

Loading practice…