# Trace Summarization

How to fetch a trace, walk its span tree, and produce a free-form natural-language summary of what happened. The goal is a synthesized narrative, not a raw dump of span data.

---

## Fetching Trace Data

Use the `adk traces` CLI with filters to get the raw data.

```bash
# Full trace with LLM reasoning included
adk traces trace=<trace-id> --include-llm --format json

# All traces for a conversation
adk traces conversation=<id> --include-llm --format json

# Recent traces (start here if you don't have an ID)
adk traces --include-llm --format json
```

**Always pass `--include-llm`** when summarizing. Without it, `think` spans are omitted and you lose the model's reasoning, which is essential for explaining *why* the agent did what it did.

**Always pass `--format json`** for structured, parseable output.

---

## Reading the Span Tree

Traces contain a flat list of spans, but spans form a parent-child hierarchy via `parentSpanId`. To summarize effectively, reconstruct the tree.

### Span hierarchy (typical)

```
handler.conversation (or handler.workflow, handler.action)
  └─ autonomous.execution
       └─ autonomous.iteration (one per LLM turn)
            ├─ cognitive.request (the LLM call)
            ├─ think (model reasoning)
            ├─ tool_call (tool invocation)
            │    └─ autonomous.tool (tool execution detail)
            ├─ tool_call (another tool)
            ├─ code_execution_exception (if something broke)
            └─ end (turn complete)
```

### How to walk it

1. **Find the root span** -- the span with no `parentSpanId`, or the handler span (`handler.conversation`, `handler.workflow`, `handler.action`). This tells you what triggered the trace.
2. **Walk children in chronological order** by `startTime`. Each child span is a step in the agent's behavior.
3. **Group by iteration** -- `autonomous.iteration` spans each represent one LLM turn. Within each iteration, look for the `think` -> `tool_call` -> `end` sequence.
4. **Follow errors upward** -- if a `code_execution_exception` or failed `tool_call` appears, check its parent iteration and the subsequent iteration to see how the agent recovered (or didn't).

### Key fields per span type

| Span Type | Fields to Read | What They Tell You |
|-----------|---------------|-------------------|
| `handler.conversation` | `context.conversationId`, `context.userId` | What triggered the trace (incoming message) |
| `handler.workflow` | `name`, `context` | Which workflow was invoked |
| `handler.action` | `name`, `context` | Which action was called |
| `autonomous.iteration` | `data.iterationIndex` | Which LLM turn this is (0-indexed) |
| `cognitive.request` | `data.model`, `data.tokens` | Which model was used, token counts |
| `think` | `data.content` | The LLM's reasoning -- why it chose an action |
| `tool_call` | `data.tool_name`, `data.input`, `data.output`, `status`, `data.error` | What tool was called, with what, and what happened |
| `code_execution_exception` | `data.message`, `data.stackTrace` | Runtime error in the LLMz sandbox |
| `end` | `data.response` | What the agent said back to the user |

---

## Producing a Summary

Do **not** use a fixed template. Write a natural-language narrative that reads like a concise incident report or activity log. Cover these aspects in whatever order makes the most sense for the specific trace:

### What to cover

1. **The trigger** -- What started this trace? An incoming user message? A workflow invocation? A scheduled trigger? Extract this from the root span type and context.

2. **The LLM's plan** -- What did the model decide to do and why? Synthesize from `think` spans. Don't quote them verbatim unless a specific phrase is important -- paraphrase the reasoning.

3. **Tool calls and their outcomes** -- Which tools were called, with what key inputs, and what happened? For successful calls, note what was returned if relevant. For failures, state the error clearly.

4. **Errors and recovery** -- Were there exceptions? Did the agent retry or give up? What was the error message? If the agent recovered, explain how.

5. **The outcome** -- What was the final result? What did the agent respond with? Did the conversation turn succeed or fail?

6. **Performance** -- Only mention if relevant (e.g., unusually slow, many iterations, high token usage). Don't include timing details for normal traces.

### Adapting depth to context

The summary depth should match what the developer is asking:

| Developer Question | Summary Depth |
|-------------------|---------------|
| "What happened?" / "Summarize this trace" | **Brief** -- 3-5 sentences covering trigger, actions taken, outcome |
| "Why did it do X?" / "Why did the bot call tool Y?" | **Focused** -- Zoom into the relevant `think` span and the tool call, explain the reasoning chain |
| "What went wrong?" / "Why did this fail?" | **Diagnostic** -- Focus on the error path: what led to the failure, what the error was, whether recovery was attempted |
| "Walk me through the whole trace" | **Detailed** -- Full chronological narrative covering every iteration and tool call |

---

## Examples

### Sample trace data (abbreviated)

```json
{
  "traceId": "tr_01J5EXAMPLE",
  "spans": [
    {
      "spanId": "sp_001",
      "name": "handler.conversation",
      "startTime": "2026-04-21T14:00:00.000Z",
      "endTime": "2026-04-21T14:00:03.200Z",
      "status": "ok",
      "context": {
        "conversationId": "conv_abc123",
        "userId": "user_xyz"
      }
    },
    {
      "spanId": "sp_002",
      "parentSpanId": "sp_001",
      "name": "autonomous.execution",
      "startTime": "2026-04-21T14:00:00.050Z",
      "endTime": "2026-04-21T14:00:03.100Z",
      "status": "ok"
    },
    {
      "spanId": "sp_003",
      "parentSpanId": "sp_002",
      "name": "autonomous.iteration",
      "startTime": "2026-04-21T14:00:00.100Z",
      "endTime": "2026-04-21T14:00:02.800Z",
      "status": "ok",
      "data": { "iterationIndex": 0 }
    },
    {
      "spanId": "sp_004",
      "parentSpanId": "sp_003",
      "name": "think",
      "startTime": "2026-04-21T14:00:00.200Z",
      "data": {
        "content": "The user is asking for the status of order #4521. I should look this up using the lookupOrder tool with the order ID."
      }
    },
    {
      "spanId": "sp_005",
      "parentSpanId": "sp_003",
      "name": "tool_call",
      "startTime": "2026-04-21T14:00:00.500Z",
      "endTime": "2026-04-21T14:00:01.200Z",
      "status": "ok",
      "data": {
        "tool_name": "lookupOrder",
        "input": { "orderId": "4521" },
        "output": { "status": "shipped", "trackingNumber": "1Z999AA10123456784", "estimatedDelivery": "2026-04-23" }
      }
    },
    {
      "spanId": "sp_006",
      "parentSpanId": "sp_003",
      "name": "end",
      "startTime": "2026-04-21T14:00:02.800Z",
      "data": {
        "response": "Your order #4521 has been shipped! Tracking number: 1Z999AA10123456784. Estimated delivery: April 23rd."
      }
    }
  ]
}
```

### Brief summary ("What happened?")

> The user asked about order #4521. The agent looked it up with `lookupOrder`, found it was shipped with tracking number 1Z999AA10123456784 and an estimated delivery of April 23rd, and relayed that information to the user. Completed in one iteration, ~3 seconds.

### Sample trace with an error (abbreviated)

```json
{
  "traceId": "tr_01J5FAILURE",
  "spans": [
    {
      "spanId": "sp_010",
      "name": "handler.conversation",
      "startTime": "2026-04-21T15:00:00.000Z",
      "endTime": "2026-04-21T15:00:08.500Z",
      "status": "error",
      "context": {
        "conversationId": "conv_def456",
        "userId": "user_xyz"
      }
    },
    {
      "spanId": "sp_011",
      "parentSpanId": "sp_010",
      "name": "autonomous.execution",
      "startTime": "2026-04-21T15:00:00.050Z",
      "endTime": "2026-04-21T15:00:08.400Z",
      "status": "error"
    },
    {
      "spanId": "sp_012",
      "parentSpanId": "sp_011",
      "name": "autonomous.iteration",
      "startTime": "2026-04-21T15:00:00.100Z",
      "endTime": "2026-04-21T15:00:04.000Z",
      "status": "error",
      "data": { "iterationIndex": 0 }
    },
    {
      "spanId": "sp_013",
      "parentSpanId": "sp_012",
      "name": "think",
      "startTime": "2026-04-21T15:00:00.200Z",
      "data": {
        "content": "The user wants to cancel order #7890. I'll use the cancelOrder tool."
      }
    },
    {
      "spanId": "sp_014",
      "parentSpanId": "sp_012",
      "name": "tool_call",
      "startTime": "2026-04-21T15:00:00.500Z",
      "endTime": "2026-04-21T15:00:02.000Z",
      "status": "error",
      "data": {
        "tool_name": "cancelOrder",
        "input": { "orderId": "7890" },
        "error": "OrderService: Cannot cancel order in 'shipped' status"
      }
    },
    {
      "spanId": "sp_015",
      "parentSpanId": "sp_011",
      "name": "autonomous.iteration",
      "startTime": "2026-04-21T15:00:04.100Z",
      "endTime": "2026-04-21T15:00:08.000Z",
      "status": "ok",
      "data": { "iterationIndex": 1 }
    },
    {
      "spanId": "sp_016",
      "parentSpanId": "sp_015",
      "name": "think",
      "startTime": "2026-04-21T15:00:04.200Z",
      "data": {
        "content": "The cancelOrder tool failed because the order is already shipped. I should inform the user that shipped orders cannot be cancelled and suggest they initiate a return instead."
      }
    },
    {
      "spanId": "sp_017",
      "parentSpanId": "sp_015",
      "name": "end",
      "startTime": "2026-04-21T15:00:07.900Z",
      "data": {
        "response": "I wasn't able to cancel order #7890 because it has already shipped. You can initiate a return once it arrives — would you like me to help with that?"
      }
    }
  ]
}
```

### Diagnostic summary ("What went wrong?")

> The user asked to cancel order #7890. The agent called `cancelOrder` but it failed with "Cannot cancel order in 'shipped' status" -- the order was already shipped. In the second iteration, the agent recognized the failure, informed the user that shipped orders can't be cancelled, and suggested initiating a return instead. The agent handled the error gracefully; this is expected behavior for an already-shipped order, not a bug.

### Focused summary ("Why did it suggest a return?")

> After `cancelOrder` failed with a "shipped" status error, the agent's reasoning (iteration 1 `think` span) explicitly noted that shipped orders can't be cancelled and decided to suggest a return as an alternative. This came from the model's own reasoning, not from the tool output or instructions -- it inferred the next-best action based on the error context.

---

## Patterns

✅ **Synthesize, don't transcribe**

```
Good: "The agent looked up the order, found it was shipped, and told the user."
Bad:  "Span sp_004 is a think span with content 'The user is asking...' then span sp_005 is a tool_call to lookupOrder with input orderId=4521..."
```

✅ **Name tools and key values**

```
Good: "Called `lookupOrder` with orderId '4521', got status 'shipped'."
Bad:  "A tool was called and it returned some data."
```

✅ **Explain causation, not just sequence**

```
Good: "The cancelOrder call failed because the order was already shipped, so the agent suggested a return instead."
Bad:  "cancelOrder failed. Then the agent said to try a return."
```

✅ **Flag what matters for the developer's question**

```
Good (for "why did it fail?"): "The root cause is that cancelOrder doesn't handle shipped orders -- it throws instead of returning an error object."
Bad:  Giving a full trace walkthrough when the developer only asked about the failure.
```

❌ **Don't dump raw JSON or span IDs in the summary**

Span IDs and raw field values are debugging artifacts. The summary is for understanding, not for grep. Reference tool names, error messages, and key data values instead.

❌ **Don't speculate beyond the trace data**

If the trace doesn't show why something happened, say so. Don't invent explanations.

❌ **Don't include timing unless it's notable**

A 3-second conversation turn is normal. A 45-second turn with 12 iterations is worth calling out.
