重启之后,Session 能恢复什么
Agent 已经读取文件,进程却在下一轮模型请求前退出。重新启动后,聊天窗口还能显示用户问题和工具调用。
界面恢复,不等于执行器知道工具结果是否落盘、下一轮请求是否还在队列、写操作能否重试,也不代表它知道已经消耗了多少预算。
重新显示历史与继续未完成的运行,需要不同的数据。
Pi 的 Session 是一棵追加写入的树
Section titled “Pi 的 Session 是一棵追加写入的树”AgentHarness Session 使用 entry 记录 message、model change、thinking level、active tools、compaction、branch summary、label 和自定义状态。每个 entry 指向父节点,因此用户可以从旧节点派生新分支,不需要覆盖原历史。
核心结构见 packages/agent/src/harness/session/session.ts。
JSONL storage 先写一条 v3 header,后续每次变化追加一行。切换 leaf 也会留下记录。查看 JSONL storage 的读取与追加。
JSONL 指“一行一个 JSON 对象”。下面是为了说明关系而简化的三行,不是源码字段的逐字拷贝:
{"type":"header","version":3,"sessionId":"s-01"}{"id":"e-01","parent":null,"type":"message","role":"user","text":"检查项目"}{"id":"e-02","parent":"e-01","type":"message","role":"assistant","text":"开始读取"}entry 是一条追加记录,parent 指向它从哪条记录继续,leaf 是当前选中的分支末端。切回 e-01 再追加新消息,就会得到另一条 branch,原来的 e-02 仍保留。
这套结构很适合重建对话、模型选择和分支。模型对象、工具实现、Extension、认证信息和工作环境仍需宿主程序重新装配。
Session、Compaction、Memory 不是一回事
Section titled “Session、Compaction、Memory 不是一回事”这三个词经常被统称为“记忆”,实际用途不同:
| 机制 | 主要用途 | 典型寿命 |
|---|---|---|
| Session | 保存一次任务的消息、状态与分支 | 一次任务到长期归档 |
| Compaction | 给当前模型请求腾出窗口 | 当前任务的后续 turn |
| Long-term memory | 在多个任务之间复用少量事实或偏好 | 直到被更新或删除 |
Session 恢复不应该擅自把每段对话抽成用户事实。长期记忆也不应该覆盖当前任务刚验证出的新信息。至少要为记忆保存来源、作用域、写入时间与失效条件。
为什么它还不能算完全 durable
Section titled “为什么它还不能算完全 durable”Pi 的 durable harness 设计稿很坦率地列出当前缺口:查看 durable harness 的故障模型。
- Provider 的网络流无法从任意 token 位置接着收;
- 进程重启后要重新创建模型、工具与资源;
- 尚未落盘的队列项会丢失;
- 非幂等工具在结果未记录时不能安全重放。
设计稿继续提出 operation、queue 与 tool lifecycle 的持久化方向,查看恢复记录方案。这些内容是设计目标,不能据此把当前 CLI 写成任意位置可恢复的 durable runtime。
教学项目目前保存了什么
Section titled “教学项目目前保存了什么”MemorySessionStore 保存一次已结束运行的 messages、events、terminal 与 reason。
cd agent-harness-labnpm run lab -- 06预期观察:
{ "terminal": "completed", "messages": 2, "events": 4, "hasInventedMemory": false}hasInventedMemory: false 表示 Session 没有根据一段聊天擅自添加长期事实。这个实验能证明最终快照可以重新读取,不能证明进程在任何指令位置退出后都能继续。
要继续未完成的运行,还需追加更细的记录:
queue_enqueued / queue_consumedprovider_started / provider_interruptedtool_started / tool_finishedoperation_started / operation_finished这些记录要在动作发生时写入。如果只在整次 run 结束时一次性保存,最危险的中间状态仍然是空白。
下一章先定义任务何时停止。再往后把 operation journal 接进工具执行,处理程序死在 tool_started 和 tool_finished 之间的情况。