- 人工智能
- AI Agent
- 多智能体
- Agent 编排
- 代码智能体
- CLI
【免费下载链接】openrig
Multi-agent harness that runs Claude Code and Codex together as one system
openrig(Multi-agent harness,将 Claude Code 与 Codex 组织为一个统一系统)在 release-0.5.4 的 Wave 1 S3 中定义了一个名为Delivery Honesty(交付诚实)的切片(Slice 06),其核心主张是:"Sent" 必须意味着 "CONSUMED"(被对方真正消费),而绝不仅仅是 "typed"(文本被敲进了终端)。本文基于仓库中的规格文档 .evidence/SPEC-before-F4-amendment.md(OPR.0.5.4.6),结合 CLI 与 daemon 两端的真实实现,完整讲解send --verify如何通过 pane 效果区分"已消费"与"暂存未提交(staged)"、如何诚实报告检测证据,以及如何用"单次 Enter 提交路径"作为唯一补救手段而绝不盲目重发。读完本文,你将掌握 openrig 交付验证的完整机制、底层判定算法与可验证的测试证据。
背景:为什么 "Sent" 可能撒谎
在多 Agent 协作场景中,一个 Agent(seat)向另一个 Agent 的终端发送指令是家常便饭。但 openrig 在 0.5.3 的实际运行中发现了两个真实的"交付谎言":
- send-staging 现象:文本被发送后停留在对方的输入提示符(prompt)处,处于"暂存(staged)"状态——打字了,但没有提交。对方从未真正消费这条消息,而发送方却看到了"已发送/已通过验证"。
- T1 walk saga:在 walk 流程(逐段投递并逐段验证)中,这种 staged 文本造成的误解被完整记录下来,度量了它的真实成本。
当时的处理方式是"座位纪律(seat lore)":操作者需要自己"capture 看一眼"来区分文本是否被消费,出了问题就盲目重发,结果常常双重投递(double-deliver)。
0.5.4 的 S3 切片(OPR.0.5.4.6)正是要把这条纪律从"人工经验"升级为"产品行为":由产品自己检测并诚实报告 staged 状态,让"发送"这个动词恢复它应有的含义。
核心意图与设计约束
规格文档开宗明义:
"Sent" must mean CONSUMED, never merely typed。
这意味着send --verify必须按效果(effect)判断消息是否被消费——即检查对方 pane 在发送后的实际状态,而不是依赖传输层的返回码。文档特别强调:传输返回码的负向信号被度量过、并不可靠(例如超时可能发生在消息已经送达之后,两条真实案例证明了"报未发送但实际已投递")。
整个切片遵循四条 mini-requirements:
- 按效果区分:
send --verify通过 pane 发送后的状态区分 CONSUMED 与 STAGED(把 walk 已泛化的模式推广到普通发送),永远不依赖传输返回码。 - 诚实报告:staged-unsent 检测报告必须诚实——说明"检查了什么"(checked)与"观察到了什么"(observed);补救面是现有的 submit 路径,不重发、不双重投递。
- 领域边界:只涉及
packages/daemon/src/routes/transport.ts、packages/cli/src/commands/send.ts、packages/cli/src/commands/broadcast.ts及它们对应的聚焦测试。 - 保持接缝:S2 切片(OPR.0.5.4.3)确立的 unknown-sender 行为是基础,本切片不重新打开它;door07 证据链继续有效。
文档还记录了一条重要的纪律性表达,现在变成了产品行为而非人工常识:
text sitting AT the prompt = staged, not consumed; the fix is one Enter, not a re-send
实现剖析:CLI 端的交付效果分类
效果判定的主战场在 packages/cli/src/commands/send.ts。rig send命令在--verify选项下,在输出编码之前先做效果分类(源码注释称为 "r2 F2"),确保人类可读输出、--json输出与 fan-out 输出渲染的是同一条效果真相。
从传输应答到效果真相
发送请求返回后,若--verify且传输层状态码 < 400,CLI 调用classifyDeliveryEffect(send.ts 中的实现),其流程是:
- 调用
detectStagedAtPrompt探测 pane 是否残留本发送的暂存文本; - 若探测不可用(unchecked),如实返回"未检查"及其原因;
- 若未发现暂存残留,返回
no-staged-residual——注意:pane 重绘可能导致残留读不到,因此"没有残留"不构成消费证明,此时传输层的裁决原样保留; - 若发现暂存残留,走一次且仅一次的 guarded submit(见下文),然后复查一次,停止。
EffectCheck是一个纯分类类型(无副作用、不打印):
type EffectCheck = | { checked: true; state: "staged"; remedy: "submitted-cleared" | "submitted-still-staged" | "submit-refused"; detail?: string } | { checked: true; state: "no-staged-residual" } | { checked: false; why: string };关键设计:"staged" 是唯一可以推翻传输层"已发送"结论的证据;而"未发现残留"什么也不推翻(见 send.ts 中的判定注释)。
staged 探测器:只看当前输入区,身份先行
detectStagedAtPrompt(send.ts 实现)是效果判定的核心算法,有三条铁律:
- 只隔离当前输入区:从 pane 的最后一个提示符行(
❯/›)开始到 pane 末尾,其上方的一切都算历史(scrollback),历史中的占位符永远不算 staged 证据——guarded submit 绝不允许对历史开火。 - 身份先行(identity first):字面残留匹配使用 daemon submit 预检查同款的归一化(去掉所有空白、连续包含),即
stagedIdentityFor(send.ts 实现)产出的payloadHead(用户负载头部、去空白后前 24 字符)。这样"探测器判为 staged"与"guarded submit 的预检查"天然兼容。 - 占位符归属判定:输入区若出现
[Pasted text #N +X lines]占位符,只有当其行数与本次发送的期望行数绑定(|extra - expectedLines| <= 2且多于一行)时,才认定是"本次发送"的 staged 证据;否则返回unchecked,并明确声明"不可验证、不作为本次发送处理、不发起提交"。
StagedIdentity三要素(send.ts 定义):
| 字段 | 含义 | 用途 |
|---|---|---|
expectedStagedText | guarded submit 预检查要验证的字节 | 与 pane 残留逐字节比对 |
expectedLines | 文本行数 | 绑定 pasted-text 占位符的行数 |
payloadHead | 负载头部(去空白前 24 字符) | 字面残留的包含匹配 |
guarded submit:单次 Enter 的补救,绝不重发
当 staged 被确认后,CLI 通过POST /api/transport/send发起一次submitOnly: true的请求(send.ts 中的调用)——只敲一次 Enter,不重新输入任何文本,因此不可能重复投递。daemon 端在 packages/daemon/src/routes/transport.ts 中接收submitOnly、expectedStagedText、expectedStagedLineCount并透传给SessionTransport(transport.ts 中的透传 与 提交参数)。
真正的守卫在 packages/daemon/src/domain/session-transport.ts 的 submitOnly 分支中(约 第 855-963 行):
submitOnly发送时text 参数必须为空,否则拒绝(invalid_submit_only);- 必须提供
expectedStagedText,因为"Enter 只能落在完全一致的暂存内容上"; - 提交前预检查 pane 是否真的显示了期望的暂存文本,不匹配则拒绝提交——"在这里按 Enter 可能驱动完全不同的东西,什么都不会被提交"(
staged_mismatch,HTTP 409); - Enter 实际落地后若失败,返回
submit_failed(HTTP 502)。
CLI 端对补救结果做一次复查,输出三种诚实结局(send.ts 中的 renderer):
submitted-cleared:一次 guarded Enter 提交,暂存文本离开提示符(已消费);submitted-still-staged:提交了,但文本仍在提示符——不是已消费,停在这里(单次提交是契约),提示rig capture <session>人工检查;submit-refused:单次 guarded Enter 被拒绝(如预检查不匹配),同样停下,绝不重试。
任何未以submitted-cleared收场的 staged 都通过effectUnresolved(send.ts 定义)被判定为"非静默失败":人类输出设置非零退出码,--json输出的信封里携带verified: false与outcome: "staged-not-consumed",不再附带任何 delivered 声明。
三种输出编码:同一条效果真相
S3 的一个关键修复是让所有输出路径渲染同一条效果真相:
人类路径:
Verified: no之后紧跟三行式报告,例如:Delivery: staged, not consumed (checked: post-send pane capture; observed: the sent text is still at the prompt — typed, never submitted) Remedy: one guarded Enter submitted — the staged text left the prompt.(
Verified: yes行被保留逐字不变,因为现有脚本会 grepVerified:;真正的三态词汇在随后的Delivery:行:delivered/rendered-unconfirmed/ staged 报告。)--json路径:信封内携带effectCheck字段;staged 未解决时强制verified: false、outcome: "staged-not-consumed",退出码为 1。fan-out 路径:
rig send --to/--pod/--rig --verify对每个成功投递的接收者逐一做 pane 效果分类(daemon 逐个包裹信封,因此 guarded submit 的期望文本就是裸负载,包裹渲染天然包含它)。任何 staged 未解决的接收者:- 该行输出"staged, not consumed",不再称其为 sent;
- 汇总行的 delivered 计数会扣除 staged 未解决者(send.ts 中的聚合逻辑);
--json的机器可读聚合从分类后的编码结果推导,绝不引用原始传输计数(send.ts 中的 F1 实现)。
跨主机边界:诚实的"未检查"
效果检查是 pane 级的,而跨主机发送(--host,含 ssh 与 http 两种传输)无法在本机运行远程 pane 检查。实现选择诚实声明"未检查",而不是假装验证(send.ts 中 ssh 路径说明 与 http 路径说明):
http 路径在
--verify时输出Verified:与Delivery:的远程路由原始裁决(远程权威、逐字呈现),并追加一行:Effect: UNCHECKED — the pane-effect check does not run cross-host; the verdict above is transport-level only.--json信封同样携带effectCheck: { checked: false, why: "cross-host http — the pane-effect check does not run cross-host" }。
这延续了本切片的诚实基调:能验证就验证,验证不了就明说验证不了,绝不把传输层裁决包装成消费证明。
与传输失败处理的衔接
本切片还明确了"传输失败"与"staged"两类情形的边界(send.ts 中的 printTransportFailure):
- 超时 = 交付未确认(delivery-UNCONFIRMED):daemon 可能已收到并投递(两条真实案例证明了"报未发送后实际已送达"),因此补救建议是"先按效果核对再考虑重发,
rig capture <session>",绝不诱导盲目重发; - 硬连接失败 = 未发送:才给出"was not sent"的结论与诊断路径(检查
OPENRIG_URL/RIGGED_URL、daemon.host/port,确认后rig daemon start)。
两类输出都遵循事实/后果/行动(fact / consequence / action)三段式,--json下输出可解析的结构化信封。
Proof Contract:四项可验证契约
规格文档定义了四个证明项,全部可以在 packages/cli/test/send.test.ts 的 "S3 — delivery honesty (OPR.0.5.4.6)" 测试分组中找到对应用例:
- STAGED-UNSENT DETECTED BY EFFECT(PROOF-1):文本落在提示符(staged、未消费)时,
send --verify如实报告 staged——判别证据是 pane 效果,不是传输返回。 - CONSUMED MEANS CONSUMED(PROOF-2):真正被消费的发送验证为正向;两种结局绝不可互换,staged 报告必须点名"检查了什么"。
- NO DOUBLE DELIVERY(PROOF-3):staged 的补救是 submit 路径(单次 Enter),测试断言普通发送(含
hello there文本的 POST)恰好一次、submitOnly提交恰好一次,产品从不建议盲目重发。 - INTERIM LORE RETIRED:产品自身的报告使旧的座位纪律("暂存在提示符,修复是敲一次 Enter")不再必要,并在传授该纪律的 guidance 中记录退役,按路径引用。
测试还覆盖了防御性细节(send.test.ts 相关用例):scrollback 中的过期占位符不构成staged 证据(不触发报告、不触发 guarded submit);--json --verify信封携带效果分类且 staged 未解决时退出码为 1;fan-out 逐接收者报告效果、staged 命名、已消费者绝不被称 staged。
实操速查:rig send --verify的完整参数面
结合 send.ts 命令定义,与交付验证相关的完整选项如下:
| 选项 | 作用 | 与 Delivery Honesty 的关系 |
|---|---|---|
--verify | 发送后检查 pane 是否出现内容 | 本切片的主角:发送后做 pane 效果分类 |
--wait-for-idle <秒> | 目标明确空闲后再发送 | 可与--verify组合,不能与--force/--dangerously-interact组合 |
--force | 向后兼容空操作 | 忙碌 pane 默认"带提示发送";永不绕过交互提示/权限守卫 |
--raw | 发送精确文本/按键,不带 From/To 信封 | 仍受守卫 |
--dangerously-interact --reason <why> | 刻意驱动交互提示/权限块(唯一绕过守卫的开关) | 要求 reason,写入审计日志 |
--json | Agent 可解析的 JSON 输出 | 携带effectCheck、verified、outcome字段 |
--host <id> | 跨主机发送 | 效果检查跨主机不运行,输出Effect: UNCHECKED |
典型组合:
# 单席位:发送并验证 pane 效果(staged 会自动走单次 Enter 提交) rig send dev-impl@my-rig "Context update: QA approved. Proceed." --verify # 等待空闲后发送并验证 rig send dev-impl@my-rig "safe proof prompt" --wait-for-idle 30 --verify # fan-out 到两个席位,逐接收者报告效果 rig send --to dev-impl@my-rig,dev-qa@my-rig "message to two seats" --verify # Agent 消费的结构化输出 rig send dev-impl@my-rig "message" --json # 跨主机(http 注册主机):远程权威裁决 + 诚实的 UNCHECKED 声明 rig send --host remote-dev dev-impl@my-rig "remote message" --verifystaged 场景下的输出形态:
Sent to dev-impl@my-rig Verified: no Delivery: staged, not consumed (checked: post-send pane capture; observed: the sent text is still at the prompt — typed, never submitted) Remedy: one guarded Enter submitted — the staged text left the prompt.小结
Delivery Honesty(OPR.0.5.4.6)把 openrig 的交付语义从"传输层说成功就算成功"升级为"pane 效果证明已消费才算成功":探测器只认当前输入区的真实证据、身份先行防止误判他人的暂存内容、guarded submit 以expectedStagedText预检查保证单次 Enter 只落在本次发送的文本上、所有输出编码渲染同一条效果真相,跨主机场景则诚实声明"未检查"。四个 proof contract 项均以聚焦测试锁定,使"Sent means consumed"从口号变成可验证、可回归的产品契约。对于任何依赖 Agent 间可靠指令传递的编排场景,send --verify都是消除"暂存即假装已发送"这一整类误会的标准工具。
- 人工智能
- AI Agent
- 多智能体
- Agent 编排
- 代码智能体
- CLI
【免费下载链接】openrig
Multi-agent harness that runs Claude Code and Codex together as one system
相关推荐
Scenario: Send a chat message and verify response
Scenario: Send a chat message and verify response Steps 1. Type "explain the cod
开发工具代码编辑器ChatGLM3-6B Code Interpreter 部署实战:让大模型真正"动手"执行代码
ChatGLM3 6B Code Interpreter 部署实战:让大模型真正"动手"执行代码 本文是一篇基于《开源大模型食用指南》(self llm 项目)
教程大模型本地部署微调GraphRAG实体消歧技术:如何让AI真正理解文本中的多义实体
GraphRAG实体消歧技术:如何让AI真正理解文本中的多义实体 你是否遇到过这样的情况:AI系统把"苹果"理解为水果,而实际上上下文讨论的是科技公司?或者AI
人工智能RAG知识图谱数据工程大模型
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考