3.3 KiB
3.3 KiB
Why
阶段 6A 已完成内部 Chat Application Use Case,但公开入口仍由 ChatController 直接持有旧 ChatService、模型、工具、Redis 历史和无界线程池。当前 /api/chat 是同步 JSON,/api/chat_stream 则在完整答案生成后切片,既绕过新 Harness 释放边界,也让前端维持两套不一致消费者。
What Changes
- 将唯一
POST /api/chat原子切换为text/event-stream,只调用阶段 6AChatApplicationUseCase。 - 删除同步 Chat 响应路径和
/api/chat_stream,Controller 不再获取 ChatModel、ToolCallbackProvider、旧 Session 历史或 ChatService。 - 固定五类 SSE 事件与顺序:
metadata -> status* -> content|failure -> done;业务 event name 与 payload schema 均稳定。 content最多一次且只承载阶段 6A typed safe content,不做 Token/字符切片;技术失败使用一次failure。- 客户端断开、SSE timeout 或发送失败取消同一个
ChatRunControl,内部 Run 记录 CANCELLED,断开后不再发送终态。 - 使用 Spring 管理的有界 Chat worker 和 Harness model executor;Controller 不创建线程池。
- 新增完整 Harness 生产 Bean 装配,使 Router、三类 executor、Diagnosis Agent、Guards、canonical Tool boundary 和 JPA store 使用同一 Core/ChatModel/ObjectMapper。
- 前端删除快速/流式双模式,统一以 fetch streaming 消费
/api/chat的 named SSE events,并保存 metadata 中的 session/run ID。
Capabilities
New Capabilities
single-react-chat-sse-cutover: 定义唯一 Chat SSE 入口、五事件状态机、连接取消、生产 Harness 装配和前端消费者迁移。
Modified Capabilities
- None. 阶段 6A application use case 和
/api/ai_ops对外行为保持不变。
Scope
ChatControllerChat 入口、SSE DTO/adapter、连接生命周期和 focused MVC tests。- Harness 生产配置、集中 limits、受控 executors 和装配启动测试。
app.js/index.htmlChat consumer 和模式控件清理。- SSE schema/order/mutual exclusion/cancel/failure tests,以及阶段 2-6A regression。
Non-goals
- 不修改
/api/ai_ops协议或迁移其旧多 Agent 实现。 - 不删除旧 ChatService、Planner/Executor/Verifier/Composer、Hook 或 ThreadLocal;阶段 7 物理清理。
- 不实现 Token streaming、断线续传、事件重放、轮询或 WebSocket。
- 不运行真实模型/Redis/MySQL live E2E;阶段 7 统一完成。
Context Constraints
Diagnosis Agent是唯一拥有 Tool loop 的业务 Agent;Controller 和 SSE adapter 不得拥有模型或工具。- SemanticGuard 完成前不得发送
content;Fallback 使用content + done(FALLBACK),技术失败使用failure + done(FAILED)。 - metadata 固定第一且一次,done 固定最后且一次;content/failure 互斥。
- 这是 L4 破坏性公开协议变更,不保留旧 endpoint 或同步兼容分支。
Risks
- 阶段 6A 组件尚未生产装配,单改 Controller 会导致 Spring 启动失败。
- SseEmitter completion/error/timeout 与 worker 完成存在竞态,必须 first-terminal-wins 且断开后禁止继续发送。
- 前端解析器当前按单行 data 和旧
type字段兼容,迁移不完整会丢失 metadata、终态或错误。 - 有界 executor 饱和时必须 fail closed,不能退化为 Controller 线程执行或无界排队。