# Claude 追加与压缩协议本地验证 日期:2026-10-20 验证状态:SDK/CLI 协议探针和生产 ClaudeKernel 追加、压缩集成回归通过;Electron 主进程端到端结果另见本轮交接记录,不代表 WorkBuddy 1:1 验收。 ## 1. 验证对象 - `@anthropic-ai/claude-agent-sdk`:`0.3.304` - SDK 内置 Claude Code:`2.1.304` - `node_modules/@anthropic-ai/claude-agent-sdk-win32-x64/claude.exe` - Claude Code SHA-256:`019E5174D5D954585EDB1A946FE280E44A973050B4897034ADF0E16306F85FDD` - 运行平台:Windows x64 本验证使用本机回环模拟的 Anthropic Messages SSE,不连接真实模型服务。HOME、USERPROFILE、 `CLAUDE_CONFIG_DIR` 和 `CLAUDE_SECURESTORAGE_CONFIG_DIR` 均重定向到临时目录,仅使用 dummy key。 因此本文件证明的是当前 SDK/CLI 的消息协议和帧归属行为,不是模型质量、真实供应商行为或 WorkBuddy 原版行为。WorkBuddy 原版结论仍必须通过 REA 采集并记录其 Evidence ID。 ## 2. 追加协议探针 探针文件: - `scripts/claude-append-protocol-probe.ts` - `scripts/build-claude-append-probe.mjs` 探针通过 SDK 原始 `query()` API 创建一个保持打开的异步输入流,流程如下: 1. 发送带 UUID `INITIAL` 的 `PROBE_INITIAL`。 2. 挂起首个模型请求的 SSE 响应。 3. 在首个请求仍在途时,向同一输入流追加带 UUID 的 `PROBE_APPEND_A`、`PROBE_APPEND_B`。 4. 不调用 `interrupt()`,不关闭输入流;释放首个响应后等待全部逻辑回合结束。 5. 对照捕获的模型请求体、SDK 运行时帧和 `result` 帧。 本次生成报告:`.tmp/claude-append-protocol-probe.json`,顶层结果为 `PASS`。 ### 请求侧结果 请求 1 只包含 `PROBE_INITIAL`,且正常完成,未被追加消息取消或改写。 请求 2 包含: 1. 初始用户消息 `PROBE_INITIAL`; 2. 首轮 assistant 文本 `answer-1:PROBE_INITIAL`; 3. 同一个 user message 中按顺序合并的 A、B 文本块。 本次 CLI 将 A 序列化为 `PROBE_APPEND_A\n`,B 保持 `PROBE_APPEND_B`。因此追加消息不会注入 已经在途的 HTTP 请求,而是在首轮完成后成为下一逻辑回合的输入;相邻追加可合并为一个 user message。 ### 结果与归属 本次观察到两个 `result`: - `result[0]` 只归属 `INITIAL` UUID; - `result[1]` 同时归属 A、B 两个 UUID,其中 `user_message_uuid` 是最后一条 B 的 UUID。 两个 `assistant` 帧也按相同边界归属:首轮 assistant 不包含 A/B UUID,合并后的第二轮 assistant 同时包含 A/B UUID。输入文本没有产生 SDK `user` echo 帧。 当前版本的 assistant/result 帧未观察到 `prompt_id`。可用的稳定归属键是 `user_message_uuid` / `user_message_uuids`;在合并回合中,`user_message_uuid` 只是 `user_message_uuids` 的最后一项,不能代表该 result 只覆盖 B。 关键结论: - 一个 `result` 可能覆盖多个追加 UUID;不能用“收到一次 result”直接结算所有排队发送。 - 在途请求和后续追加属于不同逻辑回合,当前观察到一个逻辑回合对应一个 `assistant` 和一个 `result`。 - 该协议结论来自 SDK 原始异步输入流;生产 `ClaudeKernel` 的实现和验证单独记录在第 4 节。 ## 3. 原生压缩边界复验 使用 `scripts/claude-kernel-integration.ts` 的 `compact` 分支,设置 `CLAUDE_PROTOCOL_PROBE=1` 后运行真实 SDK + 内置 CLI + 回环假模型。观察到 `system/compact_boundary`,后续收到成功 `result`,探针断言通过。 集成回归同时继续发送压缩后的请求,断言旧 ASK 内容不再出现在上游请求中。生产命令专用路径不附加普通聊天提醒,成功必须同时收到原生边界和成功结果;应用可见历史不随压缩删除。没有证明: - 真实模型压缩后的内容质量或语义完整性; - 自动压缩的 token 阈值和触发条件; - 并发追加用户消息与压缩同时发生时的行为; - 压缩失败、重试和真实供应商错误分类。 ## 4. 对 YCode 内核的影响 生产 `src/main/agent/claude/claude-kernel.ts` 保留单个活动根运行,新增 `appendInput()`,不放开并发 `runTurn()`: 1. 输入带独立 UUID 推入同一原生输入流,不取消当前请求,不声称改写已发出的上游请求。 2. 按 `user_message_uuid(s)` 路由后续输入组;首个 result 不会提前结算仍待交付的追加项。 3. 前一组完成后先保存旧 assistant;匹配到新组的原生身份帧后,由宿主原子保存完整用户消息及新 assistant,再确认对应队列项交付。A/B 可合并到同一原生组,但正式历史保留两条用户消息。 4. 后续组沿用根运行的冻结模型、权限和工作区;新组保存期间工具/审批等待交接,避免挂到旧 assistant。 5. 取消会关闭并排空原生生产者,再允许下一运行;推入前失败可明确重试,推入后未确认的消息标记 unknown,不自动重放。 `scripts/claude-kernel-integration.ts` 直接调用生产内核验证双追加、不打断首请求、身份归属、交接回调、空闲追加拒绝、原生压缩和压缩后请求。2026-10-20 重新构建后运行 `CLAUDE_PROTOCOL_PROBE=1`,输出 PASS(16 requests / 43 events / 9 turns)。这些数字属于确定性回环夹具,不是实际模型效果或完整 UI 验收。 ## 5. 复验命令 在仓库根目录执行: ```powershell npx tsc --ignoreConfig --noEmit --target ES2023 --module ESNext --moduleResolution Bundler --strict --skipLibCheck --types node --lib ES2023 scripts/claude-append-protocol-probe.ts node scripts/build-claude-append-probe.mjs node .tmp/claude-append-protocol-probe.mjs node scripts/build-claude-kernel-regression.mjs $env:CLAUDE_PROTOCOL_PROBE='1' node .tmp/claude-kernel-integration.mjs npm run typecheck ``` 预期: - 追加探针输出 `result: PASS`,报告写入 `.tmp/claude-append-protocol-probe.json`; - 压缩探针输出 `probe: compact`、`boundary: true`,随后 integration 输出 `result: PASS`; - `npm run typecheck` 通过。 `node .tmp/claude-append-protocol-probe.mjs` 使用随机回环端口和临时配置目录;报告中的端口、 UUID 和消息 UUID 每次运行都会变化。稳定复验依据是版本、二进制哈希、帧结构和上述断言。 ## 6. 限制与后续 - 探针只覆盖 Windows x64 和当前 SDK/CLI 版本,不能外推到其他平台或版本。 - 假模型只返回固定文本,不覆盖真实长上下文、网络重试、限流和供应商差异。 - 没有验证 WorkBuddy 原版是否采用相同的追加/压缩交互;该比较需另行通过 REA 完成并记录证据。 - 原生追加与压缩混发被产品入口拒绝;真实网络故障、工具密集追加、多平台进程崩溃注入仍需要进一步验证。