feat(chat): cut over to single SSE endpoint

This commit is contained in:
zhuyongxin
2026-07-22 10:01:12 +08:00
parent f8809cb7dd
commit bc36248cd8
36 changed files with 2187 additions and 945 deletions
@@ -0,0 +1,52 @@
## Why
阶段 6A 已完成内部 Chat Application Use Case,但公开入口仍由 `ChatController` 直接持有旧 `ChatService`、模型、工具、Redis 历史和无界线程池。当前 `/api/chat` 是同步 JSON,`/api/chat_stream` 则在完整答案生成后切片,既绕过新 Harness 释放边界,也让前端维持两套不一致消费者。
## What Changes
- 将唯一 `POST /api/chat` 原子切换为 `text/event-stream`,只调用阶段 6A `ChatApplicationUseCase`。
- 删除同步 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
- `ChatController` Chat 入口、SSE DTO/adapter、连接生命周期和 focused MVC tests。
- Harness 生产配置、集中 limits、受控 executors 和装配启动测试。
- `app.js`/`index.html` Chat 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 线程执行或无界排队。