Skip to content

features tool cards

Zachary BENSALEM edited this page Aug 15, 2026 · 1 revision

Tool cards

Active contributors: Mario Zechner, kt, Armin Ronacher

Purpose

Tool cards are the web UI's rendering of tool calls the agent makes during a turn. Each tool call arrives as a tool-* frame, is normalized into a ChatToolPart, and is dispatched by web/design to a per-kind card component. The card lifecycle derives entirely from the part state: input-streaming renders a pending or streaming card, output-available renders success, and output-error renders an error. The same tool events are rendered differently by the TUI, which has its own components in packages/coding-agent.

Tool cards live in web/design/src/components/agent-elements/tools/. They consume the ChatToolPart shape from web/protocol and are driven by frames produced in web/server/src/event-mapper.ts (see streaming-chat).

How it works

From tool event to card

A tool execution on the runtime emits tool_execution_start, tool_execution_update, and tool_execution_end. The event mapper (web/server/src/event-mapper.ts) turns these into tool frames carrying a ChatToolPart with a state of input-streaming, then output-available or output-error. The client reducer upserts the part into the assistant message by toolCallId. In web/design, buildAssistantElements (web/design/src/components/agent-elements/message-turns.tsx) walks message parts, assigns stable keys, and hands each tool part to ToolRenderer.

ToolRenderer (web/design/src/components/agent-elements/tools/tool-renderer.tsx) dispatches on part.type. Specialized components handle the common tools; MCP tools and custom renderers are resolved by prefix and registry lookup; anything else falls back to GenericTool. The dispatch order is: specialized switch, MCP parsing, custom renderers for plain tool-* parts, registry-based generic tools, then a fallback that shows the tool name.

flowchart LR
    A[AgentSessionEvent tool_execution_*] --> B[event-mapper]
    B --> C[tool frame / ChatToolPart]
    C --> D[client reducer upsert by toolCallId]
    D --> E[ToolRenderer dispatch on part.type]
    E --> F{tool-IPython?}
    E --> G{tool-Bash?}
    E --> H{tool-Edit / tool-Write?}
    E --> I{tool-WebSearch / Grep / Glob?}
    E --> J{tool-PlanWrite?}
    E --> K{tool-TodoWrite?}
    E --> L{tool-Question?}
    E --> M{tool-Task / tool-Agent?}
    E --> N{tool-Thinking?}
    E --> O{mcp__?}
    F --> P[IpythonTool]
    G --> Q[BashTool]
    H --> R[EditTool]
    I --> S[SearchTool]
    J --> T[PlanTool]
    K --> U[TodoTool]
    L --> V[QuestionTool]
    M --> W[ToolGroup]
    N --> X[ThinkingTool]
    O --> Y{has custom renderer?}
    Y -->|yes| Z[CustomRenderer]
    Y -->|no| AA[McpTool]
    E --> AB[else: toolRegistry lookup / GenericTool]
Loading

Tool registry and normalizer

toolRegistry (web/design/src/components/agent-elements/tools/tool-registry.ts) holds metadata (icon, title, subtitle, variant) for generic tools such as Read, Grep, Glob, WebFetch, Edit, Write, Bash, IPython, TodoWrite, PlanWrite, and Thinking. It also parses MCP tool types: parseMcpToolType recognizes the tool-mcp__<server>__<tool> prefix and the built-in resource tool names, returning a McpToolInfo used by McpTool.

tool-part-normalizer.ts (web/design/src/components/agent-elements/utils/tool-part-normalizer.ts) parses stringified input/output/result JSON on tool parts so card components can read structured fields. tool-adapters.ts (web/design/src/components/agent-elements/utils/tool-adapters.ts) maps a protocol tool part to a timeline ToolStep, translating part state to a step state (input-streaming to partial-call, output-available to result) and extracting per-tool detail such as bash commands, file paths, diff stats, search queries, and thinking content. format-tool.ts derives pending/error/success status and elapsed time, and memoizes tool parts by comparing state, input, and output.

Per-tool cards

  • ipython-tool.tsx: renders an IPython cell with a per-session cell index (In [n]), the code, and the output or error. Recognizes %%bash cells and shows kernel-restart status.
  • bash-tool.tsx: renders a terminal card with the command and its output, and a command summary for the header.
  • edit-tool.tsx: renders a diff card using @pierre/diffs/react, computes old/new file contents from input and output, and shows diff stats and a collapsible body.
  • thinking-tool.tsx: renders the thinking trace as a collapsible block.
  • todo-tool.tsx: renders todo updates from the TodoWrite tool.
  • plan-tool.tsx: renders a plan with its title, summary, status, and an approval footer with Execute/Stay/Refine actions plus a refine textarea.
  • search-tool.tsx: renders a search group showing the query and a result list for web/code searches.
  • mcp-tool.tsx: renders an MCP tool call, deriving a display name from the tool name, formatting prioritized arguments, and rendering JSON output through Streamdown.
  • generic-tool.tsx: the fallback row used by registry tools and nested tool summaries.

Tool groups and nested subagent calls

tool-group.tsx (web/design/src/components/agent-elements/tools/tool-group.tsx) renders a tool-Task or tool-Agent subagent call. It summarizes nested tools by category (file reads/edits, searches, commands), reveals nested tool rows progressively while pending, auto-expands shortly after the group starts, and shows an elapsed-time or output-duration label. Nested parts are re-derived with the last one marked input-streaming while the group is still running.

Approval footer

tool-approval-footer.tsx (web/design/src/components/agent-elements/tools/tool-approval-footer.tsx) is the reusable two-button footer (approve/reject) rendered by IpythonTool, BashTool, and EditTool when the part input carries an approval object. It shows a Starting or Waiting status while pending and locks the decision once chosen.

TUI rendering

The TUI renders the same tool events with its own components in packages/coding-agent/src/modes/interactive/components/. tool-execution.ts is a TUI Container that manages a tool call's call/result renderers, IPython cell component, bash streaming, image rendering, and expansion state, using built-in tool definitions for replay. ipython-cell.ts renders IPython cells in the terminal, tool-panel.ts hosts the panel, and edit-summary.ts summarizes file changes. These run in the terminal's component tree rather than as DOM cards, so the lifecycle is expressed through TUI component state and the working-icon pulse instead of part states.

Integration points

  • Wire contract: ChatToolPart and tool frames from web/protocol. See web-protocol.
  • Frame production: web/server/src/event-mapper.ts (toPascalCase tool naming, input-streaming/output-available/output-error states). See web-server and streaming-chat.
  • Client assembly: web/app message state and reducer. See web-app.
  • Rendering dispatch and cards: web/design. See web-design.
  • TUI rendering: packages/coding-agent/src/modes/interactive/components/. See tui.

Entry points for modification

  • Add or change a tool card: edit the dispatch in web/design/src/components/agent-elements/tools/tool-renderer.tsx, add metadata in tool-registry.ts, and add the component under web/design/src/components/agent-elements/tools/.
  • Change how a tool part becomes a timeline step: edit web/design/src/components/agent-elements/utils/tool-adapters.ts.
  • Change status derivation or memoization: edit web/design/src/components/agent-elements/utils/format-tool.ts.
  • Change subagent/tool-group behavior: edit web/design/src/components/agent-elements/tools/tool-group.tsx.
  • Change the approval footer: edit web/design/src/components/agent-elements/tools/tool-approval-footer.tsx.
  • Change TUI tool rendering: edit the components under packages/coding-agent/src/modes/interactive/components/.

Key source files

File Role
web/server/src/event-mapper.ts Produces tool frames with ChatToolPart states; toPascalCase tool naming.
web/design/src/components/agent-elements/tools/tool-renderer.tsx Core dispatch by part.type to card components.
web/design/src/components/agent-elements/tools/tool-registry.ts Tool metadata (icon/title/subtitle/variant) and MCP tool name parsing.
web/design/src/components/agent-elements/utils/tool-adapters.ts Maps protocol tool parts to a timeline ToolStep and step state.
web/design/src/components/agent-elements/utils/tool-part-normalizer.ts Parses stringified input/output/result JSON on tool parts.
web/design/src/components/agent-elements/utils/format-tool.ts Tool status derivation, elapsed time, and memo comparison.
web/design/src/components/agent-elements/tools/tool-group.tsx Subagent/task tool group with nested tool rows and progressive reveal.
web/design/src/components/agent-elements/tools/tool-approval-footer.tsx Reusable approve/reject footer for tool cards.
web/design/src/components/agent-elements/tools/ipython-tool.tsx IPython cell card with cell index, code, output, and kernel status.
web/design/src/components/agent-elements/tools/bash-tool.tsx Terminal card for bash commands.
web/design/src/components/agent-elements/tools/edit-tool.tsx Diff card for edit/write tools.
web/design/src/components/agent-elements/tools/plan-tool.tsx Plan card with approval and refine actions.
web/design/src/components/agent-elements/tools/mcp-tool.tsx MCP tool card with argument formatting and JSON output.
packages/coding-agent/src/modes/interactive/components/tool-execution.ts TUI container for tool call rendering.

Clone this wiki locally