fix(web): keep skill row pairing client-local

This commit is contained in:
Yichen Jiang
2026-08-07 13:56:42 +08:00
parent 09d1b0d27f
commit 768e2e866f
31 changed files with 79 additions and 273 deletions

View File

@@ -2,5 +2,5 @@
# side as of the last confirmed-consistent state. Both languages carry equal authority;
# after editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write .agents/notes/implemented/feature/2026-08-06-web-skill-tool-row.md
2026-08-06-web-skill-tool-row.md: bebcf658de33d133ffea8eb190fb4e8e63bf82ff
2026-08-06-web-skill-tool-row.zh.md: 9377829aab1cb6b347cb837dafe7e7e4afb63868
2026-08-06-web-skill-tool-row.md: 6583062f38b0e9cff059fa4477313ff6a5bdd2aa
2026-08-06-web-skill-tool-row.zh.md: 3d5c4b712896c2cf41df3ec913c597f7f791486c

View File

@@ -14,16 +14,16 @@ The Web transcript renders `skill` calls through the generic fallback row, so a
The collapsed row uses a 16-pixel document-and-sparkle glyph and the Bash row's neutral hierarchy: tertiary glyph, secondary `Skill` title, caption separator, and tertiary skill name. Running, failed, and interrupted calls retain the transcript's shimmer, error dot and first-line summary, and warning dot semantics. A settled call expands through the whole summary row into a 260-pixel bounded `Instructions` card containing the exact durable result text; the existing trajectory `Inspect` handoff remains available below the card.
The row derives every visible value from the logged call/result slice. It reads the skill name from the recorded `name` argument and the instructions from durable result content, and never joins the current skill catalog for descriptions or provider metadata. Because a history page can contain a `tool/result` after its `tool/call` fell outside the window, the generic `HistoryEntry` envelope now carries the paired call's name, exact arguments JSON, and event time on result entries. The Host derives this transient annotation and the result render intent from the complete log; the runtime prefers an in-window call and otherwise materializes the same `ToolResultNode.call` and `callTime` from the annotation. An orphan result still has `call: null`, and a call-side render intent remains unavailable when its event is outside the page. The existing ACP `skill-load` recording is seeded through the real Web persistence and composition path for a keyless interaction and accessibility snapshot.
The row derives every visible value from a paired call/result slice in the current runtime window. It reads the skill name from the recorded `name` argument and the instructions from durable result content, and never joins the current skill catalog for descriptions or provider metadata. If pagination leaves the call outside the window, the result has no tool identity and remains on the generic fallback rather than extending the history wire contract. The existing ACP `skill-load` recording is seeded through the real Web persistence and composition path for a keyless interaction and accessibility snapshot.
## Alternatives considered
- Keep the generic tool row and add only a `skill` color selector in `ui-conversation`. This leaves the redundant input envelope and generic expanded body in place, and makes the conversation package own a domain-specific visual rule.
- Add a new `skill` value to the host tool render-intent union. The keyed client slot already identifies this tool; the cross-page fix belongs to the generic history pairing envelope used by every tool rather than a skill-specific presentation value.
- Add a new `skill` value to the host tool render-intent union. The keyed client slot already identifies this tool when its call is in the runtime window, so a new cross-boundary presentation value adds protocol and snapshot surface without enabling another consumer.
- Export the conversation package's private `ToolRow` component for reuse. Client packages intentionally expose contracts rather than cross-package components; exporting it would couple independent feature packages to conversation implementation details.
## Consequences
`ui-skill` now depends on the public conversation toolview contract, locale and primitive packages, and React in addition to its reference-source dependencies. It owns a small copy of the disclosure-row chrome, so future global interaction changes must update this registrant alongside the Bash sample and conversation rows.
Cold replay stays deterministic across pagination and when the installed skill catalog changes, and the transcript remains compact until instructions are explicitly expanded. The generic pairing annotation also prevents other keyed tool rows and result presenters from changing identity at a page boundary without persisting duplicate data. The dedicated card intentionally shows the tool's complete framed output rather than extracting only `<skill_instructions>`, preserving exactly what reached the model and avoiding a second parser for the skill result format.
Cold replay stays deterministic when the installed skill catalog changes, and the transcript remains compact until instructions are explicitly expanded. A result-only history page intentionally uses the generic fallback; keeping this edge case generic preserves the existing history protocol and confines the feature to client presentation. The dedicated card intentionally shows the tool's complete framed output rather than extracting only `<skill_instructions>`, preserving exactly what reached the model and avoiding a second parser for the skill result format.

View File

@@ -14,16 +14,16 @@ Web transcript文本记录通过通用后备行渲染 `skill` 调用,使
收起的行使用 16 像素的文档与闪光组合图标,并沿用 Bash 行的中性色层级:图标采用三级色,`Skill` 标题采用二级色,分隔符采用 caption 色skill 名称采用三级色。运行、失败和中断调用分别沿用 transcript 的扫光、错误状态点加首行摘要,以及警告状态点语义。已结算调用可以通过整个摘要行展开一个高度上限为 260 像素的 `Instructions` 卡片,其中原样呈现持久化结果文本;用于跳转至 trajectory 的现有 `Inspect` 入口仍保留在卡片下方。
该行的所有可见值均派生自已记录的调用结果片段。skill 名称来自已记录的 `name` 参数,指令来自持久化的结果内容;该行绝不关联当前 skill 目录来读取描述或提供方元数据。由于 history 页可能包含 `tool/result`,而与之配对的 `tool/call` 已落在窗口外,通用 `HistoryEntry` envelope 现在会在结果条目上携带配对调用的名称、精确的 arguments JSON 和事件时间。Host 从完整日志派生这份瞬时注解和结果渲染意图runtime 优先使用窗口内调用,否则从该注解物化出相同的 `ToolResultNode.call``callTime`。无配对结果仍为 `call: null`;调用事件位于页面外时,调用侧渲染意图仍不可用。现有的 ACPAgent Client Protocol`skill-load` 记录经由真实的 Web 持久化与组合路径写入,用于无需密钥的交互和无障碍快照。
该行的所有可见值均派生自当前 runtime 窗口中已配对的调用结果片段。skill 名称来自已记录的 `name` 参数,指令来自持久化的结果内容;该行绝不关联当前 skill 目录来读取描述或提供方元数据。如果分页将调用留在窗口外,结果便没有工具身份,并继续使用通用后备路径,而不是扩展 history 协议契约。现有的 ACPAgent Client Protocol`skill-load` 记录经由真实的 Web 持久化与组合路径写入,用于无需密钥的交互和无障碍快照。
## 考虑过的替代方案
- 保留通用工具行,只添加一个 `skill` 颜色选择器,并将其放在 `ui-conversation` 中。该方案仍会保留多余的输入外层结构和通用展开体,也会让 conversation 包拥有特定领域的视觉规则。
- 在宿主工具渲染意图联合类型中添加新的 `skill` 值。键控客户端 slot 已经能够识别该工具;跨页修复属于所有工具共用的通用 history 配对 envelope而不是 skill 专用的呈现值
- 在宿主工具渲染意图联合类型中添加新的 `skill` 值。键控客户端 slot 在调用位于 runtime 窗口内时已经能够识别该工具,因此新的跨边界呈现值只会增加协议和快照表层,却不会支持其他消费方
- 导出 conversation 包的私有 `ToolRow` 组件供复用。客户端包刻意对外暴露契约而非跨包组件;导出该组件会使独立功能包耦合到 conversation 的实现细节。
## 后果
除了引用 source 的依赖外,`ui-skill` 现在还依赖公开的 conversation toolview 契约、locale 包、原语包和 React。它自行保留了一小份折叠展开行 chrome因此未来的全局交互变更必须与 Bash 示例和 conversation 行同步更新这个注册方。
无论跨越分页,还是已安装的 skill 目录发生变化,冷回放保持确定性在用户显式展开指令前transcript 保持紧凑。通用配对注解还可防止其他键控工具行和结果 presenter 在分页边界改变身份,同时无需持久化重复数据。专用卡片有意显示工具完整封装的输出,而不是只提取 `<skill_instructions>`,从而原样保留模型实际收到的内容,也避免为 skill 结果格式再引入一个解析器。
即使已安装的 skill 目录发生变化,冷回放保持确定性在用户显式展开指令前transcript 保持紧凑。仅含结果的 history 页有意使用通用后备路径;让这个边缘情况保持通用呈现,可以保留现有 history 协议,并将该功能限定在客户端呈现层。专用卡片有意显示工具完整封装的输出,而不是只提取 `<skill_instructions>`,从而原样保留模型实际收到的内容,也避免为 skill 结果格式再引入一个解析器。