Overview
Reference usage
The side panel of one tool call, opened from a ToolCallRail row. The header names the tool with its identifier small and monospaced, then says where the call stands: a dot, the state, how long it took and where it falls in the turn ("Failed 10.0s, call 28 of 30"). Under it, an Input section lists what the call was given as labelled fields, and the rest depends on the state: a done call shows its Result, a running call says the result is coming, a failed call shows an Error block with its message first and the next steps, and a waiting call carries a note field with Deny and Approve.
Use ToolCallPanel for one call's details beside a conversation. Use PayloadInspector for an arbitrary payload on its own page, and Drawer for navigation or settings from a page edge. The panel is a Drawer below the width it docks at, so it never reflows the conversation on a small screen.
Placement
docked: an inset panel about 340px wide in the flow of the page, with an X. Esc closes it while focus is inside.overlay: a right sheet over the content on a dimming scrim, closed by its X or Esc. The conversation stays visible behind it.sheet: a full-height bottom sheet with a grabber and aClosebutton, like the shared sheets. It cross-fades under reduced motion. The copy buttons give way to the retry button, which rests at the foot.auto(the default):sheetbelow 640px,overlayup todockedFrom(1280px), anddockedfrom there. 1280px is where a 190px sidebar, a 250px list, about 480px of conversation and the 340px panel fit; it is a threshold of its own, apart from the shared 1024px desktop breakpoint.
Usage
Kinds of call
done,approvedanddenied: Input and Result as fields, with secondaryCopy inputandCopy resultbuttons. PassresultLabel="Output"for a tool that calls its answer an output.running: Input, and a Result that reads "The result appears when the call finishes."waiting: Input, a "Note (optional)" field and Deny and Approve. Approve is the only primary action on the screen.onApproveandonDenyreceive the note;resolvingwrites "Approving…" or "Denying…" on that button and turns both off.failed: Input and an Error block, tinted red, with the message first and then the code in monospace and Retryable. It explains what retrying sends (retryMessage), then a full-width secondaryAsk the agent to retry(onRetry) and secondaryCopy inputandCopy error.
Input and Result read as the Fields view of PayloadInspector does: keys become sentence-case words with acronyms kept (orderId reads "Order ID"), ISO dates read as dates, booleans as "Yes" and "No", null as "None" and an empty string as "Empty". Values the caller's schema marks secret, or that read as secrets when redact is not passed, show "Hidden" in both views and in the copy buttons. view="json" shows the stored value in a code block instead; text that is already JSON is shown as it was stored.
Closing and focus
open is bindable and onClose fires once whenever the panel closes. Call focusCall(id) on the rail from onClose to hand focus back to the row that opened it; the overlay and the sheet also restore focus to triggerRef, or to where it was before they opened.
Props
-
-
- Mail server didn't reply within 10s. The refund notice for 4471 wasn't sent.
When to use
- Opening a tool call from a ToolCallRail row to read what it was given and what came back.
- Letting a person answer a call that is waiting on them, with a note, without leaving the conversation.
- Showing an arbitrary payload on its own — use payload-inspector.
- Showing supplementary navigation or settings from a page edge — use drawer.
Examples
Beside the rail
The rail and its panel together: the selected Send email row is tinted and, at 1280px and wider, its panel docks to the right. Below that it opens over the page on a scrim, and on a phone as a bottom sheet, so it never covers the rail. Esc or the X closes the panel and Close hands focus back to the row; choosing the row again closes it too.
At 375px, a bottom sheet
On a phone the panel is a full-height bottom sheet with a grabber and a Close button, like the shared sheets. The title is "Send email" with "send-email", a red "Failed, 10.0s, call 28 of 30", Input fields (To, Template), Error fields (Message, Retryable Yes) and a secondary full-width 44px "Ask the agent to retry" at the foot. It cross-fades under reduced motion.
A phone sheet with JSON blocks
The phone panel for Lookup order opens as a bottom sheet over the run page with a grabber, the title "Lookup order", Close, "Reads, ran in 0.4s", and Input and Output JSON blocks. The line under the title is the caller's own words, and Output is the Result heading renamed.
The panel for each kind of call
A done call shows its Input and its Result as fields with secondary "Copy input" and "Copy result". The waiting call carries a "Note (optional)" field with its description, a secondary Deny and the only primary, Approve. A running call shows its Input and a Result that reads "The result appears when the call finishes." The three panels are the same width.
A failed call, docked
Selecting a rail row docks its panel beside the conversation, about 340px wide, with an X to close it. The header reads "Send email" with "send-email" small and monospaced, then a red dot and "Failed 10.0s, call 28 of 30". The Input section lists its fields (To, Template, Order ID) and the Error section is a tinted danger block with the message first, then the code in monospace and Retryable Yes. Under it the panel says what retrying sends, then a full-width secondary "Ask the agent to retry" with a refresh icon and secondary "Copy input" and "Copy error" buttons. Approve elsewhere on the page stays the only primary action.
Below 1280px, an overlay
Under 1280px the panel opens over the conversation on a dimming scrim, closed by its X or Esc, with the same Send email content as the docked panel. It docks only at 1280px and wider (190 sidebar + 250 list + about 480 conversation + 340 panel = 1,260 plus gutters), a threshold separate from the shared 1024px desktop breakpoint. This example forces the overlay so it shows at any width.
Props
Name | Type | Default | Description |
|---|---|---|---|
open bindable | boolean | true | Whether the panel is open. Bindable: the X, Close and Esc set it to false, and the page then
hands focus back to the call's row. |
name required | text | The tool's name as a person reads it ("Send email"). It names the panel. | |
identifier | text | The tool's identifier ("send-email"), small and monospaced after the name. | |
status required | 'done''approved''running''waiting''denied''failed''interrupted' | Where the call stands. It picks the status dot, the status word and which sections show. | |
duration | text | How long the call took, or has run so far ("10.0s"), formatted by the caller. | |
position | text | Where the call falls in its turn ("call 28 of 30"), written after the duration. | |
summary | text | The line under the name, in the caller's words ("Reads, ran in 0.4s"). When set it replaces the status word, duration and position. | |
input | unknown | What the call was given. An object shows as labelled fields, a list or a single value as one
row, and undefined reads "This tool call takes no input." | |
result | unknown | What the call returned, for a call that finished. Hidden for a failed or waiting call, and a running call says the result is coming. | |
resultLabel | text | 'Result' | The Result heading. A call that returns "Output" in the caller's vocabulary says so here. |
error | {
/** What went wrong, in words ("No reply from mail.example.com after 10s"). Shown first. */
message: string;
/** The machine code for the failure ("smtp… Show full type{
/** What went wrong, in words ("No reply from mail.example.com after 10s"). Shown first. */
message: string;
/** The machine code for the failure ("smtp-timeout"), in small monospace. */
code?: string | undefined;
/** Whether trying the call again can work. Written "Yes" or "No". */
retryable?: boolean | undefined;
} | Why a failed call failed. It shows as a tinted danger block under the Input, message first. | |
view bindable | 'fields' | 'json' | 'fields' | How Input and Result show. fields lists each property with a sentence-case label; json
shows the stored value in a code block. Bindable. |
redact | string[] | Secret paths to hide in both views and in the copy buttons, as PayloadInspector's redact:
dot-separated property names, * for any one name or position. Without it, a property whose
name reads as a secret (token, key, password, authorization) is hidden; pass [] to hide nothing. | |
retryMessage | text | The message the retry button sends as the person's own ("Please retry Send email to
maya@example.com"). It is quoted in the note under a failed call; the button shows only when
onRetry is set. | |
onRetry | (() => void) | undefined | Fired when the person asks the agent to retry a failed call. The button is secondary, full width, and shows only when this is set. | |
onApprove | ((note: string) => void)undefined | Fired with the note when Approve is pressed on a waiting call. The decision bar shows only when this or onDeny is set. | |
onDeny | ((note: string) => void)undefined | Fired with the note when Deny is pressed on a waiting call. If the person denies, the agent reads the note as the reason. | |
resolving | 'approve' | 'deny' | The answer that is on its way for a waiting call. | |
onClose | (() => void) | undefined | Fired once each time the panel closes, whether by its X, Close, Esc or the caller setting
open to false. A page hands focus back to the call's row here, with focusCall(id) on the
rail. | |
placement | 'auto' | 'docked' | 'overlay' | 'sheet' | 'auto' | How the panel sits on the page. |
dockedFrom | text | '1280px' | The viewport width the panel docks from, as a CSS length. Narrower than this it opens as an overlay on a scrim: a docked panel beside a 190px sidebar, a 250px list, a conversation and the panel needs about 1,260px. A separate threshold from the shared 1024px desktop breakpoint. |
triggerRef | HTMLElement | null | undefined | null | The element that opened the panel, for focus to return to when an overlay or sheet closes. |
labels | {
/** The status word of each status. Defaults to Done, Approved, Running, Waiting on you, Denied, Failed and Interrupted. */
status?: Partial<Record<ToolCallPanelStatus, string>> | undefined;
/** The Input heading. Defaults to "Input". */
input?: string | undefined;
/** What the Input section says when the call took no input. Defaults to "This tool call takes no input." */
noInput?: string | undefined;
/** The Error heading. Defaults to "Error". */
error?: string | undefined;
/** The Error section's Message row. Defaults to "Message". */
message?: string | undefined;
/** The Error section's Code row. Defaults to "Code". */
code?: string | undefined;
/** The Error section's Retryable row. Defaults to "Retryable". */
retryable?: string | undefined;
/** What a running call's Result section says. Defaults to "The result appears when the call finishes." */
pending?: string | undefined;
/** The note under a failed call, given the retry message. Defaults to the sentence that explains what retrying sends. */
retryNote?: ((retryMessage: string) => string)undefined;
/** The retry button. Defaults to "Ask the agent to retry". */
retry?: stringundefined;
/** The button that copies the input. Defaults to "Copy input". */
copyInput?: stringundefined;
/** The button that copies the result, which writes the result heading after "Copy". Defaults to "Copy result". */
copyResult?: stringundefined;
/** The button that copies the error. Defaults to "Copy error". */
copyError?: stringundefined;
/** The Note field's label. Defaults to "Note (optional)". */
note?: string | undefined;
/** The Note field's description. Defaults to "Saved with your decision. If you deny, the agent reads it as the reason." */
noteDescription?: stringundefined;
/** The Deny button. Defaults to "Deny". */
deny?: stringundefined;
/** The Approve button. Defaults to "Approve". */
approve?: string 5 more membersundefined;
/** The Deny button while the answer is on its way. Defaults to "Denying…". */
denying?: stringundefined;
/** The Approve button while the answer is on its way. Defaults to "Approving…". */
approving?: stringundefined;
/** The text of the close control on a bottom sheet. Defaults to "Close". */
close?: stringundefined;
/** The accessible name of the X that closes a docked or overlay panel. Defaults to "Close panel". */
closeIcon?: stringundefined;
} | The panel's words. | |
children | Snippet | undefined | Extra sections after the Input and Result, such as a link to the run. |