写作现场:2026 年 1 月 27 日。 pi-mono v0.50.1 将 provider stream、Agent loop、coding session 和终端界面拆成独立包。这个结构暴露了 Agent 系统常被压成一个 done 的问题:消息闭合、工具批次结束、loop 退出、消息落盘和 session 后处理发生在不同边界。

事件层级与完成条件

主要包之间的调用链为:

AgentSession
→ Agent
→ runAgentLoop
→ pi-ai provider stream
→ tool execution
→ 下一轮或退出

pi-ai 统一 provider 的流式消息;pi-agent-core 管理状态与 loop;pi-coding-agent 增加工具、session、compaction、extensions 和 CLI;pi-tui 负责终端呈现。事件流依次出现 agent_startturn_start、消息与工具事件、turn_end,最后才是 agent_end

四个关键边界不能互换:

  • message_end:token 已组装成完整 assistant message,其中仍可能包含待执行 tool call;
  • turn_end:本轮 assistant message 与对应 tool result 已闭合;
  • agent_end:loop 没有待处理工具或 follow-up,Agent 回到 idle;
  • session settled:AgentSession 完成自动重试、compaction 等后处理。

UI spinner、SDK promise、账单、通知和下游自动化依赖不同边界。若界面在 message_end 就开放下一任务,上一轮工具可能尚未结束;若指标只计算 provider stream,则会漏掉工具执行、持久化和 session 后处理。

消息持久化、分支与 Compaction

pi 在 message_end 时 append session entry。逐 token 持久化会产生大量碎片,只在 agent_end 写入又可能丢失已经闭合、并即将触发工具的 assistant message。选择 message 边界,是在恢复粒度和写入成本之间取中间点。

session 使用 append-only JSONL tree,每个 entry 包含 idparentId,当前 leaf 决定下一轮使用的分支:

root
└─ 用户问题
   ├─ 回答 A ─ 工具结果 ─ 当前 leaf
   └─ 回答 B ─ 另一条实验

历史日志保留发生过的分支,模型上下文只包含当前路径的投影。达到 context window 阈值后,compaction summary 替换较老内容并保留近期 tail;原始 JSONL 仍在磁盘,但模型看到的是有损摘要。

需要区分三种数据:session log 记录发生过什么,branch 定义当前沿哪条路径,compaction 定义有限窗口里保留什么解释。append-only 提供可追溯性,不保证摘要完整,也不是外部工具状态的 checkpoint。恢复 transcript 无法复活进程、凭据或进行中的请求,更不能安全重放状态未知的付款与部署。

pi-mono 适合希望直接控制 provider、事件和 session 边界的框架作者与基础设施工程师;审批、RBAC、跨进程 exactly-once 和可视化工作流需要额外实现。成熟的 Agent 产品应分别暴露模型输出、工具批次、消息持久化、session 后处理和外部副作用的完成状态,而不是用一个绿色对勾覆盖全部阶段。

版本与源码

信息边界:本文写于 2026 年 1 月 27 日,只依据 v0.50.1;后续仓库迁移、通用 harness 与新增生命周期事件不在本文判断中。