docs(i18n): align Agent Note terminology

This commit is contained in:
Tianyi Cui
2026-07-24 13:57:16 +08:00
parent d46471e11f
commit c0eacae2ba
228 changed files with 584 additions and 584 deletions
@@ -6,21 +6,21 @@ Status: implemented
## 问题
ACP(Agent Client Protocol)快照层([快照 Agent Note(agent 决策记录)](2026-06-19-acp-snapshot-tests.md))由位于一个示例测试目录内的三个模块构建:`snapshot-harness.ts`(启动真实 bin 子进程,通过 ACP JSON-RPC 驱动它,采集持久化日志)、`snapshot-normalize.ts`(纯预期输出规范化器),以及 `acp.snapshot.ts` 中约 150 行的场景主体与 fixture(测试前置数据)守卫(记录/重放模式、stdout 预期输出与日志比较、固定请求头一致性守卫、孤立项/必需文件/单一固定项元测试)。
ACP(Agent Client Protocol)快照层([快照 Agent Note(agent 决策记录)](2026-06-19-acp-snapshot-tests.md))由位于一个示例测试目录内的三个模块构建:`snapshot-harness.ts`(启动真实 bin 子进程,通过 ACP JSON-RPC 驱动它,采集持久化日志)、`snapshot-normalize.ts`(纯预期输出规范化器),以及 `acp.snapshot.ts` 中约 150 行的场景主体与 fixture(测试前置数据)守卫(记录/回放模式、stdout 预期输出与日志比较、固定请求头一致性守卫、孤立项/必需文件/单一固定项元测试)。
第二个希望获得快照覆盖的 ACP 示例——直接消费方是 sandbox/approval 组合——只能复制这些模块,恰好分叉了绝不能漂移的逻辑:记录写回、请求头清理、子 session 采集顺序。spawn/client 胶水也在 `acp.e2e.ts`、`hooks.e2e.ts` 和 harness 中重复三份。文件位置决定了测试严格度:逐文件 100% 覆盖率门禁只测量 `packages/*/*/src`,因此这些机制完全未被测量——正是同一种缺口,曾推动 `dsh-llm-replay` 从 `examples/` 移入 [packages/support](../../../../packages/support/README.md)。此外,harness 的 ACP client 硬编码 `requestPermission → cancelled`,因此 approval 往返——sandbox 组合的主打行为——完全无法在快照层表达。
第二个希望获得快照覆盖的 ACP 示例——直接消费方是沙箱/approval 组合——只能复制这些模块,恰好分叉了绝不能漂移的逻辑:记录写回、请求头清理、子会话采集顺序。spawn/client 胶水也在 `acp.e2e.ts`、`hooks.e2e.ts` 和 harness 中重复三份。文件位置决定了测试严格度:逐文件 100% 覆盖率门禁只测量 `packages/*/*/src`,因此这些机制完全未被测量——正是同一种缺口,曾推动 `dsh-llm-replay` 从 `examples/` 移入 [packages/support](../../../../packages/support/README.md)。此外,harness 的 ACP client 硬编码 `requestPermission → cancelled`,因此 approval 往返——沙箱组合的主打行为——完全无法在快照层表达。
## 决策
这些机制位于 [`packages/support/acp-snapshot`](../../../../packages/support/acp-snapshot/README.md)(`@deepseek-ai/dsh-acp-snapshot`);示例的 `*.snapshot.ts` 只包含场景表、agent 路径和一次工厂调用,依赖自己的 `snapshots/` fixture 与 `cordis.snapshot.yml` overlay([单源 replay 配置](2026-07-04-single-source-acp-replay-config.md))。读取 `DSH_SNAPSHOT` 留在边缘层——库接收的是已解析的 `mode`。
这些机制位于 [`packages/support/acp-snapshot`](../../../../packages/support/acp-snapshot/README.md)(`@deepseek-ai/dsh-acp-snapshot`);示例的 `*.snapshot.ts` 只包含场景表、agent 路径和一次工厂调用,依赖自己的 `snapshots/` fixture 与 `cordis.snapshot.yml` overlay([单源回放配置](2026-07-04-single-source-acp-replay-config.md))。读取 `DSH_SNAPSHOT` 留在边缘层——库接收的是已解析的 `mode`。
**`src/launcher.ts`**——`launchAcpTestAgent` 拥有通用的未构建进程边界:绝对 tsx loader 解析、`TSX_TSCONFIG_PATH`、隔离的 harness home、stdio 接线、原始字节 stdout tee、stderr 与更新捕获、失败关闭的权限后备、更新 waiter,以及优雅或信号式关闭。快照场景和普通 e2e 套件提供相同的 `AgentUnderTest`(`binScript`、`configPath`、`tsconfigPath`);扮演用户的测试只提供其权限 handler。ACP 与 hook e2e 套件以及 sandbox/approval e2e 套件都使用该 launcher,而不再重新构建 SDK client 边界。
**`src/launcher.ts`**——`launchAcpTestAgent` 拥有通用的未构建进程边界:绝对 tsx loader 解析、`TSX_TSCONFIG_PATH`、隔离的 harness home、stdio 接线、原始字节 stdout tee、stderr 与更新捕获、失败关闭的权限后备、更新 waiter,以及优雅或信号式关闭。快照场景和普通 e2e 套件提供相同的 `AgentUnderTest`(`binScript`、`configPath`、`tsconfigPath`);扮演用户的测试只提供其权限 handler。ACP 与钩子 e2e 套件以及沙箱/approval e2e 套件都使用该 launcher,而不再重新构建 SDK client 边界。
**`src/harness.ts`**——`runScenario` 和输入脚本/结果类型在 launcher 之上叠加确定性步骤、临时 workspace、快照环境和持久化日志采集。其 `session/request_permission` handler 消费可选的 `InputScript.permissionAnswers` FIFO 队列,每个条目按选项**类型**进行选择(id 是 agent 生成的随机值,已提交脚本无法预知;类型是 ACP 稳定词汇,会在回答时映射到已提供的 `optionId`);队列不存在或耗尽时回答 `cancelled`,若请求从未提供某种类型则拒绝该次运行——agent 自身收到的回答是 `cancelled`,因此场景 bug 会使 harness 失败,而不会被吸收为 agent 侧拒绝。由此,approval 套件可以根据 `input.json` 确定性地驱动允许/拒绝往返。
**`src/normalize.ts`** 是纯规范化器,按策略不含钩子:当未来某个事件携带新的易变字段(例如审批耗时),共享规范化器在同一个变更中学会它,保持「规范化」的含义只有一个归属,而非各套件各自扩展清洗逻辑。
**`src/suite.ts`**——包含 `Scenario` 类型和 `defineAcpSnapshotSuite(options)`,注册各场景比较、记录/刷新 fixture 写回、带实时一致性守卫的请求头固定项,以及 fixture 守卫块(没有孤立场景目录、必需文件存在、每种类别恰好一个固定项、每份 JSONL 都是 `scrubSystemPrompts` 固定点、非固定 fixture 同时也是 `scrubRequestHeaders` 固定点)。刷新会先展开打包的计时信封,再对齐现有易变事件时间,因此在打包与未打包布局之间切换不会移动后续记录;全新的 chunk fragment 数组仍为权威,因为其边界属于重放行为。场景目录中的 `session.jsonl` 加连续的 `session.<n>.jsonl` 同级文件构成有序主项/子项清单,因此场景表可以声明策略而不重复子项数量。固定请求头契约([固定请求头 Agent Note](2026-07-06-pin-request-header-content-in-one-scenario.md))按套件生效:每种请求头类别恰好标记一个 `pinsHeader` 场景,其 `system-prompt.expected.md` 和 JSONL 工具列表把组合请求头拆成可评审产物;一致性守卫会将两者与该类别的每个实时请求头比较。固定场景可以声明任何合法的变更请求头数量,其 Markdown 产物记录每个完整的已变 prompt。纯辅助函数(`sessionFixtureNames`、`fixtureContext`、`normalizedHeaders`、`normalizedSystemPrompts`、`formatSystemPromptSnapshot`、`headerChangeCount`)从模块导出,以便直接进行单元覆盖。
**`src/suite.ts`**——包含 `Scenario` 类型和 `defineAcpSnapshotSuite(options)`,注册各场景比较、记录/刷新 fixture 写回、带实时一致性守卫的请求头固定项,以及 fixture 守卫块(没有孤立场景目录、必需文件存在、每种类别恰好一个固定项、每份 JSONL 都是 `scrubSystemPrompts` 固定点、非固定 fixture 同时也是 `scrubRequestHeaders` 固定点)。刷新会先展开打包的计时信封,再对齐现有易变事件时间,因此在打包与未打包布局之间切换不会移动后续记录;全新的分片片段数组仍为权威,因为其边界属于回放行为。场景目录中的 `session.jsonl` 加连续的 `session.<n>.jsonl` 同级文件构成有序主项/子项清单,因此场景表可以声明策略而不重复子项数量。固定请求头契约([固定请求头 Agent Note](2026-07-06-pin-request-header-content-in-one-scenario.md))按套件生效:每种请求头类别恰好标记一个 `pinsHeader` 场景,其 `system-prompt.expected.md` 和 JSONL 工具列表把组合请求头拆成可评审产物;一致性守卫会将两者与该类别的每个实时请求头比较。固定场景可以声明任何合法的变更请求头数量,其 Markdown 产物记录每个完整的已变提示词。纯辅助函数(`sessionFixtureNames`、`fixtureContext`、`normalizedHeaders`、`normalizedSystemPrompts`、`formatSystemPromptSnapshot`、`headerChangeCount`)从模块导出,以便直接进行单元覆盖。
## 曾考虑的替代方案
@@ -33,7 +33,7 @@ ACP(Agent Client Protocol)快照层([快照 Agent Note(agent 决策记
## 测试
提取一致性得到机械证明:迁移后,`pnpm run test:snapshot` 的结果与基准提交匹配,`examples/acp-agent/tests/snapshots/` 下没有任何字节变化。包的 `src/` 在门禁单元运行中保持逐文件 100% 语句/分支/函数/行覆盖,并通过脚本化 fake ACP bin(`tests/fixtures/fake-acp-agent.ts`,每个场景由 fixture 旁的 `behavior.json` 编排行为)经过真实 launcher 驱动:`harness.spec.ts` 直接覆盖 launcher 默认值、捕获、更新等待、关闭以及环境/配置变体,随后覆盖每种场景步骤操作、两个 expect-error 分支、权限队列(选择、后备、不可能点击)、workspace seed,以及采集顺序/噪音/后备分支;`suite.spec.ts` 在收集时真实运行 factory——一个针对已提交合成 fixture 的重放套件和一个针对临时副本的记录套件(写回从不触及已提交树;`ACP_SNAPSHOT_SPEC_BOOTSTRAP=1` 会重新引导它)——并包含纯辅助函数的直接用例。fake bin 会把 `session/new` cwd 而非 `process.cwd()` 代入脚本化日志,与真实 bin 请求头携带的内容一致(darwin 会将 `/var/folders/…` realpath 为 `/private/var/folders/…`)。
提取一致性得到机械证明:迁移后,`pnpm run test:snapshot` 的结果与基准提交匹配,`examples/acp-agent/tests/snapshots/` 下没有任何字节变化。包的 `src/` 在门禁单元运行中保持逐文件 100% 语句/分支/函数/行覆盖,并通过脚本化 fake ACP bin(`tests/fixtures/fake-acp-agent.ts`,每个场景由 fixture 旁的 `behavior.json` 编排行为)经过真实 launcher 驱动:`harness.spec.ts` 直接覆盖 launcher 默认值、捕获、更新等待、关闭以及环境/配置变体,随后覆盖每种场景步骤操作、两个 expect-error 分支、权限队列(选择、后备、不可能点击)、workspace seed,以及采集顺序/噪音/后备分支;`suite.spec.ts` 在收集时真实运行 factory——一个针对已提交合成 fixture 的回放套件和一个针对临时副本的记录套件(写回从不触及已提交树;`ACP_SNAPSHOT_SPEC_BOOTSTRAP=1` 会重新引导它)——并包含纯辅助函数的直接用例。fake bin 会把 `session/new` cwd 而非 `process.cwd()` 代入脚本化日志,与真实 bin 请求头携带的内容一致(darwin 会将 `/var/folders/…` realpath 为 `/private/var/folders/…`)。
## 后果