Skip to content
Kura UI

Tool Call

beta

One tool invocation: name and icon, queued/running/done/failed/awaiting-approval status, live elapsed time and collapsible JSON args and result.

@kura-ui/react/tool-callCopy page for agents.mdregistry.json

Finished call

minimal
read_file Completed
Arguments
{ "path": "src/app/page.tsx"}
Result
export default function Page() {\n return <Chat />;\n}

Live lifecycle

pending → running (shimmer + timer) → success with a JSON result; controlled open state.

full
search_web Queued
Arguments
{ "query": "react useOptimistic rollback", "max_results": 2}

All states

Queued, running, done and failed.

state
list_files Queued
Arguments
{ "dir": "src/components"}
run_tests Running
Arguments
{ "filter": "message"}
read_file Completed
Arguments
{ "path": "README.md"}
Result
# Kura UI
deploy_preview Failed
Arguments
{ "branch": "feat/message"}
Error: build failed — Type error in message.tsx:295

Inline

A compact row inside answer text.

variant

I checked the docs before answering:

fetch_url Completed
Arguments
{ "url": "https://react.dev/reference/react/useOptimistic"}
Result
{ "status": 200, "bytes": 48213}

The hook drops the optimistic value automatically when the action throws.

Awaiting approval

Approve/Deny Buttons in the actions footer resolve the call.

composition
run_command Waiting for approval
Arguments
{ "command": "pnpm db:migrate --env production"}

Installation

npx shadcn@latest add https://kuro.abstergo.fyi/r/tool-call.json

Copies the source into components/kura/tool-call with its dependencies (kura-theme, code-block, shimmer-text, use-controllable-state, utils). Tokens come from the kura-theme item.

When to use it

Use it for

  • Show a function/tool call an LLM made (AI SDK tool parts, MCP calls, OpenAI/Anthropic tool_use blocks) inside an assistant message.
  • Show a tool's progress with a live timer, then its result or error.
  • A tool that needs the user's go-ahead: status="awaiting-approval" with Approve/Deny buttons in `actions`.
  • Compact inline mentions of tool use within answer text (variant="inline").

Reach for something else when

  • A multi-step plan with many steps and progress — use agent-timeline (put ToolCalls inside steps if needed).
  • A dedicated, prominent permission request with risk level and keyboard shortcuts — use approval-prompt.
  • Plain code output — use code-block.
  • Model thinking — use reasoning.

Props

PropTypeDefaultDescription
name*string—Tool identifier, e.g. "search_web". Rendered in mono when no `title` is given; also used in the status announcement.
titleReact.ReactNode—Human label, e.g. "Searching the web" → "Searched the web". Replaces `name` visually.
iconReact.ReactNode—Tool icon (lucide), e.g. <Globe />. Default a wrench.
status"pending" | "running" | "success" | "error" | "awaiting-approval""running"Lifecycle. pending = hollow ring; running = jade pulse + shimmering title + ticking timer; success = check; error = cross (details open by default); awaiting-approval = jade hand.
argsunknown—Arguments. Objects are pretty-printed JSON with syntax tint (CodeBlock); strings render as-is.
resultunknown—Output. Objects are pretty-printed JSON; strings render as-is. Long values collapse at 220px with “Show N more lines”.
errorReact.ReactNode—Error message for status="error", shown in a danger panel in the details.
summaryReact.ReactNode—One-line summary next to the title (truncated). Default: the first primitive value in `args`. Pass null to hide.
startedAtDate | number—Start time for the live timer (e.g. from the server). Default: when status became running.
durationnumber—Final duration in ms (persisted calls). Default: measured from running → success/error.
variant"card" | "inline""card"card = bordered card; inline = compact borderless row for use inside message text.
openboolean—Details expanded (controlled).
defaultOpenboolean—Initial expanded state when uncontrolled. Default true for "error" and "awaiting-approval".
onOpenChange(open: boolean) => void—Called when details are toggled.
actionsReact.ReactNode—Always-visible footer row (right-aligned), e.g. Deny / Approve buttons.

All native attributes of the root element, className and ref pass through.

Anatomy

  1. ToolCall`data-status`, `data-variant`, `data-state="open" | "closed"` (when it has details).data-slot="tool-call"
  2. TriggerHeader row; a button with aria-expanded when there are details.data-slot="tool-call-trigger"
  3. Status20px status glyph (aria-hidden).data-slot="tool-call-status"
  4. IconTool icon (aria-hidden).data-slot="tool-call-icon"
  5. TitleTitle or mono name; shimmers while running.data-slot="tool-call-title"
  6. SummaryTruncated one-line summary.data-slot="tool-call-summary"
  7. ElapsedMono tabular duration: 180ms, 1.5s, 1m 5s.data-slot="tool-call-elapsed"
  8. DetailsCollapsible args/error/result (grid-rows transition, inert when closed).data-slot="tool-call-details"
  9. Section“Arguments” / “Result” label + headerless CodeBlock.data-slot="tool-call-section"
  10. ErrorDanger panel with the error message.data-slot="tool-call-error"
  11. ActionsFooter for `actions`.data-slot="tool-call-actions"

Accessibility

  • The header is a button (aria-expanded/aria-controls) only when there is something to expand.
  • Each call has a polite status region (“search_web Running” → “search_web Completed”); the ticking timer is not announced.
  • Status is conveyed by text for screen readers, not only by colour/icon.
  • Collapsed details are inert; JSON panes are keyboard-scrollable regions named “Arguments code” / “Result code”.
  • Reduced motion: The running pulse and title shimmer stop; the chevron and details change without travel (fade only).
KeysAction
Enter / SpaceExpand or collapse the details
TabInto the JSON panes and footer actions

Notes for agents

  • Map AI SDK tool part states: input-streaming → pending, input-available → running, output-available → success, output-error → error.
  • Keep the same ToolCall mounted across states so the measured timer works; for history, pass `duration` (ms).
  • Swap `title` between present and past tense (“Searching…” → “Searched the web”) as the status changes.
  • args/result accept any JSON-serializable value; circular objects fall back to String().