ToolCall Component
Displays the steps an agent took with its tools: the latest step prominently, earlier steps folded.
Import
import { ToolCall, ToolCalls } from "@cognipeer/chat-ui";Usage
<ToolCall
toolName="get_weather"
toolCallId="call_123"
args={{ location: "NYC" }}
result={{ temperature: 72, conditions: "Sunny" }}
/>Props
ToolCall
ToolCall shows one call. It is ToolCalls with a single entry.
| Prop | Type | Description |
|---|---|---|
toolName | string | The tool's name (shown prettified: get_weather becomes "Get Weather") |
toolCallId | string | The call's id |
args | Record<string, unknown> | Arguments |
result | unknown | Result, when available |
isExecuting | boolean | A spinner instead of a tick |
defaultExpanded | boolean | Start with the older steps open (only matters with several calls) |
renderIcon | (toolName: string) => ReactNode | Declared on the props type; the built-in rows draw their own marks |
className | string | Container class name |
ToolCalls (Multiple)
| Prop | Type | Description |
|---|---|---|
toolCalls | Map<id, call> | { id, name, args, result?, reasoning?, displayName? }[] | The calls: a Map while streaming, an array for a stored message. The last one is the latest step |
isExecuting | boolean | The turn is running: the latest step shows a spinner |
durationSeconds | number | Shown next to "N previous steps" once the turn finished |
defaultExpanded | boolean | Start with the earlier steps expanded |
waitingIds | ReadonlySet<string> | Calls paused on an approval or a question (waitingToolCallIds(message, calls)): a clock instead of the tick of a finished call. ChatMessage sets it for a message with open cards |
className | string | Container class name |
What a step shows
- The label is the call's
reasoningwhen it has one, else itsdisplayName, else the prettified tool name. When the label is the reasoning or display name, the tool's own name sits under it in a smaller type. - Mark: spinner (running), clock (waiting for the person, labelled "Waiting for your answer"), tick (finished).
- "N previous steps" folds every step but the latest; click it to expand a compact list. With
durationSecondsit reads "3 previous steps · 4s".
Arguments and results are not drawn by these components; read them from onToolCall / onToolResult, or render your own rows from message.metadata.toolCallDetails.
Examples
Basic
<ToolCall toolName="search" toolCallId="1" args={{ query: "weather in NYC" }} />Running
<ToolCall toolName="fetch_data" toolCallId="1" args={{ url: "..." }} isExecuting />Multiple Tool Calls
<ToolCalls
toolCalls={[
{ id: "1", name: "search", args: { q: "..." }, result: { results: [] } },
{ id: "2", name: "calculate", args: { expr: "..." }, reasoning: "Adding up the invoice" },
{ id: "3", name: "get_time", args: {} },
]}
durationSeconds={4}
/>Waiting for an approval
<ToolCalls
toolCalls={[{ id: "call_9", name: "send_email", args: { to: "a@example.com" } }]}
waitingIds={new Set(["call_9"])}
/>Custom Rendering
Build your own rows from a stored message or from useChat().activeToolCalls:
function CustomToolCalls({ message }) {
const calls = (message.metadata?.toolCallDetails ?? []) as Array<{ id: string; name: string; args: object; result?: unknown }>;
return (
<ul>
{calls.map((call) => (
<li key={call.id}>
{call.name} {call.result !== undefined ? "(done)" : "(running)"}
<pre>{JSON.stringify(call.args, null, 2)}</pre>
</li>
))}
</ul>
);
}In Messages
Tool calls of a finished assistant message are read from metadata.toolCallDetails and drawn above the message text. renderMessageActions and the other render props do not change them.
Styling
Colours come from the theme variables: --chat-accent-primary (spinner and tick), --chat-warning (the waiting clock), --chat-text-secondary and --chat-text-tertiary (labels), --chat-border-secondary (the folded list's rule). See Theming.

