Debugging the Agent Transcript
Explore debugging techniques for the Claude Client SDK agent loop by implementing structured logging that captures API calls, stop reasons, tool inputs, and results. Understand how to read annotated transcripts to identify where and why failures occur in multi-turn AI agent loops.
The loop from the previous lessons works, but when it breaks, there is nothing to inspect. The messages array changes on every iteration, tool calls come and go, and errors surface only as wrong output or silent None returns. Without visibility into what happened between the first API call and the final answer, debugging is guesswork.
In this lesson, we instrument the loop with structured logging that prints state at each decision point. We then use that output to trace a failing run and identify the exact turn where it went wrong.
By the end of this lesson, we will have:
A logging helper that formats message-array turns in human-readable form
Turn-level log output for every API call, stop reason, tool call, and tool result
A failing transcript annotated to show where and why it breaks
A methodology for reading agent transcripts that applies to any loop
What to log and why
A loop produces four types of events worth capturing, each at a different moment in the iteration:
Event | When It Fires | What to Capture |
API call | Before | Turn count, message count, input token estimate |
Stop reason | After the response arrives |
|
Tool dispatch | Before each tool function runs | Tool name, input arguments |
Tool result | After each tool function returns | Tool name, result string (truncated if long) |
These four points cover the full life cycle of one iteration. Any failure in the loop, wrong stop reason handling, missing tool result, ID mismatch, or truncation will be visible in at least one of these log lines.
The logging helper
Rather than scattering print() calls throughout the loop, we write one helper that formats any event as a consistent, scannable line:
import jsondef log(event: str, **kwargs) -> None:parts = [f"[{event}]"]for key, value in kwargs.items():if isinstance(value, (dict, list)):parts.append(f"{key}={json.dumps(value, default=str)[:120]}")else:parts.append(f"{key}={value}")print(" ".join(parts))
Line 1: ...