AgentTrace
An expandable agent trace covering step, reasoning, search, and tool forms.
Usage
Step Trace
The trace opens as it starts and folds once it settles; rows arrive in two batches. The timeline belongs to the demo — the component itself only consumes rows and working.
All Four Forms Side by Side
steps is a step row with a status glyph, reasoning is wrapping prose, search adds a query line and coloured source dots, and coding adds mono filenames with diff counters. The switch is a demo affordance — the component takes one variant and does not know it was switched.
All four variants
All four share one header and disclosure grammar; only the row form changes. Switch to compare.
Best Practices
- Treat it as a controlled primitive: keep the timeline in the host, grow
rowsand flipworking, and leave playback scripts out of the component. - Always handle
@openin search surfaces, or clicking a source does nothing at all. - Cap long traces with
moreLabelinstead of laying out dozens of rows. - Use
reasoningfor paragraph prose — it wraps and never truncates. Usestepsfor single-line labels. - In streaming UIs, store
togglein the host and feed it back throughuserOpenso a rebuild does not discard the reader's choice. - The component sizes to its container; upstream's 380px frame is the host's decision.
API Reference
Props
| Prop | Type | Default | Description |
|---|---|---|---|
rows | AgentTraceRow[] | — | The trace rows. Required. |
variant | 'steps' | 'reasoning' | 'search' | 'coding' | 'steps' | Row form and typography. |
query | string | — | search: the query echoed above the results. |
working | boolean | false | Whether the trace is still running; drives the shimmer and the spinner. |
activeLabel | string | per variant | Header text while working. |
doneLabel | string | per variant | Header text once settled. |
moreLabel | string | — | Trailing overflow note, e.g. +7 more. |
defaultOpen | boolean | — | Open state before any interaction. Falls back to working. |
userOpen | boolean | — | Host-held override that survives a rebuild. |
selectedId | string | — | coding: the selected row id. Binding it hands ownership to the host. |
AgentTraceRow is { id, primary, secondary?, mono?, added?, removed?, href?, status? }, where status is 'pending' | 'active' | 'done' | 'error'.
Per-variant default copy: steps and reasoning use Thinking / Thought, search uses Searching the web / Searched the web, and coding uses Running tools / Ran tools. Counted copy (upstream's "Thought for 4 seconds", "Ran 3 tools") folds in a measurement only the host has — pass doneLabel for those.
Events
| Event | Payload | Description |
|---|---|---|
toggle | (open: boolean) | Emitted on header click, carrying the state after the toggle. |
open | (row: AgentTraceRow) | search: emitted when a linked row is clicked. The component never navigates. |
select | (id: string | null) | coding: emitted on select or deselect; null when cleared. |
Slots
| Name | Scope | Description |
|---|---|---|
icon | { working } | Replaces the header starburst. |
label | { working } | Replaces the header text. |
row | { row, index } | Replaces the row content, keeping the row container and entrance. |
Ownership of the Open State
Open resolves through three layers, highest first: userOpen (host-held) → the component's own click override → defaultOpen → working.
Used standalone, the trace opens and folds with working, and the reader's first click takes over from then on. But a streaming host re-renders on every delta, and a branch realignment can recreate the instance — an override kept only in instance state dies with it, which reads as "clicking does nothing". Lift toggle into the host and feed it back through userOpen to make the reader's choice survive any rebuild.
Overview
- Links never navigate on their own. A
searchrow still renders a realhref(copyable, middle-clickable), but a click callspreventDefaultand emitsopenso the host decides how to open it. This is required inside an Electron renderer. - The collapse carries
inertwhile closed: a0frgrid still leaves its rows in the tab order, so they have to be taken out of it too. - The header is a
buttonwitharia-expandedand anaria-controlspointing at the collapse. - The
stepsglyph readsrow.statusfirst:activespins,errormarks, anything else checks. With nostatusit falls back to upstream behaviour — only the last row spins whileworking. codingrows arebuttonelements witharia-pressed. LeaveselectedIdunbound and the component keeps the selection; bind it and the host owns it outright.- Diff counters use U+2212 MINUS SIGN (
−), not a hyphen, so the pair matches the plus in width and weight. - Per-row entrance delay runs through the
--tx-bui-agent-trace-indexCSS variable rather than inline styles, so one rule turns it all off under reduced motion. - The rail is a pure CSS
::before. Upstream measures the row stack in a layout effect and tweens its height over 500ms; dropping the measurement is safe because the collapse is already clipping it.
Technologies
- Component source:
packages/tuffex/packages/components/src/agent-trace/src/TxAgentTrace.vue. - Types:
packages/tuffex/packages/components/src/agent-trace/src/types.ts. - Verified coverage:
packages/tuffex/packages/components/src/agent-trace/__tests__/agent-trace.test.ts(23 cases) covers the three-layer open precedence,inertwhile collapsed, non-navigating links, controlled and uncontrolledcodingselection, thestepsglyph fallback, U+2212, and the per-row stagger variable. - Adapted from Beautiful UI (https://www.beautifului.dev), © 2026 Shane Levine, MIT.
- How it divides from the existing disclosures:
TxChainOfThoughtis a thinking chain with markdown bodies,TxReasoningDisclosureis a single reasoning passage, andTxSourcesis a source list. This component is a compact single-line trace carrying links, diffs, and tool selection — different data shapes, not interchangeable. - Accessibility: the
inertcollapse is a deliberate improvement over upstream, whose collapsed region leaves links in the tab order. - Known deviation: the rail's 500ms height tween was not ported (see the interaction contract); the static settled state matches the reference screenshots.