docs(wiki): 重构为模块化知识库 — 按模块组织而非按文档类型
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

问题: 旧 wiki 按文档类型组织(architecture/data-flows/file-map),
修复 Butler Router 需要读 4 个文件才能拼凑全貌。
且 SaaS Relay 主路径 vs 本地降级的优先级描述不准确。

重构为模块化结构,每个模块页自包含:
- 设计思想: 为什么这样设计
- 代码逻辑: 数据流 + 关键代码
- 关联模块: 依赖关系

新增模块页:
- routing.md: 客户端路由 (明确 SaaS Relay 是主路径,不是本地模式)
- chat.md: 聊天系统 (3种实现 + Token Pool 中转机制)
- butler.md: 管家模式 (路由/冷启动/痛点/双模式UI)
- memory.md: 记忆管道 (提取→FTS5→检索→注入)
- saas.md: SaaS平台 (认证/Token池/计费/Admin)
- middleware.md: 中间件链 (14层 + 优先级)
- hands-skills.md: Hands(9) + Skills(75)
- pipeline.md: Pipeline DSL

删除旧文件: architecture.md, data-flows.md, module-status.md, file-map.md
(内容已分布到对应模块页中)

添加 .gitignore 排除 Obsidian 工作区状态文件
This commit is contained in:
iven
2026-04-11 00:36:26 +08:00
parent 9772d6ec94
commit 36a1c87d87
18 changed files with 839 additions and 627 deletions

105
wiki/routing.md Normal file
View File

@@ -0,0 +1,105 @@
---
title: 客户端路由
updated: 2026-04-11
status: active
tags: [module, routing, connection]
---
# 客户端路由
> 从 [[index]] 导航。关联模块: [[chat]] [[saas]]
## 设计思想
**核心决策: Tauri 桌面端通过 SaaS Token Pool 中转访问 LLM不直连。**
为什么?
1. **集中密钥管理** — 用户不需要自己的 API KeySaaS 维护共享 Key 池
2. **用量追踪 + 计费** — 每次调用经过 SaaS`record_usage` worker 记录 token 消耗
3. **模型白名单** — Admin 配置哪些模型可用,`listModels()` 返回白名单
4. **降级保障** — SaaS 挂了自动切本地 Kernel桌面端不变砖
## 代码逻辑
### 4 分支决策树
入口: `connectionStore.ts:349``connect(url?, token?)`
```
connect()
├── [1] Admin 强制路由: localStorage llm_routing
│ ├── "relay" → 强制 SaaS Relay 模式
│ └── "local" → 强制本地 Kernel (adminForceLocal=true)
├── [2] SaaS Relay 模式: localStorage('zclaw-connection-mode') === 'saas'
│ ├── Tauri: KernelClient + baseUrl = saasUrl/api/v1/relay
│ │ apiKey = SaaS JWT (不是 LLM Key!)
│ ├── Browser: SaaSRelayGatewayClient (SSE)
│ └── SaaS 不可达 → 降级到本地 Kernel
├── [3] 本地 Kernel: isTauriRuntime() === true
│ KernelClient + 用户自定义模型配置
│ 用户需要自己的 API Key
└── [4] External Gateway (fallback)
GatewayClient via WebSocket/REST
```
### SaaS Relay 主路径 (Tauri 桌面端)
关键代码: `connectionStore.ts:482-535`
```ts
kernelClient.setConfig({
provider: 'custom',
model: modelToUse, // 从 SaaS listModels() 获取
apiKey: session.token, // SaaS JWT不是 LLM Key
baseUrl: `${session.saasUrl}/api/v1/relay`, // 指向 SaaS relay
apiProtocol: 'openai',
});
```
**注意**: Kernel 仍然执行 LLM 调用逻辑,但请求发往 SaaS relay 而非直连 LLM。
SaaS relay 接到请求后,从 Token Pool 中取一个可用 Key转发给真实 LLM。
### SaaS 降级流程
关键代码: `connectionStore.ts:446-468`
```
listModels() 失败
→ 401 → session 过期 → logout → 要求重新登录
→ 其他错误 → saasDegraded = true
→ saasStore.saasReachable = false
→ 降级到本地 Kernel 模式
```
### 客户端类型
| 客户端 | 传输 | 文件 | 用途 |
|--------|------|------|------|
| GatewayClient | WebSocket + REST | `lib/gateway-client.ts` | 外部 Gateway 进程 |
| KernelClient | Tauri invoke() | `lib/kernel-chat.ts` | 内置 Kernel (桌面端) |
| SaaSRelayGatewayClient | HTTP SSE | `lib/saas-relay-client.ts` | 浏览器端 SaaS 中继 |
`getClient()` 定义: `connectionStore.ts:844`
所有 Store 通过 `initializeStores()` (store/index.ts:94) 获取共享 client。
## 关联模块
- [[chat]] — 路由决定使用哪种 ChatStream
- [[saas]] — Token Pool、认证、模型管理
- [[middleware]] — 请求经过中间件链处理
- [[butler]] — 管家模式通过 ButlerRouter 中间件介入
## 关键文件
| 文件 | 职责 |
|------|------|
| `desktop/src/store/connectionStore.ts` | 路由决策核心 (844行) |
| `desktop/src/lib/gateway-client.ts` | WebSocket 客户端 |
| `desktop/src/lib/kernel-chat.ts` | Tauri 内核聊天 |
| `desktop/src/lib/saas-relay-client.ts` | SaaS SSE 中继 |
| `desktop/src/lib/saas-client.ts` | SaaS API 客户端 |
| `desktop/src/store/index.ts` | Store 协调器 + client 注入 |