Tool Call
Anatomy
Collapsible representation of an AI agent's tool invocation (Edit, Write, Bash, Read, Grep, etc.). Renders a compact trigger row — glyph, name, summary, status pill — with an expandable body holding the arguments and result panes.
maud_ui::primitives::tool_call
Props
Generated from public Rust fields. Defaults are evaluated from the implementation.
| Prop | Type | Default | Description |
|---|---|---|---|
id | String | "" | Unique DOM id — used to wire the details disclosure. |
kind | Kind | Custom | Tool family (drives accent colour + glyph). |
name | String | "" | Tool name (e.g. "Edit", "Bash"). |
summary | String | "" | One-line summary shown in the trigger (e.g. file path, command). |
status | Status | Success | Current execution status. |
args | Option<Markup> | None | Optional args panel — rendered in the expanded body. |
result | Option<Markup> | None | Optional result panel — rendered in the expanded body. |
open | bool | false | Initial open state (default false — collapsed). |
compact | bool | false | Chip density: one rounded chip per call that sits inline in a row (mui-tool-call-row) and expands in place. What a settled turn in a chat shows instead of a card per call. |
duration | Option<String> | None | Wall time the call took, already formatted ("0.4s", "12ms"). Shown in the trigger after the summary; absent when unmeasured. |
Examples
Compact — one chip per call, expands in place
126 lines
old_string not found
Card — the inspector shape
old_string: "role: Role::Default" new_string: "role: Role::Assistant"
Applied edit — 1 replacement.
Usage and composition
Import
use maud_ui::primitives::tool_call::{self, Kind, Status, Props};
Example
use maud::html;
use maud_ui::primitives::tool_call;
html! {
(tool_call::render(tool_call::Props {
id: "edit-1".into(),
kind: tool_call::Kind::Edit,
name: "Edit".into(),
summary: "src/primitives/message.rs".into(),
status: tool_call::Status::Success,
args: Some(html! { pre { "old_string: \"role: Role::Default\"\nnew_string: \"role: Role::Assistant\"" } }),
result: Some(html! { pre { "Applied edit — 1 replacement." } }),
open: true,
}))
}
Props derives Default, so defaults above come from #[derive(Default)] on Props, Kind, and Status (each enum marks its default variant with #[default]) — there is no hand-written impl Default block.
Variants / Enums
Kind
Tool families, each with its own accent colour and glyph.
Custom(default) — glyph•, classmui-tool-call--customEdit— glyph✎, classmui-tool-call--editWrite— glyph➕, classmui-tool-call--writeRead— glyph📖, classmui-tool-call--readBash— glyph›_, classmui-tool-call--bashGrep— glyph🔍, classmui-tool-call--grepGlob— glyph✱, classmui-tool-call--globTask— glyph❖, classmui-tool-call--taskAgent— glyph◆, classmui-tool-call--agentSearch— glyph🔎, classmui-tool-call--search
Status
Execution state — drives the status pill colour and label.
Success(default) — classmui-tool-call__status--success, label "done"Running— classmui-tool-call__status--running, label "running"Error— classmui-tool-call__status--error, label "error"Pending— classmui-tool-call__status--pending, label "queued"
Helper Functions
row(chips)— a wrapping flex row (mui-tool-call-row) for compact chips, the settled-turn shape.
None. Kind and Status each carry private class()/glyph() and class()/label() methods, but neither is marked pub, so they are not part of the public API. The only pub fns in the module are render and showcase, both excluded from this section by convention.
Related
CodeBlock (for rendering args/result as code), Message (the chat bubble a tool call typically nests inside), Diff (for edit-style results), StreamingCursor (for an in-flight response alongside a Running tool call)
Shadcn reference
No shadcn/ui equivalent — this is an agent/tool-invocation primitive with no upstream shadcn component to reference.
Accessibility
- The trigger is a native
button type="button", so it is focusable and keyboard-operable (Enter/Space) without extra script. - The trigger carries
aria-expanded(reflectingprops.open, toggled by the inlineonclickhandler) andaria-controlspointing at the body'sid— the standard disclosure-button pattern. - The body
divsets itsidto matcharia-controlsand toggles the booleanhiddenattribute in lockstep witharia-expanded(both in the initial render viahidden[!props.open]and in theonclickscript at runtime). - The glyph and chevron spans are both marked
aria-hidden="true", so decorative icons are not read out. - Status is conveyed by a visible text label ("done" / "running" / "error" / "queued") inside the pill, not by colour alone — so the state is readable without colour perception.
- There is no
aria-liveregion anywhere in the markup, so a status change (e.g.Running→Successon a re-render) is not automatically announced to a screen reader unless something else moves focus to it.