上下文管理、压缩与 checkpoint
Claude Code 如何组装上下文、何时触发压缩、压缩后如何恢复,以及源码里几类 checkpoint 的边界。项目把 token/context 当成长期运行时资源管理,而不是"超过就报错"。
1. 上下文来源不是只有聊天历史#
一次模型请求的上下文大致由这些部分拼出来:
- system prompt:
constants/prompts.ts和 agent/system prompt 构造逻辑。 - system context:
context.ts中的 cwd、平台、日期、git 信息等。 - user context:
CLAUDE.md、memory prompt、MCP/agent/skill 相关提示、hook 附加上下文等。 - conversation messages:用户/助手/工具结果/attachment/system 边界消息。
- tool definitions:
tools.ts汇总的工具 schema;启用 ToolSearch 时部分工具只以 deferred 名字出现。 - 动态 attachments:
utils/attachments.ts在每轮把@file、MCP resource、deferred tools delta、agent listing delta、nested memory、relevant memories 等注入。
所以"上下文管理"实际包含三件事:控制消息历史长度、控制工具定义长度、控制外部资料/记忆/附件的注入时机。
2. auto compact 的触发阈值#
阈值仍是 effective window − 13_000(summary 预留上限 20_000)。2.1.233 多了一层窗口解析:
CLAUDE_CODE_AUTO_COMPACT_WINDOW(env)- settings 的
autoCompactWindow(/autocompact写入)。autoCompactEnabled只开关自动 compact,不是窗口来源 - clientdata / GrowthBook 实验
- 模型默认窗口
- 未知模型可强制按当前 window 收
CLAUDE_AUTOCOMPACT_PCT_OVERRIDE 仍可把阈值压成 window 的百分比。另有 CLAUDE_CODE_BLOCKING_LIMIT_OVERRIDE。DISABLE_COMPACT 关全部 compact,DISABLE_AUTO_COMPACT / autoCompactEnabled: false 只关自动 compact。
query 里还可以先吃预计算 compact(tengu_sepia_moth + precomputeCompactionEnabled)。remote 上 reactive compact 还要过 tengu_reactive_compact_remote。连续失败 3 次后本 session 不再试。
3. compactConversation 的主体流程#
services/compact/compact.ts 的 compactConversation() 不是简单地"把历史发给模型总结":
- 执行
PreCompacthooks,可追加自定义 compact 指令。 - 设置 UI/SDK 状态:
compact_start、setSDKStatus('compacting')。 - 构造
getCompactPrompt(customInstructions)。 - 通过
streamCompactSummary()生成 summary。默认走 forked-agent 路径以复用主请求 prompt cache。 - 如果 summary 请求本身遇到 prompt-too-long,会用
truncateHeadForPTLRetry()丢弃最老 API round group 后重试,最多MAX_PTL_RETRIES = 3。 - 清空/重建 read file state,生成 compact boundary、summary user message、必要 attachments、hook results。
- 把 discovered tool、file cache、invoked skills、plan 等状态带过 compact 边界。
- 执行 PostCompact hooks 和 post-compact cleanup。
compact 后的消息顺序由 buildPostCompactMessages() 固定:
compact_boundary
summaryMessages
messagesToKeep
attachments
hookResults
这说明 compact 后的会话并不是"只剩一段 summary",而是一个有边界、有保留尾部、有恢复附件的重组消息链。
4. prompt-too-long 兜底#
truncateHeadForPTLRetry() 的设计很关键:
- 先按 API round 分组,避免切断 assistant/tool_result 结构。
- 能从错误里解析 token gap 时,按 gap 丢足够老的 group;解析不了就丢 20%。
- 如果丢完后首条变成 assistant,会补一个 synthetic user marker,避免 API 要求首条必须 user 的错误。
这是 compact 自身也过长时的最后兜底,否则用户会卡在"想压缩但压缩请求也发不出去"的状态。
5. microcompact:清理旧工具结果#
services/compact/microCompact.ts 是更细粒度的上下文治理:
- compactable tools 包括
Read、shell tools、Grep、Glob、WebSearch、WebFetch、Edit、Write。 - 旧路径会把 tool result 内容替换成
[Old tool result content cleared](这串还在)。 - 2.1.233 制品里没有
CACHED_MICROCOMPACT这个 flag 名。大结果落盘 / cache edit 仍在,上限可由 GrowthBook 覆盖。
6. session-memory compact:用当前会话笔记替代全量总结#
session memory 的 viewer / current_session_memory attachment 还在。2.1.233 制品里没有 tengu_session_memory / tengu_sm_compact,也看不到“先 session-memory compact、再 legacy summary”这条默认路径。auto compact 走 summary compact / reactive compact / 预计算 compact。
7. "checkpoint" 至少有三种含义#
源码里 checkpoint 不是单一概念,需要区分:
- compact boundary checkpoint:
SystemCompactBoundaryMessage,subtype 为compact_boundary。它是压缩后的恢复边界,记录 compact metadata、pre-compact discovered tools、preserved segment 等。 - transcript parent chain checkpoint:
utils/sessionStorage.ts通过parentUuid/logicalParentUuid维护消息 DAG。compact boundary 的parentUuid会特殊处理,防止 resume 时旧消息链 orphan。 - file history checkpoint:
utils/fileHistory.ts维护文件修改快照,最多MAX_SNAPSHOTS = 100。这是面向文件回滚/历史的 checkpoint,和上下文压缩不是同一层。
另外,profileCheckpoint 这类启动性能埋点不是用户语义上的 checkpoint。