fix(chat): recover uncertain instructions after page reloads - #5373
Conversation
Signed-off-by: huangruiteng <huangrt01@163.com>
Signed-off-by: huangruiteng <huangrt01@163.com>
There was a problem hiding this comment.
Approval conclusion (author-owned PR; GitHub blocks formal self-approval)
English verdict: APPROVE - 4aecee1. Original retry identity survives reload; fresh canonical history preserves distinct instructions. The packaged UI, production HTTP/store and risk-based checks passed. Live adoption and installed promotion remain open.
动机
原来追加指令的重试标识只存在于挂载页面的 Map。执行器实际接收、回复丢失、原回合完成之后,刷新会丢失原标识,保留的草稿可能启动第二个回合。这个 PR 让用户继续使用同一个输入框和发送动作,恢复原请求并读回一个已存指令,减少重复执行和人工重述,属于有独立使用价值的恢复增量。
改动思路
继续由 Chat 服务与 ingress 存储决定送达与去重。浏览器只在发送之前保存原 Session、Turn、文本和请求标识,恢复缓存不会自动发送,也不会获得新的执行权限。对已有送达回执,复用 created=false 事实和共享 history 的 fresh read,避免再加一个乐观气泡。这个逻辑供管家与 Goal 对话共用;没有新增管家专用协调器、Provider、轮询或 Python 决策源。
具体改动
关键代码讲解
readComposerSteeringRequests只恢复四个非空身份字段,忽略无效行;浏览器存储不可用时保留当前页面内存行为,不承诺跨刷新恢复。sendMessage在传输前保留请求,只有 Session 和文本匹配才复用原身份;未知回执继续保留,确认接收或明确未送达只清除对应身份,延迟回复不擦掉新写的草稿。steerChatTurn校验既有回执中的目标、请求标识、送达状态和created。共享回调对已送达重放刷新当前历史,避免把回执读取当成一次新的本地用户消息。reconcileConversationReturns使用一个 Turn 的首个用户消息关联最初请求。之后的追加指令保留各自消息 ID,防止最新指令被错误地当成原问题。助手文本的现有合并行为保留。
现有 RFC 同步说明跨刷新边界、零自动发送、存储降级与送达不等于采用。新增回归验证当前页面的新消息读回、刷新后的原身份、同一回合两条指令、原问题身份,以及重复读取不重复展示。
对主干的风险
最强反例是“执行器接受了,但浏览器不知道”。在不可变基线 3156771e47268433c4b4b233bd37bdd3f2b37726 上执行相同最终浏览器夹具,确实复现刷新后生成不同 ingress;最终代码通过。完整审阅还发现缓存式 retry 无法显示当前页面新存指令,以及按最后用户消息补身份会吞掉指令,二者已在原共享 owner 中修正并有失败再通过的证据。
本地 TypeScript 构建、打包来源验证、29 个打包浏览器场景、共享消息单测,以及基线与最终代码上的各 10 个真实 HTTP/文件存储/脚本化 Codex 子进程用例通过。独立操作打包界面对接可丢首个回执的生产 Chat 服务,确认一个已完成原回合、一个 ingress、一个原问题、一个指令和答案;当前页面重放和后续刷新都只显示一次指令。桌面与 390×844 已检查。目录与状态投影是模拟数据,Provider 是脚本,不代表付费模型理解已验收。
精确十路径公开边界扫描与质量回执 cqr_53d9fd688f5a54ceb0c2 有效;3 项差异检查和 16 项风险验证通过,无失败或跳过。未查询或等待远端 CI。现有不支持执行器、attached 排队、只读和普通空闲发送路径保留,缓存不能越过服务端的权限或目标校验。
语义与 CI 对齐
复用既有 steer v1 的 created 和消息身份语义,没有新增服务器协议版本、调度额度规则或预算豁免。验证针对真实消费入口与消息读回;接受回执仍只表示执行器收到指令。实际模型采用、团队停止、安装升级和真实小团队周期继续由现有验收负责。
我的整体评价
这是一组围绕同一恢复结果的适度修改:小缓存解决不可推导的原请求身份,当前共享读取与 TS 消息归并解决展示重复或缺失,没有新建一套权威状态。完整差异为 146 增加、17 删除;行数本身不是价值证明。保持运行时与产品变更的维护者合并约束,不自合并。本轮没有付费模型评测,也没有全局安装;完整 App/R2/R3 目标仍待后续真实采用与安装后的验收。
Problem and result
An instruction may reach the executor while its reply is lost. Reloading the page then loses the retry identity; sending the retained draft after the original turn finishes can start a second turn. The shared steward/Goal composer now restores the original Session, Turn, text and ingress in the same browser tab, and replays only when the user sends again.
An already delivered replay reads fresh canonical history instead of adding another local bubble. The shared message reducer also keeps the original query distinct from later instructions in the same turn. Both adjacent defects were reproduced before repair. This extends GQ08 and the App conversation RFC, building on #5368.
Validation
Reviewed head:
4aecee1462ac0320bb15eecdcb19fdb5e125e079. Ten files; public-safe synthetic inputs.3156771e47268433c4b4b233bd37bdd3f2b37726and passes on this head. Ten real Chat HTTP/file-store/scripted Codex subprocess cases passed on both baseline and head.cqr_53d9fd688f5a54ceb0c2passed. Risk-based premerge passed three diff checks and 16 selected checks with no failures or skips. Remote CI was not queried or awaited.Ownership and limits
The Chat service and durable ingress remain the delivery authority. The browser cache grants no permission and dispatches nothing when restored. Unavailable browser storage retains current-page recovery but cannot guarantee recovery after reload. A receipt proves delivery, not model adoption or stopping delegated work. Attached queues, unsupported adapters and ordinary idle sends preserve their existing contracts. No initial layout or navigation changes.
The related refactor reuses fresh shared history and typed message identity rules; it adds no manager-specific coordinator, provider, capability or parallel Python owner. Installed-App promotion, live owner adoption, team stop and real small-team cycles remain open. No paid model evaluation or global installation was performed. Runtime/product changes remain for maintainer merge.