coding-tool-x 3.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +599 -0
- package/LICENSE +21 -0
- package/README.md +439 -0
- package/bin/ctx.js +8 -0
- package/dist/web/assets/Analytics-DN_YsnkW.js +39 -0
- package/dist/web/assets/Analytics-DuYvId7u.css +1 -0
- package/dist/web/assets/ConfigTemplates-Bidwfdf2.css +1 -0
- package/dist/web/assets/ConfigTemplates-DpXIMy0p.js +1 -0
- package/dist/web/assets/Home-38JTUlYt.js +1 -0
- package/dist/web/assets/Home-CjupSEWE.css +1 -0
- package/dist/web/assets/PluginManager-CX2tgq2H.js +1 -0
- package/dist/web/assets/PluginManager-ROyoZ-6m.css +1 -0
- package/dist/web/assets/ProjectList-C1lDcsn6.js +1 -0
- package/dist/web/assets/ProjectList-oJIyIRkP.css +1 -0
- package/dist/web/assets/SessionList-C55tjV7i.css +1 -0
- package/dist/web/assets/SessionList-CZ7T6rVx.js +1 -0
- package/dist/web/assets/SkillManager-D7pd-d_P.css +1 -0
- package/dist/web/assets/SkillManager-DLN9f79y.js +1 -0
- package/dist/web/assets/WorkspaceManager-CrwgQgmP.css +1 -0
- package/dist/web/assets/WorkspaceManager-DxlHZkpZ.js +1 -0
- package/dist/web/assets/icons-DRrXwWZi.js +1 -0
- package/dist/web/assets/index-CetESrXw.css +1 -0
- package/dist/web/assets/index-Cfvn-2Gb.js +2 -0
- package/dist/web/assets/markdown-BfC0goYb.css +10 -0
- package/dist/web/assets/markdown-C9MYpaSi.js +1 -0
- package/dist/web/assets/naive-ui-DlpKk-8M.js +1 -0
- package/dist/web/assets/vendors-DMjSfzlv.js +7 -0
- package/dist/web/assets/vue-vendor-DET08QYg.js +45 -0
- package/dist/web/favicon.ico +0 -0
- package/dist/web/index.html +20 -0
- package/dist/web/logo.png +0 -0
- package/docs/bannel.png +0 -0
- package/docs/home.png +0 -0
- package/docs/logo.png +0 -0
- package/docs/model-redirection.md +251 -0
- package/docs/multi-channel-load-balancing.md +249 -0
- package/package.json +80 -0
- package/src/commands/channels.js +551 -0
- package/src/commands/cli-type.js +101 -0
- package/src/commands/daemon.js +365 -0
- package/src/commands/doctor.js +333 -0
- package/src/commands/export-config.js +205 -0
- package/src/commands/list.js +222 -0
- package/src/commands/logs.js +261 -0
- package/src/commands/plugin.js +585 -0
- package/src/commands/port-config.js +135 -0
- package/src/commands/proxy-control.js +264 -0
- package/src/commands/proxy.js +152 -0
- package/src/commands/resume.js +137 -0
- package/src/commands/search.js +190 -0
- package/src/commands/security.js +37 -0
- package/src/commands/stats.js +398 -0
- package/src/commands/switch.js +48 -0
- package/src/commands/toggle-proxy.js +247 -0
- package/src/commands/ui.js +99 -0
- package/src/commands/update.js +97 -0
- package/src/commands/workspace.js +454 -0
- package/src/config/default.js +69 -0
- package/src/config/loader.js +149 -0
- package/src/config/model-metadata.js +167 -0
- package/src/config/model-metadata.json +125 -0
- package/src/config/model-pricing.js +35 -0
- package/src/config/paths.js +190 -0
- package/src/index.js +680 -0
- package/src/plugins/constants.js +15 -0
- package/src/plugins/event-bus.js +54 -0
- package/src/plugins/manifest-validator.js +129 -0
- package/src/plugins/plugin-api.js +128 -0
- package/src/plugins/plugin-installer.js +601 -0
- package/src/plugins/plugin-loader.js +229 -0
- package/src/plugins/plugin-manager.js +170 -0
- package/src/plugins/registry.js +152 -0
- package/src/plugins/schema/plugin-manifest.json +115 -0
- package/src/reset-config.js +94 -0
- package/src/server/api/agents.js +826 -0
- package/src/server/api/aliases.js +36 -0
- package/src/server/api/channels.js +368 -0
- package/src/server/api/claude-hooks.js +480 -0
- package/src/server/api/codex-channels.js +417 -0
- package/src/server/api/codex-projects.js +104 -0
- package/src/server/api/codex-proxy.js +195 -0
- package/src/server/api/codex-sessions.js +483 -0
- package/src/server/api/codex-statistics.js +57 -0
- package/src/server/api/commands.js +482 -0
- package/src/server/api/config-export.js +212 -0
- package/src/server/api/config-registry.js +357 -0
- package/src/server/api/config-sync.js +155 -0
- package/src/server/api/config-templates.js +248 -0
- package/src/server/api/config.js +521 -0
- package/src/server/api/convert.js +260 -0
- package/src/server/api/dashboard.js +142 -0
- package/src/server/api/env.js +144 -0
- package/src/server/api/favorites.js +77 -0
- package/src/server/api/gemini-channels.js +366 -0
- package/src/server/api/gemini-projects.js +91 -0
- package/src/server/api/gemini-proxy.js +173 -0
- package/src/server/api/gemini-sessions.js +376 -0
- package/src/server/api/gemini-statistics.js +57 -0
- package/src/server/api/health-check.js +31 -0
- package/src/server/api/mcp.js +399 -0
- package/src/server/api/opencode-channels.js +419 -0
- package/src/server/api/opencode-projects.js +99 -0
- package/src/server/api/opencode-proxy.js +207 -0
- package/src/server/api/opencode-sessions.js +327 -0
- package/src/server/api/opencode-statistics.js +57 -0
- package/src/server/api/plugins.js +463 -0
- package/src/server/api/pm2-autostart.js +269 -0
- package/src/server/api/projects.js +124 -0
- package/src/server/api/prompts.js +279 -0
- package/src/server/api/proxy.js +306 -0
- package/src/server/api/security.js +53 -0
- package/src/server/api/sessions.js +514 -0
- package/src/server/api/settings.js +142 -0
- package/src/server/api/skills.js +570 -0
- package/src/server/api/statistics.js +238 -0
- package/src/server/api/ui-config.js +64 -0
- package/src/server/api/workspaces.js +456 -0
- package/src/server/codex-proxy-server.js +681 -0
- package/src/server/dev-server.js +26 -0
- package/src/server/gemini-proxy-server.js +610 -0
- package/src/server/index.js +422 -0
- package/src/server/opencode-proxy-server.js +4771 -0
- package/src/server/proxy-server.js +669 -0
- package/src/server/services/agents-service.js +1137 -0
- package/src/server/services/alias.js +71 -0
- package/src/server/services/channel-health.js +234 -0
- package/src/server/services/channel-scheduler.js +240 -0
- package/src/server/services/channels.js +447 -0
- package/src/server/services/codex-channels.js +705 -0
- package/src/server/services/codex-config.js +90 -0
- package/src/server/services/codex-parser.js +322 -0
- package/src/server/services/codex-sessions.js +936 -0
- package/src/server/services/codex-settings-manager.js +619 -0
- package/src/server/services/codex-speed-test-template.json +24 -0
- package/src/server/services/codex-statistics-service.js +161 -0
- package/src/server/services/commands-service.js +574 -0
- package/src/server/services/config-export-service.js +1165 -0
- package/src/server/services/config-registry-service.js +828 -0
- package/src/server/services/config-sync-manager.js +941 -0
- package/src/server/services/config-sync-service.js +504 -0
- package/src/server/services/config-templates-service.js +913 -0
- package/src/server/services/enhanced-cache.js +196 -0
- package/src/server/services/env-checker.js +409 -0
- package/src/server/services/env-manager.js +436 -0
- package/src/server/services/favorites.js +165 -0
- package/src/server/services/format-converter.js +620 -0
- package/src/server/services/gemini-channels.js +459 -0
- package/src/server/services/gemini-config.js +73 -0
- package/src/server/services/gemini-sessions.js +689 -0
- package/src/server/services/gemini-settings-manager.js +263 -0
- package/src/server/services/gemini-statistics-service.js +157 -0
- package/src/server/services/health-check.js +85 -0
- package/src/server/services/mcp-client.js +790 -0
- package/src/server/services/mcp-service.js +1732 -0
- package/src/server/services/model-detector.js +1245 -0
- package/src/server/services/network-access.js +80 -0
- package/src/server/services/opencode-channels.js +366 -0
- package/src/server/services/opencode-gateway-adapters.js +1168 -0
- package/src/server/services/opencode-gateway-converter.js +639 -0
- package/src/server/services/opencode-sessions.js +931 -0
- package/src/server/services/opencode-settings-manager.js +478 -0
- package/src/server/services/opencode-statistics-service.js +161 -0
- package/src/server/services/plugins-service.js +1268 -0
- package/src/server/services/prompts-service.js +534 -0
- package/src/server/services/proxy-runtime.js +79 -0
- package/src/server/services/repo-scanner-base.js +708 -0
- package/src/server/services/request-logger.js +130 -0
- package/src/server/services/response-decoder.js +21 -0
- package/src/server/services/security-config.js +131 -0
- package/src/server/services/session-cache.js +127 -0
- package/src/server/services/session-converter.js +577 -0
- package/src/server/services/sessions.js +900 -0
- package/src/server/services/settings-manager.js +163 -0
- package/src/server/services/skill-service.js +1482 -0
- package/src/server/services/speed-test.js +1146 -0
- package/src/server/services/statistics-service.js +1043 -0
- package/src/server/services/ui-config.js +132 -0
- package/src/server/services/workspace-service.js +830 -0
- package/src/server/utils/pricing.js +73 -0
- package/src/server/websocket-server.js +513 -0
- package/src/ui/menu.js +139 -0
- package/src/ui/prompts.js +100 -0
- package/src/utils/format.js +43 -0
- package/src/utils/port-helper.js +108 -0
- package/src/utils/session.js +240 -0
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
# 模型重定向功能
|
|
2
|
+
|
|
3
|
+
## 功能概述
|
|
4
|
+
|
|
5
|
+
模型重定向功能允许在代理模式下自动将高成本模型请求重定向到低成本模型,从而节省 token 消耗。
|
|
6
|
+
|
|
7
|
+
例如:将 `claude-opus-4` 重定向到 `claude-sonnet-4-5`,可以大幅降低成本,同时保持良好的性能。
|
|
8
|
+
|
|
9
|
+
## 使用场景
|
|
10
|
+
|
|
11
|
+
- GitHub 插件或 oh-my-claudecode skills 默认使用 opus 模型
|
|
12
|
+
- 修改这些插件/skills 的模型配置过于复杂
|
|
13
|
+
- 希望在不修改代码的情况下降低 token 消耗
|
|
14
|
+
|
|
15
|
+
## 工作原理
|
|
16
|
+
|
|
17
|
+
### 双重语义
|
|
18
|
+
|
|
19
|
+
`modelConfig` 字段根据代理状态有不同的含义:
|
|
20
|
+
|
|
21
|
+
| 代理状态 | 语义 | 行为 |
|
|
22
|
+
|---------|------|------|
|
|
23
|
+
| **代理关闭** | 模型映射 | 写入 `~/.claude/settings.json`,Claude Code CLI 读取环境变量 |
|
|
24
|
+
| **代理开启** | 模型重定向 | 在代理服务器中拦截请求,修改 `model` 字段 |
|
|
25
|
+
|
|
26
|
+
### 重定向规则
|
|
27
|
+
|
|
28
|
+
1. **层级检测**:根据模型名称检测层级(opus/sonnet/haiku)
|
|
29
|
+
2. **优先级匹配**:
|
|
30
|
+
- 优先使用层级特定配置(如 `opusModel`)
|
|
31
|
+
- 回退到通用配置(`model`)
|
|
32
|
+
- 无配置则保持原样
|
|
33
|
+
|
|
34
|
+
### 示例
|
|
35
|
+
|
|
36
|
+
**配置**:
|
|
37
|
+
```json
|
|
38
|
+
{
|
|
39
|
+
"modelConfig": {
|
|
40
|
+
"opusModel": "claude-sonnet-4-5",
|
|
41
|
+
"sonnetModel": "",
|
|
42
|
+
"haikuModel": ""
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
**重定向结果**:
|
|
48
|
+
- `claude-opus-4-20250514` → `claude-sonnet-4-5`
|
|
49
|
+
- `claude-sonnet-4-5` → `claude-sonnet-4-5`(不变)
|
|
50
|
+
- `claude-3-5-haiku-20241022` → `claude-3-5-haiku-20241022`(不变)
|
|
51
|
+
|
|
52
|
+
## 配置方法
|
|
53
|
+
|
|
54
|
+
### 1. 官方渠道
|
|
55
|
+
|
|
56
|
+
在渠道编辑面板中,展开 **"模型重定向"** 部分:
|
|
57
|
+
|
|
58
|
+
- **Haiku 重定向**:将所有 haiku 模型重定向到指定模型
|
|
59
|
+
- **Sonnet 重定向**:将所有 sonnet 模型重定向到指定模型
|
|
60
|
+
- **Opus 重定向**:将所有 opus 模型重定向到指定模型(推荐配置为 sonnet)
|
|
61
|
+
|
|
62
|
+
### 2. 非官方渠道
|
|
63
|
+
|
|
64
|
+
在渠道编辑面板中,展开 **"模型配置"** 部分:
|
|
65
|
+
|
|
66
|
+
- 代理关闭时:作为模型映射使用
|
|
67
|
+
- 代理开启时:作为模型重定向使用
|
|
68
|
+
|
|
69
|
+
## 测试步骤
|
|
70
|
+
|
|
71
|
+
### 前置条件
|
|
72
|
+
|
|
73
|
+
1. 启动代理:`ctx proxy start`
|
|
74
|
+
2. 配置渠道的模型重定向规则
|
|
75
|
+
3. 确保渠道已启用
|
|
76
|
+
|
|
77
|
+
### 测试用例
|
|
78
|
+
|
|
79
|
+
#### 测试 1:Opus → Sonnet 重定向
|
|
80
|
+
|
|
81
|
+
**配置**:
|
|
82
|
+
```json
|
|
83
|
+
{
|
|
84
|
+
"opusModel": "claude-sonnet-4-5"
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
**测试命令**:
|
|
89
|
+
```bash
|
|
90
|
+
curl -X POST http://localhost:<proxy-port>/v1/messages \
|
|
91
|
+
-H "Content-Type: application/json" \
|
|
92
|
+
-H "x-api-key: sk-test" \
|
|
93
|
+
-d '{
|
|
94
|
+
"model": "claude-opus-4-20250514",
|
|
95
|
+
"max_tokens": 100,
|
|
96
|
+
"messages": [{"role": "user", "content": "Hello"}]
|
|
97
|
+
}'
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
**预期结果**:
|
|
101
|
+
- 控制台输出:`[Model Redirect] claude-opus-4-20250514 → claude-sonnet-4-5 (channel: <渠道名>)`
|
|
102
|
+
- 请求成功返回
|
|
103
|
+
|
|
104
|
+
#### 测试 2:无重定向配置
|
|
105
|
+
|
|
106
|
+
**配置**:
|
|
107
|
+
```json
|
|
108
|
+
{
|
|
109
|
+
"opusModel": "",
|
|
110
|
+
"sonnetModel": "",
|
|
111
|
+
"haikuModel": ""
|
|
112
|
+
}
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
**测试命令**:同上
|
|
116
|
+
|
|
117
|
+
**预期结果**:
|
|
118
|
+
- 无控制台输出(不重定向)
|
|
119
|
+
- 请求使用原始模型
|
|
120
|
+
|
|
121
|
+
#### 测试 3:Haiku 保持不变
|
|
122
|
+
|
|
123
|
+
**配置**:
|
|
124
|
+
```json
|
|
125
|
+
{
|
|
126
|
+
"opusModel": "claude-sonnet-4-5",
|
|
127
|
+
"haikuModel": ""
|
|
128
|
+
}
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
**测试命令**:
|
|
132
|
+
```bash
|
|
133
|
+
curl -X POST http://localhost:<proxy-port>/v1/messages \
|
|
134
|
+
-H "Content-Type: application/json" \
|
|
135
|
+
-H "x-api-key: sk-test" \
|
|
136
|
+
-d '{
|
|
137
|
+
"model": "claude-3-5-haiku-20241022",
|
|
138
|
+
"max_tokens": 100,
|
|
139
|
+
"messages": [{"role": "user", "content": "Hello"}]
|
|
140
|
+
}'
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
**预期结果**:
|
|
144
|
+
- 无控制台输出(haiku 未配置重定向)
|
|
145
|
+
- 请求使用原始 haiku 模型
|
|
146
|
+
|
|
147
|
+
## 实现细节
|
|
148
|
+
|
|
149
|
+
### 代码位置
|
|
150
|
+
|
|
151
|
+
- **后端逻辑**:
|
|
152
|
+
- `src/server/proxy-server.js` (Claude 代理)
|
|
153
|
+
- `src/server/codex-proxy-server.js` (Codex 代理)
|
|
154
|
+
|
|
155
|
+
- **前端 UI**:
|
|
156
|
+
- `src/web/src/components/channel/channelPanelFactories.js`
|
|
157
|
+
|
|
158
|
+
### 核心函数
|
|
159
|
+
|
|
160
|
+
```javascript
|
|
161
|
+
// 检测模型层级
|
|
162
|
+
function detectModelTier(modelName) {
|
|
163
|
+
if (!modelName) return null;
|
|
164
|
+
const lower = modelName.toLowerCase();
|
|
165
|
+
if (lower.includes('opus')) return 'opus';
|
|
166
|
+
if (lower.includes('sonnet')) return 'sonnet';
|
|
167
|
+
if (lower.includes('haiku')) return 'haiku';
|
|
168
|
+
return null;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// 应用模型重定向
|
|
172
|
+
function redirectModel(originalModel, modelConfig) {
|
|
173
|
+
if (!modelConfig || !originalModel) return originalModel;
|
|
174
|
+
|
|
175
|
+
const tier = detectModelTier(originalModel);
|
|
176
|
+
|
|
177
|
+
// 优先级:层级特定配置 > 通用模型覆盖
|
|
178
|
+
if (tier === 'opus' && modelConfig.opusModel) {
|
|
179
|
+
return modelConfig.opusModel;
|
|
180
|
+
}
|
|
181
|
+
if (tier === 'sonnet' && modelConfig.sonnetModel) {
|
|
182
|
+
return modelConfig.sonnetModel;
|
|
183
|
+
}
|
|
184
|
+
if (tier === 'haiku' && modelConfig.haikuModel) {
|
|
185
|
+
return modelConfig.haikuModel;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// 回退到通用模型覆盖
|
|
189
|
+
if (modelConfig.model) {
|
|
190
|
+
return modelConfig.model;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
return originalModel;
|
|
194
|
+
}
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
### 请求流程
|
|
198
|
+
|
|
199
|
+
```
|
|
200
|
+
Client Request
|
|
201
|
+
↓
|
|
202
|
+
Proxy Server (allocate channel)
|
|
203
|
+
↓
|
|
204
|
+
Check req.body.model
|
|
205
|
+
↓
|
|
206
|
+
Apply redirectModel(originalModel, channel.modelConfig)
|
|
207
|
+
↓
|
|
208
|
+
Update req.body.model & req.rawBody
|
|
209
|
+
↓
|
|
210
|
+
Forward to upstream API
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
## 注意事项
|
|
214
|
+
|
|
215
|
+
1. **仅在代理开启时生效**:代理关闭时,modelConfig 用于模型映射
|
|
216
|
+
2. **不修改响应**:只修改请求中的 model 字段,不影响响应
|
|
217
|
+
3. **日志记录**:每次重定向都会在控制台输出日志
|
|
218
|
+
4. **向后兼容**:未配置重定向时,保持原有行为
|
|
219
|
+
|
|
220
|
+
## 常见问题
|
|
221
|
+
|
|
222
|
+
### Q: 为什么我的重定向没有生效?
|
|
223
|
+
|
|
224
|
+
A: 检查以下几点:
|
|
225
|
+
1. 代理是否已启动(`ctx proxy status`)
|
|
226
|
+
2. 渠道的 modelConfig 是否正确配置
|
|
227
|
+
3. 渠道是否已启用
|
|
228
|
+
4. 查看控制台是否有重定向日志
|
|
229
|
+
|
|
230
|
+
### Q: 可以将 sonnet 重定向到 opus 吗?
|
|
231
|
+
|
|
232
|
+
A: 可以,但不推荐。重定向的目的是降低成本,将低成本模型重定向到高成本模型会增加开销。
|
|
233
|
+
|
|
234
|
+
### Q: 重定向会影响响应质量吗?
|
|
235
|
+
|
|
236
|
+
A: 取决于重定向的目标模型。例如 opus → sonnet 可能会略微降低质量,但通常差异不大。建议根据实际场景测试。
|
|
237
|
+
|
|
238
|
+
### Q: 可以为不同渠道配置不同的重定向规则吗?
|
|
239
|
+
|
|
240
|
+
A: 可以。每个渠道都有独立的 modelConfig,可以配置不同的重定向规则。
|
|
241
|
+
|
|
242
|
+
## 成本节省示例
|
|
243
|
+
|
|
244
|
+
假设使用 oh-my-claudecode 的 opus 级别 agent:
|
|
245
|
+
|
|
246
|
+
| 场景 | 原始模型 | 重定向模型 | 输入成本 | 输出成本 | 节省比例 |
|
|
247
|
+
|------|---------|-----------|---------|---------|---------|
|
|
248
|
+
| 默认 | opus-4 | - | $15/M | $75/M | - |
|
|
249
|
+
| 重定向 | opus-4 | sonnet-4-5 | $3/M | $15/M | 80% |
|
|
250
|
+
|
|
251
|
+
对于大量使用 opus 的场景,成本节省非常显著。
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
# 多渠道负载均衡与智能切换
|
|
2
|
+
|
|
3
|
+
本文档详细说明 Coding-Tool 的多渠道负载均衡系统的设计和工作原理。
|
|
4
|
+
|
|
5
|
+
## 功能概述
|
|
6
|
+
|
|
7
|
+
多渠道负载均衡系统允许用户配置多个 API 渠道,系统会根据权重、并发限制和健康状态智能分配请求,实现:
|
|
8
|
+
|
|
9
|
+
- **负载分散**:将请求分散到多个渠道,避免单点压力
|
|
10
|
+
- **故障转移**:自动检测故障渠道并切换到健康渠道
|
|
11
|
+
- **会话连续性**:可选的会话绑定,保证对话上下文
|
|
12
|
+
|
|
13
|
+
## 模块架构
|
|
14
|
+
|
|
15
|
+
```
|
|
16
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
17
|
+
│ proxy-server.js │
|
|
18
|
+
│ (代理服务器入口) │
|
|
19
|
+
└─────────────────────┬───────────────────────────────────────────┘
|
|
20
|
+
│ 请求分配 / 结果记录
|
|
21
|
+
▼
|
|
22
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
23
|
+
│ channel-scheduler.js │
|
|
24
|
+
│ (渠道调度器) │
|
|
25
|
+
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
|
|
26
|
+
│ │ 加权随机选择 │ │ 并发控制 │ │ 会话绑定 │ │
|
|
27
|
+
│ └─────────────┘ └─────────────┘ └─────────────┘ │
|
|
28
|
+
└─────────────────────┬───────────────────────────────────────────┘
|
|
29
|
+
│ 健康检查
|
|
30
|
+
▼
|
|
31
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
32
|
+
│ channel-health.js │
|
|
33
|
+
│ (健康检查模块) │
|
|
34
|
+
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
|
|
35
|
+
│ │ 故障检测 │ │ 冻结管理 │ │ 自动恢复 │ │
|
|
36
|
+
│ └─────────────┘ └─────────────┘ └─────────────┘ │
|
|
37
|
+
└─────────────────────────────────────────────────────────────────┘
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## 核心模块说明
|
|
41
|
+
|
|
42
|
+
### 1. channel-scheduler.js(渠道调度器)
|
|
43
|
+
|
|
44
|
+
负责请求的渠道分配和并发控制。
|
|
45
|
+
|
|
46
|
+
#### 主要功能
|
|
47
|
+
|
|
48
|
+
| 功能 | 说明 |
|
|
49
|
+
|------|------|
|
|
50
|
+
| `allocateChannel()` | 分配一个可用渠道 |
|
|
51
|
+
| `releaseChannel()` | 释放渠道(请求完成时调用) |
|
|
52
|
+
| `getSchedulerState()` | 获取调度器状态 |
|
|
53
|
+
|
|
54
|
+
#### 加权随机算法
|
|
55
|
+
|
|
56
|
+
```javascript
|
|
57
|
+
// 权重越高,被选中概率越大
|
|
58
|
+
// 例如:渠道A(权重2) + 渠道B(权重1) + 渠道C(权重1)
|
|
59
|
+
// A 被选中概率 = 2/4 = 50%
|
|
60
|
+
// B 被选中概率 = 1/4 = 25%
|
|
61
|
+
// C 被选中概率 = 1/4 = 25%
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
#### 并发控制
|
|
65
|
+
|
|
66
|
+
- `maxConcurrency = null`:无并发限制
|
|
67
|
+
- `maxConcurrency = N`:最多同时处理 N 个请求
|
|
68
|
+
- 超过并发限制的请求进入队列等待(最长 15 秒)
|
|
69
|
+
|
|
70
|
+
#### 会话绑定(可选)
|
|
71
|
+
|
|
72
|
+
- **开启时**:同一 sessionId 的请求始终使用同一渠道
|
|
73
|
+
- **关闭时**:每次请求独立进行加权随机分配
|
|
74
|
+
- 配置位置:设置 → 高级设置 → 多渠道负载会话绑定
|
|
75
|
+
|
|
76
|
+
### 2. channel-health.js(健康检查模块)
|
|
77
|
+
|
|
78
|
+
负责监控渠道健康状态,自动冻结故障渠道。
|
|
79
|
+
|
|
80
|
+
#### 状态流转
|
|
81
|
+
|
|
82
|
+
```
|
|
83
|
+
连续成功5次
|
|
84
|
+
┌──────────────────┐
|
|
85
|
+
│ │
|
|
86
|
+
▼ │
|
|
87
|
+
┌────────┐ 连续失败3次 ┌──────────┐ 冻结到期 ┌──────────┐
|
|
88
|
+
│ healthy │────────────►│ frozen │──────────►│ checking │
|
|
89
|
+
│ (健康) │ │ (冻结) │ │ (检测中) │
|
|
90
|
+
└────────┘ └──────────┘ └────┬─────┘
|
|
91
|
+
▲ ▲ │
|
|
92
|
+
│ │ 连续失败3次 │
|
|
93
|
+
│ └──────────────────────┘
|
|
94
|
+
│ 连续成功5次
|
|
95
|
+
└──────────────────────────────────────────────┘
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
#### 冻结时间策略
|
|
99
|
+
|
|
100
|
+
| 次数 | 冻结时间 |
|
|
101
|
+
|------|----------|
|
|
102
|
+
| 第1次 | 1 分钟 |
|
|
103
|
+
| 第2次 | 2 分钟 |
|
|
104
|
+
| 第3次 | 4 分钟 |
|
|
105
|
+
| 第4次 | 8 分钟 |
|
|
106
|
+
| 第5次 | 16 分钟 |
|
|
107
|
+
| 第6次+ | 30 分钟(上限)|
|
|
108
|
+
|
|
109
|
+
#### 恢复检测
|
|
110
|
+
|
|
111
|
+
- 冻结到期后,渠道进入"检测中"状态
|
|
112
|
+
- 使用真实请求进行健康检测(被动检测,不消耗额外配额)
|
|
113
|
+
- 连续 5 次成功后恢复为"健康"状态
|
|
114
|
+
- 检测期间失败则重新冻结
|
|
115
|
+
|
|
116
|
+
### 3. proxy-server.js(代理服务器)
|
|
117
|
+
|
|
118
|
+
负责接收请求、转发到选定渠道、记录结果。
|
|
119
|
+
|
|
120
|
+
#### 请求处理流程
|
|
121
|
+
|
|
122
|
+
```
|
|
123
|
+
1. 接收请求
|
|
124
|
+
│
|
|
125
|
+
2. 调用 allocateChannel() 获取渠道
|
|
126
|
+
│
|
|
127
|
+
3. 转发请求到渠道
|
|
128
|
+
│
|
|
129
|
+
4. 等待响应
|
|
130
|
+
│
|
|
131
|
+
├── 成功 → recordSuccess() → 更新健康状态
|
|
132
|
+
│
|
|
133
|
+
└── 失败 → recordFailure() → 可能触发冻结
|
|
134
|
+
│
|
|
135
|
+
5. 调用 releaseChannel() 释放并发位
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
## 配置参数
|
|
139
|
+
|
|
140
|
+
### 渠道配置
|
|
141
|
+
|
|
142
|
+
| 参数 | 类型 | 默认值 | 说明 |
|
|
143
|
+
|------|------|--------|------|
|
|
144
|
+
| `name` | string | - | 渠道名称 |
|
|
145
|
+
| `baseUrl` | string | - | API 地址 |
|
|
146
|
+
| `apiKey` | string | - | API 密钥 |
|
|
147
|
+
| `enabled` | boolean | true | 是否启用 |
|
|
148
|
+
| `weight` | number | 1 | 权重(越高越容易被选中)|
|
|
149
|
+
| `maxConcurrency` | number/null | null | 最大并发(null=不限制)|
|
|
150
|
+
|
|
151
|
+
### 全局配置
|
|
152
|
+
|
|
153
|
+
| 参数 | 位置 | 默认值 | 说明 |
|
|
154
|
+
|------|------|--------|------|
|
|
155
|
+
| `enableSessionBinding` | 高级设置 | true | 是否启用会话绑定 |
|
|
156
|
+
|
|
157
|
+
### 健康检查配置
|
|
158
|
+
|
|
159
|
+
| 参数 | 值 | 说明 |
|
|
160
|
+
|------|-----|------|
|
|
161
|
+
| `failureThreshold` | 3 | 连续失败多少次触发冻结 |
|
|
162
|
+
| `initialFreezeTime` | 60秒 | 初始冻结时间 |
|
|
163
|
+
| `maxFreezeTime` | 30分钟 | 最大冻结时间 |
|
|
164
|
+
| `freezeMultiplier` | 2 | 冻结时间倍增系数 |
|
|
165
|
+
| `healthCheckWindow` | 5 | 恢复需要连续成功次数 |
|
|
166
|
+
|
|
167
|
+
## 使用场景
|
|
168
|
+
|
|
169
|
+
### 场景1:多渠道负载均衡
|
|
170
|
+
|
|
171
|
+
```
|
|
172
|
+
配置:
|
|
173
|
+
- 渠道A:权重=2, 并发=不限制
|
|
174
|
+
- 渠道B:权重=1, 并发=不限制
|
|
175
|
+
- 渠道C:权重=1, 并发=不限制
|
|
176
|
+
|
|
177
|
+
效果:
|
|
178
|
+
- A 处理 50% 的请求
|
|
179
|
+
- B 处理 25% 的请求
|
|
180
|
+
- C 处理 25% 的请求
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
### 场景2:主备切换
|
|
184
|
+
|
|
185
|
+
```
|
|
186
|
+
配置:
|
|
187
|
+
- 主渠道:权重=100, 并发=不限制
|
|
188
|
+
- 备渠道:权重=1, 并发=不限制
|
|
189
|
+
|
|
190
|
+
效果:
|
|
191
|
+
- 正常情况:几乎所有请求走主渠道
|
|
192
|
+
- 主渠道故障:自动切换到备渠道
|
|
193
|
+
- 主渠道恢复:自动切回主渠道
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
### 场景3:并发控制
|
|
197
|
+
|
|
198
|
+
```
|
|
199
|
+
配置:
|
|
200
|
+
- 渠道A:权重=1, 并发=2
|
|
201
|
+
- 渠道B:权重=1, 并发=2
|
|
202
|
+
|
|
203
|
+
效果:
|
|
204
|
+
- 同时最多 4 个请求(每个渠道 2 个)
|
|
205
|
+
- 超过 4 个请求时排队等待
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
## 前端展示
|
|
209
|
+
|
|
210
|
+
### 渠道卡片状态
|
|
211
|
+
|
|
212
|
+
- 🟢 **绿色左边框**:健康状态
|
|
213
|
+
- 🟡 **黄色左边框 + 渐变背景**:检测中状态
|
|
214
|
+
- 🔴 **红色左边框 + 渐变背景**:冻结状态
|
|
215
|
+
- ⚪ **灰色左边框**:未启用
|
|
216
|
+
|
|
217
|
+
### 卡片信息
|
|
218
|
+
|
|
219
|
+
- `W:N`:权重值
|
|
220
|
+
- `C:N` 或 `C:∞`:并发限制
|
|
221
|
+
- 冻结标签显示剩余时间
|
|
222
|
+
|
|
223
|
+
## API 接口
|
|
224
|
+
|
|
225
|
+
### 获取渠道列表(含健康状态)
|
|
226
|
+
|
|
227
|
+
```
|
|
228
|
+
GET /api/channels
|
|
229
|
+
Response: {
|
|
230
|
+
channels: [{
|
|
231
|
+
id, name, baseUrl, apiKey, enabled, weight, maxConcurrency,
|
|
232
|
+
health: { status, statusText, freezeRemaining, ... }
|
|
233
|
+
}]
|
|
234
|
+
}
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
### 重置渠道健康状态
|
|
238
|
+
|
|
239
|
+
```
|
|
240
|
+
POST /api/channels/:id/reset-health
|
|
241
|
+
Response: { success: true, health: {...} }
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
## 注意事项
|
|
245
|
+
|
|
246
|
+
1. **会话绑定与故障转移**:渠道被冻结时,绑定到该渠道的会话会自动解绑
|
|
247
|
+
2. **被动健康检测**:不主动发送检测请求,使用真实请求检测
|
|
248
|
+
3. **冻结时间递增**:避免频繁检测故障渠道
|
|
249
|
+
4. **手动重置**:可在前端手动重置渠道健康状态
|
package/package.json
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "coding-tool-x",
|
|
3
|
+
"version": "3.2.0",
|
|
4
|
+
"description": "Vibe Coding 增强工作助手 - 智能会话管理、动态渠道切换、全局搜索、实时监控",
|
|
5
|
+
"main": "src/index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"ctx": "bin/ctx.js"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"start": "node bin/ctx.js",
|
|
11
|
+
"test": "npm run test:basic && npm run test:api && npm run test:codex-agents",
|
|
12
|
+
"test:basic": "node scripts/test-basic.js",
|
|
13
|
+
"test:api": "node scripts/test-api-consistency.js",
|
|
14
|
+
"test:codex-agents": "node scripts/test-codex-agents.js",
|
|
15
|
+
"benchmark:codex": "node scripts/benchmark-codex-loading.js",
|
|
16
|
+
"build:web": "cd src/web && npm run build",
|
|
17
|
+
"dev:web": "cd src/web && npm run dev",
|
|
18
|
+
"dev:server": "nodemon"
|
|
19
|
+
},
|
|
20
|
+
"keywords": [
|
|
21
|
+
"claude",
|
|
22
|
+
"claude-code",
|
|
23
|
+
"claude-cli",
|
|
24
|
+
"session-manager",
|
|
25
|
+
"cli",
|
|
26
|
+
"interactive",
|
|
27
|
+
"conversation",
|
|
28
|
+
"history",
|
|
29
|
+
"cc switch"
|
|
30
|
+
],
|
|
31
|
+
"author": "CooperJiang",
|
|
32
|
+
"license": "MIT",
|
|
33
|
+
"engines": {
|
|
34
|
+
"node": ">=14.0.0"
|
|
35
|
+
},
|
|
36
|
+
"files": [
|
|
37
|
+
"bin/",
|
|
38
|
+
"src/commands/",
|
|
39
|
+
"src/config/",
|
|
40
|
+
"src/plugins/",
|
|
41
|
+
"src/server/",
|
|
42
|
+
"src/ui/",
|
|
43
|
+
"src/utils/",
|
|
44
|
+
"src/index.js",
|
|
45
|
+
"src/reset-config.js",
|
|
46
|
+
"docs/",
|
|
47
|
+
"dist/",
|
|
48
|
+
"CHANGELOG.md",
|
|
49
|
+
"README.md",
|
|
50
|
+
"LICENSE"
|
|
51
|
+
],
|
|
52
|
+
"dependencies": {
|
|
53
|
+
"@iarna/toml": "^2.2.5",
|
|
54
|
+
"adm-zip": "^0.5.16",
|
|
55
|
+
"ajv": "^8.12.0",
|
|
56
|
+
"cc-tool-web": "file:src/web",
|
|
57
|
+
"chalk": "^4.1.2",
|
|
58
|
+
"express": "^4.18.2",
|
|
59
|
+
"http-proxy": "^1.18.1",
|
|
60
|
+
"https-proxy-agent": "^7.0.6",
|
|
61
|
+
"inquirer": "^8.2.7",
|
|
62
|
+
"open": "^8.4.2",
|
|
63
|
+
"ora": "^5.4.1",
|
|
64
|
+
"pm2": "^5.4.3",
|
|
65
|
+
"semver": "^7.6.0",
|
|
66
|
+
"toml": "^3.0.0",
|
|
67
|
+
"ws": "^8.18.3"
|
|
68
|
+
},
|
|
69
|
+
"devDependencies": {
|
|
70
|
+
"nodemon": "^3.0.2"
|
|
71
|
+
},
|
|
72
|
+
"repository": {
|
|
73
|
+
"type": "git",
|
|
74
|
+
"url": "git+https://github.com/ZeaoZhang/coding-tool.git"
|
|
75
|
+
},
|
|
76
|
+
"bugs": {
|
|
77
|
+
"url": "https://github.com/ZeaoZhang/coding-tool/issues"
|
|
78
|
+
},
|
|
79
|
+
"homepage": "https://github.com/ZeaoZhang/coding-tool#readme"
|
|
80
|
+
}
|