OpenProgram / Web UI / Runtime contract

聊天发送队列可靠性设计

基线:b6460fdcb67b6b12843491490968696a5438d4d6。本页定义用户在 turn 运行期间提交下一条普通文本消息时,浏览器队列、WebSocket 和后端 session 独占之间的合同,并记录实现与验证状态。

确定方案。 队列保持 renderer 内存态并按 session_id 隔离;队首成功写入 WebSocket 后,该 session 立即进入 optimistic running,直到服务端 ACK/运行态事件接管。后端通过单个原子占用操作确保同一 session 只有一个 turn 可以开始。重连先恢复服务端运行态,再仅处理确认空闲的队列。运行期间暂不接收带附件的排队提交,附件和文字完整保留在 composer 中。

01 · 目标与边界

必须保证

  • 同一 session 同时最多发送一个队首。
  • 重复 clear 不会发送后续项。
  • 断线前未成功写出的项留在队首。
  • run_active 拒绝不会产生错误气泡或丢失文本。

产品边界

  • 队列不写磁盘,页面刷新会清除未发送项。
  • 队列只处理普通纯文本 turn。
  • slash、fn-form、附件继续使用各自入口。
  • 不同窗口各自持有其提交的队列。

不引入

  • 不恢复已删除的 v2 MessageStore
  • 不增加 broker、数据库表或新依赖。
  • 不把 queued message 提前写进服务端 transcript。
  • 不改变 steering 的语义。

02 · 状态与顺序

queued
队列中可撤回
→ idle + drain
socket write
队首暂时移出队列
→ success
optimistic running
阻止第二次 drain
→ ACK / running_task
server running
服务端状态接管
→ clear
next queued
仅发送下一条

socket write 失败时,队首放回原位置且不进入 running。run_active 表示服务端已有 turn:被拒绝的普通发送放回队首,当前 session 保持 running,等待真实 clear。任何 idle→idle 重复更新都不是新的 drain 信号。

03 · 组件职责

组件唯一职责禁止行为
state/send-queue.tsFIFO、按 session 隔离、发送失败恢复队首。不判断服务端权威状态,不持久化 transcript。
legacy-send.ts写 WebSocket;成功后立即设置该 session 的 optimistic running。不得在同一 session 已有 provisional send 时把第二条视为成功。
session-store只在 running→idle 转换时触发一次 drain。idle→idle 不得触发 drain。
use-ws.ts连接恢复后,当前 session 通过 load_session 恢复;后台队列通过无焦点副作用的 get_run_state 查询状态。不得在未知 run 状态下直接发送队列,也不得为后台队列改变 socket 的 focused session。
ws_actions/chat.py原子占用 session,成功者才能写 user message 和启动 turn。不得把“检查”和“占用”分成可并发穿过的两个阶段。

04 · 附件、断线与失败语义

队列不是持久消息系统。它保证当前 renderer 生命周期内不因重复状态事件、已知 socket 写失败或服务端忙拒绝而丢失文本;页面刷新和已成功写入但 ACK 丢失仍遵循现有非持久边界。

05 · 验证合同

场景预期状态
两条排队消息 + 两次连续 clear只发送第一条,第二条保留。已验证
第一条 ACK 后运行结束第二条才发送。已验证
socket 写失败后重连消息留在队首,确认 idle 后发送。已验证
运行中带附件提交不排队、不清空草稿。已验证
两个 WebSocket 同时提交同一 session一个取得占用,另一个收到 run_active;reservation 在 runtime 接管前始终有效。已验证
现有 FIFO、撤回、置顶、跨 session 隔离行为保持。已有检查

06 · 实现记录

实现与 review 完成。前端修改集中在发送队列、composer、session running 状态和 WebSocket 重连;后端增加原子 reservation、runtime 接管以及无焦点副作用的运行态查询。review 发现的 reservation 接管窗口和后台 load_session 焦点污染均已修复。

验证命令实际结果
cd web && npm run check通过,包含 send-queue、chat-ui、Markdown sanitize 和 WS action 合同。
python -m pytest tests/unit/test_webui_head_mirror_and_run_guard.py tests/unit/test_webui_chat_dispatcher.py tests/unit/test_turn_cancellation.py tests/unit/test_retry_function.py tests/unit/test_dispatcher_integration.py -q61 passed, 1 skipped
cd web && npx tsc --noEmit通过
cd web && npm run build27 个静态页面生成完成

同轮追加修复:assistant Markdown 不再依赖 CDN marked;CDN 不可用时使用已安装的 npm 包,因此普通回复不会退化为带边框的 <pre>