oh-my-pi 语义压缩的 rewrite 工具契约:草稿提交、损失声明与审查回合机制
【免费下载链接】oh-my-pi⌥ Coding agent with the IDE wired in项目地址: https://gitcode.com/GitHub_Trending/oh/oh-my-pi
导读
本文剖析 oh-my-pi(pi)Coding Agent 中omp compress语义压缩管线的核心工具契约——rewrite。该工具负责把一段源文本(系统提示词、工具描述、规范文档)压缩成可直接交付的稠密提示词,并与approve工具构成一个两工具审查协议。读完本文,你将理解rewrite的参数语义、losses损失声明机制、审查回合(review turn)的驱动逻辑,以及它在源码中的完整实现与测试保障。
背景:两工具压缩协议中的rewrite
omp compress是 oh-my-pi 提供的一条命令行能力,用于把文本文件"重写"为稠密的提示词寄存器格式。其运行模型非常克制:每个文件一个独立的 Agent 会话,每个会话只有两个工具——rewrite与approve。会话不允许读取文件、搜索、运行命令或访问扩展/MCP/LSP,一切输入都随对话送达,确保输出不受源文本之外的任何内容影响。这条约束在 compress/session.ts 中写得很明确:
customTools仅注册rewriteTool()与approveTool()两个工具;skills、rules、contextFiles、promptTemplates、slashCommands全部清空;enableMCP、enableIrc、enableLsp、hasUI均置为关闭。
rewrite的官方契约文档位于 prompts/tools/rewrite.md,而它的姊妹工具 prompts/tools/approve.md 负责接受最新草稿并结束运行。二者的关系是:rewrite提交草稿 → 命令返回审查回合 → Agent 裁决 → 要么再次rewrite要么approve。
rewrite 工具的参数契约
rewrite接受两个必填参数,其运行时校验模式定义在 compress/protocol.ts 的rewriteSchema中,均要求非空字符串并开启"+"拒绝未知字段:
| 参数 | 类型 | 语义 | 运行时校验 |
|---|---|---|---|
text | string | 完整、逐字、可直接交付的压缩输出;绝不输出 diff、摘要或编辑描述 | "string > 0",即非空字符串 |
losses | { content, reason }[] | 每个被省略的声明、限定词、默认值、边界值、示例或精确字符串对应一条记录;须引用或命名被删内容并说明为何省略后仍正确;空数组表示无损失 | 元素须满足content、reason均为非空字符串 |
text的"完整交付"语义是整个协议的第一原则:命令侧在写入文件时原样落盘(compress/index.ts 中fs.writeFile(destination, draft.text.endsWith("\n") ? draft.text : \${draft.text}\n`)),期间不做任何二次处理。也就是说,rewrite提交的text` 就是最终产物,Agent 必须保证它开箱即用。
losses数组则承担"可审计性"职责。类型定义见 compress/types.ts 中的CompressLoss:content是从源文中引用或精确描述的被删内容,reason说明草稿在缺少它的情况下依然正确的理由。
每次调用后的审查回合(Review Turn)
原文档规定的调用流程是:每次rewrite调用 → 审查回合 → 回复草稿、测量尺寸、声明的损失 → 请求裁决。rewrite替换草稿,approve接受草稿。这条流程在命令侧被严格执行,核心逻辑位于 compress/index.ts:
- Agent 首次收到 请求模板,其中携带源文本、源大小(词数/token 数)以及一个 per-run 随机 nonce,源文被包裹在
<source-{{nonce}}>惰性数据块中; - Agent 调用
rewrite提交草稿; rewriteTool()执行器记录草稿并立即返回统计摘要:"Draft N recorded: sourceTokens → draftTokens tokens (x.x% smaller), N declared loss(es). A review turn follows.";- 命令调用
renderReview(compress/index.ts 的renderReview函数)构造审查回合提示词,把草稿、度量结果与损失清单原样引述回给 Agent,并附上裁决请求:approve接受该草稿,或rewrite再次提交; - 循环直到
approve达成、无草稿、草稿回合未推进或超过预算。
审查回合之所以存在,是因为命令侧刻意不做任何 diff 或关键词校验——验证责任完全落在 Agent 声明的损失清单加审查回合上。这让 Agent 在损失清单摊在面前时评判自己的工作,而不是在产生草稿的同一轮里自我认证。
度量由CompressProtocol.metrics()完成,返回CompressMetrics:源/草稿的词数、token 数与压缩比ratio = (sourceTokens - draftTokens) / sourceTokens。注意当草稿比源文更长时 ratio 为负数,此时命令会如实报告"增长了"而非掩盖。
三条 critical 红线
原文档在<critical>块中规定了三条不可违背的约束,它们也是整个压缩协议的安全护栏:
1. 诚实声明损失(Declare losses honestly):声明的损失是可审计的;未声明的损失等于静默回归。这意味着删掉的内容必须一条条写进losses,哪怕它只是"默认值 30 秒"这样的限定词。系统提示词 compress/prompts/system.md 同样强调"压缩迫使读者猜测就是 bug,不是节省"。
2.text必须独立成立:没有源文的读者必须能够直接执行它。压缩产物会被原样替换进系统提示词、工具描述或规范中,由模型冷启动阅读,作者不在场消歧——因此任何需要猜测的省略都是失败的压缩。这与 system.md 中"NEVER ship"清单一脉相承:外部指代("上面的 claim")、草稿残留("Hmm")、分层修正等一律禁止出现在输出中。
3. 新草稿取代先前的批准:一旦 Agent 在approve之后又调用rewrite,先前的批准即刻失效,新草稿必须重新走审查回合。源码中submit()(protocol.ts)在入账新草稿的同时把#approved复位为false、清空#verdict,正是这条规则的实现。
源码级验证:协议如何强制这些约束
CompressProtocol类(protocol.ts)通过记账状态机把契约文档落成可执行逻辑,并有 compress.test.ts 逐条锁定行为:
- 先 approve 后 rewrite 会被拒绝:
accept()在没有草稿时抛出"Call rewrite before approve: there is no draft to accept",对应测试"approve before any draft is rejected"; - approve 被审查门控:草稿未被
markReviewed前调用accept()会抛出"Draft N has not been reviewed yet...",对应测试"approve is gated on the review turn for the newest draft"——这正是"每次调用后必有一个审查回合"的程序化表达; - 新草稿取代旧批准:
submit()复位批准状态,测试"a new draft supersedes an approval and needs its own review"验证了这一点; - 损失清单不可变拷贝:
submit()对losses做映射拷贝,外部后续修改不会污染草稿; - 度量诚实:
"metrics measure the draft against the source and report growth as a negative ratio"验证了膨胀草稿得到负 ratio; - 空源兜底:空文本返回 0 尺寸、ratio 为 0,避免除零,对应
"an empty source yields zero sizes instead of dividing by zero"。
此外,compress/index.ts 对空文件直接返回stalled("no text to compress"),对每个文件的最终状态approved / unapproved / stalled / cancelled进行汇总;只有approved的草稿才会被写入磁盘或 stdout。
运行方式:omp compress与相关配置
rewrite/approve协议由 commands/compress.ts 暴露为 CLI:
# 单个文件压缩,默认输出到 stdout omp compress prompts/tools/read.md # 输出到指定文件(仅限单文件) omp compress notes.md -o notes.compressed.md # 通配符批量压缩并原地覆盖 omp compress 'src/prompts/**/*.md' -i # 多文件并发压缩(-n 控制并发度) omp compress a.md b.md c.md -i -n 8 # 指定模型与更大的草稿预算 omp compress spec.md -r 5 -m opus| 标志 | 简写 | 默认值 | 说明 |
|---|---|---|---|
--out | -o | stdout | 将批准后的文本写入指定文件(仅单文件) |
--in-place | -i | false | 用批准文本覆盖每个源文件 |
--rounds | -r | 3 | 每个文件的最大草稿轮数,超限则按 unapproved 放弃 |
--agents | -n | 4 | 并发压缩的文件数 |
--model | -m | 会话默认模型 | 指定压缩所用模型选择器 |
值得注意的边界约束:--in-place与--out互斥;多文件场景必须配合--in-place(--out只接受单文件);匹配不到任何文件会直接报错,因为"静默压缩比请求更少的文件"比失败更糟。每个文件的审查回合在到达预算的最后一轮会给出强提示:approve接受,或仅在草稿确实不可交付时再rewrite一次——未批准的运行不写入任何内容。
延伸阅读
- rewrite 工具契约原文:本文分析的关联文档
- approve 工具契约:协议的接受端
- 压缩系统提示词:压缩方法论、帧语法与 NEVER ship 清单
- 协议实现:两工具的 schema、记账状态机与度量实现
- 命令编排:审查回合渲染、文件写入与结果汇总
- 协议测试:协议行为逐条锁定
rewrite工具的契约设计体现了一个明确理念:压缩的正确性由"声明的损失 + 审查回合"共同担保,而不是由命令侧的机械校验担保。理解这套契约,是理解 oh-my-pi 语义压缩管线乃至其提示词工程哲学的关键入口。
【免费下载链接】oh-my-pi⌥ Coding agent with the IDE wired in项目地址: https://gitcode.com/GitHub_Trending/oh/oh-my-pi
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考