# PLAN: S4 — SSE 流式回复 ## Goal 新增 SSE endpoint 实现 AI 回复的逐字流式传输。 ## Current State - S3: call_hermes() 使用 subprocess.run(阻塞,一次性返回全部输出) - app.py: 已有 POST /api/conversations//messages(一次性回复) ## What to Build 1. 新增函数 `call_hermes_stream(user_input, timeout=120)` → generator yielding text chunks - 使用 subprocess.Popen 启动 `hermes chat -m ` - 用 stdout.readline() 逐行读取输出 - 每读到一行就 yield 出去 - 超时或结束时清理进程 2. 新增 SSE endpoint: `GET /api/conversations//stream?message=` - 使用 Flask Response + text/event-stream content type - 先保存用户消息到 DB - 构建历史上下文 - 调用 call_hermes_stream() 生成流式输出 - 每个 chunk 通过 SSE 发送: `data: \n\n` - 流结束后发送 `data: [DONE]\n\n` - 在生成器中累积全文,流结束后保存 AI 回复到 DB - 需要设置 threading 让 DB 写入不阻塞主线程 ## Files - `app.py`: 新增 call_hermes_stream() + GET /api/conversations//stream - `test_s4_sse.py`: 集成测试 ## Data Flow ``` Browser (EventSource) → GET /stream?message=hello → Flask saves user msg to DB → call_hermes_stream(history + message) → Popen(["hermes", "chat", "-m", input]) → for line in stdout: yield chunk → SSE to client → after loop: save full AI reply to DB ``` ## Risks - Flask's default WSGI server (Werkzeug) is single-threaded; SSE streaming blocks one worker - Need to ensure DB writes don't conflict with streaming - Popen process cleanup on client disconnect ## Verification - Syntax check - Unit test: mock Popen to verify SSE format - Smoke test: all 8 pass