跳转到内容

第 16 课:Session 持久化源码

从阶段二的 resume 示例进入 Pi session JSONL、树结构、fork、clone、import/export 和 metadata 源码。

Session 不是一段扁平聊天记录,而是一棵 append-only 的任务树。它保存 header、message、model change、thinking change、compaction、branch summary、label 和 metadata;每个 entry 通过 id 和 parentId 形成分支,当前上下文由 leaf 回溯到 root 后生成。

为什么一个长任务可以中断、恢复、fork 和导出审阅,而不会丢失上下文?

  • append-only 让历史可审计。
  • parentId 让历史可以分支。
  • leaf 表示当前恢复点。
  • compaction 和 branch summary 让长历史仍能进入模型上下文。

下面不是完整源码,而是把本课主线压缩成可以在文档里直接阅读的关键形状。读者即使不打开本地源码,也应该能看出运行时如何组织职责。

function appendEntry(parent: Entry, payload: Payload) {
const entry = { id: newId(), parentId: parent.id, payload };
journal.write(entry);
return entry;
}
function contextForLeaf(leafId: string) {
const branch = tree.walkToRoot(leafId).reverse();
return branch.flatMap(expandForModel);
}
  • 这段源码形状说明持久化的核心不是“保存数组”,而是“保存可恢复的树”。
  • contextForLeaf() 只取当前分支,避免不同尝试方向互相污染。
  • 导出、回放和评审都建立在 append-only journal 上。

设计一个 session browser 的输出,能展示 entry 数量、当前 leaf、分支树和某个 leaf 的上下文摘要。

  • 能解释 append-only journal 的价值。
  • 能说明 resume、fork、import/export 的关系。
  • 能设计 session 元数据用于任务复盘。
  1. 实践题:基于本课的省略版源码,补出一个最小实现草图,要求写清输入、输出、副作用和错误处理。
  2. 思考题:本课机制如果只靠 prompt 约束,而不放进 harness 或 runtime,会出现什么工程风险?