oh-my-pi 功能详解:Pi 与 omp 的关系及特性

Pi 和 oh-my-pi 的关系

Pi 是 Mario Zechner 在 2025 年 8 月创建的编码代理项目,纯 TypeScript。oh-my-pi(omp)是 Can Bölük 从 Pi fork 出来的独立项目,两个项目各自发展。omp 会定期从 Pi 合并上游变更。

规模对比

Pi 至今约 20 万行 TypeScript,没有 Rust,4 个包,4,600 多个 commit。omp 约 112 万行 TypeScript 加 17 万行 Rust,16 个包加 8 个 Rust crate,14,000 多个 commit。

两个项目有四个同名包(fork 时的原始包),各自独立发展后规模差距很大:

包 Pi 当前 omp 当前
ai(LLM 接口) 58K 188K
agent(运行时) 14K 26K
coding-agent(CLI) 104K 631K
tui(终端 UI) 26K 61K

差距最大的 coding-agent,Pi 那边是 agent 的核心流程(会话管理、工具调度、RPC 模式),omp 在这个基础上加进了下面要介绍的所有功能。

以下简单介绍 omp 的主要特色功能。其中多数是 Pi 没有的,少数(子代理、自动 commit)Pi 有基础版本,omp 做得更深。


一、Hashline:用哈希锚点代替抄代码

AI 改代码的标准做法是:把文件里要改的旧代码原样抄一遍,附上新代码,告诉工具"把这段旧的换成这段新的"。问题在"抄一遍"。空格、Tab、换行,AI 抄的时候经常差一点,工具在文件里找不到一模一样的文本,就报错,然后重试。有时候十几轮才改对一次。

Hashline 的做法是:工具在读文件时用 tree-sitter 把代码解析成语法块(函数、类、if 块等),给每个块算一个哈希值作为标识。AI 要改某个块时,不需要抄旧代码,只需说"把标识是 a3f2 的代码块换成……"。工具用哈希去定位,精确命中。

哈希是工具自己算的,不是 AI 抄的,所以不会抄错。另外,如果在你改代码的过程中文件被别处动了,原来那个块的哈希就对不上了。工具会拒绝写入,告诉你文件已变更,先重新读一遍,不会蒙头覆盖搞坏文件。

实测效果(摘自 Readme,我没测过):Grok 4 Fast 用 Hashline 比用传统文本匹配,输出 token 少了 61%,因为不需要花 token 抄旧代码,也不需要反复重试。


二、AST 编辑:按语法结构改代码

AST(抽象语法树)是把代码表示成一棵树,每个节点对应一个语法单元。比如 console.log("hi") 这行,会变成一棵树,根节点是"函数调用",子节点分别是函数名 console.log 和参数 "hi"。

传统文本匹配搜 console.log( 靠的是字符拼写,会误伤 myConsole.log(,也会漏掉 console .log((中间多了空格)。AST 搜索找的是"语法上是 console.log 的函数调用",空格和换行怎么排都不影响。

omp 的 AST 编辑流程:

  1. AI 说"找出所有匹配 console.log($X) 的调用",其中 $X 是占位符,表示参数可以是任意内容
  2. 工具用 AST 引擎(ast-grep,基于 tree-sitter,覆盖 50 多种编程语言)定位所有命中点
  3. 找到后先不写入,挂起来给你看预览,标注"准备替换 3 处,在 1 个文件里"
  4. AI 调用 resolve 确认后,一次性全部写入

写入是原子操作:3 处要么全改,要么一处都不改,不会改到一半卡住。

与 Hashline 的区别:


三、LSP 集成:像 IDE 一样理解代码关系

LSP(Language Server Protocol)是编辑器用来跟语言服务器通信的标准协议。语言服务器理解代码结构,提供跳转定义、查找引用、重命名符号等功能。VS Code 的代码补全和跳转靠的就是它。

大部分编码 AI 只看得懂文件内容,不知道函数在哪定义的、谁在调用它。omp 内嵌了一个 LSP 客户端,直接用你项目的语言服务器干活。

比如你让 omp 重命名一个函数,它不只是改函数定义那一处。它走 workspace/willRenameFiles 这个 LSP 流程:在文件实际移动前,barrel file(即 index.ts 里的 export * from "./foo")和别名导入里对这个函数的引用,全部同步更新。改一处函数名,十几处引用全部到位。


四、DAP 调试器:AI 真的运行程序找 bug

DAP(Debug Adapter Protocol)是调试器的标准协议,和 LSP 类似,但控制的是断点、单步执行、读取变量这些调试操作。

大部分 AI 只能看源码猜 bug。omp 可以接到真正的调试器上:

AI 不是用 bug,是可以跑程序、看运行时状态。


五、子代理:并行分解工作

子代理(subagent)是从主代理中分裂出来的独立工作进程,各自有独立的工具权限和上下文。Pi 也支持子代理(通过扩展),omp 的版本多了三个能力:

git worktree 隔离。 worktree 是 git 的一个功能,允许你在同一个仓库里创建多个独立的工作目录。A 子代理在 worktree-A 里改,B 在 worktree-B 里改,相互不冲突。改完后主代理将结果合并。

子代理间通信。 通过 IRC(内部消息通道),子代理之间可以协调依赖关系。比如 A 改了一个函数签名,通知 B 更新对应的调用处。

结构化输出。 子代理返回的不是自然语言,而是 schema 校验过的结构化数据。主代理不用从"嗯,我改好了,大概在 XX 文件里"这种散文里解析结果,直接拿结构化字段用。


六、Advisor:第二模型实时审查

Advisor 是 omp 的双模型功能:你为同一个会话配置两个模型,一个负责写(主力),一个负责审(Advisor)。

Advisor 在每一轮都读取主力模型的操作。发现问题时注入一条备注:可能是提醒(“你这样会把别的错误也吞掉”),可能是担忧,也可能是硬性阻止。Advisor 运行在自己独立的上下文和模型上,不需要和主力抢 token。

主力看到 Advisor 的备注后可以修正操作,也可以告诉你为什么不采纳。


七、持久化代码执行

大部分工具的 Python/JS 执行是离散的:每次调 bash 跑一个脚本,跑完进程退出,变量和状态全部丢失。

omp 维护两个持久化的代码执行环境:一个 Python 进程,一个 JavaScript(Bun)进程。它们在会话期间一直运行,你在第一步定义的变量,第二步还能用。比如第一步用 Python 加载 CSV 做数据统计,第二步用 JavaScript 拿统计结果画图表。

另外,这两个执行环境可以通过 loopback bridge 反过来调用 omp 的工具。loopback bridge 就是内部通信通道,让 Python 代码里能调用 read 读文件,或者调用 search 搜代码。AI 在 Python 里加载数据,在 JS 里绘图,一次对话全部完成。


八、TTSR:只在触发时才激活的规则

TTSR(Time-Traveling Stream Rules)解决的是:设定给 AI 的规则,如果每次都塞进上下文,大部分时候用不上,白白占 token 和钱。但如果只在需要的时候提醒,什么时候"需要"又很难预先判断。

TTSR 的做法:规则平时静默,不占上下文。当 AI 的输出流中出现了匹配正则表达式的文本(比如准备调用 Box::leak),系统在流中间打断,将对应的规则注入系统消息,然后让 AI 从被中断的同一个位置重新输出。

规则不需要提前占位,用到才激活。而且注入的规则在对话被压缩后依然保留,不会因为上下文过长被裁掉。


九、Hindsight:跨会话记忆

大部分 AI 聊完就忘。下次新会话,要重新介绍项目结构和背景。

Hindsight 是一个跨会话记忆系统。使用方式:

每次会话结束后,Hindsight 自动压缩这次对话的要点,加载到项目的记忆库中。下次新会话启动时,AI 第一轮就加载记忆,“上次我们聊过,你们的 API 主路由是 /v2/orders”。记忆按项目隔离,聊项目 A 学到的东西不会串到项目 B。


十、协作共享

/collab 生成一个链接和二维码,别人用 omp join 或浏览器打开,就能实时观看你的 AI 会话。

有读写和只读两种模式。读写模式允许多人操作同一个 AI,适合结对编程。只读模式只能看不能动。会话数据加密后通过中继服务器转发,中继服务器就是中转站,只负责传递加密数据,没有密钥所以看不到内容。


十一、原生引擎

大多数终端编码工具依赖系统里安装的外部命令:用 grep 搜文本、用 find 找文件、用 bash 执行脚本。这有两个问题:一是 Mac/Linux 上的工具 Windows 上未必有;二是每次调用外部命令都需要 fork-exec,即创建一个子进程来运行它,带来性能开销。

omp 把这些工具直接编译进了程序内部:ripgrep 做文本搜索,原生 glob 做文件匹配,brush 做 shell。不依赖系统安装,同一份二进制文件在 macOS、Linux、Windows 上都能跑,不需要 WSL。也避免了反复创建子进程的性能开销。


十二、内部 URL 体系

omp 把多种信息源统一到了 read 这一个工具下,区别只在于"路径":

模型只需要学一个接口。search 同样支持 diff 搜索,write 可以写冲突解决结果。


十三、Agentic Commit

Pi 有一个简单的 auto-commit-on-exit 扩展:退出时自动提交所有改动。omp 的 omp commit 在此基础上做了分析和拆分:检查未提交改动后,自动拆分为多个有意义的 commit,按依赖关系排列。源码文件优先于测试和文档。lock 文件改动被排除。如果发现循环依赖(改 A 依赖改 B,改 B 又依赖改 A),拒绝拆分并报错。


十四、浏览器和 Web 搜索

web_search 从多个搜索引擎聚合结果,返回答案和引用链接。read 能直接打开 arXiv 的 PDF 论文、GitHub 页面、Stack Overflow 帖子,提取为结构化文本。

browser 通过 Puppeteer(一个控制无头 Chrome 浏览器的库)操作网页。可以填表单、截图、抓取动态页面。默认开启了 stealth 模式,即模拟正常用户行为特征,避免被网站识别为自动化脚本。

同一套浏览器驱动也可以接入已打开的 Electron 应用,比如控制 Slack 读取消息,操作方式和控制网页一致。


pi 还是 omp 用哪个?如果喜欢开箱即用可以用 omp,如果喜欢极简自己折腾就用 pi 吧~