OpenProgram / WebUI 可靠性 / 实施交接

WebSocket 命令与交互等待生命周期

本页限定单条 WebSocket 命令失败、连接断开和 legacy ask_user 等待的所有权与可观察行为;实现状态与验证证据见第 07 节。

确定方案。 单条命令异常在 receive loop 内隔离并返回低敏 operation_error;新前端继续消费旧服务端的 action_error。dispatcher 不清理 action 自己取得的 reservation,避免误删另一连接的 owner。连接断开时,仅当该 session 没有其他聚焦连接,才向 legacy follow-up queue 投递进程内 sentinel;等待者收到 sentinel 后返回 None,不能把断连解释为空字符串答案。

01 · 当前实现与边界

入口当前行为边界
server._websocket_handlerreceive loop 分别隔离 JSON 解析和单条 handler 异常;handler failure 返回 operation_error 后继续接收后续命令。transport disconnect 与错误帧发送失败仍结束连接;dispatcher 不推测 action 已取得资源的所有权。
server._handle_ws_command未知 action 返回 operation_error(code=unknown_action);已注册 handler 的异常传播到 receive loop,由同一构造器返回 handler_error。wire 只含受约束的 action、session、request metadata 和注册错误分类;异常详情只写本地日志。
server._web_follow_up使用 session queue 等待;最后观察者断开或取消时返回 None,真实空字符串保持 ""。legacy queue 仍是当前进程内状态,不承担 worker 重启后的持久恢复。
stop/delete取消对象与断连 sentinel 统一解释为非答案;queue 由 owner 的 finally 清理。通用 dispatcher 不按 session 清理 reservation;取得资源的 action 必须按自己的 owner token 回滚。

02 · 参考机制与取舍

Starlette WebSocket

transport 断开通过 WebSocketDisconnect 结束连接。采用连接级清理放在 finally,命令级应用异常留在 receive loop 内处理。

QuestionRegistry

新 runtime question 已有 session-scoped、claim-once 的 cancel_session()。legacy follow-up 不迁移协议,只采用相同的“取消不是答案”语义。

现有 run reservation

_release_run_reservation(session_id,msg_id) 已按 owner 清理。dispatcher 缺少 owner token,因此拒绝在通用异常分支按 session 清理。

采用:命令级错误帧、最后观察者断连 sentinel、owner-scoped action cleanup。修改:legacy queue 的返回类型允许 None。拒绝:任何 tab 断开都取消、dispatcher 按 session 删除 reservation、异常后关闭连接、把 sentinel 传给业务函数。

03 · 目标数据流

1
收到文本;非法 JSON 记录低敏诊断并继续 receive。
2
解析为 object 后执行 action handler;未知 action 返回 operation_error,并回显合法 request_id。
3
handler 异常写结构化日志,仅包含 action/session/type;向同一 socket 返回 code=handler_error,然后继续接收下一条命令。
4
transport 断开后先从连接集合移除当前 socket,再检查其 focused session 是否仍有其他连接。
5
若没有其他聚焦连接且存在 legacy follow-up queue,投递唯一 sentinel;queue 仍由 _web_follow_up 的 finally 删除。
6
等待者把 sentinel 转为 None;真实空字符串仍保持空字符串,因此两者可区分。

04 · 信任边界、失败与兼容

05 · 明确排除

06 · 验收矩阵

公共入口场景可观察断言
_websocket_handler第一条已注册 action 抛 KeyError,第二条为 ping同一连接先收到低敏 operation_error,再收到 pong;连接未因第一条关闭。
_websocket_handler非法 JSON忽略该帧并继续处理下一条;不回显原文本。
_web_follow_up + disconnect唯一聚焦连接断开等待线程在测试时限内返回 None,不等待 300 秒;queue 最终删除。
disconnect同 session 仍有另一聚焦连接不投 sentinel,等待保持;另一连接提交正常答案后返回该答案。
follow_up_answer用户提交空字符串返回 "",不得转换为断连。

07 · 实现文件与证据

文件职责
apps/server/openprogram_server/server.py命令级异常边界、低敏错误帧、连接观察者清理、follow-up sentinel 解释。
tests/component/webui/runtime/test_websocket_command_lifecycle.py真实 receive-loop、断连和等待线程的公共入口回归。

第一切片已实现并完成规格与质量独立审查。 命令级隔离、低敏 operation_error、旧帧前端兼容和 follow-up 断连语义均由公共入口回归覆盖;持久 error store、acknowledge 和 reconnect recovery 不在本页实现范围。

交互响应速度

Socket 写入成功后,发送方立即仅清除已捕获的输入草稿,并在所属对话中显示本地待确认用户消息。待确认记录保留原始文本与附件,直到收到权威确认。服务端确认协调本地身份而不重复消息;拒绝时保留可恢复消息,不覆盖更新的草稿。客户端待确认消息不代表模型已经开始执行。

无关资源投影和会话/侧栏工作不得延迟消息接收或阻塞服务端事件循环。资源关闭定位精确页面与关联身份,保留代次和序列顺序,不扫描无关执行输入。本地关闭反馈与原生关闭确认保持区分;旧待处理动作不能隐藏失败或更新的资源代次。

受控测试覆盖确认延迟、拒绝、会话切换、绑定输入框、排队/steer 行为、资源关闭顺序和无关事件循环进展。不从合成测试计时推断生产延迟。本次仅修改源码,不重新构建、打包、重启或操作已安装 App 与运行中的 worker。

实现状态:源码实现通过独立规格与质量审查。公开入口回归检查覆盖 socket 接收、确认协调、可恢复拒绝、会话历史并发、附件取消和已确认原生关闭。Runtime 安装延期。后端改动限于已识别的阻塞调用路径,不引入通用协议替换或并发框架。