π Pi Agent Study
Chapter 01 · entry runtime

01 · 使用入口

从 pi 命令追到 agent loop

这一章不试图读完整个项目,而是只追一条干净主线:一次用户输入如何从 CLI 进入 AgentSession,再进入 Agent,最后由 runLoop() 驱动模型输出、工具调用和事件流。

学完要会什么

这一章的验收标准不是会改功能,而是能解释 pi 为什么不是普通的一问一答程序。

能找到入口

  • 知道 bin.pi 指向构建后的 CLI。
  • 知道源码入口是 packages/coding-agent/src/cli.ts
  • 知道 main.ts 负责模式分发。

能拆清职责

  • AgentSession 是会话和产品逻辑。
  • Agent 是执行层状态机。
  • agent-loop 是模型和工具循环。

能读事件流

  • 知道 message_update 来自模型 stream。
  • 知道 tool result 会回填上下文。
  • 知道 agent_end 是一次 run 的结束。

第一次运行 Pi 看什么

第一次不要急着评价回答质量,先确认一次 prompt 是否真的进入了 agent 核心链路。

看 session

  • 输出里先出现 session
  • 说明 CLI 已经创建或恢复会话。
  • 这一步还不是模型开始推理。

看 agent run

  • agent_start 表示进入一次 agent run。
  • turn_start 表示开始一轮模型/工具循环。
  • 一次 prompt 可能有多轮 turn。

看工具闭环

  • message_update 可能包含 text、thinking 或 tool call 增量。
  • tool_execution_start/end 才是本地工具执行。
  • toolResult 回填后模型才知道工具结果。
建议命令 pi --mode json -p "Read README.md and summarize it"。JSON mode 最适合第一遍观察,因为它把 session、agent、message 和 tool 事件按顺序打印出来。

入口链路

第一条主线只看一次 prompt 如何进入 agent,不展开所有配置、扩展和 UI 分支。

01pi 命令用户在终端输入。
02cli.ts初始化运行环境。
03main.ts解析参数,选择模式。
04SessionManager创建或恢复 session。
05AgentSession会话层入口。
06Agent启动一次 run。
07runAgentLoop进入核心循环。
08provider/tools模型输出和工具执行。
本章读法 不要从 TUI 开始。interactive mode 代码量大,会把 UI、快捷键、渲染和事件订阅混在一起。先看 print mode,更容易看到 agent 的骨架。

不同 mode 只是外壳

print、json、interactive、RPC、SDK 的入口不同,但它们不是五套 agent 核心。

我们先用 JSON

pi --mode json -p "Read README.md and summarize it"

CLI 外壳

  • print 适合只要最终文本。
  • json 适合观察事件流。
  • interactive 适合真实终端交互。

复用外壳

  • RPC 把事件给外部客户端。
  • SDK 把 agent 能力给程序调用。
  • 核心仍然围绕 AgentSession -> Agent -> runLoop
读源码时的判断 看到 mode 分支时先问:它是在改变输入/输出外壳,还是在改变 agent 核心执行?本章重点只追后者的共用路径。

三层职责边界

这一节最重要的能力是判断某段逻辑应该属于哪一层。

层级
负责什么
不负责什么
AgentSession
产品会话层:命令、skill、prompt template、鉴权、compaction、retry、session 持久化。
不直接执行模型循环,不应该变成 provider 实现。
Agent
执行层状态机:保存 messages/tools/systemPrompt,创建 context snapshot 和 loop config。
不关心 CLI/TUI/RPC,也不关心 session 文件如何展示。
agent-loop
核心循环:模型 stream、tool call、tool result、下一轮 turn、停止条件。
不处理产品交互细节,不知道用户是从哪个 mode 进来的。
本节结论 AgentSession.prompt() 不是请求模型;它把用户输入预处理成 agent 可执行消息。 Agent.prompt() 也不是请求模型;它启动一次 agent run。 真正的执行引擎是 runAgentLoop()runLoop()

runLoop 的两层 while

这就是 pi agent 不是一问一答的核心原因。

内层 while

  • 处理 pending 或 steering message。
  • 调用 streamAssistantResponse()
  • 检查 assistant message 里的 tool call。
  • 执行工具,把 tool result 加回上下文。
  • 如果还有工具调用或 steering,继续下一轮。

外层 while

  • 当内层准备停下时,检查 follow-up。
  • follow-up 不打断当前工具链。
  • 如果有 follow-up,把它作为下一轮 pending message。
  • 如果没有 follow-up,发出 agent_end
一句话总结 一次 prompt 会触发持续事件流,并在 runLoop 里反复执行“模型生成、工具调用、工具结果回填、继续生成”,直到没有工具、steering 或 follow-up 才结束。

用 JSON 事件验证

真实输出可以直接对应到源码里的 emit 时机。

pi --mode json -p "Read README.md and summarize it"

{"type":"session", ...}
{"type":"agent_start"}
{"type":"turn_start"}
{"type":"message_start","message":{"role":"user", ...}}
{"type":"message_end","message":{"role":"user", ...}}
{"type":"message_start","message":{"role":"assistant", ...}}
{"type":"message_update","assistantMessageEvent":{"type":"thinking_start", ...}}
{"type":"message_update","assistantMessageEvent":{"type":"thinking_end", ...}}

怎么看

  • session 是 session header,不是 agent loop 事件。
  • agent_start 表示一次 agent run 开始。
  • turn_start 表示一轮模型/工具循环开始。
  • user message 是 AgentSession.prompt() 构造出来的。
  • assistant update 来自 provider 的 stream event。
如果模型调用工具 后续还会看到 toolcall_starttool_execution_starttool_execution_endtoolResultturn_endagent_end。工具细节留到第 04 章。
事件
怎么看
说明什么
session
打印当前会话信息。
CLI 层已经准备好 session,还没代表模型开始。
agent_start
一次 agent run 开始。
后面所有 turn/message/tool 事件都属于这次 run。
turn_start
一轮模型/工具循环开始。
一次 prompt 可能因为 tool result 回填而产生多个 turn。
message_start
user 或 assistant message 开始进入事件流。
user message 通常来自 AgentSession.prompt(),assistant message 来自 provider stream。
message_update
assistant 正在增量输出。
可能是 thinking、text,也可能是 tool call 参数的增量。
tool_execution_start
本地工具真正开始执行。
它晚于模型生成 tool call;tool call 本身还不是工具执行。
tool_execution_end
本地工具执行完成。
成功或失败都会形成可回填的 tool result。
turn_end
当前 turn 结束。
如果有新的 tool result 或 follow-up,agent 还可能继续下一轮。
agent_end
这次 agent run 结束。
没有待执行工具、steering 或 follow-up 后才会出现。

01 完成度

本章已经完成概念导读和事件观察,工具实现细节留给后续章节。

已经完成

  • 找到 pi 命令入口。
  • 理解 main.ts 的 mode 分发。
  • 理解 AgentSession.prompt() 的会话层职责。
  • 理解 Agent.prompt() 的执行层职责。
  • 理解 runLoop() 的内外循环。
  • 用 JSON mode 观察真实事件流。

下一章继续

  • 进入 packages/ai
  • 理解 provider 如何返回 stream event。
  • 理解 ContexttoolCalltoolResult
  • 解释为什么 tool result 必须回到上下文。