6cd4793081
The card follows the approval bar's consent vocabulary (primary-tinted action + ghost decline, ⌘⏎/Esc with clarify's focus-stand-down rule) on clarify's widget shell. Install prefers the reviewed catalog entry (env prompts inline, background installs polled to completion) and falls back to the desktop suggestion directory via the validated add-server POST + OAuth; success reloads live MCP tools before unblocking the agent so it resumes with the tools it was just promised. Esc stays live mid-flight as cancel — the abandoned flow aborts at its next poll and a post-write cancel rolls the config entry back. Typing while the card is pending declines it and sends normally (skipClarifyRequest's pattern), and the request/tool.start rows merge on the server arg so reconnects can't double-render the card.
47 lines
2.1 KiB
TypeScript
47 lines
2.1 KiB
TypeScript
/**
|
|
* Which surface a tool call renders as.
|
|
*
|
|
* Two consumers have to agree on this and they sit on opposite sides of the
|
|
* app: the transcript decides what to draw, and the DOM render budget decides
|
|
* how much of the transcript to mount. Pricing a turn correctly means pricing
|
|
* what the grouping actually renders, so the classification lives on its own
|
|
* rather than inside either one.
|
|
*/
|
|
|
|
const FILE_EDIT_TOOL_NAMES = new Set(['edit_file', 'patch', 'write_file'])
|
|
|
|
/** Renders a diff — the deliverable of the turn, and the one card whose cost scales. */
|
|
export function isFileEditTool(toolName: string): boolean {
|
|
return FILE_EDIT_TOOL_NAMES.has(toolName)
|
|
}
|
|
|
|
// Tools that draw their own surface and must never be folded into a run's
|
|
// summary. Two kinds, for the same reason — the thing on screen IS the point:
|
|
//
|
|
// - File edits are the deliverable, not scaffolding. The diff is what the
|
|
// user reviews, so it stays visible at its place in the turn, live and
|
|
// settled, the way a PR shows its changes.
|
|
// - `clarify`, `image_generate` and `delegate_task` bypass ToolEntry to
|
|
// render their own markup: a question the user has to answer, an image
|
|
// they asked for, the several agents a fan-out is running.
|
|
// - `setup_mcp` is the same kind: an inline consent card the user has to
|
|
// act on. Folding it into a "Using 2 tools" summary hides the buttons.
|
|
//
|
|
// Everything else is ephemeral activity — reads, searches, commands — which is
|
|
// what a run summarizes and what the live ticker cycles through.
|
|
const CARD_TOOL_NAMES = new Set(['clarify', 'delegate_task', 'image_generate', 'setup_mcp'])
|
|
|
|
export function isCardTool(toolName: string): boolean {
|
|
return CARD_TOOL_NAMES.has(toolName) || isFileEditTool(toolName)
|
|
}
|
|
|
|
// Activity tools that render nothing at all: `todo` parts are hoisted to a
|
|
// dedicated panel above the message content, and a reaction's UI is the emoji
|
|
// landing on the bubble. Both still render when they FAIL, which is a bounded
|
|
// error row either way.
|
|
const SILENT_TOOL_NAMES = new Set(['react_to_message', 'todo'])
|
|
|
|
export function isSilentTool(toolName: string): boolean {
|
|
return SILENT_TOOL_NAMES.has(toolName)
|
|
}
|