Files
zclaw_openfang/wiki/chat.md
iven ed77095a37
Some checks failed
CI / Lint & TypeCheck (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Build Frontend (push) Has been cancelled
CI / Rust Check (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled
docs(wiki): 系统性更新 — L0速览+L1模块标准化+L2功能链路映射(33条)
三层架构增强:
- L0 index.md: 用户功能清单+跨模块数据流全景图+导航树增强 (92→143行)
- L1 8个模块页标准化: 功能清单/API接口/测试链路/已知问题
  routing(252→326) chat(101→157) saas(153→230) memory(182→333)
  butler(137→179) middleware(121→159) hands-skills(218→257) pipeline(111→156)
- L1 新增2页: security.md(157行) data-model.md(180行)
- L2 feature-map.md: 33条端到端功能链路映射(408行)

维护机制: CLAUDE.md §8.3 wiki触发规则 5→9条
设计文档: docs/superpowers/specs/2026-04-21-wiki-systematic-overhaul-design.md
2026-04-21 23:48:19 +08:00

158 lines
6.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
title: 聊天系统
updated: 2026-04-21
status: active
tags: [module, chat, stream]
---
# 聊天系统
> 从 [[index]] 导航。关联模块: [[routing]] [[saas]] [[butler]]
## 设计思想
**核心问题: 3 种运行环境需要 3 种 ChatStream 实现。**
| 环境 | 实现 | 传输 | 为什么 |
|------|------|------|--------|
| 桌面端 (Tauri) | KernelClient | Tauri Event | 内置 Kernel但 baseUrl 可指向 SaaS relay |
| 桌面端 (Tauri + SaaS) | KernelClient + relay | Tauri Event → SaaS | 主路径: Token Pool 中转 |
| 浏览器端 | SaaSRelayGatewayClient | HTTP SSE | 无 Tauri 运行时 |
| 外部 Gateway | GatewayClient | WebSocket | 独立进程部署 |
**统一接口**: 3 种实现共享同一套回调:
```ts
{ onDelta, onThinkingDelta, onTool, onHand, onComplete, onError }
```
## 功能清单
| 功能 | 描述 | 入口文件 | 状态 |
|------|------|----------|------|
| 发送消息 | 流式/非流式,支持 thinking | streamStore.ts | ✅ |
| 流式响应 | SSE/Tauri Event 实时推送 | streamStore.ts | ✅ |
| 模型切换 | 运行时切换 LLM 模型 | conversationStore.ts | ✅ |
| 上下文管理 | 会话持久化 + 跨会话恢复 | conversationStore.ts | ✅ |
| 取消流式 | 原子标志位中断 | kernel-chat.ts | ✅ |
| Agent 聊天 | 指定 agent_id 独立对话 | streamStore.ts | ✅ |
| 课堂聊天 | 教育场景专用 | classroomStore.ts | ✅ |
| 消息持久化 | IndexedDB 存储 | messageStore.ts | ✅ |
| 聊天产物 | 附件/代码块管理 | artifactStore.ts | ✅ |
## 代码逻辑
### 发送消息流
入口: `streamStore.sendMessage(content)``store/chat/streamStore.ts`
```
sendMessage(content)
→ effectiveSessionKey = conversationStore.sessionKey || uuid()
→ effectiveAgentId = resolveGatewayAgentId(currentAgent)
→ client.chatStream(content, callbacks, { sessionKey, agentId, chatMode })
→ KernelClient: Tauri invoke('kernel_chat', ...)
→ Kernel → loop_runner → LLM Driver
→ 如果 baseUrl 指向 SaaS relay → 请求发往 Token Pool → LLM
→ 如果 baseUrl 指向 LLM 直连 → 请求直接发往 LLM
→ Tauri Event emit('chat-response-delta', ...)
→ onDelta(text) → streamStore 追加 delta
→ onTool(tool) → toolStore 更新
→ onHand(hand) → handStore 更新
→ onComplete() → conversationStore 持久化
→ SaaSRelay: HTTP POST /api/v1/relay/chat/completions → SSE
→ GatewayClient: WebSocket send → onmessage
→ 5 分钟超时守护 (kernel-chat.ts:76) 防止流挂起
```
### Store 拆分 (5 Store)
原来 908 行的 ChatStore 已拆分为:
| Store | 文件 | 职责 |
|-------|------|------|
| streamStore | `store/chat/streamStore.ts` | 流式消息编排、发送、取消 |
| conversationStore | `store/chat/conversationStore.ts` | 会话管理、当前模型 |
| messageStore | `store/chat/messageStore.ts` | 消息持久化 |
| chatStore | `store/chat/chatStore.ts` | 聊天通用状态 |
| artifactStore | `store/chat/artifactStore.ts` | 聊天产物/附件 |
### 前端 Tauri 命令映射
```
kernel_chat / agent_chat / agent_chat_stream → 发送消息
cancel_stream → 取消流式响应
```
### 模型切换
```
UI 选择模型 → conversationStore.currentModel = newModel
→ 下次 sendMessage 时connectionStore 读取 currentModel
→ SaaS 模式: relay 白名单验证 → 可用则切换
→ 本地模式: 直接使用用户配置的模型
```
## API 接口
### Tauri 命令
**聊天核心** (`desktop/src-tauri/src/kernel_commands/chat.rs`):
| 命令 | 参数 | 返回值 | 说明 |
|------|------|--------|------|
| `agent_chat` | ChatRequest { agent_id, message, thinking_enabled?, model? } | `ChatResponse` | 非流式聊天 |
| `agent_chat_stream` | StreamChatRequest { +session_id } | Tauri Event 流 | 流式聊天(主路径) |
| `cancel_stream` | session_id | `()` | 取消当前流式 |
**课堂聊天** (`desktop/src-tauri/src/classroom_commands/chat.rs`):
| 命令 | 参数 | 返回值 | 说明 |
|------|------|--------|------|
| `classroom_chat` | { classroom_id, user_message, scene_context? } | `Vec<ClassroomChatMessage>` | 课堂对话 |
| `classroom_chat_history` | classroom_id | `Vec<ClassroomChatMessage>` | 历史消息 |
**流式事件类型** (agent_chat_stream emit):
`Delta` / `ThinkingDelta` / `ToolStart` / `ToolEnd` / `HandStart` / `HandEnd` / `SubtaskStatus` / `IterationStart` / `Complete` / `Error`
### SaaS Relay 路由
| 方法 | 路径 | 说明 |
|------|------|------|
| POST | `/api/v1/relay/chat/completions` | OpenAI 兼容格式,支持 session_key/agent_id 透传 |
## 测试链路
| 功能 | 测试文件 | 测试数 | 覆盖状态 |
|------|---------|--------|---------|
| ChatStore 完整流程 | `tests/desktop/chatStore.test.ts` | 11 | ✅ sendMessage/sessionKey/agent隔离/stream相关 |
| 类型契约测试 | `tests/seam/chat-seam.test.ts` | 8 | ✅ StreamChatRequest/ChatResponse camelCase/Event tagged union |
## 关联模块
- [[routing]] — 路由决定使用哪种 client
- [[saas]] — Token Pool 提供模型和 API Key
- [[butler]] — ButlerRouter 中间件增强 system prompt
- [[middleware]] — 消息经过 15 层 runtime 中间件处理
- [[memory]] — 对话内容可能触发记忆提取
## 关键文件
| 文件 | 职责 |
|------|------|
| `desktop/src/store/chat/streamStore.ts` | 流式消息编排 |
| `desktop/src/store/chat/conversationStore.ts` | 会话管理 |
| `desktop/src/store/chat/artifactStore.ts` | 聊天产物管理 |
| `desktop/src/lib/kernel-chat.ts` | Kernel ChatStream (Tauri) |
| `desktop/src/lib/saas-relay-client.ts` | SaaS Relay ChatStream |
| `desktop/src/lib/gateway-client.ts` | Gateway ChatStream (WS) |
| `desktop/src/components/ChatArea.tsx` | 聊天区域 UI |
| `crates/zclaw-runtime/src/loop_runner.rs` | Rust 主聊天循环 |
## 已知问题
- ⚠️ **B-CHAT-07: 混合域截断** — P2 Open。跨域消息时可能截断上下文
-**SSE Token 统计为 0** — P2 已修复 (SseUsageCapture stream_done flag)
-**Tauri invoke 参数名 snake_case** — P1 已修复 (commit f6c5dd2)
-**Provider Key 解密致 relay 500** — P1 已修复 (commit b69dc61)