Repository navigation
fix(chat): restore historical answers and retain unanswered originals - #8038
Conversation
Signed-off-by: LoopX Agent <337587101+loopx-agent@users.noreply.github.com>
Signed-off-by: LoopX Agent <337587101+loopx-agent@users.noreply.github.com>
loopx-agent
left a comment
There was a problem hiding this comment.
Reviewer: actor_kind=model_agent; model=GPT-6 (Codex); provider=OpenAI; self_reported (host execution observation unavailable).
Approval conclusion (author-owned PR; GitHub blocks formal self-approval)
当前 exact head 980373731d8d63785b2d6361aaaacec0d268c06b 没有阻塞发现;历史答案混入后续问题及越权重放两个关键反例均被原路径拒绝。没有把本次源代码修复当成所有历史问题已完成。
动机 / Motivation
通过原生管家连续提问、在模型中断后等待补答的用户,以及读取已有消息积压状态的客户端。 一条提问已生成完整答案但连接中断,随后又提了新问题:旧实现拒绝旧答案;现在只有原输入 hash、起止步骤和正常结束都匹配时,原 worker 才补回对应正文。 原消息收到与其输入绑定的完整正文;失败 Turn 与原失败通知不被改写,后续提问不混入旧答复,也不启动新的模型 Turn。 不重放未知效果,不代接收者执行业务,不创建另一消费者,不把 Key 存在或 route 时间戳当作真实可消费额度。 本 PR 交付已生成历史答案的原路补发、失败问题的保留及只读积压查询批处理;没有结论且已用工具的请求仍需原服务核对执行结果后补分析,不能因此宣称全部历史消息已答。
改动思路 / Approach
继续使用同一 TypeScript 准入与投影 owner、同一 Core 请求账本和原回复 worker;只放宽已生成正文的历史输入匹配,不创建新队列、消费者、业务重放或凭据策略。 状态查询依然读完整历史,并把最多 64 个只读观察交给同一个 typed owner;既无历史缓存,也不把 provider 不可用误判为零积压。历史答复沿已有恢复账本和原回复 worker 返回,要求原输入 hash、正常结束和闭合片段精确匹配;原失败 Turn 保持原样。继续使用同一 TypeScript 准入与投影 owner、同一 Core 请求账本和原回复 worker;只放宽已生成正文的历史输入匹配,不创建新队列、消费者、业务重放或凭据策略。 本 PR 交付已生成历史答案的原路补发、失败问题的保留及只读积压查询批处理;没有结论且已用工具的请求仍需原服务核对执行结果后补分析,不能因此宣称全部历史消息已答。
具体改动 / Changes
规范依据 docs/architecture/rfcs/capable-manager-semantic-handoff-v0.md,不可变 revision 53374543abfd7dcfe72d63bfdf2c60bb3ce17786:request-level-coverage 由原答案账本和原消息回复测试覆盖;no-effect-replay 由禁止 enqueue/resume、保留原 Turn/通知字节覆盖;operational-source-coverage 由全历史和新停止条件覆盖;installed-roundtrip 留给合并后的原服务安装和真实消息读回,不由合成测试类推通过。
关键代码讲解
quota_backlog_observer(loopx/capabilities/native_chat/external_conversations.py:191)把同一批的控制记录读取共享,响应仍经原 typed 判定;64 条和字节边界拆分后按原顺序返回,超大单项保留旧传输限制,错误形状显式失败。planContextRecovery(loopx/control_plane/collaboration/conversation_binding.ts:621)只对已有完整答案允许历史闭合片段;未绑定输入的旧结果仍要求最新输入,source、stop、hash、thread、端点权限及正常结束检查保持。manager_session_quota_route(loopx/chat_manager.py:943)为已核对的 API-primary 路由附上当前观察时间;它没有把该时间当 API 余额,也没有新增 Key 选择器或 worker 路由策略。
对主干的风险 / Risks
最强反例是后续提问让旧结果指向错误消息,或旧答复中提到“已处理”就被误读为其他请求也完成。原 worker 集成测试实际通过原生协议、文件账本和 provider adapter,验证独立后问不混入、source 修改/停止时不发送、原失败与通知不变、一次补发且无模型 Turn 重放。历史正文明确保留其他完成声明的未核实边界。生产仍只有原消费者。34 affected Python integration tests and 52 TypeScript cases pass; 6 direct and 10 selected premerge checks pass; same three regression cases fail on immutable base and pass at this head.
相同三项回归断言在 immutable base 上全部失败,在该 head 全部通过。批处理 130 条得到 64/64/2、次轮 stop 立即生效、超大输入和错误结果形状均覆盖。受控同一冻结数据、各自隔离 TS runtime 的三次热读中,局部中位数 1.097 秒到 0.948 秒;13.6% 仅是这份固定数据的本地测量,不能称为生产 p95 或已解决所有超时。早先共享 runtime 的混杂比较不作为收益证据。旧测试 spy 的可变 list 引用、测试变量重名及误用 CLI 的失败均已分别定位;最终未删除断言、放宽检查或改预算。
语义与 CI 对齐
本变更复用原 vocabulary,未改变 Goal work/quota/权限合同。runtime_error 与 server_restarted 只改变 owed question 可见性,没有增加重放资格;历史提示说明 provenance,不授予新动作。没有增加默认关闭能力或加载指令,故 default-off 不适用。按当前配置 wait_for_ci=false,没有查询、轮询或等待远端 CI。
我的整体评价 / Verdict
long_horizon 与 user_experience 均改善:后续提问不再让已有答案失去补发资格,用户不必重新提问,历史中断也不被失败通知掩盖。继续使用同一 TypeScript 准入与投影 owner、同一 Core 请求账本和原回复 worker;只放宽已生成正文的历史输入匹配,不创建新队列、消费者、业务重放或凭据策略。 本 PR 交付已生成历史答案的原路补发、失败问题的保留及只读积压查询批处理;没有结论且已用工具的请求仍需原服务核对执行结果后补分析,不能因此宣称全部历史消息已答。 没有页面结构、布局或密度修改,因此视觉审查不适用;实际安装、原 provider 回传、上游可消费额度和仍缺分析结论的问题保留独立验收。代码复用现有单 owner,范围与问题相称,可合并这一可用修复切片。
English verdict: APPROVE 9803737; exact anchored historical answers return through the original owner without replay, while unanswered and unknown-effect requests remain owed.
A native answer could be complete even when Core recorded a transport failure. Once a later user question arrived, the latest-input-only recovery rule stranded the earlier answer. Restore only an exact, source-verified, normally terminated original segment through the existing reply owner; preserve the original failed Turn and never replay the business request.
Keep runtime/server failures visible as unanswered questions. Batch read-only private backlog projections through the same typed owner with strict ordering/byte bounds, and attach a fresh observation time to the existing API-primary route without claiming usable API balance.
Validation: 34 affected Python integration tests, 52 TypeScript tests, 6 direct and 10 selected repository premerge checks pass. The same three regression cases fail against the immutable base and pass at this head. Source/stop mismatches, wrong native anchors, uncertain delivery and malformed batches fail closed. Controlled local frozen-data health median improved from 1.097s to 0.948s; this is not production throughput or p95 evidence.
Installation and real original-provider returns remain separate acceptance. Interrupted requests with observed effects and no final answer remain owed; this PR does not replay them or claim all historical questions answered.