Pi SDK
Pi SDK 是 Pi 的第四种入口(官方文档与导航只称之为「SDK」,「Pi SDK」为本库独立成页采用的惯例写法,非官方品牌名):它把终端编码 Agent 的会话管理、工具循环、资源加载、模型认证和设置系统以 TypeScript API 形式暴露在 @earendil-works/pi-coding-agent 主包中,不需要单独安装。CLI、TUI、RPC 与 SDK 共享同一套核心;本页专注 SDK 层的 API 结构与语义,项目整体设计与安全边界见 Pi 词条。
官方列出的典型用途:构建自定义 UI(web / 桌面 / 移动)、把 Agent 能力嵌入既有应用、自动化流水线、构建派生 Subagent(子智能体)的自定义工具,以及程序化测试 Agent 行为。仓库 examples/sdk/ 提供从最小调用到完全控制的示例序列。
最小形态
import { createAgentSession, ModelRuntime, SessionManager } from "@earendil-works/pi-coding-agent";
const modelRuntime = await ModelRuntime.create();
const { session } = await createAgentSession({
sessionManager: SessionManager.inMemory(),
modelRuntime,
});
session.subscribe((event) => {
if (event.type === "message_update" && event.assistantMessageEvent.type === "text_delta") {
process.stdout.write(event.assistantMessageEvent.delta);
}
});
await session.prompt("What files are in the current directory?");这个最小调用已经体现 SDK 的结构:ModelRuntime 负责模型注册与认证,SessionManager 负责会话持久化(这里是纯内存),createAgentSession() 把各部件组装成会话,之后全部交互就是事件订阅与 prompt()。
正交部件而非黑盒
SDK 最值得注意的设计是不提供一个黑盒 run(),而是暴露一组可独立替换的部件:
| 部件 | 职责 | 可替换性 |
|---|---|---|
AgentSession | 单个会话生命周期:prompt、消息历史、模型状态、压缩、事件流 | 由 createAgentSession() 工厂组装 |
AgentSessionRuntime | 替换活动会话(new / switch / fork / import),重建 cwd 绑定状态 | 整个 runtime 由工厂闭包构建 |
SessionManager | 会话树持久化(JSONL、id/parentId)、列举、分支 | inMemory() / create() / continueRecent() / open() |
SettingsManager | 全局+项目设置合并与持久化 | create() / inMemory(),测试免文件 IO |
ModelRuntime | 模型注册表、凭证存储、认证检查 | 自定义 authPath / modelsPath,或注入 pi-ai CredentialStore |
ResourceLoader | 扩展、技能、提示模板、主题、上下文文件的发现与覆盖 | DefaultResourceLoader 各 *Override 钩子,或完全自定义实现 |
flowchart LR
App["嵌入方应用"] --> CAS["createAgentSession()"]
MR["ModelRuntime
模型与认证"] --> CAS
SM["SessionManager
会话树"] --> CAS
ST["SettingsManager
设置"] --> CAS
RL["ResourceLoader
扩展/技能/模板"] --> CAS
CAS --> S["AgentSession"]
S --> Core["pi-agent-core
Agent + 工具循环"]
所有部件都有 in-memory 变体,单元测试可以在无文件系统、无凭证的环境下构造完整 Agent 会话——这是把 Harness Engineering(驾驭工程)的各层显式对象化后的直接收益。
会话生命周期与替换语义
AgentSession 的核心接口(节选):
prompt(text, options?)发送并等待整轮完成;流式期间用steer(text)/followUp(text)排队消息subscribe(listener)返回取消订阅函数setModel()/setThinkingLevel()/cycleModel()在会话中切换模型与 thinking levelnavigateTree(targetId, ...)会话树原地跳转(对应 CLI 的/tree)compact(customInstructions?)/abortCompaction()手动压缩abort()/dispose()中止与清理
会话替换 API 不在 AgentSession 上,而在 AgentSessionRuntime 上:newSession()、switchSession(path)、fork(entryId)、clone(fork(entryId, { position: "at" }))、importFromJsonl()。替换后有两个容易踩的坑:
runtime.session指向新对象,事件订阅绑定在具体 session 上,必须重新 subscribe;- 使用扩展时需对新 session 再次调用
runtime.session.bindExtensions(...)。
这把"会话对象"与"运行时"显式分层:AgentSession 是一次性的具体对话,runtime 才是承载 /new、/resume、/fork 语义的那一层。创建与替换失败由方法抛出、调用方自行处理;创建结果还带 diagnostics。
Prompt 队列:steer 与 followUp
PromptOptions 的 streamingBehavior: "steer" | "followUp" 控制流式期间的入队行为;不传则 prompt() 在流式期间直接抛错。语义分层:
- steer:当前 assistant turn 的工具调用完成后立即送达,用于中途改指令
- followUp:等 Agent 完全停下才送达,用于追加任务
- Extension 命令(如
/mycommand)总是立即执行、不能排队;文件型 prompt template 发送或入队前展开成内容
preflightResult 回调每次 prompt() 触发一次:true 表示被接受、入队或立即处理;false 表示 preflight 阶段即被拒绝。而 prompt() 本身的 resolve 仍需等整个被接受的 run(含自动重试)结束,接受后的失败走正常事件与消息流。
这组 API 把 CLI 交互层的排队行为变成显式契约:嵌入方必须自己为"用户中途输入"选择 steering 还是 followUp,而不是依赖某个 UI 层的隐式约定。
事件流
SDK 事件与 Agent Loop(智能体循环)的阶段一一对应:
- 消息:
message_start/message_update(text_delta、thinking_delta)/message_end - 工具:
tool_execution_start/tool_execution_update(流式工具输出)/tool_execution_end(带isError) - turn:
turn_start/turn_end(本轮 assistant message 与 toolResults) - Agent:
agent_start/agent_end(event.messages含新增消息) - 会话级:
queue_update、compaction_start/end、auto_retry_start/end、summarization_retry_*
session.agent.state 暴露持久状态(messages、model、thinkingLevel、tools、streamingMessage),并允许直接替换 messages / tools 数组实现分支或恢复;waitForIdle() 等待处理完成。
资源发现与切断
DefaultResourceLoader 的发现路径对嵌入方很关键,因为嵌入场景经常需要切断 默认发现:
cwd:项目扩展.pi/extensions/;技能.pi/skills/与.agents/skills/(沿目录向上至 git 根,非仓库则到文件系统根);.pi/prompts/;向上 walk 的AGENTS.md;会话目录命名agentDir(默认~/.pi/agent):全局扩展与技能(含~/.agents/skills/)、prompts、AGENTS.md、settings.json、models.json、auth.json、sessions/
传入自定义 ResourceLoader 后,cwd / agentDir 不再控制资源发现(仍影响会话命名与工具路径解析)。覆盖钩子包括 systemPromptOverride、skillsOverride、agentsFilesOverride、promptsOverride、additionalExtensionPaths 与 extensionFactories;命名 inline 扩展(InlineExtension 对象)在启动列表显示为 <inline:name> 而不是 <inline:1>,扩展间可通过共享 eventBus 通信。
安全含义同样明确:不切断发现,SDK 会读取宿主机真实的 ~/.pi/agent 凭证并加载项目级扩展,等于继承 CLI 的信任边界与风险面——参照 Agent Sandbox(Agent 沙箱)对 Pi 默认权限模型的说明。
模型与认证
ModelRuntime 拥有凭证存储,认证解析优先级为:运行时覆盖(setRuntimeApiKey,不落盘)→ auth.json(API key 或 OAuth token)→ 环境变量 → models.json 自定义供应商的 fallback resolver。可注入 InMemoryCredentialStore 实现完全进程内认证,getAvailable() 只返回认证有效的模型。
模型解析有两个对齐 CLI 的辅助函数:resolveCliModel() 处理 provider/model:thinking 字符串(首次配置、尚无存储凭证时也能解析);resolveModelScopeWithDiagnostics() 对齐 --models / enabledModels 语义并返回诊断而不是直接打印。scopedModels 配置交互模式 Ctrl+P 的模型循环列表。
工具面
- 内置工具名:
read、bash、edit、write、grep、find、ls;默认为前四个 tools白名单、excludeTools黑名单(白名单应用后再排除)、noTools: "all" | "builtin"(后者保留扩展与自定义工具)edit工具结果带双格式:details.diff供 Pi TUI 展示,details.patch是标准 unified patch 供 SDK 消费者——同一工具结果为不同客户端形态准备了不同投影,是 Agent Tool Design(Agent 工具设计)中结果投影的具体实例- 自定义工具用
defineTool()+ typebox schema 定义,经customTools传入,与扩展注册的工具合并;若同时用tools白名单,自定义工具名也必须列入
一个易错细节:传自定义 cwd 时 createAgentSession() 会为该 cwd 构建内置工具,SessionManager.inMemory(cwd) 也要带上同一个 cwd,两者必须一致。
运行模式复用与 SDK / RPC 选择
SDK 还导出 CLI 自身的三种运行模式实现:InteractiveMode(完整 TUI)、runPrintMode()(一次性输出)、runRpcMode()(JSON-RPC 子进程协议),自定义界面不必从零拼装。不使用 SDK 时,也可直接 pi --mode rpc --no-session 起子进程。官方给出的选择边界:
| 选 SDK | 选 RPC |
|---|---|
| 需要类型安全 | 从其他语言集成 |
| 同一 Node.js 进程 | 需要进程隔离 |
| 直接访问 Agent 状态 | 构建语言无关客户端 |
| 程序化定制工具与扩展 | — |
定位:组装件而非托管 runtime
与 Claude Agent SDK 相比,Pi SDK 暴露的部件更细碎——SessionManager、SettingsManager、ModelRuntime、ResourceLoader 都可独立替换,且没有内建权限审批层;与 OpenAI Agents SDK 相比,它不平台化 handoff、guardrail 与 tracing,而是保持 Pi 一贯的"极简核心 + 自行组合"路线。对嵌入方而言,这既意味着控制面大(内存化测试、自定义系统提示、细粒度事件、直接替换消息树),也意味着生产所需的安全边界、审计与持久化策略都要自己补齐:SDK 给的是部件,不是托管 runtime。
相关概念
- Pi — 本 SDK 所属的项目、分层架构与安全边界
- Harness Engineering(驾驭工程) — SDK 是 harness 各层对象化的接口面
- Agent Loop(智能体循环) — 事件流与 turn 结构对应的控制循环
- Agent Skills —
skillsOverride注入的技能格式 - Context Engineering(上下文工程) —
compact()、会话树导航与消息替换所属的工程面 - Agent Tool Design(Agent 工具设计) —
details.diff/details.patch双投影的归类 - Subagent(子智能体) — “构建派生 sub-agent 的自定义工具"是官方 SDK 用途之一
- Claude Agent SDK、OpenAI Agents SDK — 另外两种 Agent SDK 路线参照