# Agent Step Timeline

Agent Step Timeline [#agent-step-timeline]

The **AgentStepTimeline** is a vertical timeline of ReAct agent steps. Each step is a collapsible card (color-coded tool badge via an optional `toolColorMap`, formatted args, observation with show-more, index, elapsed-ms). A `finish` step renders a success-styled final-answer card; the timeline auto-scrolls, shows a "Thinking…" row while running, and a terminal finish-reason badge (`max_steps` / `timeout` / `loop_detected` / `error`). It supports nested sub-agent/handoff rendering. Data source: `useAgent`.

Preview [#preview]

```tsx
'use client';

/**
 * @file agent-step-timeline-demo.tsx
 * @description Docs preview for `AgentStepTimeline`. Renders a finished ReAct run
 * (shaped like `useAgent().steps`) with a tool color map, a nested sub-agent
 * handoff, durations, and a distinguished final answer.
 */
import {
  AgentStepTimeline,
  type AgentStep,
  type ToolColorMap,
} from '@/components/agent-step-timeline';

const TOOL_COLORS: ToolColorMap = {
  search_documents: 'bg-blue-500/15 text-blue-600 dark:text-blue-400',
  calculator: 'bg-purple-500/15 text-purple-600 dark:text-purple-400',
};

const STEPS: AgentStep[] = [
  {
    index: 0,
    type: 'tool_call',
    toolName: 'search_documents',
    toolArgs: { query: 'quarterly revenue', topK: 5 },
    observation:
      'Retrieved 5 passages. The strongest match reports Q3 revenue of $4.2M, up 18% YoY, driven by enterprise seat expansion and lower churn across the SMB segment.',
    durationMs: 740,
  },
  {
    index: 1,
    type: 'tool_call',
    toolName: 'calculator',
    toolArgs: { expression: '4.2 * 1.18' },
    observation: 'Computed projected next-quarter figure.',
    durationMs: 12,
    subSteps: [
      {
        index: 0,
        type: 'tool_call',
        toolName: 'search_documents',
        toolArgs: { query: 'guidance' },
        observation: 'Sub-agent fetched guidance notes.',
        durationMs: 210,
      },
    ],
  },
  {
    index: 2,
    type: 'finish',
    result: 'Q3 revenue was $4.2M (+18% YoY); next-quarter projection ≈ $4.96M.',
  },
];

export default function AgentStepTimelineDemo() {
  return (
    <div className="w-full max-w-xl">
      <AgentStepTimeline
        steps={STEPS}
        finishReason="finish"
        toolColorMap={TOOL_COLORS}
      />
    </div>
  );
}
```

Installation [#installation]

```bash
npx shadcn@latest add @localmode/ui/conversation/agent-step-timeline
```

Data source & dependencies [#data-source--dependencies]

**Data source:** renders the agent-step shape (`steps`, `isRunning`, run result) you pass — works with any backend. Recommended producer: `useAgent` from `@localmode/react` (on-device, optional).

* `clsx` + `tailwind-merge` — via the shared `cn()` util (installed automatically as a registry dependency)

Files installed [#files-installed]

* `agent-step-timeline.tsx` — `AgentStepTimeline` + `AgentStepCard`
* `lib/utils.ts` — the `cn()` helper (if not already present)

Props [#props]

**AgentStepTimeline**

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `steps` | `array` | — | **Required.** The agent steps (e.g. `useAgent().steps`). |
| `isRunning` | `boolean` | — | Whether the agent loop is still running (e.g. `useAgent().isRunning`). |
| `finishReason` | `"error" \| "aborted" \| "loop_detected" \| "timeout" \| "max_steps" \| "finish"` | — | Terminal reason once the run ends. |
| `toolColorMap` | `ToolColorMap` | — | Optional per-tool badge colors. |
| `autoScroll` | `boolean` | `true` | Auto-scroll to the newest step while running. |

Examples [#examples]

Drive a live ReAct loop [#drive-a-live-react-loop]

```tsx
import { useAgent } from '@localmode/react';
import { AgentStepTimeline } from '@/components/agent-step-timeline';

const { steps, isRunning, result } = useAgent({ model, tools });

<AgentStepTimeline steps={steps} isRunning={isRunning} finishReason={result?.finishReason} />
```

Customization [#customization]

Pass a `toolColorMap` (`{ toolName: "tailwind classes" }`) to color tool badges. Each step may carry `subSteps` for nested sub-agent runs, which render indented inside the parent step.

These primitives are presentational and hook-driven: they render props and emit callbacks, holding only local view state. The orchestration state (e.g. `useAgent`) lives in your app. Every surface uses shadcn/ui CSS-variable utilities, so it inherits your theme — restyle the copied file freely.

Accessibility [#accessibility]

Each expandable step is a real disclosure: the toggle carries `aria-expanded` (reflecting open/closed) and, when open, `aria-controls` pointing at the revealed detail region's id, so assistive tech announces the collapse state and the relationship. Finish steps that have no collapsible body omit `aria-expanded` rather than exposing an inert toggle.