Repository navigation
Deliver native child results on the next Turn - #8670
huangruiteng wants to merge 1 commit into
Conversation
Signed-off-by: huangruiteng <huangrt01@163.com>
loopx-agent
left a comment
There was a problem hiding this comment.
Reviewer: model_agent · gpt-6.1-sol · OpenAI · runtime_reported · reasoning_effort=max
评审提交 8d76419078daaeae1d10070f0bb12cd2dc7c0572,对照主干 167b0a1f3a3307c284b021ea9a09c7c0b5e5a11f。
[P1] 拒绝的终态重放仍会把矛盾正文送进 Inbox。 同一 native wait 先报告 completed,宿主这次未提供 message。恢复原 invocation 后,重放同一 wait,改为 errored 并携带文字。 主干和候选的终态记录均保留 completed,且都拒绝了矛盾重放。候选的下一次 manager-inbox read 却返回了 failed 和这次已拒绝的文字,主干未出现该候选结果。 让正文在原终态约束及身份核验下保存,并只在匹配的终态提交后对 Inbox 可见。处理提交中断时可重用同一待提交正文,冲突记录始终不可见。 先写正文再校验终态
[P2] 2,000 条已确认历史会让新结果长期不可达。 同一 Goal 生命周期内先保留 2,000 条已确认结果,再交付一条哈希文件名排在其后的未确认结果。 两次普通 Inbox 读取都返回零条结果、scan_complete=false 和 has_more=true,外层没有续读游标。仅在对照夹具里移走一条已确认元数据,下一次读回才出现同一个新结果 ID。 提供能越过已确认历史的有界读取路径,保留确认回执和幂等性。可使用可续读游标或由持久索引先选未确认项,保留普通读取的恢复入口。 按文件名截断扫描 Inbox 返回字段
动机 / Motivation
运行托管 Codex 子任务、下一 Turn 要依据其结论继续工作的主 Agent 会遇到这个问题。 子任务已结束,主干留下完成回执,却无法在下一次 Inbox 读取中交回宿主实际观察到的最终文字。 候选版能在正常完成后返回原文和稳定 ID,读取后重启仍可查看,显式确认才停止重放。 同一终态事件的矛盾重放可以进入 Inbox,已有大量已确认历史的父任务也可能一直读不到新结果。 评审运行了隔离的源码 Host adapter、真实进程流解析、落盘和 Inbox CLI。真实模型、安装版和 Lark 未验证。
改动思路 / Approach
托管 exec 和 app-server 从已有连接取得终态事件。原事件流维持操作、准入和终态,新增私有存储保存原文及交付状态。既有 manager-context hook 提醒父 Agent 先读 Inbox,父级用明确 disposition 确认处理。正文可单独保存在私有 runtime,是否能交付仍应由已有终态回执决定。当前先写可见记录,再校验终态,两个读回会互相矛盾。 本 PR 应让同一原始操作的已核对终态与私有正文一起恢复,保留未确认内容的可达性和既有父级验收。
具体改动 / Changes
关键代码讲解
CodexNativeChildObserver.observe用原 wait 绑定关联终态。新分支先保存 message,之后才调用原 recorder 校验冲突。两者之间缺少可见性约束。 宿主分支- TypeScript Inbox 把稳定结果 ID、摘要与内容落盘。短文字内联,长文字走摘要验证后的私有文件引用。分离 delivery 与 acknowledgement 让一次读取后的重启仍可复用原 ID。扫描先按哈希文件名截断,再过滤已确认项,历史可以占满整个可扫窗口。 私有存储
- 现有
manager-inbox read和 before-work hook 接入同一列表。Python 生成原 Turn 的 ACK 命令,受控交付和普通读取都写本地 delivery。ACK 可在关闭未来 spawn 后使用,原父级验收仍按终态、证据和独立验证执行。 读取与交付 启动读取 确认入口
按 167b0a1f3a3307c284b021ea9a09c7c0b5e5a11f 的 docs/integrations/host-native-child-receipts.md 检查现有生命周期。 terminal-replay-integrity 未满足,矛盾正文可见。 parent-review-boundary 在有效路径保持父级验收独立。 private-readback-scope 的本地 Goal/Agent 隔离和公开回执无正文已覆盖。 主干约束
对主干的风险 / Risks
配对用例经过真实 CLI Host 进程、流解析、持久化和独立的 Inbox 读取,宿主事件由合成进程发出。普通路径中,主干只写完成回执,候选还能读回原文和相同 ID。冲突路径两版都保留唯一 completed 终态、一个 guard 回执和零扣费,候选额外暴露了 failed 内容。规模对照通过同一 CLI 读取,当前说明提示扫描不完整,却没有给下一页的操作入口。
语义与 CI 对齐
110 项聚焦 Python、6 项 TypeScript、控制面 typecheck 和 quick premerge 的 6 项直接检查及 3 项选中检查通过。两项原生宿主 opt-in 测试跳过。托管 CI 未查询。用实际 Host 事件入口重放先无正文、后带正文的冲突终态。保留 completed 回执,下一 Turn 不得读到被拒文字。另测合法补齐和两步提交之间中断后的原身份恢复。 在普通 manager-inbox read 上保留 2,000 条已确认元数据,新增一个确定排序在边界外的结果,按公开返回的下一步读到原 ID 并验证重复确认。
我的整体评价 / Verdict
将结果正文的可见条件收敛到现有权威终态。让长期保留的确认历史和待交付结果在有界读取中都可对账,父任务才能可靠接续。改动集中在 Host adapter、私有存储和 CLI 投递,diff 没有页面组件或可视交互。 评审运行了隔离的源码 Host adapter、真实进程流解析、落盘和 Inbox CLI。真实模型、安装版和 Lark 未验证。
English verdict: REQUEST_CHANGES. The reviewed head exposes text from a rejected terminal replay and can strand new results behind 2,000 acknowledged records. Gate visibility on the matching terminal receipt and provide bounded continuation past acknowledged history.
| if operation_id is not None: | ||
| message = state.get("message") | ||
| if isinstance(message, str): | ||
| ingest_native_child_result( |
There was a problem hiding this comment.
[P1] 拒绝的终态重放仍会把矛盾正文送进 Inbox。 同一 native wait 先报告 completed,宿主这次未提供 message。恢复原 invocation 后,重放同一 wait,改为 errored 并携带文字。 主干和候选的终态记录均保留 completed,且都拒绝了矛盾重放。候选的下一次 manager-inbox read 却返回了 failed 和这次已拒绝的文字,主干未出现该候选结果。 让正文在原终态约束及身份核验下保存,并只在匹配的终态提交后对 Inbox 可见。处理提交中断时可重用同一待提交正文,冲突记录始终不可见。
| try { names = (await readdir(source.root)).filter(name => /^ncr_[0-9a-f]{32}\.json$/u.test(name)).sort(); } | ||
| catch (error) { if ((error as NodeJS.ErrnoException).code !== "ENOENT") throw error; } | ||
| const scanComplete = names.length <= MAX_SCAN; | ||
| names = names.slice(0, MAX_SCAN); |
There was a problem hiding this comment.
[P2] 2,000 条已确认历史会让新结果长期不可达。 同一 Goal 生命周期内先保留 2,000 条已确认结果,再交付一条哈希文件名排在其后的未确认结果。 两次普通 Inbox 读取都返回零条结果、scan_complete=false 和 has_more=true,外层没有续读游标。仅在对照夹具里移走一条已确认元数据,下一次读回才出现同一个新结果 ID。 提供能越过已确认历史的有界读取路径,保留确认回执和幂等性。可使用可续读游标或由持久索引先选未确认项,保留普通读取的恢复入口。
A host-native child could finish successfully while its final text disappeared after the parent Turn: LoopX retained only the typed terminal receipt and discarded the host's result message. This change stores observed final text in an owner-private, Goal-lifetime-scoped inbox before exposing the terminal receipt, then delivers it through the existing
manager-inboxhook on the next Turn.Reading records delivery without consuming the result. The parent must explicitly acknowledge
accepted,deferred, orrejected; unacknowledged results replay with a stable ID after restart. Exact ingest and acknowledgement retries are idempotent, conflicting text or dispositions fail closed, large results use digest-verified private file references, and corrupt or truncated scans remain visible instead of starving later results. Disabling future child spawning does not prevent acknowledgement of an already delivered result.The built-in managed Codex CLI and app-server observers call this contract directly. Other hosts must provide the same live terminal event; persisted Codex history is not treated as a reliable reconstruction source.
Validation:
npm run typecheck:control-planeloopx checkpublic-boundary scan over all 13 changed files