Components
ToolCallTimeline
Every tool call with its state, a measured duration and a waterfall; errors inline.
Example
ENOENT: no such file or directory, open 'middleware.ts'
- !
Interactive, and the same on the components page. Try the keyboard below on it.
Installation
npm i @dgesteves/agent-ui-kit aiimport { ToolCallTimeline } from '@dgesteves/agent-ui-kit';
// Once per app (with Tailwind v4: @import '@dgesteves/agent-ui-kit/tailwind.css'; in your CSS)
import '@dgesteves/agent-ui-kit/styles.css';npx shadcn@latest add @agent-ui-kit/tool-call-timelineimport { ToolCallTimeline } from '@/components/agent-ui/tool-call-timeline';The styles are once per app; Getting started has the Tailwind v4 and plain CSS options.
Usage
<ToolCallTimeline
parts={message.parts}
tools={{
read_file: { label: 'Read file', summary: (input) => (input as { path?: string }).path },
run_command: { label: 'Run command', risk: 'high' },
}}
// Once the run has ended, calls that never settled read "Stopped".
active={status === 'submitted' || status === 'streaming'}
/>API reference
Generated from the types the package ships, so it matches the version you install.
ToolCallTimeline
A vertical timeline of tool calls with live states, durations, a waterfall, and expandable input/output. Follows the WAI-ARIA disclosure pattern; Arrow Up/Down, Home and End move between calls.
Props
partsrequiredreadonly AnyUIPart[]Tool parts, or every part of a message: non-tool parts are ignored.
toolsRecord<string, ToolMeta>timingsToolTimingsExternally measured timings by
toolCallId. Measured client-side when omitted.expandedreadonly string[]Controlled set of expanded
toolCallIds.defaultExpandedreadonly string[]onExpandedChange(expanded: string[]) => voidexpandErrorsbooleanDefaultfalseExpand calls automatically when they fail. Default
false: the error message is always shown inline under a failed call, with details on demand.waterfallbooleanDefaulttrueShow a per-call waterfall bar relative to the whole timeline.
announcebooleanDefaulttrueAnnounce completions and failures to screen readers.
renderExtra(part: ToolPart) => ReactNodeExtra content under a call, e.g. an approval card.
labelstringDefault'Tool calls'Accessible name for the list.
activebooleanDefaulttrueWhether the run can still make progress. Pass
falseonce it has ended (stopped, failed, or restored from history): calls still streaming their input or running then read "Stopped" and their clocks stop, instead of counting up forever.
Other props go to the root <div>: className (merged with tailwind-merge), id, aria-*, data-* and event handlers.
ToolMeta
Per-tool presentation. Every field is optional.
labelstringDisplay label. Defaults to the humanized tool name.
iconReactNodesummary(input: unknown, part: ToolPart) => ReactNodeOne-line summary shown next to the label. Defaults to the most descriptive input field. Not called before any input has arrived; while the input streams it can be partial.
renderOutput(output: unknown, part: ToolPart) => ReactNodeReplace the default JSON output view.
riskRiskLevel | ((input: unknown) => RiskLevel)Risk shown on approval requests for this tool.
ToolTiming
startedAtnumberFirst time the call was observed (input started streaming).
runningAtnumberWhen execution began: input complete, or approval granted.
endedAtnumberWhen the call settled (output, error or denial).
RiskLevel
type RiskLevel = 'low' | 'medium' | 'high' | 'critical';Accessibility
| Keys | Action |
|---|---|
| ↑↓ | Previous or next call |
| HomeEnd | First or last call |
| EnterSpace | Show or hide the call’s input and output |
- An ordered list named by
label("Tool calls"). Each call is a disclosure button witharia-expanded, as in the WAI-ARIA accordion pattern; the arrow keys move between them. - A call’s name, summary, state and duration are in its button’s accessible name. In narrow containers the summary is hidden visually but still read.
- Completions and failures are announced through a polite live region, such as "Read file finished in 1.2 seconds" or "Read file failed: ENOENT…". Turn it off with
announce={false}when something else announces them. - States are never color alone: each has an icon and a word ("Failed", "Needs approval", "Denied").
- The expand and collapse animation runs only without
prefers-reduced-motion.
Theming
Every color, radius and font is a CSS variable, so the overrides in Theming apply, on :root or scoped to any element. These hooks are read from the component's markup.
- Slots (data-slot)
- tool-call-triggertool-call-timelinetool-call
- State attributes
- data-phaseon
tool-call'denied' | 'awaiting-approval' | 'error' | 'streaming' | 'running' | 'success'data-stateontool-call'input-streaming' | 'input-available' | 'approval-requested' | 'approval-responded' | 'output-available' | 'output-error' | 'output-denied'data-interruptedontool-callset once the run ended before the call settled - Tokens it uses
- --aui-accent--aui-accent-fg--aui-bg--aui-border--aui-border-strong--aui-fg--aui-fg-muted--aui-fg-subtle--aui-font-mono--aui-font-sans--aui-hot--aui-hot-fg--aui-ring--aui-surface-2
/* Only this component, and only inside .settings-panel */
.settings-panel [data-slot='tool-call-timeline'] {
--aui-radius: 4px;
}
[data-slot='tool-call'][data-phase='denied'] {
outline: 1px solid var(--aui-accent);
}