所属专题簇:记忆与上下文算法深挖
建议前读:19. 上下文压缩与历史治理
Claude Code 如何在长会话里同时做到“UI 还看得见历史”和“实际运行时不再背着整段历史前进”?
它在 QueryEngine 里预留了一条 HISTORY_SNIP 路径:通过 snip boundary、replay 和 projected view,把“用户能回看的历史”和“运行时真正保留的消息集”拆开。
这一章解释当前快照里可见的 snip 机制接口、边界消息语义,以及它与普通 compact 的不同。需要说明的是:snipCompact.ts 与 snipProjection.ts 在当前仓库中由 QueryEngine 条件导入,但实际文件未出现在可见快照中,因此本章只依据调用点和注释解释其协议,不伪造实现细节。
- Snip 不是普通 compact 的别名。
- 它更像“历史重放和运行时裁剪协议”。
- 目标不是只省 token,还要让 SDK / headless 会话真正释放旧消息占用。
- QueryEngine 中的 snip 接口:src/QueryEngine.ts
- API round grouping:src/services/compact/grouping.ts
- 目录中可见的 compact 组件:src/services/compact/
flowchart TD
A["长会话 mutableMessages"] --> B["yield compact/snip boundary"]
B --> C["snipReplay hook"]
C --> D{"是否真的是 snip boundary?"}
D -- 否 --> E["忽略"]
D -- 是 --> F["重放 / 投影保留段"]
F --> G["替换 QueryEngine 内 store"]
G --> H["释放 pre-boundary messages for GC"]
H --> I["UI 或 SDK 继续基于投影视图工作"]
src/QueryEngine.ts 明确有:
feature('HISTORY_SNIP')- 条件导入
snipCompact.js - 条件导入
snipProjection.js snipReplay配置项projectSnippedView相关注释
这足以证明 snip 是正式设计的一部分,而不是注释残留。
QueryEngineConfig 对 snipReplay 的注释已经把语义说得很清楚:
- REPL 保留 full history 用于 UI scrollback
- SDK / headless 会话需要在这里真正裁剪历史
- replay 的目标是让存储中的消息集缩短,而不是只发一个通知消息
这说明 snip 的核心作用是控制运行时消息存储,而不是只生成一个总结。
QueryEngine.ts 中关于 compact_boundary 的处理能确认:
- boundary 本身会被当作系统消息
- 会带
compactMetadata - 其中有
preservedSegment.tailUuid - 在 boundary 写入前后会 flush transcript / 剪掉前缀
这说明系统不是“把旧消息全扔掉”,而是明确维护一个保留段边界。
src/services/compact/grouping.ts 很有价值,因为它已经把 compact 分组策略从 human turn 改成 assistant message.id 驱动的 API round:
- 同一个 assistant response 的 streaming chunk 保持同组
tool_use/tool_result的配对有效性依赖这个边界- malformed input 的 dangling tool use 由后续修复逻辑兜底
这说明 Anthropic 已经接受一个现实:agentic 会话不能只按“人发一轮、模型回一轮”理解。
普通 compact 关注的是:
- 总结旧消息
- 重建必要 attachment
- 替换上下文前缀
而 snip 更像:
- 产生边界
- 对历史做投影视图
- 在 headless path 里真正缩短 store
- 支持 GC 释放 pre-boundary messages
因此它更接近“运行时内存治理协议”,不是普通摘要流程。
- 历史裁剪后仍要保留足够的 boundary 语义,避免 replay 断裂
tool_use/tool_result配对不能在分组过程中被拆坏- UI scrollback 和运行时 store 可以不完全相同
- headless 会话应真正缩短内存占用,而不是只逻辑上“说自己 compact 了”
- Snip 是 Claude Code 长会话治理里更激进的一条路径。
- 它处理的是“怎么保留可理解历史,同时真的裁掉运行时负担”。
- 即使当前快照缺少
snipCompact.ts正文,QueryEngine暴露的接口和注释已经足以证明这套协议存在。