- 将 /api/sessions/{sid}/ws 端点移入 create_app(此前置于模块级导致整模块 import NameError,回归被验证拦截)
- register_loop + subscribe 调整至 accept 之前,缩小连接已开但未订阅期间的进度丢失窗口
- 新增 tests/test_verify_ws_real_flow.py:驱动真实 HTTP 聊天流程断言 WS 收到 agent 实际发射的 parse/impact 进度
- 同步 WebSocket 计划文档 Task 3 代码片段(标注端点必须位于 create_app 内)
- 全量 pytest 实测 583 passed / 99.03% 达标
2.9 KiB
2.9 KiB
Task 2 报告:agent 产出进度/错误时发射事件
状态
完成(2 passed)。
提交
- 提交短哈希:
8493bea - 提交信息:
feat(chat): agent 产出进度/错误时发射事件(保留持久化兜底) - 仅变更:
src/genesis/chat/agent.py、tests/test_chat_agent_ws.py
测试输出摘要
python -m pytest tests/test_chat_agent_ws.py -q -o addopts=""→2 passedpython -m pytest tests/test_chat_agent.py tests/test_server_chat_api.py -q -o addopts=""→43 passed(既有聊天测试全绿,未破坏)
实现要点
- 顶部新增导入
from genesis.server.hub import hub as _progress_hub(原文件无hub局部变量/导入,故直接用_progress_hub别名,无冲突)。 ChatAgent.__init__新增可选参数progress_sink: Callable[[dict], None] | None = None,保存为self.progress_sink。- 新增
_emit_progress(session_id, item)与_emit_error(session_id, reply, action):优先progress_sink回调,否则经_progress_hub.emit发射。 - 在全部
progress.append(item)之后紧接着调用self._emit_progress(session_id, progress[-1])(覆盖_handle_confirmation确认成功、_parse_and_confirm中 parse/impact、_run_impact的 impact、_run_generate的 generate/qa ok/qa warn、_run_qa的 qa ok 共 8 处)。 - 在全部错误分支调用
_store_error(...)之前先调用self._emit_error(session_id, reply, action)(共 6 处:confirm/generate(解析)/parse/impact/生成失败/qa)。 - 既有
_persist_progress/_store_error数据库持久化保持不变(重载兜底)。
疑虑与偏离
- 测试偏离说明(重要):任务给定的测试模板使用
SessionStore(db_path=":memory:")。但本仓库SessionStore的_conn()每次都新建连接,而:memory:每次连接是独立空库,_init_db()建表对后续create_session不可见,导致no such table: sessions。实测按原样:memory:两个测试均OperationalError失败。为达到「2 passed」目标,将测试中的:memory:改为临时目录下的真实文件(tempfile.mkdtemp+ 固定文件名),其余断言完全照抄。功能验证不受影响(两个测试仅直接调用_emit_progress/_emit_error,session_id 仅作占位)。建议后续评估SessionStore对:memory:的兼容性,或仓库统一测试约定。 - 旧错误回复写法:核查确认原
agent.py所有错误分支均已使用self._store_error(...)(无self.store.add_message(..., "assistant", ...)旧写法),故未改动错误回复的持久化写法,仅在每处_store_error前插入_emit_error。 - progress.append 位置:已逐处确认 8 个
progress.append均位于实际流程产出点;其中_parse_and_confirm内 emit 在if rec.status == "impact_running"分支的 impact append 之后,符合“每处 append 后 emit”的要求。