core(§7 Phase G G4): chat 发送 + SSE 流式回复
- web/broker.py RunBroker:in-process pub/sub,subscribe/emit/close/
unsubscribe;同 run_id 多订阅者 fan-out(刷新 / 多 tab / 桌面+移动
都能同时看流);_done 集合让晚到订阅者立刻收 done(不挂)。
- web/sinks.py WebEventSink:实现 §7 A sink 协议,把 AgentLoop._emit
桥到 broker.emit(run_id, ev),AgentLoop 完全不知 web 存在。
- 异步策略 = asyncio.to_thread(不改 core):POST /tasks/{tid}/messages
async handler → INSERT runs 行 + asyncio.create_task(to_thread(
_run_agent_bg)),_run_agent_bg 工作线程跑 build_agent + agent.run,
sink 通过 loop.call_soon_threadsafe 跨线程把 event 桥回 asyncio queue。
- GET /tasks/{tid}/runs/{rid}/events:StreamingResponse async gen,
响应头 text/event-stream + Cache-Control: no-cache + X-Accel-
Buffering: no(nginx 反代友好);第一帧 retry/connected 让 ES 立
即建立,30s 无 event 发 : ping 心跳。SSE multi-line data 每行加
data: 前缀(SSE spec),客户端 ES 自动还原 \n 拼接的 HTML。
- _render_event_fragment 渲染 text/tool_call/tool_result/error
HTML 片段;run_start/llm_start/llm_end/done 发空 data(只让客户端
识别 event type)。
- 新模板:_frag_text/_frag_tool_call/_frag_tool_result/_frag_error +
_send_response(POST 响应:user msg 卡 + msg-assistant streaming
容器带 sse-connect/sse-swap/sse-close)。
- chat.html 加 send 表单(Enter 发,Shift+Enter 换行,HTMX hx-post /
hx-target=#chat-stream / hx-swap=beforeend / 提交后 reset);chat
section 改 id=chat-stream;非 active task 隐藏表单。
- CSS:.streaming .run-indicator 红点脉冲 / .send-form 输入框 /
.tool-result-inline 追加式样式 / .msg-error 错误卡。
- runs 表写状态:POST 时 status=running,正常完结 ok + tokens_p/c,
异常 error + error 文本(DB 写失败不放大噪声,已 emit error 给前端)。
- lifespan bind_loop(asyncio.get_running_loop()) 让 broker 拿到
loop 引用,emit 跨线程才能 call_soon_threadsafe。
- RUN 故障兜底加 3 条:SSE 经 nginx 卡住、浏览器 send 无反应、并发
POST messages idx 冲突(已知 TODO)。
Smoke 双层全绿:
- broker 单元 8 case (subscribe/emit/get/fan-out/跨 run 隔离/close/
late subscribe instant done/unsubscribe/未 bind silent drop)
- 端到端 24 case (POST 200 + sse-connect/run_id 抽取 + content-type/
x-accel-buffering/cache-control 头对 + event 序列 run_start→done
+ text 片段 <strong> + tool_call <details> + tool_result preview
+ empty body 400 + 各种 404 + late done + runs 行 INSERT)
版本 0.3 → 0.4。
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>