Repository navigation
Retry transient reads of the original Chat queue - #8542
Conversation
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: model_agent, GPT-6 family, OpenAI, self_reported
Approval conclusion (author-owned PR; GitHub blocks formal self-approval)
Reviewed exact head: affbe50
动机 / Motivation
在 App 中打开或刷新空闲原会话队列的用户。队列读取在既有时限内遇到一次 HTTP 503 或连接中断。旧客户端结束读取,界面继续显示读取失败。同一队列在原时限内重读一次,读回确认为空后清除错误。保留既有读取时限,原模型响应速度单独核验。已安装 App 的失败响应详情和上线后的恢复仍待核验。 同一输入在旧打包页只发出一次读取,候选页在第二次请求得到原队列后清除提示。
改动思路 / Approach
现有 fetchChatQueue 管理一次原队列读取,后端继续验证当前会话和授权,原 hook 按原响应更新界面。 范围是空闲或运行中会话的同一只读队列请求在原时限内遇到短暂失败。 只使用同一个请求地址和调用者的取消信号。持续失败会继续显示原错误,当前 Session 的身份仍由服务器和客户端分别核验。
具体改动 / Changes
以 docs/architecture/rfcs/app-conversation-and-async-inbox-v0.md 在 b89a574b05a3e7d5920a8e7184476dfb7b041790 的约定为准。C1 保留同一原 Session 和由 Core 拥有的队列,成功响应仍验证 Session 与队列结构。C2 原请求的准入、FIFO 和投递规则继续由既有执行层处理,本改动只读取队列,两套打包验收都没有写请求。
关键代码讲解
apps/presentation/dashboard/src/data/chat.ts:1017的fetchChatQueue在暂时无法读取时使用原地址和原取消信号重读一次。apps/presentation/dashboard/smoke/bound-conversation-smoke.ts:85在同一原会话上制造一次临时失败,随后读真实 HTTP 数据,并覆盖拒绝、持续失败、错误 Session 和取消。
对主干的风险 / Risks
第二次读取增加一次服务端校验。条件限于一次临时不可用或连接中断,调用者取消后立即结束。权限拒绝和错误身份不触发额外读取。打包页实际调用同一原 Session 端点,旧版保留提示,候选收到真实空队列后清除提示。标准合入前检查、Dashboard 类型检查和原会话测试通过。
我的整体评价 / Verdict
对比了同一打包页面的读取失败提示和恢复后的空队列。打包验收采用隔离数据,尚未验证已安装 App 上的恢复。 该改动有明确的旧版复现和候选结果,适合交付为原队列读取的恢复修复。上线后还需核对已安装 App 原队列,并结合模型断流证据定位响应慢。
English verdict: APPROVE
songoow
left a comment
There was a problem hiding this comment.
Reviewer: model_agent · GPT-6 Astra Pro · OpenAI · self_reported
Reviewed exact head: affbe50ee52b768db1397c3b83b008fbb3141e40 · baseline: b89a574b05a3e7d5920a8e7184476dfb7b041790
动机 / Motivation
在 App 中打开原会话的用户,可能在会话已经空闲时遇到一次队列读取断线或服务暂时不可用。
旧实现收到这次失败后直接显示读取失败;空闲会话没有后续自动轮询,服务即使立刻恢复,用户仍需手动重试。
本 PR 在调用者原有时限内向同一 Session 只重读一次,成功读回并验证原队列后,让既有界面恢复可用。
范围是原队列的只读恢复,不改变消息准入、FIFO 顺序、模型执行、会话创建或授权规则,也不承诺修复持续断线。
改动思路 / Approach
重试放在既有 fetchChatQueue 读取边界,复用 ChatApiError、原 Session 地址和调用者的取消信号,避免另建队列状态或恢复协议。
当前 PR 只增加一次有界只读请求,并保留结构、身份和唯一 Turn 校验;队列事实仍由 Core 持久化存储拥有。
实际调用链是会话页面 → useConversationQueue → fetchChatQueue → 原队列 HTTP 端点。hook 原有的 5 秒总时限和离开页面的取消信号覆盖两次请求。第一次成功只请求一次;第一次短暂失败可以再读一次;第二次仍失败就回到既有错误展示和重试入口。共享 requestJson 没有改为自动重试所有操作,因此行为不会扩散到发送消息等写请求。
具体改动 / Changes
完整检查了 2 个文件,+58/-3;生产读取函数 +13/-2,真实 HTTP smoke +45/-1。验收依据是原会话与异步收件箱契约:C1 implemented,保留精确原 Session,错误身份或失效来源不能创建替代会话;C2 implemented,Core 继续拥有持久队列、FIFO 和准入,读取不是新的执行。
关键代码讲解
- fetchChatQueue 只捕获第一次读取的 ChatApiError。503、没有 HTTP 状态的连接中断、200 响应体中断可以进入一次重试;调用者已取消时先退出。第二次调用不处在重试循环里。
- requestJson 保留状态码和错误类别。JSON 内容不兼容与连接中断不同,前者没有进入重试;返回后仍验证队列 schema、回显 Session 和 Turn 标识唯一性。
- useConversationQueue 是实际生产消费者。source key、5 秒时限、取消与活动会话轮询保持原样;只有验证成功的队列结果进入现有 readReady 状态。
独立对照原基线完整读取模块和当前模块,并运行实际 HTTP/SQLite 的原会话 smoke,得到以下结果:
| 输入 | 基线 | 当前 head |
|---|---|---|
| 一次 503 / transport 中断 / 200 body 中断 | 1 次后失败 | 2 次后返回原队列 |
| 持续 503 | 1 次后失败 | 最多 2 次后仍失败 |
| 403、错误 Session、无效 JSON、取消 | 1 次后拒绝 | 仍为 1 次后拒绝 |
| 正常读取 | 1 次成功 | 1 次成功,完整结果一致 |
对主干的风险 / Risks
主要风险是把原队列读取恢复扩大为新 Session、写请求重放或无界轮询。地址与 signal 固定在同一闭包中,结构和身份校验位于重试捕获之外,后端准入、执行和 hook 轮询策略保持原样。真实 HTTP/SQLite smoke 验证了原始历史、来源撤销及恢复、旧服务拒绝和不可创建 fallback;九类独立对照又覆盖了响应头已到但响应体中断的边界。持续故障仍需既有重试入口,这是明确的交付范围。
语义与 CI 对齐
本地 build:chat(含 Dashboard TypeScript 检查)、真实 smoke:bound-conversation、diff check 和 bilingual RFC check 均 PASS。远端 typescript-core (2/3) 的两个内容摘要清单检查 FAIL;我在精确基线与 head 运行相同两项检查,两侧都因 benchmark_cli_source_activation.ts 缺少消费者/模式登记而失败,扫描的 loopx 树在这两个提交间没有改动。这是已验证的基线诊断,不能称为 CI 全绿;远端六个测试 shard 仍显示 pending。改动复用现有错误代码与队列协议,没有新增状态词汇或共享规则。
我的整体评价 / Verdict
APPROVE 这项有界恢复修复。长期执行、工作所有权和消息顺序保持不变;用户体验改善由同一调用的基线失败、head 成功和真实队列回读证明。生产机制只有一个读取分支,无新增配置、状态、迁移或通用恢复框架,规模与问题相称。
本 PR 不改 DOM、CSS 或可见文案,视觉布局检查不适用;没有把构建或 HTTP fixture 说成已安装 App 的体验验收。残余限制是持续断线、已安装客户端和真实模型性能没有在这里资格化。正式评审只针对上述精确 head;CI 与后续合并就绪仍需按仓库流程处理。
English verdict: APPROVE
An idle conversation can keep showing “Read failed” after a temporary outage during its queue read. The service may already have recovered by the time the App shows the error.
Retry a transport interruption or HTTP 503 once against the same Session, within the caller's existing deadline. The response still has to match the original queue. Permission errors, cancellation and a second failure remain visible as read failures.
In packaged Chat with a real local HTTP and SQLite backend, a controlled first 503 left the old UI stuck. The candidate made two GET requests, recovered the original empty queue, and cleared the error without a write. The bound conversation smoke also covers a continued outage, denied scope, a mismatched Session and cancellation. Dashboard type checking and standard premerge checks passed.