docs: describe shared lazy tool argument views
This commit is contained in:
1 parent
a44b143ace
commit
35aebdca70
21 files changed
+235
-59
No files matched your search
@@ -12,17 +12,17 @@
|
||||
en: a15c7c13f167e5ac
|
||||
zh: 63bcc2ef60c2f344
|
||||
/agent-note-tool-calls-own-preparation-dispatch-and-results-by-callid/decision/one-tool-owns-three-stages:
|
||||
en: ea65da88c3df35bb
|
||||
zh: a71afb4683a75290
|
||||
en: c4bac1088a4fd3bc
|
||||
zh: 549348deae5485c1
|
||||
/agent-note-tool-calls-own-preparation-dispatch-and-results-by-callid/decision/start-marks-an-initialization-candidate:
|
||||
en: 696a180246e23391
|
||||
zh: aeb2b1fdcfdf9631
|
||||
en: 7771032e6ad227e7
|
||||
zh: 313d32ab5312d965
|
||||
/agent-note-tool-calls-own-preparation-dispatch-and-results-by-callid/decision/converge-on-final-state-without-replaying-preparation:
|
||||
en: 603cbcf3379ad4f7
|
||||
zh: e34d87ea348c756b
|
||||
/agent-note-tool-calls-own-preparation-dispatch-and-results-by-callid/decision/shared-rows-reuse-their-existing-presentation:
|
||||
en: 24536588cd0c979b
|
||||
zh: 992d4c4657d6d034
|
||||
en: a5741c967212250b
|
||||
zh: de6288916a054c6e
|
||||
/agent-note-tool-calls-own-preparation-dispatch-and-results-by-callid/decision/relationship-to-existing-records:
|
||||
en: bd4984f66c507785
|
||||
zh: 4d2372fdbc4c3cec
|
||||
@@ -30,5 +30,5 @@
|
||||
en: 505095bec889700e
|
||||
zh: b77c492de3e8641a
|
||||
/agent-note-tool-calls-own-preparation-dispatch-and-results-by-callid/consequences:
|
||||
en: 3cf36b54240013da
|
||||
zh: 67e663b431bc67d2
|
||||
en: dd0e4561c50b1188
|
||||
zh: 0ec83177ef570a78
|
||||
@@ -18,7 +18,7 @@ The [Tool Definition](../../../../packages/client/ui-chat/src/client/conversatio
|
||||
|
||||
| Stage | Creation or update evidence | Available data and presentation |
|
||||
|---|---|---|
|
||||
| `preparing` | A live delta with a call ID and tool name | Call identity, name, and time; no complete arguments, and one non-expandable row. An opt-in Hook can read the raw argument prefix. |
|
||||
| `preparing` | A live delta with a call ID and tool name | Call identity, name, time, and a lazy partial-argument view; one non-expandable row. |
|
||||
| `start` | `tool/call` | Complete arguments; enables the tool's existing call presentation. |
|
||||
| `result` | `tool/result` | The result and any complete arguments paired within the loaded window. |
|
||||
|
||||
@@ -28,7 +28,7 @@ An argument block ending does not trigger dispatch presentation. Showing prepara
|
||||
|
||||
The [Conversation Definition](../../../../packages/client/ui-conversation/src/client/contract/conversation.ts) retains its match/start/update interface and existing roles. Durable events and transient deltas may both match as start. The earliest start in the current event sequence initializes State; every later Match, including another start for the same ID, goes through update.
|
||||
|
||||
A named tool delta and `tool/call` are both initialization candidates. A live delta can create preparation; a historical `tool/call` creates the dispatched stage directly. Matching still reads only the current event, without Context lookup, additional roles, registries, or separate caches.
|
||||
Every tool delta and `tool/call` are initialization candidates. A named live delta creates the preparing row; a historical `tool/call` creates the dispatched stage directly. Matching still reads only the current event, without Context lookup, additional roles, registries, or separate caches.
|
||||
|
||||
Successful stream settlement publishes the final Assistant message while retaining transient deltas until `step/end`. Each `tool/call` updates its existing callId; the Assistant keeps its live ordering anchor until the same cleanup. Failed, interrupted, or abandoned streams retire their deltas immediately. On retirement the Assembler reselects starts and recomputes State from remaining Matches. Undispatched preparations hide without synthetic execution results.
|
||||
|
||||
@@ -40,9 +40,9 @@ Groups include Tool nodes from preparation onward and classify and count them by
|
||||
|
||||
### Shared rows reuse their existing presentation
|
||||
|
||||
[ToolRow](../../../../packages/client/ui-tool/src/client/tool/components/ToolRow.tsx) reuses the existing icon, title, and row component across all stages. The shared row model selects the tool title and combines any generic tool-name prefix with the available argument summary. Preparation has no complete arguments or result, and the shared argument parser returns null without parsing JSON. The existing slot Hook binding optionally exposes a call-scoped raw prefix; it adds no preparation registration mechanism. ToolRow prevents preparation rows from expanding.
|
||||
[ToolRow](../../../../packages/client/ui-tool/src/client/tool/components/ToolRow.tsx) reuses the existing icon, title, and row component across all stages. The shared row model selects the tool title and combines any generic tool-name prefix with the available argument summary. All stages expose the [lazy argument view](2026-09-24-preparing-tool-arguments.md); cards requiring dispatched arguments still return no call during preparation. ToolRow prevents preparation rows from expanding.
|
||||
|
||||
Read, read_image, write/edit, search, web, todo, question, details, and the generic fallback use this path. Custom rows such as Bash, Skill, Present, and Cordis keep their own preparation branches. No automatic/custom registration declaration or second tool-classification list in ToolTree is introduced.
|
||||
Read, read_image, write/edit, search, web, todo, question, details, and the generic fallback use this path. Bash shares its component across stages; Skill, Present, and Cordis retain their own preparation branches. No automatic/custom registration declaration or second tool-classification list in ToolTree is introduced.
|
||||
|
||||
### Relationship to existing records
|
||||
|
||||
@@ -60,8 +60,8 @@ This decision replaces the [business-node assembly](2026-08-09-client-conversati
|
||||
|
||||
## Consequences
|
||||
|
||||
- A tool may appear before its arguments are complete, but preparation neither implies execution nor exposes interactions requiring arguments.
|
||||
- A tool may appear before its arguments are complete, but preparation never implies execution. Interactions use only fields already available.
|
||||
- Multiple starts with one ID belong to one lifecycle. Independent calls must use distinct IDs; a second-start error no longer detects identity reuse.
|
||||
- The shared row primitive is reused across stages. Write/edit separate preparing and dispatched components so only the former subscribes to raw arguments; custom rows may also switch internal components by stage.
|
||||
- Partial JSON parsing and `useToolCallDelta` are not provided. `useToolCallArgumentsPartial` exposes the existing Step's raw prefix without a second accumulator; write/edit use only its length for preparation progress.
|
||||
- The shared row primitive is reused across stages. Write/edit and Bash keep their component identity; custom rows may switch internal components by stage.
|
||||
- Partial-argument access and its update policy follow the lazy argument view; no separate raw-prefix Hook is required.
|
||||
- Assembly tests separately cover live preparation, withdrawal, active-stream reconstruction, durable history, and paged convergence. Component tests cover argument-free presentation and stage changes; a recorded session covers browser preparation and reload results.
|
||||
@@ -18,7 +18,7 @@ Status: implemented
|
||||
|
||||
| 阶段 | 创建或更新依据 | 可用数据与展示 |
|
||||
|---|---|---|
|
||||
| `preparing` | 带调用 ID 和工具名的实时 delta | 调用身份、名称和时间;不提供完整参数,只显示不可展开的一行。可选钩子可读取原始参数前缀。 |
|
||||
| `preparing` | 带调用 ID 和工具名的实时 delta | 调用身份、名称、时间和懒计算的部分参数视图;显示不可展开的一行。 |
|
||||
| `start` | `tool/call` | 完整参数;启用工具原有的调用展示。 |
|
||||
| `result` | `tool/result` | 调用结果,以及当前窗口内可配对的完整参数。 |
|
||||
|
||||
@@ -28,7 +28,7 @@ Status: implemented
|
||||
|
||||
沿用 [Conversation Definition](../../../../packages/client/ui-conversation/src/client/contract/conversation.ts) 的 `match/start/update` 接口和既有角色。持久事件与瞬态 delta 都可以匹配为 start;当前事件序列中最早的 start 初始化 State,后续 Match,包括同 ID 的其他 start,都交给 update。
|
||||
|
||||
Tool 的具名 delta 和 `tool/call` 都是创建入口。实时先收到 delta,就从 preparing 创建;历史先收到 `tool/call`,就从 start 创建。匹配函数仍然只读取当前事件,不查询 Context,不增加角色、注册表或旁路缓存。
|
||||
Tool 的每个 delta 和 `tool/call` 都是创建入口。具名实时 delta 创建准备行;历史 `tool/call` 直接创建派发阶段。匹配函数仍然只读取当前事件,不查询 Context,不增加角色、注册表或旁路缓存。
|
||||
|
||||
成功流结束时发布最终 Assistant 消息,瞬态 delta 保留到 `step/end`。每个 `tool/call` 更新已有 callId;Assistant 的实时排序锚点也保留到同一次清理。失败、中断或废弃的流立即移除 delta。清理时,Assembler 从剩余 Match 重新选择 start 并重算 State;未派发的准备节点隐藏,不合成执行结果。
|
||||
|
||||
@@ -40,9 +40,9 @@ Group 从准备阶段起就聚合 Tool 节点,按工具名分类和计数。As
|
||||
|
||||
### 通用行复用现有外壳
|
||||
|
||||
[ToolRow](../../../../packages/client/ui-tool/src/client/tool/components/ToolRow.tsx) 在三个阶段复用既有图标、标题和行组件。公共行模型选择工具标题,并组合通用工具名前缀与已有参数摘要。准备阶段没有完整参数或结果,共享参数解析入口直接返回 null,不解析 JSON。既有 slot 钩子绑定可选地提供当前调用的原始前缀,不增加准备态注册机制;ToolRow 禁止准备行展开。
|
||||
[ToolRow](../../../../packages/client/ui-tool/src/client/tool/components/ToolRow.tsx) 在三个阶段复用既有图标、标题和行组件。公共行模型选择工具标题,并组合通用工具名前缀与已有参数摘要。所有阶段都提供[懒计算参数视图](2026-09-24-preparing-tool-arguments.zh.md);需要完整派发参数的卡片在准备阶段仍返回无调用。ToolRow 禁止准备行展开。
|
||||
|
||||
read、read_image、write/edit、search、web、todo、question、details 和通用回退使用这条路径。Bash、Skill、Present、Cordis 等自定义外壳保留自己的准备态分支。不增加自动/自管注册声明,不在 ToolTree 维护另一份工具分类名单。
|
||||
read、read_image、write/edit、search、web、todo、question、details 和通用回退使用这条路径。Bash 在各阶段共用组件;Skill、Present、Cordis 保留自己的准备态分支。不增加自动/自管注册声明,不在 ToolTree 维护另一份工具分类名单。
|
||||
|
||||
### 与已有记录的关系
|
||||
|
||||
@@ -60,8 +60,8 @@ read、read_image、write/edit、search、web、todo、question、details 和通
|
||||
|
||||
## 影响
|
||||
|
||||
- 工具可以在参数完整前出现,但准备展示不表示工具已经执行,也不暴露依赖参数的交互。
|
||||
- 工具可以在参数完整前出现,但准备展示不表示工具已经执行;交互只使用已可用的字段。
|
||||
- 同一 ID 的多个 start 被视为同一个生命周期;业务必须为独立调用提供不同 ID,不能再依赖第二个 start 报错检测身份复用。
|
||||
- 各阶段复用通用行基础组件。write/edit 分离准备态与派发后组件,只有前者订阅原始参数;自定义外壳也可按阶段切换内部组件。
|
||||
- 不提供部分 JSON 解析或 `useToolCallDelta`。`useToolCallArgumentsPartial` 暴露既有 Step 的原始前缀,不另建累积器;write/edit 只使用其长度展示准备进度。
|
||||
- 各阶段复用通用行基础组件。write/edit 和 Bash 保持组件身份;自定义外壳可按阶段切换内部组件。
|
||||
- 部分参数的读取与更新策略遵循懒计算参数视图,不需要独立的原始前缀钩子。
|
||||
- 组装测试分别覆盖实时准备态、撤回、活跃流重建、持久历史与分页收敛;组件测试检查无参数展示和阶段切换,录制会话覆盖浏览器中的准备态与重载结果。
|
||||
@@ -0,0 +1,31 @@
|
||||
# Bilingual-pair consistency record for 2026-09-24-preparing-tool-arguments.md (docs/i18n/README.md): per heading
|
||||
# section, a hash of its English and Chinese blocks outside code blocks and generated regions.
|
||||
# After editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write .agents/notes/implemented/architecture/2026-09-24-preparing-tool-arguments.md
|
||||
/agent-note-incremental-tool-argument-scanning-and-argument-order-during-preparation:
|
||||
en: 07f6420c67ea2700
|
||||
zh: b9b53250e050cf6e
|
||||
/agent-note-incremental-tool-argument-scanning-and-argument-order-during-preparation/problem:
|
||||
en: c97b3edd4ef1d063
|
||||
zh: 5c8b6065e662f326
|
||||
/agent-note-incremental-tool-argument-scanning-and-argument-order-during-preparation/decision:
|
||||
en: a15c7c13f167e5ac
|
||||
zh: 63bcc2ef60c2f344
|
||||
/agent-note-incremental-tool-argument-scanning-and-argument-order-during-preparation/decision/a-lazily-computed-argument-view-lives-in-dsh-util-values:
|
||||
en: b7300e53bead90eb
|
||||
zh: 7549b74ce32970f1
|
||||
/agent-note-incremental-tool-argument-scanning-and-argument-order-during-preparation/decision/parsing-happens-in-the-tool-definition-not-in-react:
|
||||
en: 63b022a5ec7ec17e
|
||||
zh: 82b38d3909585672
|
||||
/agent-note-incremental-tool-argument-scanning-and-argument-order-during-preparation/decision/argument-declaration-order:
|
||||
en: a092b8af61631d7c
|
||||
zh: 32ff2293afc92d9a
|
||||
/agent-note-incremental-tool-argument-scanning-and-argument-order-during-preparation/alternatives-considered:
|
||||
en: bb74d0897bc22645
|
||||
zh: 8956a007b87b9b05
|
||||
/agent-note-incremental-tool-argument-scanning-and-argument-order-during-preparation/verification:
|
||||
en: 28836dd26f653dae
|
||||
zh: 679e28935eefc969
|
||||
/agent-note-incremental-tool-argument-scanning-and-argument-order-during-preparation/consequences:
|
||||
en: d74f1c2348788c41
|
||||
zh: 5aea9a6f2c2f1ffe
|
||||
@@ -0,0 +1,66 @@
|
||||
# Agent Note: Incremental tool-argument scanning and argument order during preparation
|
||||
|
||||
Status: implemented
|
||||
|
||||
English | [中文](2026-09-24-preparing-tool-arguments.zh.md)
|
||||
|
||||
## Problem
|
||||
|
||||
[Three-stage tool calls](2026-09-22-tool-call-three-phases.md) make tool identity visible before `tool/call`. A raw argument prefix alone cannot supply field-aware presentation: write/edit need a complete path and decoded content length, while bash/run_code need the description before the command or program finishes streaming.
|
||||
|
||||
The order in which the model generates arguments also decides what can appear first. On 2026-09-24, 310 controlled requests against the real DeepSeek V4 API exercised bash/run_code/write/edit:
|
||||
|
||||
| Variant | Change | bash first key is description | run_code first key is description |
|
||||
|---|---|---|---|
|
||||
| Baseline | — | 0/20 | 1/20 |
|
||||
| `properties` order only | description moved first | 0/20 | 0/20 |
|
||||
| `properties` + `required` together | Same plus reordered `required` | Forced tool_choice 10/10; free calling Pro 7/10, Flash 0/10 | Forced 10/10; free 20/20 |
|
||||
| Together + one ordering instruction in the description text | Appends "Provide `description` before `command` in the arguments." | Free calling Flash 19/20, Pro 20/20 | 20/20 |
|
||||
|
||||
In these samples, reordering `required` changes argument order where reordering `properties` alone does not; V4 Flash's free bash calls also need the explicit instruction. The `dsh-tools` schema DSL generates `required` in property declaration order, so changing the declaration order in source reorders both. The probe uses a minimal system prompt, not the complete Harness prompt.
|
||||
|
||||
## Decision
|
||||
|
||||
### A lazily computed argument view lives in `dsh-util-values`
|
||||
|
||||
`PartialArguments` is a lazily computed class that knows no tool. It holds the raw text (the accumulated deltas while preparing; the event's string after `tool/call`; the event's object for a PTC child) and a level-one index, and any reader (`has`, `complete`, `stringLength`, `text`, `value`, `keys`) resumes scanning from the last consumed position only when called; with no reader, not one character is scanned. Text is decoded on demand from the raw slice, so no specification of "which fields keep text" and no registry is needed.
|
||||
|
||||
The view judges change itself: it remembers every question it answered, and `append(delta)` recomputes only those, returning true only when an answer differs; with nothing read yet it is always false. The business states its granularity as it reads: `stringLength('content', { step: 1024 })` makes only a kilobyte crossing count, `text('description')` makes every character count. An `offset` includes completed strings when edit progress combines old and new text.
|
||||
|
||||
### Parsing happens in the Tool Definition, not in React
|
||||
|
||||
The [Tool Definition](../../../../packages/client/ui-chat/src/client/conversation-nodes/tool.ts) matches every `tool-call-delta` carrying an id as a start candidate: the earliest opens the Context whether or not it is named, later ones fold as updates. The named delta creates the preparing root with a fresh streaming view; every delta only calls `args.append(delta)`, and the root reference is replaced only when the view reports a change. Publication keeps the `animation-frame` cadence. A stream whose arguments precede the name is not scanned: a view opened late sees a non-object prefix, turns invalid, and reports no fields.
|
||||
|
||||
Every stage's block exposes `name` and `args`; legacy `argsRaw` and result `call: { name, argsRaw } | null` remain available. Dispatched roots use `PartialArguments.fromText(argsRaw)`, PTC children use `fromObject(payload)` without stringifying, and results reuse the started view. An unpaired root result has an empty name and shared empty view. Card models continue to read `argsRaw`.
|
||||
|
||||
Rows use the same readers across stages: read/write/edit show an openable path once `file_path` closes; write/edit show decoded content length in 1024-character units while content streams; bash/pwsh/run_code show the description prefix. Chat group detail reads the same view using its existing field priority. Without usable detail it stays empty while fields can still arrive, then falls back to the tool name once `closed()` is true, for every category.
|
||||
|
||||
Third-party tools receive the same view without registration or a separate subscription. Write/edit and Bash share their component across stages. The mutable argument reader is a narrow exception to JSON-compatible owner data: its Definition publishes a new block reference when an observed answer changes. Scan caches use private fields so read history does not affect structural comparison of equal sources.
|
||||
|
||||
### Argument declaration order
|
||||
|
||||
`tool-bash` and `tool-pwsh` declare `description` before `command` and include the ordering instruction; both `parameters` declarations of `run_code` put `description` before `code` without an instruction. `file_path` is already first for write/edit/read. Other tools retain their argument order.
|
||||
|
||||
## Alternatives considered
|
||||
|
||||
**Parse inside a hook closure (a selector subscribing to the Step source).** Only the subscribing row sees the parsed result, so group titles need another subscription and each row owns parser lifetime. Definition-owned views share parsed fields across consumers.
|
||||
|
||||
**Keeping a per-tool field specification in the Definition (built-in table plus a runtime registry).** The Definition is a pure function without ctx, so a runtime registry could only reach it through a factory closure, and a third-party tool would register in two places, the slot and the registry; the specification only ever said which fields keep text, information that on-demand decoding from the raw text no longer needs.
|
||||
|
||||
**Third-party `partial-json`.** It reparses the cumulative input each frame and does not expose string completion separately from the decoded value.
|
||||
|
||||
**Eagerly parse every field.** Large fields such as `content` usually need only a length; eagerly materializing their text adds decoding and memory costs before a consumer asks for it.
|
||||
|
||||
**Reorder `properties` only.** Measured 0/40 effective; the model follows the `required` order.
|
||||
|
||||
## Verification
|
||||
|
||||
- Parser tests cover lazy scanning, observed-answer changes, empty and repeated keys, split escapes, non-string values, invalid input, sealed views, and read-independent structural equality.
|
||||
- Row and grouping tests cover streamed paths and descriptions, content length, shared row identity, and name fallback only when arguments cannot grow.
|
||||
|
||||
## Consequences
|
||||
|
||||
- Observed argument changes replace preparing blocks; unread calls retain their block reference. Views retain source text, and group headers can request fields independently of tool rows. Started and settled views scan on first read without publishing updates.
|
||||
- Model ordering is probabilistic: the reorder and the description sentence raise description-first to about 100% but are not a contract; the row logic shows whichever field closes first, so a reversed order only loses the benefit.
|
||||
- Presentation remains Client-derived; argument scanning adds no Session event or persistence format.
|
||||
- A stream whose name arrives after its arguments gives up scanning; that call's preparing row falls back to the title alone.
|
||||
@@ -0,0 +1,66 @@
|
||||
# Agent Note: 准备阶段的工具参数增量扫描与参数顺序
|
||||
|
||||
Status: implemented
|
||||
|
||||
[English](2026-09-24-preparing-tool-arguments.md) | 中文
|
||||
|
||||
## 问题
|
||||
|
||||
[三阶段工具调用](2026-09-22-tool-call-three-phases.zh.md)让工具身份在 `tool/call` 之前就可见。只有原始参数前缀不足以按字段展示:write/edit 需要完整路径和解码后的内容长度,bash/run_code 需要在命令或程序流入结束前显示描述。
|
||||
|
||||
模型生成参数的顺序也决定了什么能先显示。2026-09-24 用真实 DeepSeek V4 API 对 bash/run_code/write/edit 做了 310 次受控请求:
|
||||
|
||||
| 变体 | 改了什么 | bash 首键为 description | run_code 首键为 description |
|
||||
|---|---|---|---|
|
||||
| 现状 | — | 0/20 | 1/20 |
|
||||
| 只调 `properties` 顺序 | description 提前 | 0/20 | 0/20 |
|
||||
| `properties` + `required` 同调 | 同上并调 `required` | 强制 tool_choice 10/10;自由调用 pro 7/10、flash 0/10 | 强制 10/10;自由 20/20 |
|
||||
| 同调 + 描述文本加一句顺序指令 | 追加「Provide `description` before `command` in the arguments.」 | 自由调用 flash 19/20、pro 20/20 | 20/20 |
|
||||
|
||||
在这些样本中,单调 `properties` 无效时,调整 `required` 能改变参数顺序;V4 Flash 自由调用 bash 还需要显式指令。`dsh-tools` 的 schema DSL 按属性声明顺序生成 `required`,所以改源码声明顺序会同时调整两者。探针使用极简系统提示词,不是完整 Harness 提示词。
|
||||
|
||||
## 决策
|
||||
|
||||
### 懒计算的参数视图住在 `dsh-util-values`
|
||||
|
||||
`PartialArguments` 是一个不认识任何工具的懒计算类。它持有原始文本(preparing 期是累积的 delta;`tool/call` 后直接包着事件里的字符串;PTC 子调用包着事件里的对象)和一份一级索引,任何读器(`has`、`complete`、`stringLength`、`text`、`value`、`keys`)被调用时才从上次消费的位置继续扫到末尾;没人读就一个字符都不扫。原文按需从原始文本切出解码,所以不需要"哪些字段保留文本"的规格,也不需要注册表。
|
||||
|
||||
变化由视图自己判定:它记住每个被问过的问题及其答案,`append(delta)` 只重算这些问题,某个答案变了才返回 true;没人读过就永远 false。业务在读的时候说明粒度——`stringLength('content', { step: 1024 })` 让跨 KB 才算变化,`text('description')` 让每个字符都算变化。edit 进度合计新旧文本时,`offset` 计入已完成的字符串。
|
||||
|
||||
### 解析在 Tool Definition 层,不在 React
|
||||
|
||||
[Tool Definition](../../../../packages/client/ui-chat/src/client/conversation-nodes/tool.ts) 把每个带 id 的 `tool-call-delta` 都匹配为 start 候选:最早的一个打开 Context(无论是否带名),后续折叠为 update。带名 delta 创建 preparing 根并挂上一个新的流式视图;每个 delta 只做 `args.append(delta)`,视图报告变化时才换根块引用。发布节奏沿用 `animation-frame`。参数在名字之前到达的流不扫描:迟开的视图看到非对象前缀即 invalid、零字段。
|
||||
|
||||
三个阶段的块都提供 `name` 和 `args`,原有 `argsRaw` 和 result 的 `call: { name, argsRaw } | null` 仍可使用。已派发根调用使用 `PartialArguments.fromText(argsRaw)`,PTC 子调用使用 `fromObject(payload)` 而不 stringify,结果复用已派发视图。未配对的根结果使用空名称和共享空视图。卡片模型继续读取 `argsRaw`。
|
||||
|
||||
工具行在各阶段使用相同读器:read/write/edit 在 `file_path` 闭合后显示可打开的路径;write/edit 在内容流入时按 1024 字符单位显示解码后长度;bash/pwsh/run_code 显示描述前缀。Chat 分组详情按既有字段优先级读取同一视图。没有可用详情时,只要字段还可能到达就留空;`closed()` 为真后才回退工具名,所有类别一致。
|
||||
|
||||
三方工具无需注册或独立订阅就能取得同一视图。write/edit 和 Bash 在各阶段共用组件。可变参数读器是 owner 数据要求 JSON 兼容的一项限定例外:已读取答案变化时,所属 Definition 发布新的块引用。扫描缓存使用私有字段,同源视图的结构比较不受读取历史影响。
|
||||
|
||||
### 参数声明顺序
|
||||
|
||||
`tool-bash`、`tool-pwsh` 在 `command` 前声明 `description`,并包含顺序指令;`run_code` 两处 `parameters` 将 `description` 放在 `code` 前,不加指令。write/edit/read 的 `file_path` 已在首位。其他工具保留原有参数顺序。
|
||||
|
||||
## 考虑过的替代方案
|
||||
|
||||
**在 hook 闭包里解析(选择器订阅 Step source)。** 只有订阅行能看到解析结果,分组标题需要另一份订阅,每行还要负责解析器生命周期。Definition 持有的视图让消费方共享已解析字段。
|
||||
|
||||
**在 Definition 里维护每工具字段规格(内建表 + 运行时注册表)。** Definition 是纯函数、拿不到 ctx,运行时注册表只能经工厂闭包注入,三方工具要在坑位与注册表两处登记;而规格表本质只是"哪些字段保留文本",懒计算按需从原始文本切出原文后这条信息不再需要。
|
||||
|
||||
**第三方 `partial-json`。** 每帧重解析累计输入,且不独立于解码值暴露字符串完成状态。
|
||||
|
||||
**提前解析所有字段。** `content` 等大字段通常只需要长度;在消费方请求前构造全文,会增加解码和内存成本。
|
||||
|
||||
**只调 `properties` 顺序。** 实测 0/40 生效;模型跟随 `required` 顺序。
|
||||
|
||||
## 验证
|
||||
|
||||
- 解析器测试覆盖懒扫描、已读取答案变化、空键与重复键、跨片转义、非字符串值、非法输入、封存视图,以及不受读取历史影响的结构相等。
|
||||
- 工具行和分组测试覆盖流式路径与描述、内容长度、共用行身份,以及参数不再增长后才回退工具名。
|
||||
|
||||
## 影响
|
||||
|
||||
- 已读取参数变化时替换准备态块,无人读取的调用保留块引用。视图保留源文本,分组标题可以独立于工具行请求字段。已派发和已结算视图在首次读取时扫描,不发布更新。
|
||||
- 模型顺序是概率行为:调序与描述指令把 description 先到的比例提到约 100%,但不是契约;行的显示逻辑按「哪个字段先闭合先显示哪个」设计,顺序反转时只是收益消失。
|
||||
- 展示仍由 Client 派生;参数扫描不新增 Session 事件或持久化格式。
|
||||
- 名字晚于参数到达的流放弃扫描,该调用的准备行退回只显示标题。
|
||||
@@ -24,7 +24,7 @@ How live data reaches render code, and what UI domains may share:
|
||||
1. **Everything a render reads that can change outside React arrives through a framework hook** (rule 4 above). Event-handler code may read live snapshots (e.g. `keyboard.snapshot`); render code subscribes.
|
||||
2. **Business components contain no subscription machinery** — no `useSyncExternalStore`, no manual subscribe wiring, no mirroring an external snapshot into local state or a second store. Give each reactive fact its owning channel instead: registrant-private → the inject `hooks` compartment; cross-entry or remount-surviving → a declared store; per-session standard → `sessions.provide`.
|
||||
3. **Data-access ladder** — resolve needs in this order: framework hooks (standing seats + provide/inject-bound `use<Name>`) → a declared store (`useStore`/`actions`) → inject callbacks → anything else is a new framework extension point and needs main-thread arbitration.
|
||||
4. **UI domains share JSON-compatible data and callbacks.** Owner props, injected values, store state, and provide contributions use these values. Transient file-read and document-preview content may also carry `Uint8Array`: published buffers are borrowed read-only, copied before Worker transfer, and never persisted in layout or Session JSON. The injected `hooks` compartment is the only place for bare observables, and components never receive those sources directly. Route ReactNode content through a slot; do not add ReactNode-valued owner props or injected members (the composer's existing `accessory`/`overlay`/`leftItems`/`rightItems` fields remain until they move to slots).
|
||||
4. **UI domains share JSON-compatible data and callbacks.** Owner props, injected values, store state, and provide contributions use these values. Tool `args` may carry the [lazy argument reader](../../.agents/notes/implemented/architecture/2026-09-24-preparing-tool-arguments.md); its Definition republishes the block when an observed answer changes. Transient file-read and document-preview content may also carry `Uint8Array`: published buffers are borrowed read-only, copied before Worker transfer, and never persisted in layout or Session JSON. The injected `hooks` compartment is the only place for bare observables, and components never receive those sources directly. Route ReactNode content through a slot; do not add ReactNode-valued owner props or injected members (the composer's existing `accessory`/`overlay`/`leftItems`/`rightItems` fields remain until they move to slots).
|
||||
5. **An observable source keeps two identities stable**: the source object itself (hook binding is cached per source), and its snapshot between changes (`getSnapshot` returns the same reference until the fact moves).
|
||||
6. **Whoever rebuilds a published value republishes it through the same source in the same step**, and a registration path that can run after consumers exist notifies the live consumers as part of registering.
|
||||
|
||||
|
||||
@@ -91,7 +91,7 @@ Chat registers its process Group Definition through `uiConversation.groups`. Rea
|
||||
|
||||
`groupPart` selects reasoning or response in the Assistant renderer without copying Node payloads. A Tool node owns its preparing, dispatched, and result stages under one callId. Each part has a distinct DOM anchor for reading-position restoration; Turn navigation addresses the original Node key and lands on its first visible part. Group sources, member parents, and keys survive display-mode changes and newly loaded prefixes that extend an intact group. The source Node Store remains the only Node-data owner, and a replaced Builder rebinds keyed subscriptions without remounting seats. Mode changes retain size observers and reuse the Turn-state selector.
|
||||
|
||||
Live tool deltas share reasoning's frame-batched publication; durable calls and results publish immediately. Repeated named deltas retain the Tool node and its data when the projected call, anchor, location, and visibility are unchanged.
|
||||
Live tool deltas share reasoning's frame-batched publication; durable calls and results publish immediately. Repeated deltas retain the Tool node when observed argument answers, the anchor, location, and visibility are unchanged. The Definition supplies the same lazy argument reader to tool rows and group detail, without tool-specific registration.
|
||||
|
||||
The process group uses a stable `div` layout box, a scroll body, and an uncapped content box that reports growth inside the body. Business styles must adapt spacing within and across groups, including hidden or empty members and the answer-spacing exception. CSS variables do not belong in the Group Definition.
|
||||
|
||||
|
||||
@@ -91,7 +91,7 @@ Chat 通过 `uiConversation.groups` 注册过程 Group Definition。React 通过
|
||||
|
||||
`groupPart` 在 Assistant 渲染器中选择推理或回复,不复制 Node 载荷。同一个 callId 的准备、派发与结果阶段由 Tool 节点自己拥有。每个部分有独立的 DOM 锚点用于恢复阅读位置;轮次导航使用原 Node key,落到它的第一个可见部分。展示模式切换以及为完整旧组补入更早成员时,保留组来源、成员父级及 key。原 Node Store 仍是唯一节点数据所有者,替换 Builder 时重新绑定按键订阅,不重挂载容器。模式变化保留尺寸观察器,并复用整轮状态选择器。
|
||||
|
||||
实时工具 delta 与推理共用按帧合并的发布节奏;持久调用和结果立即发布。重复具名 delta 在投影调用、锚点、位置及可见性均未变化时保留 Tool 节点及其数据引用。
|
||||
实时工具 delta 与推理共用按帧合并的发布节奏;持久调用和结果立即发布。当已读取参数的答案、锚点、位置及可见性均未变化时,重复 delta 保持 Tool 节点不变。Definition 向工具行和分组详情提供同一个懒计算参数读器,无需按工具注册。
|
||||
|
||||
过程组使用稳定的 `div` 布局盒子、滚动正文及不限高的内容盒子,后者报告正文内部的内容增长。业务样式必须适配组内及组边界间距,处理隐藏或空成员以及回答前的间距特例。CSS 变量不属于 Group Definition。
|
||||
|
||||
|
||||
@@ -54,5 +54,5 @@
|
||||
en: e7796e7ba825c3d6
|
||||
zh: c377d9eab0a8869f
|
||||
/chat-conversation-node-rules/activity-summaries/live-activity-and-detail:
|
||||
en: d4256eadd2e9ba96
|
||||
zh: ff6eeb1187ac683a
|
||||
en: b5f61cbf72a94b87
|
||||
zh: 17d7f4eb5a1574e7
|
||||
@@ -134,7 +134,7 @@ Reading a default does not automatically save configuration. When the user chang
|
||||
|
||||
A closed group's header names the first three categories from its ranked summary, without displaying counts. A group without categories uses the thinking label. A running header names its live tool category, otherwise thinking; Standard appends live detail. Live titles remain visible for at least 150ms, retaining only the newest pending title.
|
||||
|
||||
All three stages share the tool-name classification below. A preparing Tool node uses its category's preparation label: read files for `read`, read images for `read_image`, write files for `write`, edit files for `edit` and `apply_patch`, and update the plan for `todo_write` and goal tools. Only the generic “Preparing tool calls” category appends the wire tool name in Standard mode; other categories omit it. It contributes one call without parsing arguments and renders one non-expandable row. A named live delta can create this node; historical calls start directly from tool/call without replaying preparation.
|
||||
All three stages share the tool-name classification below. A preparing Tool node uses its category's preparation label: read files for `read`, read images for `read_image`, write files for `write`, edit files for `edit` and `apply_patch`, and update the plan for `todo_write` and goal tools. Standard mode appends available argument detail using the same readers as dispatched calls. It contributes one call and renders one non-expandable row. A named live delta can create this node; historical calls start directly from tool/call without replaying preparation.
|
||||
|
||||
The labels below describe recorded activity, not successful outcomes. For example, a failed read still participates in the “Read files” category.
|
||||
|
||||
@@ -276,7 +276,7 @@ Exact-name rules also mean that a recorded name such as `functions.read`, `mcp.r
|
||||
|
||||
### Live activity and detail
|
||||
|
||||
Preparing calls use their first named delta time; only the generic tool category provides the tool name as detail. Dispatched calls use their tool/call time and complete arguments.
|
||||
Preparing calls use their first named delta time; dispatched calls use their tool/call time. Both read detail from the block's lazy `args` view.
|
||||
|
||||
Among running calls, the greatest `time` selects the live category and detail; equal times select the later visited call. With no running call, the category is absent and detail comes from the last nonempty reasoning paragraph of the latest running Assistant with nonempty reasoning, in member order. Reasoning detail removes `**` markers and does not require a newline-terminated first line; the individual reasoning-row preview has separate rules.
|
||||
|
||||
@@ -291,7 +291,7 @@ Live selection uses call start `time`, not the latest output/progress time. A ca
|
||||
| No running tool or usable running reasoning; the group is not closed | No live tool category and empty detail, even when category counts are nonzero. |
|
||||
| A reply or another group boundary closes the group while a tool still lacks a result | Published live category and detail are cleared. Group closure takes precedence over the unfinished call. |
|
||||
|
||||
Tool detail uses the first nonempty supported argument field in this priority order: `title`, `description`, `objective`, `task`, `task_name`, `name`, `question`, `questions`, `prompt`, `message`, `command`, `cmd`, `queries`, `query`, `pattern`, `url`, `uri`, `file_path`, `path`, `target`, `action`, `status`. Strings and arrays consisting entirely of strings are supported; arrays join with `, `. The `questions` field instead selects the first nonempty `question` in its object array. Invalid, partial, or free-form JSON and arguments without usable detail fall back to the tool name.
|
||||
Tool detail uses the first nonempty supported argument field in this priority order: `title`, `description`, `objective`, `task`, `task_name`, `name`, `question`, `questions`, `prompt`, `message`, `command`, `cmd`, `queries`, `query`, `pattern`, `url`, `uri`, `file_path`, `path`, `target`, `action`, `status`. Strings may still be streaming; arrays become available when complete and must contain only strings, joined with `, `. The `questions` field instead selects the first nonempty `question` in its object array. Without usable detail, every category stays empty while fields can still arrive and falls back to the tool name only once the view is closed, invalid, or sealed after dispatch.
|
||||
|
||||
The priority list is shared by every tool, not specialized per category. For example, `description` can override `command` on a shell call, and `title` can override a file path. The first field whose supported value remains nonempty after whitespace normalization wins; unsupported values are skipped.
|
||||
|
||||
@@ -309,6 +309,6 @@ The priority list is shared by every tool, not specialized per category. For exa
|
||||
| `run_code` with only `{"code":"print(1)"}` | `run_code`; `code` is not in the detail-field list. |
|
||||
| `apply_patch` with raw patch text rather than a JSON object | `apply_patch`; no patch-path extraction. |
|
||||
| Any tool with `{"description":" ","command":42,"path":"src/app.ts"}` | `src/app.ts`; whitespace-only strings and numbers are skipped. |
|
||||
| Partial JSON, a JSON scalar, a mixed-type array, or only unsupported fields | Use the tool name if no other usable field exists. No partial-argument guessing. |
|
||||
| No usable field yet | Empty while arguments can grow; otherwise the tool name. |
|
||||
|
||||
All live detail collapses whitespace, trims its ends, and is limited to 160 grapheme clusters, including a final `…` when truncated. A closed group's published summary clears its live category and detail while retaining category counts.
|
||||
@@ -134,7 +134,7 @@ description: "Chat 过程分组与活动摘要的明细业务规则。"
|
||||
|
||||
已结束组的组头展示排序摘要的前三类,不显示次数;没有类别时使用思考标题。运行中的组头展示实时工具类别,没有运行工具时使用思考标题;标准模式附加实时详情。实时标题至少保留 150ms,只保留最新待显示标题。
|
||||
|
||||
三个阶段共用下方工具名分类。准备中的 Tool 节点使用对应类别的准备文案;`read` 为「准备读取文件」,`read_image` 为「准备读取图片」,`write` 为「准备写入文件」,`edit` 和 `apply_patch` 为「准备编辑文件」,`todo_write` 及目标工具为「准备更新计划」。只有通用类别的「准备调用工具」在标准模式中追加协议工具名,其他类别不追加。它计为一次调用,不解析参数,只渲染不可展开的一行。具名实时 delta 可以创建该节点;历史调用直接从 tool/call 开始,不重现准备过程。
|
||||
三个阶段共用下方工具名分类。准备中的 Tool 节点使用对应类别的准备文案;`read` 为「准备读取文件」,`read_image` 为「准备读取图片」,`write` 为「准备写入文件」,`edit` 和 `apply_patch` 为「准备编辑文件」,`todo_write` 及目标工具为「准备更新计划」。标准模式通过与已派发调用相同的读器追加可用参数详情。它计为一次调用,只渲染不可展开的一行。具名实时 delta 可以创建该节点;历史调用直接从 tool/call 开始,不重现准备过程。
|
||||
|
||||
以下文案描述已记录的活动,不保证操作成功;例如失败的读取仍参与「已读取文件」类别。
|
||||
|
||||
@@ -276,7 +276,7 @@ Subagent 工具遵循普通分组边界,不会仅因委派任务就单独成
|
||||
|
||||
### 实时活动与详情
|
||||
|
||||
准备中的调用使用首个具名 delta 的时间,只有通用工具类别提供工具名详情。已派发调用使用 tool/call 的时间和完整参数。
|
||||
准备中的调用使用首个具名 delta 的时间,已派发调用使用 tool/call 的时间。两者都从块的懒计算 `args` 视图读取详情。
|
||||
|
||||
运行中的调用以最大 `time` 决定实时类别和详情;时间相同时取后遍历的调用。没有运行调用时,类别为空,详情取成员顺序中最近一个含有非空推理段落的运行中 Assistant 的最后一个非空段落。推理详情移除 `**` 标记,不要求首行以换行结束;单个推理行的预览另有规则。
|
||||
|
||||
@@ -291,7 +291,7 @@ Subagent 工具遵循普通分组边界,不会仅因委派任务就单独成
|
||||
| 没有运行工具或可用的运行中推理,组尚未结束 | 实时工具类别为空、详情为空,即使类别次数非零。 |
|
||||
| 工具尚无结果,但回复或其他分组边界已结束该组 | 发布的实时类别与详情清空;组结束优先于调用未完成。 |
|
||||
|
||||
工具详情按以下优先级取第一个非空且受支持的参数字段:`title`、`description`、`objective`、`task`、`task_name`、`name`、`question`、`questions`、`prompt`、`message`、`command`、`cmd`、`queries`、`query`、`pattern`、`url`、`uri`、`file_path`、`path`、`target`、`action`、`status`。支持字符串及全部元素均为字符串的数组,数组使用 `, ` 连接。`questions` 字段则取对象数组中首个非空的 `question`。无效、不完整或自由文本形式的 JSON,以及没有可用详情的参数,均回退到工具名。
|
||||
工具详情按以下优先级取第一个非空且受支持的参数字段:`title`、`description`、`objective`、`task`、`task_name`、`name`、`question`、`questions`、`prompt`、`message`、`command`、`cmd`、`queries`、`query`、`pattern`、`url`、`uri`、`file_path`、`path`、`target`、`action`、`status`。字符串可仍在流入;数组完整后才可用,且必须全部为字符串,使用 `, ` 连接。`questions` 字段则取对象数组中首个非空的 `question`。没有可用详情时,所有类别在字段仍可能到达期间留空,只有视图已闭合、非法或随派发封存后才回退工具名。
|
||||
|
||||
这份优先级对所有工具相同,不按类别定制。例如 shell 调用的 `description` 可以覆盖 `command`,`title` 可以覆盖文件路径。按顺序选择受支持且合并空白后仍非空的首个字段,不支持的值会跳过。
|
||||
|
||||
@@ -309,6 +309,6 @@ Subagent 工具遵循普通分组边界,不会仅因委派任务就单独成
|
||||
| `run_code`,仅有 `{"code":"print(1)"}` | `run_code`,`code` 不在详情字段列表中。 |
|
||||
| `apply_patch`,参数为原始补丁文本而非 JSON 对象 | `apply_patch`,不从补丁中提取路径。 |
|
||||
| 任意工具,`{"description":" ","command":42,"path":"src/app.ts"}` | `src/app.ts`,跳过纯空白字符串和数值。 |
|
||||
| 不完整 JSON、JSON 标量、混合类型数组,或仅有不支持的字段 | 没有其他可用字段时使用工具名,不猜测不完整参数。 |
|
||||
| 暂无可用字段 | 参数仍可增长时留空,否则使用工具名。 |
|
||||
|
||||
所有实时详情都合并空白、去除首尾空白,并限制为 160 个字素簇;截断时末尾的 `…` 计入上限。已结束组发布的摘要清空实时类别和详情,保留类别次数。
|
||||
@@ -15,11 +15,11 @@
|
||||
en: d152484eb41ac6b4
|
||||
zh: 09388d293f9be9cb
|
||||
/deepseek-ai-dsh-client-ui-tool/use-this-package:
|
||||
en: be2bc859e0d64fe5
|
||||
zh: d51a35fb36675dd3
|
||||
en: 83b01ee6e554504b
|
||||
zh: 3d33b3a110e4dfdc
|
||||
/deepseek-ai-dsh-client-ui-tool/use-this-package/registering-a-business-tool-view:
|
||||
en: 5332d87e76037f07
|
||||
zh: db5d06e7e46b8429
|
||||
en: f19e077425b8f312
|
||||
zh: 24d88794be439302
|
||||
/deepseek-ai-dsh-client-ui-tool/use-this-package/built-in-views:
|
||||
en: 5bdd3af9df9b2b7c
|
||||
zh: ff3517e71a2be98a
|
||||
@@ -27,8 +27,8 @@
|
||||
en: 00bc7b0c84edc603
|
||||
zh: 1cfcf5b435248a91
|
||||
/deepseek-ai-dsh-client-ui-tool/understand-the-implementation/rendering-contract:
|
||||
en: 2959b10b01e08a7b
|
||||
zh: 7084ca22650cbb5b
|
||||
en: fc6bc5aeb693692d
|
||||
zh: ca3df7cff8126785
|
||||
/deepseek-ai-dsh-client-ui-tool/understand-the-implementation/cards:
|
||||
en: d202f30c846543d2
|
||||
zh: a84656956c66a574
|
||||
|
||||
@@ -29,7 +29,7 @@ Tool calls appear in the conversation as cards: a root call tree with its nested
|
||||
|
||||
Shared Tool rows and Bash rows retain error and warning colors for failed and stopped summaries, including on hover. Hover darkens only summaries without those states.
|
||||
|
||||
Before dispatch, a named model call appears as one non-expandable row with its tool-owned icon and title. A generic row shows `Tool call · <tool name>`. Preparation exposes no complete arguments, file link, result, or parameter-dependent interaction. Write/edit show `Preparing content NKB` in the summary; N is `Math.ceil(raw.length / 1024)`, an integer estimate of the raw argument string length, not the file's byte size. `tool/call` enables the existing call presentation; completing an argument block alone does not start execution.
|
||||
Before dispatch, a named model call appears as one non-expandable row with its tool-owned icon and title. A generic row shows `Tool call · <tool name>`. Read/write/edit show an openable path once `file_path` closes; write/edit also show `Preparing content NKB` while content streams. N rounds the decoded content's UTF-16 length up in units of 1024, not file bytes. Command rows show the streamed description. `tool/call` enables the existing call presentation; completing an argument block alone does not start execution.
|
||||
|
||||
### Registering a business tool view
|
||||
|
||||
@@ -43,11 +43,11 @@ ctx.slots.inject('tool.call.toolview', () =>
|
||||
}, BusinessToolRow))
|
||||
```
|
||||
|
||||
The owner payload is `ToolCallOwnerProps`: `callId`, `toolName`, the `phase` discriminant and its frozen stage-specific `block`, optional `cwd` and `home`, the session-authorized `loadImage` loader (for a view whose result carries durable images), and plain `openFile`/`inspect` callbacks. A PTC dispatch block retains its event's `parentCallId`; a root Session call has no such field, so descendants route through the same keyed dispatch — a registered view such as `read_image` renders its card there, and unregistered descendants keep the generic flattened form. Path summaries relativize to the Session cwd first, then replace a leftover POSIX Host home with `~`; `filePath` and Host open keep the authored filesystem path. The registration receives the normal Session slot runtime share but no React node or Runtime service.
|
||||
The owner payload is `ToolCallOwnerProps`: `callId`, `toolName`, the `phase` discriminant and its stage-specific `block`, optional `cwd` and `home`, the session-authorized `loadImage` loader (for a view whose result carries durable images), and plain `openFile`/`inspect` callbacks. A PTC dispatch block retains its event's `parentCallId`; a root Session call has no such field, so descendants route through the same keyed dispatch — a registered view such as `read_image` renders its card there, and unregistered descendants keep the generic flattened form. Path summaries relativize to the Session cwd first, then replace a leftover POSIX Host home with `~`; `filePath` and Host open keep the authored filesystem path. The registration receives the normal Session slot runtime share but no React node or Runtime service.
|
||||
|
||||
### Built-in views
|
||||
|
||||
Every registered view receives the explicit `preparing`, `start`, and `result` props declared in [the Tool slot types](src/client/contract/slots.ts). Shared rows use the same `ToolRow` in all stages. Their row model selects the title and combines any generic tool-name prefix with the available argument summary independently of lifecycle state. Tool-owned titles omit the English name. The shared argument parser returns no call during preparation and does not parse partial JSON. Write/edit use separate preparing and dispatched components, so only the preparing component invokes `useToolCallArgumentsPartial`; start and result share the dispatched component. Custom renderers such as Bash, Skill, and Cordis handle preparation separately; their argument-dependent components accept `StartedToolCallViewProps`.
|
||||
Every registered view receives the explicit `preparing`, `start`, and `result` props declared in [the Tool slot types](src/client/contract/slots.ts). All blocks expose `name` and a lazy `args` reader; legacy `argsRaw` and result `call` fields remain available. The row model selects the title and combines any generic tool-name prefix with the available argument summary independently of lifecycle state. Tool-owned titles omit the English name. Write/edit and Bash share their component across stages. Custom renderers may retain separate preparation branches; argument-dependent components accept `StartedToolCallViewProps`.
|
||||
|
||||
This package owns the generic fallback and the built-in shell/pwsh, read, read_image, write/edit, running `str_replace_editor` `create`/`str_replace`, grep/glob, web, todo, question, and PTC dispatch presentations. Structured cards derive directly from first-party raw event fields; Host `presentCall` and `presentResult` values never enter the Client. Running atomic rows share one left-to-right highlight across their titles, separators, summaries, and suffixes, while settled rows stay static. Running and settled foreground standard `bash`/`pwsh` and `terminal_send` calls use terminal cards at the root and in PTC dispatch children, subject to the same argument, result, and error checks. Persistent `bash`/`pwsh` calls use terminal cards only while running. Shell output ending in a recognized spill-policy notice uses expandable generic output in shell rows and generic output in Details; a displaced or omitted exit marker cannot establish success. Settled persistent-shell results stay generic because reset and partial-output diagnostics do not always describe one process exit status; root persistent results are expandable, while background acknowledgements remain collapsed. A native or PTC dispatch failure carrying `AUTO_REVIEW_DENIED` shows the Auto review verdict in its collapsed row and one normalized not-executed reason when expanded; a missing or whitespace-only reason uses localized fallback text. `ui-skill` demonstrates a business-owned registration for `skill`.
|
||||
|
||||
@@ -72,7 +72,7 @@ The package realizes one dispatch rule: atomic Tool views are keyed by wire Tool
|
||||
Tool owner props forward Chat's stable `useDisclosure` Hook through root and nested calls. Rows invoke it where they own their expanded bodies; intermediate renderers do not subscribe. Each invocation has independent open state that resets when the enclosing Turn collapses, without replacing React identity. Presentation-mode switches preserve it.
|
||||
|
||||
|
||||
The slot-injected `useToolCallArgumentsPartial` Hook lazily subscribes to the owning Step's `assistant-step` source and selects this callId's raw argument prefix. Missing sources or calls return an empty string. Other calls in the same Step may trigger a snapshot check, but an unchanged selected string does not refresh the consumer. Tools that do not invoke the Hook add no subscription; dispatched calls have no argument-prefix source.
|
||||
Tool Definitions own the [lazy argument view](../../util/values/README.md). Rows choose their fields and update granularity through its readers, without a separate subscription or registration. A streamed delta replaces the block only when an observed answer changes; publication remains frame-batched. Card models that need dispatched arguments continue to read `argsRaw`.
|
||||
|
||||
### Cards
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ kind: "package-reference"
|
||||
|
||||
共享工具行和 Bash 行的失败、停止摘要在悬停时仍保留错误色和警告色;只有不处于这两种状态的摘要会在悬停时加深。
|
||||
|
||||
派发前,模型已给出名称的调用显示为不可展开的一行,使用工具自己的图标与标题。通用行显示为`工具调用 · <工具名>`。准备阶段不提供完整参数、文件链接、结果或依赖参数的交互。write/edit 的摘要显示「正在准备内容 NKB」;N 为 `Math.ceil(raw.length / 1024)`,是原始参数字符串长度的整数近似值,不是文件字节数。`tool/call` 才启用既有调用展示;参数块结束本身不代表开始执行。
|
||||
派发前,模型已给出名称的调用显示为不可展开的一行,使用工具自己的图标与标题。通用行显示为 `工具调用 · <工具名>`。read/write/edit 在 `file_path` 闭合后显示可打开的路径;write/edit 在内容流入时还显示「正在准备内容 NKB」。N 按解码后内容的 UTF-16 长度除以 1024 向上取整,不是文件字节数。命令行显示流入中的描述。`tool/call` 才启用既有调用展示;参数块结束本身不代表开始执行。
|
||||
|
||||
### 注册业务工具视图
|
||||
|
||||
@@ -43,11 +43,11 @@ ctx.slots.inject('tool.call.toolview', () =>
|
||||
}, BusinessToolRow))
|
||||
```
|
||||
|
||||
owner 载荷为 `ToolCallOwnerProps`:`callId`、`toolName`、`phase` 判别字段及对应阶段的冻结 `block`、可选 `cwd` 与 `home`、会话授权的 `loadImage` loader(供结果携带持久图像的视图使用),以及普通的 `openFile`/`inspect` 回调。PTC dispatch 块保留事件的 `parentCallId`;根会话调用没有该字段,因此后代调用都走同一条按 key 分发路径:已注册视图的调用(如 `read_image`)也会在嵌套处渲染对应卡片,未注册的后代调用则保持通用压平形式。路径摘要先相对会话 cwd 缩短,再把剩余的 POSIX Host home 写成 `~`;`filePath` 与 Host 打开仍使用作者给出的文件系统路径。注册项会收到常规的会话 slot 运行时共享数据,但不会收到 React 节点或运行时服务。
|
||||
owner 载荷为 `ToolCallOwnerProps`:`callId`、`toolName`、`phase` 判别字段及对应阶段的 `block`、可选 `cwd` 与 `home`、会话授权的 `loadImage` loader(供结果携带持久图像的视图使用),以及普通的 `openFile`/`inspect` 回调。PTC dispatch 块保留事件的 `parentCallId`;根会话调用没有该字段,因此后代调用都走同一条按 key 分发路径:已注册视图的调用(如 `read_image`)也会在嵌套处渲染对应卡片,未注册的后代调用则保持通用压平形式。路径摘要先相对会话 cwd 缩短,再把剩余的 POSIX Host home 写成 `~`;`filePath` 与 Host 打开仍使用作者给出的文件系统路径。注册项会收到常规的会话 slot 运行时共享数据,但不会收到 React 节点或运行时服务。
|
||||
|
||||
### 内置视图
|
||||
|
||||
每个注册视图都接收[工具 slot 类型](src/client/contract/slots.ts)声明的显式 `preparing`、`start` 和 `result` props。通用行在三个阶段使用同一个 `ToolRow`。行模型统一选择标题,并组合通用工具名前缀与已有参数摘要,不按生命周期阶段改变前缀;专用标题不附带英文名。准备阶段的共享参数解析入口直接返回无调用,不解析部分 JSON。write/edit 将准备态和派发后阶段拆成两个组件,只有准备态组件调用 `useToolCallArgumentsPartial`,start 与 result 共用派发后组件。Bash、Skill、Cordis 等自定义 renderer 分别处理准备态,其依赖参数的组件接收 `StartedToolCallViewProps`。
|
||||
每个注册视图都接收[工具 slot 类型](src/client/contract/slots.ts)声明的显式 `preparing`、`start` 和 `result` props。所有块都提供 `name` 和懒计算的 `args` 读器,原有 `argsRaw` 和 result 的 `call` 字段仍可使用。行模型统一选择标题,并组合通用工具名前缀与已有参数摘要,不按生命周期阶段改变前缀;专用标题不附带英文名。write/edit 和 Bash 在各阶段共用组件。自定义 renderer 可保留独立准备态分支;依赖参数的组件接收 `StartedToolCallViewProps`。
|
||||
|
||||
本包拥有 generic fallback,以及 shell/pwsh、read、read_image、write/edit、运行中的 `str_replace_editor` `create`/`str_replace`、grep/glob、web、todo、question 与 PTC dispatch 的内置展示。结构化卡片直接从第一方原始 event 字段派生;Host `presentCall` 与 `presentResult` 值不会进入 Client。运行中的原子工具行以同一道高光从左到右扫过标题、分隔符、摘要与后缀;已完成行保持静态。运行中与已完成的前台标准 `bash`/`pwsh` 和 `terminal_send` 调用,无论位于根还是 PTC dispatch 子调用中,都在通过相同的参数、结果和错误检查后使用 terminal 卡片。持久 `bash`/`pwsh` 调用仅在运行中使用 terminal 卡片。以已识别的 spill 策略提示结尾的 shell 输出,在 shell 行中使用可展开的 generic 输出,在 Details 中使用 generic 输出;位置被改变或被省略的退出标记无法证明成功。已完成的持久 shell 结果保持 generic 展示,因为 reset 与部分输出诊断不一定描述单个进程的退出状态;根调用的持久 shell 结果可展开,后台启动回执则保持折叠。带有 `AUTO_REVIEW_DENIED` 的原生或 PTC dispatch 失败会在折叠行显示 Auto review 裁决,展开时显示一行归一化后的“未执行”原因;原因缺失或只有空白时使用本地化 fallback 文案。`ui-skill` 展示了业务包自行拥有的 `skill` 注册项。
|
||||
|
||||
@@ -72,7 +72,7 @@ owner 载荷为 `ToolCallOwnerProps`:`callId`、`toolName`、`phase` 判别字
|
||||
Tool 所有者属性将 Chat 注入的稳定 `useDisclosure` 钩子传给根调用及嵌套调用。工具行在拥有展开正文的位置调用它,中间 renderer 不订阅。每次调用拥有独立展开状态,外层轮次收起时重置该状态,不替换 React 身份;展示模式切换保留该状态。
|
||||
|
||||
|
||||
slot 注入的 `useToolCallArgumentsPartial` 钩子按需订阅所属 Step 的 `assistant-step` 来源,并选取当前 callId 的原始参数前缀。来源或调用不存在时返回空字符串。同一步骤中的其他调用可能触发快照检查,但选中的字符串未变时不会刷新使用方。不调用钩子的工具不新增订阅,已派发的调用不再提供参数前缀来源。
|
||||
Tool Definition 拥有[懒计算参数视图](../../util/values/README.zh.md)。工具行通过读器选择字段和更新粒度,不另设订阅或注册。流式 delta 只在已读取的答案变化时替换块引用,发布仍按帧合批。需要完整派发参数的卡片模型继续读取 `argsRaw`。
|
||||
|
||||
### 卡片
|
||||
|
||||
|
||||
@@ -24,8 +24,8 @@
|
||||
en: 0331f90cbd904862
|
||||
zh: bdc2d4ed1c3c1f5e
|
||||
/deepseek-ai-dsh-client-ui-trajectory/understand-the-implementation:
|
||||
en: 925abc8e4b092cb3
|
||||
zh: ebe85c5acdbea3b1
|
||||
en: 02ef008ff74a38df
|
||||
zh: fa54d85ab89ed103
|
||||
/deepseek-ai-dsh-client-ui-trajectory/understand-the-implementation/virtual-rows:
|
||||
en: c85e342bc7eee4e6
|
||||
zh: 9feab66ef1755b94
|
||||
|
||||
@@ -55,7 +55,7 @@ The view is a pure projection: Trajectory-owned Definitions assemble business re
|
||||
|
||||
Native and nested PTC Tool results retain their raw structured error details. Failed records show the error code in the ledger and the error name and code in the inspector.
|
||||
|
||||
Tool records begin at durable tool/call events and use complete arguments. Chat's transient preparing stage does not create Trajectory tool rows or alter historical tool timing.
|
||||
Tool records begin at durable tool/call events and retain complete argument text with a lazy `args` view, reused by paired results. Chat's transient preparing stage does not create Trajectory tool rows or alter historical tool timing.
|
||||
|
||||
A complete appended prompt without a loaded request header appears as a standalone system row; only its known text is available, with no inferred request options or tool catalog. Prepending its request history replaces that standalone presentation without duplicating the prompt. In-history system prompt changes compare against the most recent request state, including earlier prompt updates without a new request header. Each request retains the prompt and change that applied at its own position. Surface replacements, including compaction, restore the last nonempty surviving system prompt even without a new system event; an unloaded prompt remains unavailable until its page arrives.
|
||||
|
||||
|
||||
@@ -55,7 +55,7 @@ Trajectory 标签页让你以按轮次组织的事件记录表和交互式时间
|
||||
|
||||
原生与嵌套 PTC 工具结果保留原始结构化错误详情。失败记录在记录表中显示错误代码,在检查器中显示错误名称和代码。
|
||||
|
||||
工具记录从持久 tool/call 事件开始,使用完整参数。Chat 的瞬态 preparing 阶段不创建 Trajectory 工具行,也不改变历史工具计时。
|
||||
工具记录从持久 tool/call 事件开始,保留完整参数文本和由配对结果复用的懒计算 `args` 视图。Chat 的瞬态 preparing 阶段不创建 Trajectory 工具行,也不改变历史工具计时。
|
||||
|
||||
完整的追加提示词在请求头未加载时显示为独立系统行;仅提供已知文本,不推断请求选项或工具目录。补入其请求历史后,该独立展示被替代而不重复提示词。历史中的系统提示词变更与最近的请求状态比较,包括没有新请求头的先前提示词更新。每个请求保留其所在位置生效的提示词与变更。包括压缩在内的 surface 替换会恢复最后一个非空的存活系统提示词,即使没有新的系统事件;未加载的提示词在对应分页到达前仍不可用。
|
||||
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
en: d4e5c3dd11f4c1f4
|
||||
zh: ac01621284cc2f99
|
||||
/deepseek-ai-dsh-util-values/summary:
|
||||
en: 0900fbf667e6bb37
|
||||
zh: 2ea81387d169a116
|
||||
en: 58a7e4eb46fea838
|
||||
zh: d2af86d7e1165edd
|
||||
/deepseek-ai-dsh-util-values/table-of-contents:
|
||||
en: 80b31a934611cb4a
|
||||
zh: 05f3f7f9cb2fd881
|
||||
@@ -20,6 +20,9 @@
|
||||
/deepseek-ai-dsh-util-values/use-this-package/validate-or-snapshot-json-data:
|
||||
en: dc6de9f27cc98557
|
||||
zh: 9c2bac179e536147
|
||||
/deepseek-ai-dsh-util-values/use-this-package/read-streamed-arguments:
|
||||
en: 3f9373ebfe39e3d7
|
||||
zh: b62a24c91fef6e16
|
||||
/deepseek-ai-dsh-util-values/use-this-package/publish-compare-or-retain-keyed-values:
|
||||
en: 13628af2abe3eea6
|
||||
zh: e284bb8d3ebe38ea
|
||||
@@ -30,8 +33,8 @@
|
||||
en: 36866610a9a7f898
|
||||
zh: aa2f0e4c3cc12335
|
||||
/deepseek-ai-dsh-util-values/understand-the-implementation/source-map:
|
||||
en: a3e80436a6006043
|
||||
zh: 1de25c1bf436e494
|
||||
en: 089278d3216a7eba
|
||||
zh: b69c9ddb0e730a06
|
||||
/deepseek-ai-dsh-util-values/further-exploration:
|
||||
en: 3be59be736dc8e9a
|
||||
zh: 4f419cb5db38fd12
|
||||
|
||||
@@ -9,7 +9,7 @@ English | [中文](README.zh.md)
|
||||
|
||||
## Summary
|
||||
|
||||
`dsh-util-values` gives runtime packages one implementation for lossless JSON values, immutable object graphs, structural JSON equality, and exhaustive closed-union failures. Callers can validate untrusted values, detach a JSON snapshot, freeze a published value, compare JSON-compatible data, or terminate an unreachable branch without importing a capability package. The helpers hold no shared registry, constructor identity, or mutable module state.
|
||||
`dsh-util-values` gives runtime packages one implementation for lossless JSON values, streamed arguments, immutable object graphs, structural JSON equality, and exhaustive closed-union failures. Callers can validate untrusted values, read partial arguments, detach a JSON snapshot, freeze a published value, compare JSON-compatible data, or terminate an unreachable branch without importing a capability package. The helpers hold no shared registry, constructor identity, or mutable module state.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
@@ -37,6 +37,10 @@ if (!isJsonValue(input)) throw new TypeError('expected lossless JSON')
|
||||
const snapshot = snapshotJsonValue(input) as JsonValue
|
||||
```
|
||||
|
||||
### Read streamed arguments
|
||||
|
||||
`PartialArguments` reads a JSON object's top-level fields lazily. Append fragments to a new instance; `append()` reports changes only to answers already read. String readers expose decoded text, completion, and UTF-16 length, with an optional step and completed-prefix offset for change detection. Non-string values become available when complete. `fromText()` and `fromObject()` create sealed views that reject appends; `closed()` also covers invalid input, where scanning stops. See [the readers](src/partial-json.ts) for return distinctions.
|
||||
|
||||
### Publish, compare, or retain keyed values
|
||||
|
||||
`deepFreeze(value)` freezes an object graph in place and returns the same value. It walks enumerable string-keyed children and deliberately leaves live `AbortSignal` objects mutable. `deepEqualJson(a, b)` compares JSON-compatible arrays and records structurally; callers must validate hostile or unconstrained values before comparison.
|
||||
@@ -62,6 +66,7 @@ The JSON validator uses an explicit work stack and tracks only the active ancest
|
||||
| File | Role |
|
||||
|---|---|
|
||||
| [`src/index.ts`](src/index.ts) | JSON value type, validation and snapshot traversal, structural equality, deep freezing, weak-key/strong-value associations, and exhaustive-union failure |
|
||||
| [`src/partial-json.ts`](src/partial-json.ts) | Lazy top-level argument scanning and observed-answer change detection |
|
||||
| — | No runtime invariant companion is published because these value operations have no shared runtime state; unit tests cover their algebra. |
|
||||
|
||||
</details>
|
||||
|
||||
@@ -9,7 +9,7 @@ kind: "package-library"
|
||||
|
||||
## 概述
|
||||
|
||||
`dsh-util-values` 为运行时包提供统一的无损 JSON 值、不可变对象图、JSON 结构相等和封闭联合类型穷尽失败实现。调用方可以校验不受信任的值、创建分离的 JSON 快照、冻结待发布值、比较 JSON 兼容数据,或终止不可达分支,而无需导入某个能力包。这些 helper 不持有共享注册表、constructor identity 或可变模块状态。
|
||||
`dsh-util-values` 为运行时包提供统一的无损 JSON 值、流式参数、不可变对象图、JSON 结构相等和封闭联合类型穷尽失败实现。调用方可以校验不受信任的值、读取部分参数、创建分离的 JSON 快照、冻结待发布值、比较 JSON 兼容数据,或终止不可达分支,而无需导入某个能力包。这些 helper 不持有共享注册表、constructor identity 或可变模块状态。
|
||||
|
||||
## 目录
|
||||
|
||||
@@ -37,6 +37,10 @@ if (!isJsonValue(input)) throw new TypeError('expected lossless JSON')
|
||||
const snapshot = snapshotJsonValue(input) as JsonValue
|
||||
```
|
||||
|
||||
### 读取流式参数
|
||||
|
||||
`PartialArguments` 懒读取 JSON 对象的顶层字段。向新实例追加分片,`append()` 只报告已读取答案的变化。字符串读器提供解码文本、完成状态和 UTF-16 长度,并可为变化判定指定步长和已完成前缀的偏移量。非字符串值在完整后可用。`fromText()` 和 `fromObject()` 创建拒绝追加的封存视图;`closed()` 也包含停止扫描的非法输入。返回值区别见[读器定义](src/partial-json.ts)。
|
||||
|
||||
### 发布、比较或保留键控值
|
||||
|
||||
`deepFreeze(value)` 原地冻结对象图并返回同一个值。它遍历可枚举字符串键的子项,并刻意让活跃 `AbortSignal` 对象保持可变。`deepEqualJson(a, b)` 按结构比较 JSON 兼容数组与记录;调用方必须先校验恶意或不受约束的值,再进行比较。
|
||||
@@ -62,6 +66,7 @@ JSON 校验器使用显式工作栈,并只跟踪当前祖先链,因此深层
|
||||
| 文件 | 职责 |
|
||||
|---|---|
|
||||
| [`src/index.ts`](src/index.ts) | JSON 值类型、校验与快照遍历、结构相等、深度冻结、弱键/强值关联和穷尽联合类型失败 |
|
||||
| [`src/partial-json.ts`](src/partial-json.ts) | 懒扫描顶层参数,并检测已读取答案的变化 |
|
||||
| — | 不发布运行时不变量伴生入口;这些值操作没有共享运行时状态,其代数行为由单元测试覆盖。 |
|
||||
|
||||
</details>
|
||||
|
||||
Reference in new issue
Block a user