用 createAgentSession、SessionManager.inMemory、session.prompt 和 session.subscribe 写出最小可运行的 headless agent runner。
第一个 Pi SDK 程序只需要四个动作:创建 session、订阅事件、发送 prompt、释放 session。真正要学的不是 API 背诵,而是如何把 SDK 程序组织成一个可控的 headless runner。

如果要把 Pi 嵌入自己的 CLI、CI 任务或后台服务,第一步应该写出什么最小结构?
- 输入层只负责得到用户任务。
- session factory 负责装配模型、资源、工具和会话策略。
- 事件订阅负责把模型输出和工具状态传给宿主。
- 生命周期收口负责释放监听器和 runtime 资源。
源码推演(省略版)
Section titled “源码推演(省略版)”下面不是完整源码,而是把本课主线压缩成可以在文档里直接阅读的关键形状。读者即使不打开本地源码,也应该能看出运行时如何组织职责。
async function runOnce(input: string) { const { session } = await createAgentSession({ sessionManager: SessionManager.inMemory(), });
session.subscribe((event) => { if (event.type === "message_update") renderDelta(event); });
try { await session.prompt(input); } finally { await session.dispose(); }}- 这段代码补上了只看路径时缺失的关键细节:runner 的输出来自
subscribe(),不是prompt()的返回字符串。 inMemory()让第一版先避开恢复会话的复杂度,适合验证生命周期。finally是长期运行宿主的基本卫生,否则监听器和 runtime 资源可能泄漏。
复制这个结构,写出一个只执行一次任务的 runner,并说明每一行的职责。
- 能独立写出最小 runner。
- 能解释为什么第一版使用内存会话。
- 能说明事件订阅、prompt 和 dispose 的先后关系。
- 实践题:基于本课的省略版源码,补出一个最小实现草图,要求写清输入、输出、副作用和错误处理。
- 思考题:本课机制如果只靠 prompt 约束,而不放进 harness 或 runtime,会出现什么工程风险?