Warren UI

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.json

Usage

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().

On this page