Trace a Tool Call and Session
Exercise objective
Trace one read_file Tool Call and observe how data changes across the Provider response, ToolRegistry, checkpoint, next model input, and final Session.
Prerequisites
- Complete the previous Tool-free Turn exercise.
- Understand the OpenAI function schema.
- Use a separate lab workspace.
Source to read
nanobot/agent/tools/filesystem.py::ReadFileToolnanobot/agent/tools/registry.py::ToolRegistry.executenanobot/agent/runner.py::_execute_toolsnanobot/agent/runner.py::_run_toolnanobot/agent/runner.py::_emit_checkpointnanobot/agent/loop.py::_state_savetests/agent/test_runner_tool_execution.pytests/agent/test_runner_persistence.py
Predict before running
- What shape does the Tool Call have in the first Provider response?
- Under which role is the tool result appended to messages?
- Is the complete Session persisted immediately after Tool execution?
- Which messages appear in the second Provider request but not the first?
- Does the user receive both the raw tool result and a natural-language answer?
Procedure
1. Prepare a read-only fixture
$nanobotLab = Join-Path $env:TEMP "nanobot-learning"
$fixture = Join-Path "$nanobotLab\workspace" "turn-observation.txt"
Set-Content -LiteralPath $fixture -Encoding utf8 -Value "marker=NANOBOT_TOOL_OK"This writes only to the lab workspace; it does not modify nanobot source code.
2. Set breakpoints
- after
AgentRunner._request_model()returns; - in
_execute_tools(); - before and after validation in
ToolRegistry.execute(); - in
ReadFileTool.execute(); - in
_emit_checkpoint(); - at the next
_request_model()call; - in
_state_save().
3. Send an explicit request
python -m nanobot agent `
--config "$nanobotLab\config.json" `
--workspace "$nanobotLab\workspace" `
--session "learning:tool-call" `
--message "You must use read_file to read turn-observation.txt, then reply with the marker value only."A real model may still choose differently. If it does, preserve that observation and complete a deterministic trace with the fake Provider used in the tests.
4. Build a message-shape table
| Moment | Role | Key fields |
|---|---|---|
| Initial input | user | content |
| First Provider response | assistant | tool_calls |
| After Tool execution | tool | tool_call_id, name, content |
| Second Provider response | assistant | final content |
Do not copy the complete prompt. Record only the structure and a short summary.
5. Inspect the checkpoint
After _emit_checkpoint(), inspect the running checkpoint in Session metadata:
- phase;
- iteration;
- model;
- assistant_message;
- completed_tool_results;
- pending_tool_calls.
After a normal SAVE, determine whether that checkpoint was cleared or materialized into official history.
6. Inspect the Tool schema
Before the first Provider request, evaluate:
spec.tools.get_definitions()Find read_file and compare its schema with the arguments returned by the model.
Expected observations
sequenceDiagram participant P as Provider participant R as AgentRunner participant T as ToolRegistry participant S as Session R->>P: messages + Tool schemas P-->>R: assistant(tool_calls) R->>S: checkpoint awaiting_tools R->>T: execute read_file T-->>R: marker=NANOBOT_TOOL_OK R->>S: checkpoint tools_completed R->>P: + assistant Tool Call + tool result P-->>R: final text R-->>S: SAVE final Turn
The central conclusions are:
- Tool schemas are generated before the model request;
- Registry validates arguments again in Python;
- a tool result is the model’s observation in the next iteration, not a direct user response by default;
- checkpoints support recovery after cancellation or interruption;
- a normal SAVE writes valid messages from this Turn to the Session.
Completion criteria
- Identify the difference between messages in the two Provider requests.
- Correlate the assistant invocation and tool result through their Tool Call ID.
- Explain the difference between a checkpoint and the final Session.
- Obtain the final response
NANOBOT_TOOL_OK. - Do not modify source code.
Verification
Run the deterministic tests:
Set-Location "example\nanobot\code-EN"
python -m pytest tests\agent\test_runner_tool_execution.py -q
python -m pytest tests\agent\test_runner_persistence.py -qSingle-step through one test and compare its object shapes with the real DeepSeek invocation.
Review questions
- Why is the Tool schema both shown to the model and validated locally?
- If a Tool has already written a file when the Runner is canceled, can the checkpoint roll that write back?
- Why can the final assistant message not be omitted?
- How does an oversized tool result affect the next model request?