Files
ycode/docs/Claude追加与压缩协议验证-2026-10-20.md

6.7 KiB
Raw Permalink Blame History

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. 复验命令

在仓库根目录执行:

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 完成并记录证据。
  • 原生追加与压缩混发被产品入口拒绝;真实网络故障、工具密集追加、多平台进程崩溃注入仍需要进一步验证。