Repository navigation
fix(chat): retry proven native routing timeouts within the live Turn - #6916
Conversation
Signed-off-by: LoopX Agent <337587101+loopx-agent@users.noreply.github.com>
There was a problem hiding this comment.
Approval conclusion (author-owned PR; GitHub blocks formal self-approval)
Reviewer: model_agent; gpt-6.1-sol; OpenAI; runtime_reported; effort=max
动机
普通项目和私人管家对话的用户,会遇到模型尚未执行就因路由发现超时结束本轮的问题。
一次普通请求收到明确路由超时,原生记录只有用户输入。旧版直接失败;新版核验后在原请求内继续,暂时故障消失时返回完整结果,持续故障仍按原预算结束。
受控原链路中,一次失败后第二次成功;连续三次失败后第四次成功;持续失败最多四次原生调用。用户消息、会话和最终回传均不重复。
本 PR 只补齐同一请求仍在执行期间的恢复分支;不重开已失败历史请求,也不解释或修复上游路由服务本身。
真实上游恢复率、长时间运行效果和完整回传时延仍需自然请求验证;本次合成通过不证明这些结果。
改动思路
错误通知只能提供候选线索,最新失败记录及完整无执行清单才是允许继续的证据;两次观察不可互相替代。
保留原 Core 执行、权限与三次重试预算,只在原 Codex 适配器补确切诊断,并由现有 Core 重试拥有者消费独立读回。
我比较了保持现状、直接放行所有 other 错误、新增消费者与当前方案。保持现状留下已复现的故障;放行所有错误无法排除执行效果;新消费者会重复持有执行职责。因此选择既有拥有者中的窄修复。新增两个值分别表示错误通知里的候选提示和独立控制读回里的派生事实,由实际原生路径自动产生,没有让人手填另一套状态。现有 Core 在每次等待前后继续核验输入、权限、模型和活动执行,预留仍写入同一重试记录,最多三次重试。
| 输入与原生记录 | 旧版 | 当前精确提交 |
|---|---|---|
| 一次确切路由超时,只有原用户输入,随后恢复 | 一次调用后失败 | 第二次调用完成同一请求 |
| 持续同类故障 | 提前失败 | 总共最多四次原生调用后保留失败 |
| 未知错误、执行条目、权限或配置变化 | 保留拒绝 | 保留拒绝,不新增执行 |
该表是源码与受控协议用例的对照,绑定 56a65cb8f787e851e50257b971a684f0bacdbad0,不是线上恢复率测量。
具体改动
全量变更为六个路径、135 行新增和18 行删除:两个既有生产模块、两个既有测试文件及一对 RFC。没有新配置、队列、消费者或模型。评审依据为 docs/architecture/rfcs/app-conversation-and-async-inbox-v0.md,spec_revision=a81c824895333249a276945a8770989231a30124;已阅读修改前的合同,新增文档本身不作为通过证据。
LIVE-1:沿用原 Core 与 Session 队列;终态失败不会重新打开,预留后崩溃也不产生下一次执行。LIVE-2:仍由原绑定和 current 检查处理输入、grant、模型、Session 和 claim;等待期间的撤销会阻止恢复。LIVE-3:适配器完整分页读取最新失败 Turn,要求只有一个原用户条目;较新 Turn、第二页工具、答案、错误正文变化和外来条目均拒绝。LIVE-4:预算和原消息结果归原拥有者;六条 provider 路径独立核对完整最终正文、App 与受众,并验证再次对账不重发。
关键代码讲解
_routing_discovery_timeout同时检查原生other类别和完整固定诊断。不是子串判断,不把任意错误正文当命令;策略/额度类别即使带相同文字也不满足这个提示。共享小谓词让通知与独立读回使用相同的 provider 定义。transport_retry_readback仍只观察、不恢复原生线程。它核对最新失败状态、完整分页、正确 Turn、工具观察与第二次稳定读回;路由分支额外要求恰好一个用户条目,结果只带结构化事实,不复制原生错误正文。_prepare_transport_retry继续属于 Core。候选提示必须有独立匹配凭证,再通过原 grant/config/active claim 与预算;先持久记录重试,再等待,最后重新核验。它返回给同一 worker,不生成新的用户消息或历史续办。
对主干的风险
最强反例是:上游用宽泛的 other 表示工具已执行后的错误,或者在第一次读回后才出现工具/纠正。直接按错误提示重试会产生重复效果。当前实现只接受完整固定诊断,并要求最新、稳定、仅含原用户的完整清单;额外答案、第二页工具、foreign Turn、变化的诊断和撤权都使恢复停止。未知和前后缀文字不会被猜成可重试。既有普通连接与过载路径及所有失败类别保持;没有默认关闭功能被暗中开启。
438 项源码检查、148 项安装包检查、六条原 provider 全正文回传路径、Ruff、双语和公开边界检查通过;标准精确提交 canary 的六项直接检查及11项所选检查通过。旧版同一回归输入3项失败、26项通过,证明测试能抓到遗漏恢复;当前同条件恢复和预算断言通过。安装包八个生产模块逐字节核对,运行期没有源码路径逃逸。按本 Goal 的配置未查询或等待 CI,没有靠改预算、删断言或缩扫描范围消除失败。
仍存在外部风险:固定诊断未来变化会安全地回到失败;独立控制读回有额外时间和至多三次调用成本;真实上游可以持续不可用。合成 native/provider 与真实 Core/文件/typed grant 路径证明当前边界,不能替代真实模型恢复率或全产品 SLA。回滚只需撤回这个窄分支,没有数据迁移,也不改写原失败。此为作者自审,不冒充两位独立评审者;合并与采用仍须各自资格。
我的整体评价
结论是 APPROVE,作为 justified_increment:该完整增量让已有授权、可证明未执行的普通请求实际恢复并回到原受众,同时保留失败终态、停止、授权和预算边界。错误通知只能提供候选线索,最新失败记录及完整无执行清单才是允许继续的证据;两次观察不可互相替代。 保留原 Core 执行、权限与三次重试预算,只在原 Codex 适配器补确切诊断,并由现有 Core 重试拥有者消费独立读回。 生产规模与问题匹配,相关的小型整理已经把确切 provider 判断集中到同一谓词;不需要新增通用重试框架。下一步是在合并资格通过后于原服务空闲边界采用,再看自然请求的实际原路结果,保留终态失败与更大范围的验收缺口,不把测试或合并当全部业务完成。
English verdict: APPROVE this exact head. It reuses the bounded Core retry path only after an exact native hint and independent latest/user-only proof, preserves authority/budget/restart and original-return boundaries, and leaves upstream-cause and live-SLA claims unqualified.
Codex can return
other / workspace routing discovery timed outbefore executing a request. Ordinary project and private-steward chats currently terminate that live Turn instead of entering the existing transport recovery path.Recognize only that exact native diagnostic, then independently require a stable, complete inventory showing the latest failed native Turn contains only its original user input. Reuse the same Core Turn, Session, input, current grants and existing three-retry/backoff journal. Unknown or changed diagnostics, extra execution items, stop/configuration/grant changes, exhausted budgets and restart uncertainty remain holds. Terminal historical requests are never reopened.
Validation:
The native/provider subprocesses are synthetic. Read-only native evidence confirms the observed failure shape; this does not establish the upstream cause of the timeout, real-model recovery quality, or the complete conversation SLA. No new setting, model, queue, consumer or retry budget is introduced.