☰
openrig Delivery Honesty 实战解析:用 `send --verify` 让 “Sent“ 真正代表 “已消费“
2026/9/30 19:41:56 网站建设 项目流程
  • 人工智能
  • AI Agent
  • 多智能体
  • Agent 编排
  • 代码智能体
  • CLI

【免费下载链接】openrig

Multi-agent harness that runs Claude Code and Codex together as one system

项目地址:https://gitcode.com/GitHub_Trending/op/openrig
点击查看免费下载

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:

  1. 按效果区分:send --verify通过 pane 发送后的状态区分 CONSUMED 与 STAGED(把 walk 已泛化的模式推广到普通发送),永远不依赖传输返回码。
  2. 诚实报告:staged-unsent 检测报告必须诚实——说明"检查了什么"(checked)与"观察到了什么"(observed);补救面是现有的 submit 路径,不重发、不双重投递。
  3. 领域边界:只涉及packages/daemon/src/routes/transport.ts、packages/cli/src/commands/send.ts、packages/cli/src/commands/broadcast.ts及它们对应的聚焦测试。
  4. 保持接缝: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 中的实现),其流程是:

  1. 调用detectStagedAtPrompt探测 pane 是否残留本发送的暂存文本;
  2. 若探测不可用(unchecked),如实返回"未检查"及其原因;
  3. 若未发现暂存残留,返回no-staged-residual——注意:pane 重绘可能导致残留读不到,因此"没有残留"不构成消费证明,此时传输层的裁决原样保留;
  4. 若发现暂存残留,走一次且仅一次的 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 实现)是效果判定的核心算法,有三条铁律:

  1. 只隔离当前输入区:从 pane 的最后一个提示符行(❯/›)开始到 pane 末尾,其上方的一切都算历史(scrollback),历史中的占位符永远不算 staged 证据——guarded submit 绝不允许对历史开火。
  2. 身份先行(identity first):字面残留匹配使用 daemon submit 预检查同款的归一化(去掉所有空白、连续包含),即stagedIdentityFor(send.ts 实现)产出的payloadHead(用户负载头部、去空白后前 24 字符)。这样"探测器判为 staged"与"guarded submit 的预检查"天然兼容。
  3. 占位符归属判定:输入区若出现[Pasted text #N +X lines]占位符,只有当其行数与本次发送的期望行数绑定(|extra - expectedLines| <= 2且多于一行)时,才认定是"本次发送"的 staged 证据;否则返回unchecked,并明确声明"不可验证、不作为本次发送处理、不发起提交"。

StagedIdentity三要素(send.ts 定义):

字段含义用途
expectedStagedTextguarded 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)" 测试分组中找到对应用例:

  1. STAGED-UNSENT DETECTED BY EFFECT(PROOF-1):文本落在提示符(staged、未消费)时,send --verify如实报告 staged——判别证据是 pane 效果,不是传输返回。
  2. CONSUMED MEANS CONSUMED(PROOF-2):真正被消费的发送验证为正向;两种结局绝不可互换,staged 报告必须点名"检查了什么"。
  3. NO DOUBLE DELIVERY(PROOF-3):staged 的补救是 submit 路径(单次 Enter),测试断言普通发送(含hello there文本的 POST)恰好一次、submitOnly提交恰好一次,产品从不建议盲目重发。
  4. 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,写入审计日志
--jsonAgent 可解析的 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" --verify

staged 场景下的输出形态:

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

项目地址:https://gitcode.com/GitHub_Trending/op/openrig
点击查看免费下载

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询