Available for: Python and TypeScript.
TypeScript
Installation
Four integration patterns
Choose the integration pattern that fits your setup:instrumentADK — recommended for production
instrumentADK wraps both your coordinator agent and its runner in a single call. Use this when building production ADK applications.
wrapADKRunner — runner-level wrapping
Wraps InMemoryRunner.runEphemeral() and Runner.run() by intercepting the ADK event stream. Emits one span per agent author turn, one span per tool call, and handoff spans on delegation.
wrapADKRunner options:
string
required
Display name for the root agent span in Zespan.
string
default:"coordinator"
Role hint for the agent registry. Use
"coordinator" for orchestrators and "specialist" for sub-agents.string
The model name used by the root agent. Shown in the trace detail panel.
string
Associates all spans from this run with a session in the Sessions view.
Record<string, string> | (agentName: string) => Record<string, string>
Extra key-value metadata merged into each span’s
metadata, for example the routing surface or tier an agent runs on. Pass a function to give each agent its own values. wrapADKAgent accepts it too and passes it to sub-agents.wrapADKAgent reads the model from the agent’s model — a string, or an ADK BaseLlm instance (its model id is used). Per-call spans record the model that actually answered when the response reports a modelVersion, for example after a failover to another model.ZespanADKCallbackHandler — native ADK callbacks
Uses ADK’s built-in callback system (beforeAgentCallback, afterModelCallback, etc.). Create one handler instance and spread .callbacks into your LlmAgent config. Captures agent spans, LLM spans with full token counts, and tool call spans.
handler.callbacks includes.
For multi-agent systems, use the same handler instance across all agents so spans share the same trace:
ZespanADKCallbackHandler is also exported as ADKCallbackHandler for shorter imports:
wrapADKAgent — agent-level wrapping
Wraps agent.run() directly. Best for unit tests and simple scripts. Recursively wraps subAgents by default.
What gets captured
All three wrappers capture the same data from the ADK event stream:Capture v2 (off by default)
Turn oncapture_v2=True (Python) or captureV2: true (TypeScript), or set ZESPAN_CAPTURE_V2=1, and ZespanADKCallbackHandler also records what the trace checks read:
- Tool results as JSON (redacted before they are cut), instead of a text copy of an object. An empty result (
None,[],{}) is kept and marked empty, and a result cut at 10,240 characters is marked as cut. - Tool definitions the model was offered, with parameter schemas, and the model’s requested tool calls with their ids, so a request can be matched to the tool span that ran it, and a request for a tool that does not exist (which ADK refuses before any tool runs) can be seen.
- The conversation as structured messages (text, function calls and function responses with roles), instead of one block of
role: textlines, plus the system instructions and the output schema. - Agent text: each agent span carries the text its agent received and the last text it produced, so an answer written by a sub-agent after a transfer is found. Each agent span’s
parent_agent_idis its direct parent. - A small marker per span saying which of these were captured, absent, cut or unavailable.
ZESPAN_CAPTURE_V2=0 turns it off. Upgrade note: older versions of the handler stored tool results as text copies of Python objects; with v2 on, new traces store JSON. See Capture fields.
Agent steps and handoffs
ZespanADKCallbackHandler records on each agent span the number of model calls the agent made (zespan.agent.step), how many sub-agents it could hand to (zespan.agent.route_candidates) and, when the model asked to transfer to another agent, zespan.agent.stop_reason: handoff with the target in zespan.agent.route. wrapADKRunner and, in Python, wrap_adk_agent record a handoff span when work passes from one agent to another (in Python, when a wrapped agent runs inside another wrapped agent; the span carries both agents’ names). See Agent steps.
Tool calls join the tool’s trace
With the callback handler, a model, MCP or HTTP call made inside a tool belongs to the tool’s span and to the run’s trace: the handler makes the tool’s span the current context inbeforeToolCallback / before_tool_callback and restores it in the after callback. In Python, a tool that raises is handled by on_tool_error_callback, which is included in handler.callbacks when your ADK version has that callback. In TypeScript the plugin (plugins: [handler.plugin]) does this for a tool that throws, because ADK for TypeScript calls its error hook only on plugins. Tools running in parallel each see their own span.
Prompt storage off
WithstorePrompts: false (TypeScript) or store_prompts=False (Python), the Google ADK integration sends no content from your agents — the same in both SDKs:
- No prompt or completion text
- No tool-call arguments, tool results, or the model’s decision rationale
- On an agent error event, only the error class name (for example
RateLimitError) instead of the provider’s error text, which can quote the prompt. The error is still classified.
Python
Installation
Three integration patterns
ZespanADKCallbackHandler — native ADK callbacks
Uses ADK’s built-in callback system. Create one handler and spread .callbacks into each LlmAgent constructor. Captures agent spans, LLM spans with full token counts, and tool spans.
ADK Python is async — run agents with InMemoryRunner inside asyncio.run().
Single agent:
invocation_id across coordinator and sub-agents, so all spans are automatically linked under one trace.
dict or any JSON-serializable value.
ZespanADKTracer — attach to an existing agent
Pass your ADK agent to ZespanADKTracer after creating it. The tracer intercepts agent.run to capture every model call, tool invocation, and agent session as hierarchical spans.
wrap_adk_agent — callback-handler style
wrap_adk_agent is the functional equivalent: it attaches tracing and returns the same agent. Use this when you want a one-liner or are composing agents inline.
ZespanADKTracer and wrap_adk_agent accept an optional guardrails argument:
Multi-agent systems
Attach
ZespanADKTracer (or call wrap_adk_agent) after the agent is fully configured. Attaching before sub_agents are set means sub-agent spans won’t be linked correctly.How multi-agent traces look in the dashboard
A coordinator + specialist ADK run produces a trace like this:
Session and user context
To associate ADK traces with a user session for the Sessions dashboard view, setsessionId and userId in the wrapper options (TypeScript) or via with_zespan_context (Python):
- TypeScript
- Python
Next steps
- Capture fields — what each check reads and which switch controls it.
- MCP — tool spans from an ADK MCP toolset carry the tool and server name, and the calls the toolset makes through the MCP client are traced.
- Agent tracing — add agent identity, tool roles and approvals.

