Featured image of post oh-my-pi 用到了哪些基础组件?以及它和 pi 到底是什么关系

oh-my-pi 用到了哪些基础组件?以及它和 pi 到底是什么关系

拆解 oh-my-pi (omp) 的依赖栈、澄清 pi-sdk/pi-coding-agent 误解、画出它和上游 pi-mono 的血缘关系图。

语速

最近在给团队内部做 omp 技术栈分享,被问到三个问题:

  1. oh-my-pi 用了哪些基础组件?
  2. “pi-coding-agent” 和 “pi-sdk” 是两个东西吗?
  3. 它和上游 pi 是什么关系?fork 了多少?自创了多少?

翻完 monorepo 之后发现这三个问题其实是同一件事的不同切面。这篇文章把它们合并回答。

TL;DR

  • 依赖栈:Bun runtime + TypeScript + Rust(~55k 行)+ 自研 19 个 workspace 包 + 第三方覆盖 LLM/TUI/协议/前端/浏览器自动化/本地推理/文档解析。
  • “pi-sdk” 不是独立包:它就是 pi-coding-agent 自己的程序化 API 表面(./sdk./session/*./modes/*./main),CLI 和 SDK 是同一个包。
  • oh-my-pi 是 pi-mono 的 fork + selective backport:上游 7 个 npm 包里 fork 了 5 个(pi-aipi-agent-corepi-tuipi-coding-agentpi-utils),丢了 3 个(pi-mompi-web-uipi-pods),并自创了一整套独占层(pi-nativespi-catalogpi-mnemopipi-wirehashlineomp-statssnapcompactswarm-extension + pi-shell Rust 内核)。
  • 三 scope 等价@oh-my-pi/*(canonical)、@mariozechner/*(上游原名)、@earendil-works/*(中间 fork)写哪个都解析到同一份宿主内置代码。

一、依赖栈全景

1.1 运行时 / 构建

组件用途证据
Bun 1.3.14+包管理 + 运行时 + 测试 + 打包 + 单文件编译packageManager: [email protected]
TypeScript 6类型检查(用 bun check,不用 tsc@typescript/native-preview: 7.0.0-dev...
Vite 8collab-web 开发/构建catalog: vite ^8.0.16
Biome 2.4Lint + 格式(取代 ESLint+Prettier)@biomejs/biome: ^2.4.16
ts-morph 28代码生成ts-morph: ^28.0.0
@babel/*AST 解析/转换(parser/traverse/generator/types)^7.29.7

1.2 自研 monorepo 包(19 个,统一 v16.2.7)

packages/coding-agent/AGENTS.md 明确 coding-agent/ 是 primary focus。其余 18 个按职责:

职责
pi-coding-agent主 CLI(焦点)
pi-ai多 provider LLM 客户端(流式)
pi-agent-coreagent runtime + 工具调用 + 状态管理
pi-catalog模型目录(models.json + 解析器)
pi-tuiTUI 库(差分渲染)
pi-utilslogger / streams / 环境变量 / 临时文件
pi-nativesNode 端原生绑定
pi-wirewire 协议(protobuf)
pi-mnemopi记忆子系统(Hindsight)
hashline / snapcompact / omp-stats工具包
swarm-extension多 agent 协作
collab-webSolid+React Web 协作 UI
terminal-bench基准测试
typescript-edit-benchmarkTS edit benchmark

1.3 Rust 内核(~55k 行)

Cargo.toml workspace 包含 crates/pi-* + crates/vendor/*

  • pi-nativesnapi-rs 原生绑定,JS 可调用的 grep / 文本 / 图像操作
  • pi-shellcrates/vendor/brush-core + brush-builtins(POSIX shell,vendored uutils/brush
  • release profile 严格:opt-level=3lto=fatpanic=unwind(napi-rs 需要捕获 panic 转 JS error)

1.4 TUI / 终端

  • @xterm/headless 6.0 — 终端模拟器
  • ghostty-web 0.4 — Web 终端
  • chalk 5.6 — 颜色
  • winston 3.19 + winston-daily-rotate-file 5.0 — 日志(写到 ~/.omp/logs/

1.5 协议 / Schema

  • @bufbuild/protobuf + protoc-gen-es 2.12 — pi-wire 协议(.proto → TS)
  • zod 4 + arktype 2.2 — 运行时 schema 校验
  • @agentclientprotocol/sdk 0.25 — Agent Client Protocol(让 Zed 等编辑器驱动 omp)

1.6 本地模型 / AI

  • @huggingface/transformers 4.2 — 本地 transformer 模型
  • onnxruntime-node 1.26 — ONNX 推理
  • fastembed 2.1 — 本地 embedding
  • sherpa-onnx 1.13 + 平台包 — 本地 ASR(whisper)
  • @opentelemetry/* 2.x — 链路追踪(OTLP)

1.7 文档 / 内容解析

用途
mammoth 1.12.docx → HTML
mupdf 1.27PDF 解析/渲染
marked 18Markdown 渲染
turndown 7.2 + turndown-plugin-gfmHTML → MD
@mozilla/readability 0.6文章正文提取
fast-xml-parser 5.9XML
linkedom 0.18DOM 解析

1.8 文件编辑 / 工具

  • @oh-my-pi/hashline — 基于 hashline 文件寻址的 edit(README 章节 “11 · Hashline: edit by content hash”)
  • diff 9.0 — diff 算法
  • regexp-tree 0.1.27 — 正则 AST
  • handlebars 4.7 — prompt 模板(.md + hbs,永不内联字符串)
  • lru-cache 11.5 — 缓存
  • fflate 0.8.3 — 压缩

1.9 浏览器自动化

1.10 前端(collab-web)

  • React 19.2.7 + react-dom + react-chartjs-2
  • Solid.js 1.9 + vite-plugin-solid(部分页面)
  • Tailwind CSS 4.3@tailwindcss/vite + @tailwindcss/node
  • chart.js 4.5 — 图表
  • lucide-react 1.17 — 图标
  • date-fns 4.4

1.11 关键设计约定(来自 AGENTS.md

这些不是依赖、但影响整个技术栈:

  • any;无 inline imports;ES #private 字段
  • prompts 走 .md + Handlebars,永不内联字符串
  • 日志用 logger,禁 console.*(保护 TUI 渲染)
  • Worker 通过 cli.ts 单入口__omp_worker_* 隐藏 argv 派发)— 无独立 worker entry,二进制不会断
  • 所有依赖集中在 package.jsonworkspaces.catalog(Bun catalog)— 一处升级,全 workspace 同步

二、关于 “pi-sdk” 的误解

2.1 真相:没有 pi-sdk 这个包

grep pi-sdk 全仓库,结果是 packages/coding-agent/test/sdk-*.test.ts 文件名前缀,里面 “sdk” 是 “以 SDK 方式测试 pi-coding-agent” 的简称,不是包名

真正的入口是 packages/coding-agent/src/index.ts —— pi-coding-agent 自己就是 SDK,SDK 和 CLI 是同一个包

1
2
3
4
// packages/coding-agent/src/index.ts:39-41
// SDK for programmatic usage
export * from "./sdk";
export * from "./session/agent-session";

2.2 你可能在想的是这三个

名字实际是什么在哪
@oh-my-pi/pi-coding-agent (16.2.7)CLI + SDK 二合一bin.omp 是 CLI;./sdk./session/*./modes/* 是程序化 APIpackages/coding-agent/
@oh-my-pi/pi-agent-core纯 runtime SDK(无 CLI / 无 I/O)— pi-coding-agent 自己用它,也对外暴露packages/agent/
@agentclientprotocol/sdk (0.25.0)第三方 ACP 协议 SDK,不是 pi-*npm 上游

2.3 pi-coding-agent 作为 SDK 的入口长这样

packages/coding-agent/examples/sdk/ 有 15 个示例:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
01-minimal.ts            入门
02-custom-model.ts       自定义模型
03-custom-prompt.ts      自定义 prompt
04-skills.ts             skills 系统
06-extensions.ts         ← ExtensionAPI
06-hooks.ts              ← HookAPI
07-context-files.ts      上下文文件
08-prompt-templates.ts   模板
08-slash-commands.ts     slash 命令
09-api-keys-and-oauth.ts 鉴权
11-sessions.ts           session 管理
12-redis-sessions.ts     Redis 持久化
13-sql-sessions.ts       SQLite 持久化

另外 examples/extensions/examples/hooks/ 是写 Extension / Hook 插件 的入口,用的是 CustomToolFactoryExtensionAPIHookAPI 类型。

结论:之前以为 “pi-sdk” 是和 pi-coding-agent 并列的另一个包,顺序反了pi-coding-agent 包本身就是 SDK,只是顺带也提供了 omp CLI 入口。

三、oh-my-pi 与 pi 的血缘

3.1 pi 是什么

pi-mono = badlogic/pi-mono,作者 @mariozechner(Mario Zechner)。一个 modular 的 LLM agent toolkit,最初发布 scope 是 @mariozechner/*,后来也有 @earendil-works/*

上游 monorepo 公开 7 个 npm 包(来源:badlogic-pi-mono.mintlify.app/concepts/packages):

上游包职责
@mariozechner/pi-ai多 provider LLM 统一 API(OpenAI/Anthropic/Google/Vertex/Bedrock + 50+ 模型)
@mariozechner/pi-agent-core有状态 agent runtime + 工具调用 + 事件流
@mariozechner/pi-tui差分渲染的 TUI 框架(line-diff / box-diff / full)
@mariozechner/pi-coding-agent交互式 coding agent CLI
@mariozechner/pi-momSlack bot
@mariozechner/pi-web-uiWeb chat 组件
@mariozechner/pi-podsvLLM GPU pod 管理

3.2 Single Source of Truth:legacy-pi-compat.ts

packages/coding-agent/src/extensibility/plugins/legacy-pi-compat.ts:161-178 是事实源头:

1
2
3
4
5
6
7
8
const PI_SCOPE_ALIASES = ["oh-my-pi", "mariozechner", "earendil-works"] as const;
const PI_PACKAGE_NAMES = ["pi-agent-core", "pi-ai", "pi-coding-agent", "pi-natives", "pi-tui", "pi-utils"] as const;

// 部分 subpath 在上游换过目录,这里把旧路径重写到新路径
const PI_SUBPATH_REMAPS: ReadonlyMap<string, string> = new Map<string, string>([
  ["pi-ai/utils/oauth", "pi-ai/oauth"],
  ["pi-ai/utils/oauth/", "pi-ai/oauth/"],
]);

含义:

  • 插件无论写 @mariozechner/pi-coding-agent 还是 @earendil-works/pi-coding-agent,都被 shim 重写到宿主内置的同一份 @oh-my-pi/pi-coding-agent
  • PI_PACKAGE_NAMES 里 6 个包都是宿主内置(plugin 即使在 node_modules 里装了同名包,也不会真正用它的代码)

3.3 血缘分类

✅ 直接 fork 上游的 pi-* 包

oh-my-pi 包上游来源
@oh-my-pi/pi-ai@mariozechner/pi-ai
@oh-my-pi/pi-agent-core@mariozechner/pi-agent-core
@oh-my-pi/pi-tui@mariozechner/pi-tui
@oh-my-pi/pi-coding-agent@mariozechner/pi-coding-agent(主包)
@oh-my-pi/pi-utils@mariozechner/pi-utils(上游文档没列在 7 个主包里但存在,porting-from-pi-mono.md:50 显式列入映射表)
@oh-my-pi/pi-nativesomp 自创——Rust napi-rs 绑定(上游没有),但 shim 也把它放进 PI_PACKAGE_NAMES,兼容老插件的 import

➕ omp 自创的 pi-* 命名包(shim 不重写)

作用对应 README 章节
@oh-my-pi/pi-catalog模型目录扩展(40+ providers vs 上游 50 模型)隐含在 README “40+ providers”
@oh-my-pi/pi-mnemopiHindsight 记忆子系统(retain / recall / 压缩会话)“13 · Hindsight”
@oh-my-pi/pi-wireprotobuf 协议层,collab relay 用隐含在 “07 · /collab”

➕ omp 自创的非 pi- 命名包

作用
@oh-my-pi/hashline“11 · Hashline: edit by content hash”
@oh-my-pi/omp-stats本地 omp stats 可观测性面板
@oh-my-pi/snapcompact上下文 snap-compact
@oh-my-pi/swarm-extensionsubagent 协作(05 · First-class subagents)

❌ 上游有但 omp 没继承

上游包omp 的替代方案
pi-mom(Slack bot)无 —— omp 不做 Slack 集成
pi-web-ui(Web chat UI)collab-web workspace 包替代(Solid+React,omp 自建,带 relay + QR)
pi-pods(vLLM pod 管理)

🦀 Rust 内核 —— omp 独有

Cargo.toml:1 workspace 包含 crates/pi-* + crates/vendor/*不是 pi-mono 的一部分:

  • pi-natives(napi-rs 绑定,导出给 JS)
  • pi-shell = vendored brush-core + brush-builtins(POSIX shell,替代 bash)—— 来自 uutils/brush
  • ~55k 行 Rust(README 数字)

3.4 同步策略

omp 与上游是 fork + selective backport,不是完全 cherry-pick:

  • docs/porting-from-pi-mono.md 是合并手册,带上次同步锚点 commit b21b42d0(2026-03-22)
  • packages/*/CHANGELOG.md 大量条目形如 Switched from local @oh-my-pi/pi-ai to upstream @mariozechner/pi-aibackported pi-mono changes (...),证明持续同步
  • 上游改 SDK → omp 同步并保留自己的扩展(session / extensions / hooks 体系)

四、一图概括依赖血缘

五、关键证据文件

文件作用
packages/coding-agent/src/extensibility/plugins/legacy-pi-compat.ts:161-178scope + subpath 重写规则(single source of truth)
packages/coding-agent/test/pi-scope-aliases.test.ts三 scope 等价的回归测试
packages/coding-agent/test/issue-973-legacy-pi-plugin.test.ts老 plugin 兼容的回归测试(issue #973)
docs/porting-from-pi-mono.md:46-51上游 → oh-my-pi 包映射表 + sync 锚点 commit
README.md:21-22, 469, 485显式声明 “fork of pi-mono by @mariozechner”
package.jsonworkspaces.catalog所有第三方依赖集中点

总结

  • oh-my-pi = pi-mono fork + 自创层 + Rust 内核。fork 占大头(5 个核心 pi-* 包),自创层集中在 “omp 独有功能”(hindsight / hashline / collab / swarm / natives)。
  • “pi-sdk” 不存在,pi-coding-agent 同时是 CLI 和 SDK。
  • 上游 7 个包里丢了 3 个(pi-mom / pi-web-ui / pi-pods),替换了 1 个(pi-web-uicollab-web)。
  • 三 scope(@mariozechner / @earendil-works / @oh-my-pi)通过 shim 等价,老 plugin 不用改一行代码就能跑在 omp 上。

如果想看具体的 “哪些 pi-mono PR/issue 被 backport 进来”,可以翻 packages/*/CHANGELOG.md 里那些 backported pi-mono changes (...) 条目,或者 git log --grep="backport"