能被 import 的工具才叫平台,命令行只是它的第一张脸。
设计思想
为了让 Pi 能够被其他程序嵌入、作为服务使用或在非交互环境中驱动,Pi 提供了两种标准的编程接口:TypeScript SDK 和 RPC 模式。这使得 Pi 的功能不再局限于终端交互,而是可以被任何语言或框架调用,从而实现自定义工作流、IDE 插件、CI/CD 集成等场景。
原理
四种运行模式
| 模式 | 入口 | 适用 |
|---|---|---|
| Interactive | pi |
终端日常使用 |
| Print / JSON | pi -p "..."、pi --mode json |
一次性任务、shell pipeline |
| RPC | pi --mode rpc |
非 Node 调用方,stdin/stdout JSONL 协议 |
| SDK | import |
Node.js 进程内嵌入 |
SDK(TypeScript)
- 三个核心构件:
ModelRuntime:负责与模型提供商通信(认证、模型目录、思考级别),用ModelRuntime.create()创建。SessionManager:会话持久化;SessionManager.inMemory()为内存态(不落盘),文件态用于真实会话。createAgentSession:工厂函数,组装出可直接使用的session。不传参数时用DefaultResourceLoader做标准发现(extensions、skills、prompts、themes、上下文文件)。
session.prompt(text)发送消息;session.subscribe(listener)订阅事件流(返回取消订阅函数),可拿到message_update/text_delta等流式增量。- 会话替换类操作在
AgentSessionRuntime上,不在AgentSession上(对应 TUI 的/new/resume/fork/clone):runtime.newSession()、runtime.switchSession(target)runtime.fork(entryId)(从某条 user message 分叉)runtime.fork(entryId, { position: "at" })(= clone,复制当前活跃分支)
- 自定义工具不走 ModelRuntime:用
defineTool()定义,经customTools: [myTool]传入;扩展加载的工具仍由pi.registerTool()注册。 - 注意:会话替换后事件订阅会失效,需 unsubscribe 后重新 subscribe。
RPC 模式
pi --mode rpc进入基于 stdin/stdout 的 JSONL 服务。- 命令(写入 stdin,每行一个 JSON 对象):
{"id": "req-1", "type": "prompt", "message": "..."}—— 注意字段是message;id可选,用于请求/响应关联。- 支持带图片:
"images": [{"type": "image", "data": "<base64>", "mimeType": "image/png"}]。 - 流式中追加消息必须带
streamingBehavior:"steer"(当前 turn 工具执行完就送达)或"followUp"(全部干完才送达),否则命令报错;也有独立的{"type": "steer", "message": "..."}命令。 /skill:name和提示模板会在发送前展开;扩展命令流式中也可立即执行。
- 响应:
{"id": "req-1", "type": "response", "command": "prompt", "success": true};接受后的失败走正常事件流,不会对同一 id 二次 response。 - 事件:agent 事件以 JSON 行流式输出到 stdout。
- 分帧铁律:严格按
\n切分记录(可剥离行尾\r)。Nodereadline不合规——它还会在 U+2028/U+2029 处切分,而这在 JSON 字符串里是合法字符。 - 详细协议见
docs/rpc.md。
用法
SDK 最小示例(官方 Quick Start)
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?");
RPC one-shot 示例
echo '{"id":"1","type":"prompt","message":"用一句话总结泰勒级数的作用。"}' | pi --mode rpc
# stdout 会依次输出 response 和流式事件(每行一个 JSON)
长连接场景:保持进程 stdin 打开,逐行写入命令、持续读 stdout 事件;用 id 关联请求与响应。
高级用法
- 自定义工具:
defineTool()定义 +customTools: [myTool]传入createAgentSession();与扩展注册的工具合并生效。 - 会话分支:
await runtime.fork("entry-id"),clone 用runtime.fork(entryId, { position: "at" })。 - 资源控制:默认
DefaultResourceLoader可换成自定义 ResourceLoader,精确控制加载哪些 extensions/skills/prompts/themes/上下文文件。 - 多实例/多租户:每个聊天独立
SessionManager与 cwd;凭据与模型目录的隔离参见docs/sdk.md与docs/environment-variables.md(如PI_CODING_AGENT_DIR)。
在项目中的应用
- 作为库:
npm install @earendil-works/pi-coding-agent后用 SDK 构建内部 AI 助手或代码审查工具(SDK 就在主包里,无需单独安装)。 - 作为服务:部署
pi --mode rpc为长运行进程,任意语言客户端通过管道/socket 发 JSONL 指令。 - 自动化流水线:
pi -p适合脚本中的一次性调用,还支持管道合并 stdin(cat README.md | pi -p "Summarize this text")。
注意事项
- 会话替换(new/fork/resume)后必须重新订阅事件。
- RPC 客户端切勿用通用行读取器(如 Node
readline);只按\n切分。 - RPC/非交互模式同样受项目信任机制约束:项目未受信时不加载
.pi/资源(非交互模式不弹询问,按defaultProjectTrust或--approve/--no-approve处理)。 - 配置来源:环境变量(
ANTHROPIC_API_KEY等)、--api-key、--provider、--model、--thinking均可用于两种编程方式。 - 一次性任务可用
--no-session避免会话落盘。