Fixed `Tool / <name>` header for tool-call cards
Fixed `Tool / <name>` header for tool-call cards
The TUI rendered each tool call as `{glyph} {title}`, where `title` was the presenter's fused verb-plus-detail string (`Read src/index.ts (1200-1360)`, `Edit files`, or a bash card's model description), bold and underlined in the status color. One flat slot carried the tool identity, the target, and the status at once, and the styling mixed bold, underline, and color inconsistently — the header read as noise, and whi
English
Problem
The TUI rendered each tool call as {glyph} {title}, where title was the presenter's fused verb-plus-detail string (Read src/index.ts (1200-1360), Edit files, or a bash card's model description), bold and underlined in the status color. One flat slot carried the tool identity, the target, and the status at once, and the styling mixed bold, underline, and color inconsistently — the header read as noise, and which tool ran was not visually separable from what it operated on.
Decision
The header is a fixed {ring} Tool / <name> frame in a single flat status color — no bold, no underline, no dim — so one color reads consistently across the whole row. Tool is a literal constant; <name> is the raw tool name. The separator is ASCII /. The ring marker is ○ while the call is pending and ● once it settles; the header color (warning pending / success ok / error) distinguishes pending from ok from error, so the same filled ring serves both settled states.
The header carries exactly one optional extra: a bash (terminal) card's model-authored description, appended as a / <desc> segment (● Tool / bash / Run the coverage gate). No other tool contributes a header detail.
Every tool-specific detail moves into the body block below the header. A non-terminal card's presenter title (Read src/index.ts, Grep pattern) becomes the first body line, unless it only repeats the tool name (the fallback presenter for a tool with no presentCall, or an unknown tool), which the header already shows. A terminal card keeps its command as the $-line. A diff card drops its title entirely — the per-file path headers and a change footer carry the meaning — and appends a dim └ +A -R · N file(s) footer summarizing added/removed line counts across the files.
The redesign is TUI-only. It touches ToolCardComponent in packages/ui/tui/src/components/transcript.ts and no presenter: the Tool / <name> frame derives the name TUI-side from the call's tool name, and the body-title relocation reuses the presenter title already returned. presentation.ts and every presentCall/presentResult are unchanged.
Alternatives considered
Bold the name to make it stand out. Rejected: on terminals that render SGR-1 as the bright color variant, a bold green name reads as a different color from the rest of the green header — reintroducing the inconsistency the redesign removes. The name stands out by position in the fixed frame, not by weight.
Keep the presenter title in the header (e.g. Tool / read / Read src/index.ts). Rejected: the verb duplicates the tool name, and non-bash tools have no genuinely distinct one-line description — the target belongs in the body, so only bash contributes a header desc.
A summary footer for every card type (line counts, exit pills, diff counts as a uniform └ … line). Deferred: only the diff footer shipped. Terminal exit keeps its existing dim [exit N] line, long output keeps its existing head+tail middle-elision, an empty result stays header-only, and an error body stays plain (only the header color carries the error) — the current treatments were kept deliberately, not by omission. The body's flat default-foreground styling was later revisited: the consolidated TUI presentation recesses the whole body into one dim tone under this note's colored status header.
Consequences
A tool call now shows its identity in one stable place, and status reads as one flat color per row, so a transcript of many calls scans as a column of Tool / <name> rather than a wall of mixed-styled verb strings. The cost is one extra body line for non-terminal tools (the relocated title) and the loss of the earlier redundancy-suppression that omitted a diff's per-file path when the header already named it — the header no longer names any path, so every diff prints its path once. Because the change is confined to ToolCardComponent, other UI bridges (ACP, JSON-RPC) keep their own tool-call presentation; the Tool / <name> shape is TUI-local and not part of any cross-package contract.
Testing
packages/ui/tui/tests/tui.spec.ts pins the new header (Tool / <name>), the dropped diff title, the relocated generic title, and the · N file(s) footer. Package semantic snapshots cover the card families in a headless terminal. The deleted application journeys formerly supplied assembled tool executions; a future terminal deployment owns equivalent transcript coverage.
中文
Problem
TUI 曾把每次工具调用渲染为 {glyph} {title},其中 title 是 presenter 拼接的「动词加细节」字符串(Read src/index.ts (1200-1360)、Edit files,或 bash 卡片的模型描述),以状态色加粗并加下划线显示。单一扁平的槽位同时承载了工具身份、操作对象和状态,而样式又混用了加粗、下划线和颜色,前后不一致——表头读起来像噪声,「运行了哪个工具」在视觉上与「它操作了什么」无法区分。
Decision
表头是固定的 {ring} Tool / <name> 框架,采用单一扁平的状态色——不加粗、不加下划线、不变暗——因此整行的颜色保持一致。Tool 是字面常量;<name> 是原始工具名。分隔符是 ASCII 的 /。环形标记在调用挂起时为 ○,落定后为 ●;表头颜色(挂起用 warning、成功用 success、错误用 error)区分挂起、成功与错误,因此同一个实心环可同时服务于两种落定状态。
表头只携带一个可选的额外内容:bash(终端)卡片由模型撰写的描述,作为 / <desc> 段追加(● Tool / bash / Run the coverage gate)。其他工具都不向表头贡献细节。
每一项工具专属的细节都移入表头下方的正文块。非终端卡片的 presenter 标题(Read src/index.ts、Grep pattern)成为正文第一行,除非它只是重复工具名(无 presentCall 的工具的兜底 presenter,或未知工具),此时表头已经显示过。终端卡片保留其命令作为 $ 行。diff 卡片完全弃用其标题——由各文件的路径表头与一条变更页脚承载含义——并追加一条变暗的 └ +A -R · N file(s) 页脚,汇总各文件增删的行数。
本次改版仅限 TUI。它改动 packages/ui/tui/src/components/transcript.ts 中的 ToolCardComponent,不触碰任何 presenter:Tool / <name> 框架在 TUI 侧从调用的工具名推导出名称,正文标题的迁移则复用 presenter 已返回的标题。presentation.ts 以及每一个 presentCall/presentResult 均保持不变。
Alternatives considered
把工具名加粗使其突出。 已否决:在把 SGR-1 渲染为亮色变体的终端上,加粗的绿色工具名读起来与其余绿色表头是不同的颜色——重新引入了改版本要消除的不一致。工具名靠它在固定框架中的位置突出,而非靠字重。
把 presenter 标题保留在表头(例如 Tool / read / Read src/index.ts)。已否决:动词与工具名重复,而非 bash 工具并没有真正独立的单行描述——操作对象属于正文,因此只有 bash 向表头贡献描述段。
为每一种卡片都加一条汇总页脚(行数、退出码徽章、diff 计数统一为一条 └ … 行)。已推迟:仅 diff 页脚落地。终端退出保留其既有的变暗 [exit N] 行,长输出保留其既有的首尾中段省略,空结果保持仅表头,错误正文保持朴素(仅表头颜色承载错误)——这些既有处理是有意保留的,而非遗漏。正文原本以默认前景色平铺,这种样式后来也经过调整:整合后的 TUI 呈现把整个正文收进本文所述彩色状态标题之下的同一种暗色调。
Consequences
工具调用现在把身份显示在一个稳定的位置,状态每行读作一种扁平色,于是许多调用的记录扫读起来是一列 Tool / <name>,而非一堵混合样式的动词字符串之墙。代价是非终端工具多出一行正文(迁移过来的标题),以及丢失了先前的冗余抑制——当表头已命名路径时省略 diff 的各文件路径;如今表头不再命名任何路径,因此每个 diff 都会把路径打印一次。由于改动局限于 ToolCardComponent,其他 UI 桥(ACP、JSON-RPC)保留各自的工具调用呈现;Tool / <name> 的形态是 TUI 局部的,不属于任何跨包契约。
Testing
packages/ui/tui/tests/tui.spec.ts 固定了新表头(Tool / <name>)、弃用的 diff 标题、迁移后的 generic 标题以及 · N file(s) 页脚。包级语义快照在无界面终端中覆盖各类卡片。已删除的应用流程此前提供组装后的工具执行;未来的终端部署负责提供等价的 transcript 覆盖。