AgentTrace
Hierarchical span tree with collapsible detail records, an optional duration timeline, and a span inspector pane.
- run
- r-42
- model
- claude-sonnet-4-6
Source
"use client"
import { useState } from "react"
import { AgentTrace } from "@/registry/warren/agent-trace/agent-trace"
import type { SpanNode } from "@/registry/warren/agent-trace/agent-trace"
const spans: SpanNode[] = [
{
id: "agent",
kind: "agent",
name: "MER-7 SUPERVISOR",
status: "error",
startMs: 0,
durationMs: 4200,
tokensIn: 15200,
tokensOut: 940,
costUsd: 0.0412,
detail: { meta: { run: "r-42", model: "claude-sonnet-4-6" } },
children: [
{
id: "plan",
kind: "llm",
name: "PLAN",
status: "ok",
startMs: 10,
durationMs: 800,
tokensIn: 12400,
tokensOut: 340,
detail: {
input: "Roll back billing-api to the last green release.",
output: "3 steps: snapshot → rollout undo → verify probes",
},
children: [
{
id: "snapshot",
kind: "tool",
name: "KUBECTL.SNAPSHOT",
status: "ok",
startMs: 850,
durationMs: 600,
detail: {
input: "kubectl argo rollouts get billing-api",
output: "revision 41 captured",
meta: { namespace: "prod" },
},
},
{
id: "undo",
kind: "tool",
name: "KUBECTL.ROLLOUT.UNDO",
status: "error",
startMs: 1500,
durationMs: 1200,
detail: {
error: "CrashLoopBackOff after revision 40 promoted",
input: "kubectl argo rollouts undo billing-api",
meta: { revision: "40", replicas: "4" },
},
children: [
{
id: "guardrail",
kind: "guardrail",
name: "POLICY.CHECK",
status: "skipped",
startMs: 2700,
},
],
},
],
},
{
id: "runbooks",
kind: "retrieval",
name: "RUNBOOKS",
status: "running",
startMs: 2800,
},
{
id: "eval",
kind: "eval",
name: "POSTMORTEM.DRAFT",
status: "skipped",
startMs: 4100,
},
],
},
]
export default function AgentTraceDemo() {
const [activeId, setActiveId] = useState<string | undefined>("agent")
return (
<div className="w-full max-w-2xl">
<AgentTrace data={spans} activeId={activeId} onSpanSelect={setActiveId} />
</div>
)
}
Installation
npx shadcn@latest add https://warren.eduard3v.com/r/agent-trace.jsonUsage
import { AgentTrace } from "@/components/ui/agent-trace"<AgentTrace data={spans} activeId={id} onSpanSelect={setActiveId} />Structure
The execution-explorer surface for agent runs: a role="tree" of nested spans
(agent → llm → tool/retrieval/guardrail/eval) with a detail pane for the selected
span. Each row is a real pair of buttons — a +/− disclosure and the row itself
for selection — separated by hairline indent guides, one per nesting level. The
status dot is the only saturated ink: success/error/warning/muted by span status,
pulsing while running (reduced-motion gated).
Rows fold the collapsible tool-call record idiom: any span with a detail payload
(input/output/error/meta) is expandable in place, errors rendered in the danger
text grade. defaultExpandDepth (default 1) keeps roots open and deeper spans
folded; expansion is uncontrolled state over the initial set.
Timeline and inspector
Source
"use client"
import { AgentTrace } from "@/registry/warren/agent-trace/agent-trace"
import type { SpanNode } from "@/registry/warren/agent-trace/agent-trace"
const spans: SpanNode[] = [
{
id: "pipeline",
kind: "agent",
name: "INGEST.PIPELINE",
status: "ok",
startMs: 0,
durationMs: 9600,
children: [
{
id: "fetch",
kind: "retrieval",
name: "S3.FETCH",
status: "ok",
startMs: 100,
durationMs: 1800,
tokensIn: 8200,
},
{
id: "embed",
kind: "llm",
name: "EMBED.BATCH",
status: "ok",
startMs: 2000,
durationMs: 2600,
tokensIn: 21400,
tokensOut: 0,
costUsd: 0.0086,
},
{
id: "index",
kind: "tool",
name: "VECTOR.UPSERT",
status: "ok",
startMs: 4700,
durationMs: 3100,
detail: { output: "12,480 vectors upserted", meta: { collection: "runbooks" } },
},
{
id: "verify",
kind: "eval",
name: "RECALL.CHECK",
status: "running",
startMs: 7900,
tokensIn: 900,
},
],
},
]
export default function AgentTraceTimeline() {
return (
<div className="w-full max-w-2xl">
<AgentTrace data={spans} defaultExpandDepth={1} showTimeline activeId="index" />
</div>
)
}
Pass showTimeline to draw a duration bar along each row's bottom edge — a muted
track for the full trace window with a *-soft wash positioned by startMs and
sized by durationMs. The right-hand inspector (drop with showInspector={false})
shows the selected span's kind, status, duration, cost, token counts, and full
detail payload.
Keyboard
Rows follow the Tabs roving precedent: ArrowUp/ArrowDown step between visible
rows, Home/End jump to the ends. Selection is aria-selected on the treeitem;
expandable rows carry aria-expanded.
API Reference
Prop
Type
Prop
Type
Prop
Type
Pure helpers
spans.ts exports the tree math for testing and reuse: flattenSpans() (depth-first
pre-order with depth annotation), visibleSpans() (subtree-aware visibility),
collapsedAtDepth() (initial fold set), traceWindow()/spanBar() (timeline
geometry), statusTone(), and the mono formatters fmtDuration()/fmtTokens().