2026-09-18 实测。起因:要自建 agent 时先问"pi 有没有 HTTP server 或 SDK,没有的话是不是该 fork codex CLI"。

结论先行

两边都没有 HTTP REST 服务端。 codex 是 JSON-RPC over WebSocket,pi 是 CBOR over Unix socket。所以"有没有 HTTP server"不是分水岭。

真正的分水岭是传输层归谁写:

  • pi 的 SDK 是进程内库 → 传输层你自己包,想 HTTP / WebSocket / queue 都行,成本极低。
  • codex 的 app-server 是官方维护的成熟服务端面 → 你接协议,不是定义协议。

pi 的接入面(三种,均非 HTTP)

方式形态适用
SDK进程内 TS 库,主包自带Node/TS 应用内嵌(首选)
RPC modepi --mode rpc,JSONL over stdin/stdout跨语言子进程
JSON modepi --mode json,stdout 事件流一次性 / 脚本
server/clientCBOR over Unix domain socket实验性,见下方限制

SDK 实测导出 151 个符号:createAgentSession、AgentSession、ModelRuntime、ModelRegistry、SessionManager、SettingsManager、DefaultResourceLoader、createCodingTools、createBashTool、RpcClient、createEventBus、compact,以及整套 TUI 组件(FooterComponent、CustomEditor、ToolExecutionComponent 等)——意味着 UI 可以完全替换或复刻。

pi-server 的三重限制(直接排除生产使用):

  • 实验性:description: "experimental server package for pi"。
  • Windows 不支持:packages/client/src/unix.ts 里硬编码 if (process.platform === "win32") throw new Error("Unix transport is not supported on Windows");传输层在 packages/server/src/transports/unix/,只有 Unix socket。
  • 不发布:按官方 development.md,pi-client / pi-protocol / pi-server 是 coding-agent 的 devDependency,实现和 server / client 命令排除在 npm 包与 standalone 二进制之外,只在 checkout 的 source 条件下可解析。

pi 无内置 MCP。docs/usage.md 原文:It intentionally does not include built-in MCP, sub-agents, permission popups, plan mode, to-dos, or background bash. MCP 只作为客户端由扩展/包提供。

Codex CLI 的服务端面

codex app-server --listen <URL>     # stdio:// (默认) | unix:// | unix://PATH | ws://IP:PORT | off
codex app-server daemon <cmd>       # start | stop | restart | bootstrap | enable-remote-control
codex app-server generate-ts        # 生成协议 TypeScript 绑定
codex app-server generate-json-schema
codex exec-server                   # 独立服务;forward 把已有 WebSocket exec-server 注册为远程环境
codex remote-control                # 管理开启远程控制的 app-server 守护进程
codex --remote <ADDR>               # TUI 连远程 app server
codex mcp <add|list|remove|...>     # 管理外部 MCP server(客户端)

要点:WebSocket 传输 + 官方 codegen(TS 绑定 / JSON Schema)+ 常驻守护进程 + 远程控制。ws:// 仍不是 HTTP REST,但对做 Web 前端、远程控制、多客户端远好过 Unix socket。

验证:pi SDK 包一层 HTTP 只要 62 行

实测文件 http-bridge.mts,POST /chat 走 SSE、GET /health:

import { createServer } from "node:http";
import { createAgentSession, ModelRuntime, SessionManager } from "@earendil-works/pi-coding-agent";

const modelRuntime = await ModelRuntime.create();
const model = modelRuntime.getModel("deepseek", "deepseek-flash");
const { session } = await createAgentSession({
  model, modelRuntime,
  sessionManager: SessionManager.inMemory(),
  tools: ["read", "bash"],
});

const server = createServer(async (req, res) => {
  const url = new URL(req.url ?? "/", "http://localhost");
  if (url.pathname =<mark> "/chat" && req.method </mark>= "POST") {
    const chunks = [];
    for await (const chunk of req) chunks.push(chunk);
    const body = JSON.parse(Buffer.concat(chunks).toString("utf8") || "{}");
    res.writeHead(200, { "content-type": "text/event-stream", "cache-control": "no-cache" });
    const send = (p) => res.write(`data: ${JSON.stringify(p)}\n\n`);
    const unsubscribe = session.subscribe((event) => {
      if (event.type === "message_update") {
        send({ type: "update", kind: event.assistantMessageEvent.type, delta: event.assistantMessageEvent.delta });
        return;
      }
      send({ type: "event", name: event.type });
    });
    try { await session.prompt(String(body.message ?? "hello")); }
    finally { unsubscribe(); res.end(); }
    return;
  }
  res.writeHead(404).end("not found");
});
server.listen(8799, "127.0.0.1");

实测事件流(一次带工具调用的对话):thinking_delta 174、text_delta 47、toolcall_delta 25,另有 message_start/end、turn_start/end、tool_execution_start/update/end、agent_start/end/settled。模型实际执行 bash 并返回正确输出。

也就是说:SSE 增量文本、思维链、工具调用与执行、生命周期全部可直接透出,不需要碰 pi 源码。

注意事项:

  • ModelRuntime.create() 启动约 30-40 秒(要加载 / 拉取模型目录),服务化时应只创建一次并复用。
  • 会话级 message_update 的增量类型不止 text_delta:实际有 thinking_start/delta/end、text_start/delta/end、toolcall_start/delta/end。只判 text_delta 会丢思维链和工具参数增量。
  • 用 SessionManager.inMemory() 会话;要持久化换成文件型 SessionManager。

选型判断

诉求选择
轻量、可改、传输自己定pi SDK + 自写 HTTP/SSE 层
官方维护的成熟服务端、守护进程、远程控制、多前端codex app-server(接协议即可,不必 fork)
想要平台化(内置 MCP、子代理、权限弹窗、plan mode)pi 需要靠扩展补齐,或直接选 oh-my-pi

补充:pi 主体是 TypeScript,扩展 jiti 热加载、改完 /reload;codex 主体是 Rust,fork 后自改成本显著更高。为"有 server"去 fork codex 不划算——pi 缺的是传输层,不是能力。

相关概念


本文归档于个人知识库 · 领域:CS & AI · 模块:04 Project_CS_AI/AI apps