Skip to content

feat: FlowTool, the tool call card #24

Description

@divyanshub024

What kind of request is this

A new component

The problem

Agents spend most of a turn running tools: searching the web, reading files, executing code. The chat has to show that work happening (which tool, on what, still running or done or failed) and then keep it in the transcript as a quiet, expandable record. flow_ui has nothing for this today. Hosts hand-roll it through FlowCustomPart, and stac_ai's tool loop has nothing to render its calls with. It pairs with the confirmation card (#22): confirmation is the ask, the tool card is the run.

What you'd like

A FlowTool card in the assistant turn: a tool icon and name, a one-line summary of the input ("flutter markdown parser", lib/main.dart), a status, and an expandable detail slot for any widget (the input, the result, a FlowCodeBlock of output).

Three states. State is data, as everywhere: the host passes the status in and re-renders. The card never flips itself.

Status The card The label
running open, working name shimmers (the FlowShimmerText idiom)
success quieted, collapsed settled ink, expandable
error quieted, marked error glyph; the failure reads without expanding

Running is the live moment; settled cards should recede. A transcript full of finished tool calls must scan as prose with small quiet rows in between, not as a wall of cards.

API sketch

FlowTool(
  icon: Icons.travel_explore,
  name: 'Web Search',
  summary: '"flutter markdown parser"',   // host-written, one line
  status: FlowToolStatus.running,
  detail: FlowCodeBlock(code: result, language: 'json'),
  expanded: expanded,        // disclosure is state too
  onToggle: toggle,          // intent out
  padding: ...,              // metric overrides, as everywhere
  borderRadius: ...,
  style: FlowToolStyle(...), // over FlowTheme.toolStyle
)

FlowToolStyle (proposed fields)

Follows the component-styles convention (#21): lives in lib/src/styles/, app-wide default on FlowTheme.toolStyle, widget wins over theme field by field, tokens under both.

  • backgroundColor: card fill. Defaults to the container ladder's low rung.
  • borderColor: card hairline. Defaults to outlineVariant.
  • iconColor: the tool glyph. Defaults to onSurfaceVariant.
  • nameStyle / summaryStyle: merged over their role defaults.
  • errorColor: the failed state's glyph and accent. Defaults to error.

Decisions to settle

  1. Ship a FlowToolPart too, rendered by FlowMessage with expansion intent threaded through FlowThread. Same precedent as FlowErrorPart and the confirmation proposal (feat: FlowConfirmation, the approval card for agent actions #22). The part carries data (name, summary, status, detail text); a builder seam covers hosts whose detail is a widget.
  2. Disclosure ownership: expanded/onToggle as host state (the package rule), or internal state with initiallyExpanded (the menus' precedent for ephemeral UI). Leaning host state: a restored transcript should reopen the way it was left.
  3. Consecutive calls: agents often run three tools back to back. Do sequential cards group into one stack ("Searched 3 sources") or stay separate rows? Could ship separate first and group later without breaking.
  4. While running, is the detail visible and growing, or hidden until settled? The code block already handles streaming content if we show it.

Accessibility

Status changes announce (a completed or failed run is news, like the error card's live region). The disclosure is a real button with the tool name as its label. The shimmer is decoration only; the name stays readable text.

Definition of done

  • FlowTool + FlowToolStatus, exported from the barrel
  • FlowToolPart + FlowMessage/FlowThread wiring (decision 1)
  • FlowToolStyle in lib/src/styles/ + FlowTheme.toolStyle (feat: component styles on every widget with app-wide FlowTheme defaults #21 convention)
  • Metrics baked from the Figma frame; padding/borderRadius overrides
  • No shipped strings; name and summary host-written, doubling as accessible names
  • Playground demo with running/success/error variants and per-variant snippets
  • Docs page with a Restyling section; README row; roadmap flipped; CHANGELOG entry
  • Dogfooded in the example's Gemini flow as a mock tool-call turn

What you're doing instead

A custom FlowCustomPart with a host-built widget. Works, but every host redoes the status handling, the shimmer, the disclosure, and the accessibility story. For reference: assistant-ui ships tool UIs as a first-class concept, and Claude, ChatGPT, and Cursor all render the same shape (icon, name, one-line summary, expandable result).

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions