Session:一棵树,不是一条数组

从 JSONL entry、parentId、active leaf 到 compaction checkpoint,理解 Pi 如何保存可分支的工作历史。

ANALYSIS SNAPSHOTPi v0.82.15bc1c2c0

为什么不是 messages.json

工作并不总沿直线前进。你可能回到上午的决策点尝试另一条路。树让旧路径还在,同时新路径可以继续。

SESSION MODELAppend-only session tree
header
user A
assistant B
├──────────────┐
user Cold pathuser Dactive leaf
JSONL 中 entries 仍按追加顺序保存;parentId 决定逻辑树,active leaf 决定当前 context。

Entry 类型的职责

Entry 进入模型 context 作用
message 用户/助手/工具事实
model_change 间接 恢复后续模型状态
thinking_level_change 间接 恢复 reasoning 配置
compaction 是,作为 summary 替代老历史
branch_summary 携带被离开路径的经验
custom 扩展持久状态
custom_message 扩展注入上下文
label / session_info 导航与元数据
packages/coding-agent/src/core/session-manager.ts:30-174SessionEntry union

JSONL 的工程含义

追加一行比重写一个巨大 JSON 数组更容易保持历史、流式落盘和故障恢复;每行仍可独立解析。代价是读取时必须迁移版本、重建索引和树,并处理截断或损坏行。

Pi 当前 CURRENT_SESSION_VERSION = 3,包含 v1→v2、v2→v3 迁移。Session discovery 只扫描有限头部字节,并用并发上限加载列表,避免在大量 session 下无界打开文件。

/tree/fork/clone

  • /tree:同一文件内移动 active leaf。
  • /fork:从较早 user message 创建新 session 文件。
  • /clone:复制当前 active branch 到新 session。

Trade-off

树保留探索空间并支持回溯,但 UI、统计和 compaction 都必须以“当前分支”而非“文件全部行”为准。线性日志更简单,树更符合真实开发工作。