Skip to content

feat(Chat): add Reasoning, ToolCall, and ToolCallGroup components - #1192

Merged
cixzhang merged 15 commits into
mainfrom
navi/feat/chat-reasoning-toolcall
Apr 10, 2026
Merged

feat(Chat): add Reasoning, ToolCall, and ToolCallGroup components#1192
cixzhang merged 15 commits into
mainfrom
navi/feat/chat-reasoning-toolcall

Conversation

@cixzhang

@cixzhang cixzhang commented Apr 8, 2026

Copy link
Copy Markdown
Contributor

Summary

Reasoning display and tool call components for AI chat interfaces. Spec: #297

XDSChatReasoning

Compact collapsible display for model reasoning/thinking content.

  • Collapsed: icon + label + duration + ellipsis preview
  • Expanded: full content (string or ReactNode like XDSMarkdown)
  • Shimmer gradient on label while isStreaming
  • Down/up chevron right after label text
  • Controlled/uncontrolled expand state

XDSChatToolCalls

Displays tool/function call invocations from LLM responses. Accepts a calls array matching the shape LLM APIs return.

Layout:

  • Single call renders inline (no group chrome)
  • Multiple calls get a collapsible pile visual with stacked depth cards
  • Wrench icon + aggregate status indicator on group header

Per-call features:

  • status: pending (pulse) → running (spin) → complete (check) | error (X)
  • node: sandbox badge rendered as XDSBadge pill (e.g. cli:devvm)
  • stats: inline additions/deletions/files/matches display
  • duration: shown when complete
  • errorMessage: title tooltip on error status icon
  • onClick: interactive rows with hover state — consumer decides the interaction (modal, panel, etc.)

Group behavior:

  • Auto-expand when any call has errors
  • Error count in red: "3 tool calls · 1 failed"
  • Aggregate status: spinning for pending, error X with count, checkmark when all complete
  • Auto-collapse when >3 calls (unless errors)

CodeBlock fix

Added display: flex; flex-direction: column to root for proper scroll behavior inside dialogs.

Stories

XDSChatReasoning (5): Collapsed, Expanded, Streaming, CustomLabel, InMessage
XDSChatToolCalls (10): SingleCall, MultipleCalls, WithNodes, WithStats, WithErrors, Running, Streaming, ManyCalls, Interactive (diff modal via useXDSImperativeDialog), ErrorWithModal (banner + code block)

Addresses Reasoning & Tool Calls findings from #1226.


@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Meta Open Source bot. label Apr 8, 2026
@github-actions

github-actions Bot commented Apr 8, 2026

Copy link
Copy Markdown
Contributor

PR Analysis Report

📚 Storybook Preview

View Storybook for this PR
GitHub Pages may take up to a minute to hydrate after deploy.

🧪 Sandbox Preview

View Sandbox for this PR
GitHub Pages may take up to a minute to hydrate after deploy.

Modified Components

Chat · View in Storybook · 🆕 XDSChatReasoning, XDSChatToolCalls
Metric Before After Delta
Bundle Size (ESM) N/A 65.2KB N/A
Lines of Code N/A 3161 -
Complexity N/A Very High (306) -
CodeBlock · View in Storybook
Metric Before After Delta
Bundle Size (ESM) N/A 646B N/A
Lines of Code N/A 1187 -
Complexity N/A Very High (63) -

Bundle Size Summary

Package Size (ESM) Size (CJS) Gzipped
@xds/core 14.8KB 23.3KB 3.5KB

Accessibility Audit

Status: 2 accessibility violation(s) found — 2 serious.

XDSCodeBlock - 2 issue(s)
  • 🟠 serious: Ensure the contrast between foreground and background colors meets WCAG 2 AA minimum contrast ratio thresholds
    • Rule: color-contrast · Affects 9/13 stories · Learn more
    • WCAG: 1.4.3 (Level AA)
  • 🟠 serious: Ensure elements that have scrollable content are accessible by keyboard
    • Rule: scrollable-region-focusable · Affects 1/13 stories · Learn more
    • WCAG: 2.1.1, 2.1.3 (Level A)

Generated by PR Enrichment workflow | Storybook | Sandbox | View full report

@cixzhang
cixzhang force-pushed the navi/feat/chat-reasoning-toolcall branch from 86e3b19 to 0141cad Compare April 9, 2026 18:49
cixzhang and others added 15 commits April 10, 2026 00:00
Co-authored-by: Navi <navi@navibot.dev>
…lCalls

Every LLM API (Vercel AI SDK, Anthropic, OpenAI) and agentic frameworks
(Navi, LangGraph) return tool calls as an array on the message. One
component with a data prop matches that shape — no compound component
wiring needed.

- calls prop accepts array of {name, status, label, duration, data}
- Single call renders inline (no group chrome)
- Multiple calls get collapsible summary (auto-expand ≤3, collapse >3)
- renderDetail callback for rich per-tool rendering (Navi file diffs, etc.)
- label prop for human-readable summaries (e.g. 'Edit Button.tsx')
- data passthrough for arbitrary per-call context

Co-authored-by: Navi <navi@navibot.dev>
Co-authored-by: Navi <navi@navibot.dev>
…streaming story

XDSChatToolCallItem:
- node?: string — sandbox badge (renders XDSBadge neutral pill)
- stats?: {additions, deletions, files, matches} — inline stats display
- errorMessage?: string — title tooltip on error status icon

Group header:
- Pile visual: stacked background cards with translateY offset
  (only when collapsed, 2+ calls). Conveys depth like Navi's tool-pile.
- Aggregate status icon: spinning for pending, error X for errors
  (with count tooltip), checkmark when all complete
- Chevron moved to start (before tools icon) matching Navi layout

8 storybook stories including Streaming demo with live status transitions.

Co-authored-by: Navi <navi@navibot.dev>
- P1: Replace unrecognizable tools icon with wrench SVG
- P1: Move expand/collapse chevron right after label text (not far right)
- P1: Chevron points down when collapsed, up when expanded (not right→rotated)
- P1: Add marginBlockStart spacing between message and reasoning/tool calls
- P1: Status icons now 16px to align with the group wrench icon

Both XDSChatReasoning and XDSChatToolCalls updated.

Co-authored-by: Navi <navi@navibot.dev>
Each call in the calls array can now have an onClick handler. When
present, the row gets pointer cursor, hover highlight, and keyboard
support (Enter/Space). Consumer decides the interaction — modal,
panel, drawer, navigation. Calls without onClick remain plain status rows.

New story: Interactive — edit call opens diff, bash opens output,
web_search is non-interactive.

Co-authored-by: Navi <navi@navibot.dev>
Demonstrates onClick with XDSDialog + XDSCodeBlock:
- Edit call (with +12/-3 stats) opens a modal with a diff code block
- Bash call opens a modal with test output
- Web search has no onClick — plain status row

Shows how consumers wire onClick to any detail view pattern.

Co-authored-by: Navi <navi@navibot.dev>
…script for diff

Co-authored-by: Navi <navi@navibot.dev>
Co-authored-by: Navi <navi@navibot.dev>
…tory

- Auto-expand group when any call has status 'error'
- Group label shows '3 tool calls · 1 failed' when errors present
- New ErrorWithModal story: clicking failed 'yarn test' opens a
  dialog with XDSBanner (error) + XDSCodeBlock (test output)
- Node names updated to realistic values (cli:devvm, workspace)

Co-authored-by: Navi <navi@navibot.dev>
Co-authored-by: Navi <navi@navibot.dev>
Co-authored-by: Navi <navi@navibot.dev>
Error output visible immediately without scrolling.

Co-authored-by: Navi <navi@navibot.dev>
… block fix

Co-authored-by: Navi <navi@navibot.dev>
@cixzhang
cixzhang force-pushed the navi/feat/chat-reasoning-toolcall branch from 5408222 to 5a569df Compare April 10, 2026 00:01
@cixzhang
cixzhang merged commit 96bbbd7 into main Apr 10, 2026
16 checks passed
@cixzhang
cixzhang deleted the navi/feat/chat-reasoning-toolcall branch April 25, 2026 20:58
cixzhang added a commit that referenced this pull request Apr 26, 2026
)

* feat(Chat): add Reasoning, ToolCall, ToolCallGroup

Co-authored-by: Navi <navi@users.noreply.github.com>

* refactor(Chat): merge ToolCall + ToolCallGroup into single XDSChatToolCalls

Every LLM API (Vercel AI SDK, Anthropic, OpenAI) and agentic frameworks
(Navi, LangGraph) return tool calls as an array on the message. One
component with a data prop matches that shape — no compound component
wiring needed.

- calls prop accepts array of {name, status, label, duration, data}
- Single call renders inline (no group chrome)
- Multiple calls get collapsible summary (auto-expand ≤3, collapse >3)
- renderDetail callback for rich per-tool rendering (Navi file diffs, etc.)
- label prop for human-readable summaries (e.g. 'Edit Button.tsx')
- data passthrough for arbitrary per-call context

Co-authored-by: Navi <navi@users.noreply.github.com>

* fix: add missing label/data to ToolCallItem type

Co-authored-by: Navi <navi@users.noreply.github.com>

* feat(Chat): tool call node badges, stats, pile visual, error status, streaming story

XDSChatToolCallItem:
- node?: string — sandbox badge (renders XDSBadge neutral pill)
- stats?: {additions, deletions, files, matches} — inline stats display
- errorMessage?: string — title tooltip on error status icon

Group header:
- Pile visual: stacked background cards with translateY offset
  (only when collapsed, 2+ calls). Conveys depth like Navi's tool-pile.
- Aggregate status icon: spinning for pending, error X for errors
  (with count tooltip), checkmark when all complete
- Chevron moved to start (before tools icon) matching Navi layout

8 storybook stories including Streaming demo with live status transitions.

Co-authored-by: Navi <navi@users.noreply.github.com>

* fix(Chat): address Kenton's feedback on Reasoning & Tool Calls (#1226)

- P1: Replace unrecognizable tools icon with wrench SVG
- P1: Move expand/collapse chevron right after label text (not far right)
- P1: Chevron points down when collapsed, up when expanded (not right→rotated)
- P1: Add marginBlockStart spacing between message and reasoning/tool calls
- P1: Status icons now 16px to align with the group wrench icon

Both XDSChatReasoning and XDSChatToolCalls updated.

Co-authored-by: Navi <navi@users.noreply.github.com>

* feat(Chat): onClick on tool call items for interactive detail viewing

Each call in the calls array can now have an onClick handler. When
present, the row gets pointer cursor, hover highlight, and keyboard
support (Enter/Space). Consumer decides the interaction — modal,
panel, drawer, navigation. Calls without onClick remain plain status rows.

New story: Interactive — edit call opens diff, bash opens output,
web_search is non-interactive.

Co-authored-by: Navi <navi@users.noreply.github.com>

* feat(Chat): Interactive story — edit opens diff modal, bash opens output

Demonstrates onClick with XDSDialog + XDSCodeBlock:
- Edit call (with +12/-3 stats) opens a modal with a diff code block
- Bash call opens a modal with test output
- Web search has no onClick — plain status row

Shows how consumers wire onClick to any detail view pattern.

Co-authored-by: Navi <navi@users.noreply.github.com>

* fix(Chat): Interactive story — remove dialog padding, wider, use typescript for diff

Co-authored-by: Navi <navi@users.noreply.github.com>

* fix: remove dialog header from Interactive story

Co-authored-by: Navi <navi@users.noreply.github.com>

* feat(Chat): auto-expand on error, error count in label, error modal story

- Auto-expand group when any call has status 'error'
- Group label shows '3 tool calls · 1 failed' when errors present
- New ErrorWithModal story: clicking failed 'yarn test' opens a
  dialog with XDSBanner (error) + XDSCodeBlock (test output)
- Node names updated to realistic values (cli:devvm, workspace)

Co-authored-by: Navi <navi@users.noreply.github.com>

* fix: red error count, banner title + spacer in error modal

Co-authored-by: Navi <navi@users.noreply.github.com>

* fix: literal · instead of escaped \u00b7 in JSX

Co-authored-by: Navi <navi@users.noreply.github.com>

* fix: show code block first in error modal, banner below

Error output visible immediately without scrolling.

Co-authored-by: Navi <navi@users.noreply.github.com>

* fix: scrollable code block (maxHeight 50vh) + spacer before banner

Co-authored-by: Navi <navi@users.noreply.github.com>

* refactor: split stories, remove renderDetail, imperative dialog, code block fix

Co-authored-by: Navi <navi@users.noreply.github.com>

---------

Co-authored-by: Navi <navi@users.noreply.github.com>
cixzhang added a commit that referenced this pull request Jun 21, 2026
)

* feat(Chat): add Reasoning, ToolCall, ToolCallGroup

Co-authored-by: Navi <navi@users.noreply.github.com>

* refactor(Chat): merge ToolCall + ToolCallGroup into single XDSChatToolCalls

Every LLM API (Vercel AI SDK, Anthropic, OpenAI) and agentic frameworks
(Navi, LangGraph) return tool calls as an array on the message. One
component with a data prop matches that shape — no compound component
wiring needed.

- calls prop accepts array of {name, status, label, duration, data}
- Single call renders inline (no group chrome)
- Multiple calls get collapsible summary (auto-expand ≤3, collapse >3)
- renderDetail callback for rich per-tool rendering (Navi file diffs, etc.)
- label prop for human-readable summaries (e.g. 'Edit Button.tsx')
- data passthrough for arbitrary per-call context

Co-authored-by: Navi <navi@users.noreply.github.com>

* fix: add missing label/data to ToolCallItem type

Co-authored-by: Navi <navi@users.noreply.github.com>

* feat(Chat): tool call node badges, stats, pile visual, error status, streaming story

XDSChatToolCallItem:
- node?: string — sandbox badge (renders XDSBadge neutral pill)
- stats?: {additions, deletions, files, matches} — inline stats display
- errorMessage?: string — title tooltip on error status icon

Group header:
- Pile visual: stacked background cards with translateY offset
  (only when collapsed, 2+ calls). Conveys depth like Navi's tool-pile.
- Aggregate status icon: spinning for pending, error X for errors
  (with count tooltip), checkmark when all complete
- Chevron moved to start (before tools icon) matching Navi layout

8 storybook stories including Streaming demo with live status transitions.

Co-authored-by: Navi <navi@users.noreply.github.com>

* fix(Chat): address Kenton's feedback on Reasoning & Tool Calls (#1226)

- P1: Replace unrecognizable tools icon with wrench SVG
- P1: Move expand/collapse chevron right after label text (not far right)
- P1: Chevron points down when collapsed, up when expanded (not right→rotated)
- P1: Add marginBlockStart spacing between message and reasoning/tool calls
- P1: Status icons now 16px to align with the group wrench icon

Both XDSChatReasoning and XDSChatToolCalls updated.

Co-authored-by: Navi <navi@users.noreply.github.com>

* feat(Chat): onClick on tool call items for interactive detail viewing

Each call in the calls array can now have an onClick handler. When
present, the row gets pointer cursor, hover highlight, and keyboard
support (Enter/Space). Consumer decides the interaction — modal,
panel, drawer, navigation. Calls without onClick remain plain status rows.

New story: Interactive — edit call opens diff, bash opens output,
web_search is non-interactive.

Co-authored-by: Navi <navi@users.noreply.github.com>

* feat(Chat): Interactive story — edit opens diff modal, bash opens output

Demonstrates onClick with XDSDialog + XDSCodeBlock:
- Edit call (with +12/-3 stats) opens a modal with a diff code block
- Bash call opens a modal with test output
- Web search has no onClick — plain status row

Shows how consumers wire onClick to any detail view pattern.

Co-authored-by: Navi <navi@users.noreply.github.com>

* fix(Chat): Interactive story — remove dialog padding, wider, use typescript for diff

Co-authored-by: Navi <navi@users.noreply.github.com>

* fix: remove dialog header from Interactive story

Co-authored-by: Navi <navi@users.noreply.github.com>

* feat(Chat): auto-expand on error, error count in label, error modal story

- Auto-expand group when any call has status 'error'
- Group label shows '3 tool calls · 1 failed' when errors present
- New ErrorWithModal story: clicking failed 'yarn test' opens a
  dialog with XDSBanner (error) + XDSCodeBlock (test output)
- Node names updated to realistic values (cli:devvm, workspace)

Co-authored-by: Navi <navi@users.noreply.github.com>

* fix: red error count, banner title + spacer in error modal

Co-authored-by: Navi <navi@users.noreply.github.com>

* fix: literal · instead of escaped \u00b7 in JSX

Co-authored-by: Navi <navi@users.noreply.github.com>

* fix: show code block first in error modal, banner below

Error output visible immediately without scrolling.

Co-authored-by: Navi <navi@users.noreply.github.com>

* fix: scrollable code block (maxHeight 50vh) + spacer before banner

Co-authored-by: Navi <navi@users.noreply.github.com>

* refactor: split stories, remove renderDetail, imperative dialog, code block fix

Co-authored-by: Navi <navi@users.noreply.github.com>

---------

Co-authored-by: Navi <navi@users.noreply.github.com>
cixzhang added a commit that referenced this pull request Jun 21, 2026
)

* feat(Chat): add Reasoning, ToolCall, ToolCallGroup


* refactor(Chat): merge ToolCall + ToolCallGroup into single XDSChatToolCalls

Every LLM API (Vercel AI SDK, Anthropic, OpenAI) and agentic frameworks
(Navi, LangGraph) return tool calls as an array on the message. One
component with a data prop matches that shape — no compound component
wiring needed.

- calls prop accepts array of {name, status, label, duration, data}
- Single call renders inline (no group chrome)
- Multiple calls get collapsible summary (auto-expand ≤3, collapse >3)
- renderDetail callback for rich per-tool rendering (Navi file diffs, etc.)
- label prop for human-readable summaries (e.g. 'Edit Button.tsx')
- data passthrough for arbitrary per-call context


* fix: add missing label/data to ToolCallItem type


* feat(Chat): tool call node badges, stats, pile visual, error status, streaming story

XDSChatToolCallItem:
- node?: string — sandbox badge (renders XDSBadge neutral pill)
- stats?: {additions, deletions, files, matches} — inline stats display
- errorMessage?: string — title tooltip on error status icon

Group header:
- Pile visual: stacked background cards with translateY offset
  (only when collapsed, 2+ calls). Conveys depth like Navi's tool-pile.
- Aggregate status icon: spinning for pending, error X for errors
  (with count tooltip), checkmark when all complete
- Chevron moved to start (before tools icon) matching Navi layout

8 storybook stories including Streaming demo with live status transitions.


* fix(Chat): address Kenton's feedback on Reasoning & Tool Calls (#1226)

- P1: Replace unrecognizable tools icon with wrench SVG
- P1: Move expand/collapse chevron right after label text (not far right)
- P1: Chevron points down when collapsed, up when expanded (not right→rotated)
- P1: Add marginBlockStart spacing between message and reasoning/tool calls
- P1: Status icons now 16px to align with the group wrench icon

Both XDSChatReasoning and XDSChatToolCalls updated.


* feat(Chat): onClick on tool call items for interactive detail viewing

Each call in the calls array can now have an onClick handler. When
present, the row gets pointer cursor, hover highlight, and keyboard
support (Enter/Space). Consumer decides the interaction — modal,
panel, drawer, navigation. Calls without onClick remain plain status rows.

New story: Interactive — edit call opens diff, bash opens output,
web_search is non-interactive.


* feat(Chat): Interactive story — edit opens diff modal, bash opens output

Demonstrates onClick with XDSDialog + XDSCodeBlock:
- Edit call (with +12/-3 stats) opens a modal with a diff code block
- Bash call opens a modal with test output
- Web search has no onClick — plain status row

Shows how consumers wire onClick to any detail view pattern.


* fix(Chat): Interactive story — remove dialog padding, wider, use typescript for diff


* fix: remove dialog header from Interactive story


* feat(Chat): auto-expand on error, error count in label, error modal story

- Auto-expand group when any call has status 'error'
- Group label shows '3 tool calls · 1 failed' when errors present
- New ErrorWithModal story: clicking failed 'yarn test' opens a
  dialog with XDSBanner (error) + XDSCodeBlock (test output)
- Node names updated to realistic values (cli:devvm, workspace)


* fix: red error count, banner title + spacer in error modal


* fix: literal · instead of escaped \u00b7 in JSX


* fix: show code block first in error modal, banner below

Error output visible immediately without scrolling.


* fix: scrollable code block (maxHeight 50vh) + spacer before banner


* refactor: split stories, remove renderDetail, imperative dialog, code block fix


---------
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Meta Open Source bot.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant