dashboard: adopt ToolUIPart state enum on SSE wire (input-streaming → output-{available,error,denied}) #959

Closed
opened 2026-05-08 12:14:04 +00:00 by claude-desktop · 1 comment
Collaborator

User story

As a frontend engineer, I want every tool-related SSE event to carry a canonical state field matching the Vercel AI SDK ToolUIPart enum, so the dashboard can render every tool call through one state-driven <ToolCard> component without provider/SDK conditioning.

Context

The Vercel AI SDK has consolidated tool-rendering vocabulary: input-streaming → input-available → approval-requested → output-available | output-error | output-denied. AI Elements + assistant-ui + AG-UI/A2UI all use this enum. Without it on our wire, every widget downstream conditions on heuristics ("did we see a tool_call_started? a tool_call_completed? does result have an error?"). Setting the enum on the server side is the cheapest possible foundation for the whole widget roadmap.

Acceptance criteria

  • Add ToolCallState to @claude-hooks/shared: "input-streaming" | "input-available" | "approval-requested" | "output-available" | "output-error" | "output-denied".
  • Both adapters set state on every tool-related event: tool_call_started (input-streaming while args still arriving, input-available once full), tool_call_progress (input-streaming), tool_call_completed (output-available or output-error).
  • When the server enforces a deny via tool policy (already in the runner) emit output-denied rather than output-error.
  • When a permission gate is blocking the call (future approval flow), emit approval-requested (placeholder until that issue lands; document the contract now so frontends can be written once).
  • Document on docs/api.md SSE section.

Out of scope

  • The <ToolCard> widget itself (separate ticket).
  • The approval flow itself.

Dependencies

  • Depends on #951 (interaction deltas) — supplies the started/progress/completed event split.
  • Depends on #954 (ToolKind taxonomy) — state rides alongside kind.

References

## User story As a frontend engineer, I want every tool-related SSE event to carry a canonical `state` field matching the Vercel AI SDK `ToolUIPart` enum, so the dashboard can render every tool call through one state-driven `<ToolCard>` component without provider/SDK conditioning. ## Context The Vercel AI SDK has consolidated tool-rendering vocabulary: `input-streaming → input-available → approval-requested → output-available | output-error | output-denied`. AI Elements + assistant-ui + AG-UI/A2UI all use this enum. Without it on our wire, every widget downstream conditions on heuristics ("did we see a `tool_call_started`? a `tool_call_completed`? does `result` have an error?"). Setting the enum on the server side is the cheapest possible foundation for the whole widget roadmap. ## Acceptance criteria - [ ] Add `ToolCallState` to `@claude-hooks/shared`: `"input-streaming" | "input-available" | "approval-requested" | "output-available" | "output-error" | "output-denied"`. - [ ] Both adapters set `state` on every tool-related event: `tool_call_started` (`input-streaming` while args still arriving, `input-available` once full), `tool_call_progress` (`input-streaming`), `tool_call_completed` (`output-available` or `output-error`). - [ ] When the server enforces a deny via tool policy (already in the runner) emit `output-denied` rather than `output-error`. - [ ] When a permission gate is blocking the call (future approval flow), emit `approval-requested` (placeholder until that issue lands; document the contract now so frontends can be written once). - [ ] Document on `docs/api.md` SSE section. ## Out of scope - The `<ToolCard>` widget itself (separate ticket). - The approval flow itself. ## Dependencies - Depends on #951 (interaction deltas) — supplies the started/progress/completed event split. - Depends on #954 (ToolKind taxonomy) — `state` rides alongside `kind`. ## References - Parent: #950, #951, #954 - AI Elements `Tool` state enum: https://elements.ai-sdk.dev/components/tool
Collaborator

🤖 Auto-assigned to dev (heuristic: area:dashboard + body 2024 bytes (≤ 2 KB) — code role). Reply /unassign to reroute.

🤖 Auto-assigned to **dev** (heuristic: area:dashboard + body 2024 bytes (≤ 2 KB) — code role). Reply `/unassign` to reroute.
Sign in to join this conversation.
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Reference
charles/claude-hooks#959
No description provided.