Skip to content

Latest commit

 

History

History
120 lines (80 loc) · 5.58 KB

File metadata and controls

120 lines (80 loc) · 5.58 KB

16. 会话持久化与恢复机制

这篇讲什么

这一章解释 Claude Code 为什么能“继续上一轮”:transcript 存在哪里,恢复时会还原哪些状态,subagent transcript 和 worktree 状态又是怎么挂回来的。

先给结论

Claude Code 的会话恢复不是只把历史消息重新读一遍。当前快照里,恢复链路至少同时处理:

  • 主 transcript JSONL
  • subagent transcript 与 metadata
  • 文件历史与 attribution 快照
  • context collapse 边界
  • TodoWrite 产生的待办状态
  • session mode / agent / model override / worktree

也就是说,resume 更接近“重建一个持续中的工程会话”,而不是“把聊天记录贴回来”。

源码依据

Mermaid 图:会话恢复流程图

flowchart TD
    A["sessionId / transcript path"] --> B["读取 JSONL transcript"]
    B --> C["deserializeMessages / 清洗中断与孤儿消息"]
    C --> D["restoreSessionStateFromLog"]
    D --> E["文件历史 / attribution / context collapse / todos"]
    B --> F["restoreSessionMetadata"]
    F --> G["session mode / agent / model override"]
    G --> H["restoreWorktreeSession"]
    E --> I["恢复后的 AppState / QueryEngine 初始消息"]
    H --> I
Loading

transcript 如何落盘

src/utils/sessionStorage.ts 直接表明:

  • 主会话 transcript 使用 JSONL 存储。
  • 默认落在 Claude 配置目录下的 projects/ 中。
  • transcript 路径与 sessionProjectDir 绑定,避免 resume 后路径漂移。
  • subagent transcript 单独写到 sessionId/subagents/... 目录。
  • transcript 中真正参与 parentUuid 链的只有 transcript message;旧版 progress 会被桥接或跳过。

这一层说明 Anthropic 把“会话状态”视为结构化日志,而不是单个大 JSON blob。

为什么要区分 transcript message 和 progress

sessionStorage.ts 里把 userassistantattachmentsystem 定义为 transcript message,同时明确把 progress 排除在 parentUuid 链之外。注释还说明旧版 progress entry 会导致 resume 后真实消息被 orphan。

这意味着恢复系统的第一原则不是“保留一切 UI 细节”,而是“保证消息链和 API 语义稳定”。高频进度条可以丢,真正参与推理的消息不能乱。

恢复时到底会还原什么

src/utils/sessionRestore.tsrestoreSessionStateFromLog() 直接恢复:

  • 文件历史快照
  • attribution 状态
  • context collapse commit log 与 snapshot
  • TodoWrite 产生的 todos

同一文件还会恢复:

  • standalone agent 的名称与颜色
  • resumed session 的 agent type
  • resumed agent 对应的 model override
  • coordinator / normal mode 切换后的 agent definition 刷新

所以 resume 不只是恢复消息,还恢复“这个 session 当时处在什么工作模式里”。

对话恢复时会清洗哪些脏状态

src/utils/conversationRecovery.ts 负责把 transcript 重新变成可继续推理的消息序列。按函数命名和注释可确认,它会处理:

  • 旧 attachment 类型迁移
  • unresolved tool use
  • orphaned thinking-only assistant message
  • 纯空白 assistant message
  • interrupted turn / interrupted prompt

这一步的意义很大。它说明 transcript 不是天然可 replay 的,需要先做“恢复期数据修复”。

worktree 为什么也属于恢复语义

sessionRestore.ts 里直接调用 restoreWorktreeSession(),也会在需要时写回 saveWorktreeState()。这说明 worktree 不是外部附加功能,而是 session identity 的一部分。

换句话说,如果一个 agent 会话是在隔离 worktree 中跑的,恢复它时不把 worktree 一起接回来,会话语义就是错的。

subagent transcript 的设计含义

sessionStorage.ts 通过 setAgentTranscriptSubdir()getAgentTranscriptPath() 给 subagent transcript 单独分目录,而且允许 workflow run 级别的 grouping。

这表明 Anthropic 在日志层已经接受了“一个主会话包含多个执行单元”的现实。主线程 transcript 和子代理 transcript 不是临时拼接,而是正式分层存储。

对研究者最有价值的观察

如果你在研究 Claude Code 的“持续运行能力”,这一章是关键,因为它揭示了几个事实:

  • 会话恢复是日志重建,不是内存续命。
  • 可恢复对象包括消息、权限模式、agent、worktree 和部分 UI/任务状态。
  • transcript 格式为了恢复正确性专门排除了某些 UI-only entry。
  • Claude Code 已经把 subagent / workflow 看成会话的一等公民。

这一章的工作结论

Claude Code 的 resume 能力来自一套分层持久化设计:主 transcript 保存推理链,恢复逻辑补回执行状态,conversation recovery 清洗脏消息,worktree 与 subagent transcript 保持工程语义连续。

延伸阅读