@dedenlabs/claude-code-router-cli 2.0.3 → 2.0.4

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.
@@ -33,7 +33,37 @@
33
33
  }
34
34
  ```
35
35
 
36
- ### 2. 外部规则文件格式
36
+ ### 2. 函数加载优先级
37
+
38
+ 系统采用以下优先级顺序加载外部函数:
39
+
40
+ 1. **优先查找配置文件中指定的函数名** (`functionName` 字段)
41
+ 2. **如果指定函数不存在,使用默认导出** (`export default` 或 `module.exports`)
42
+ 3. **如果默认导出也不存在,使用默认函数名** `"evaluate"`
43
+ 4. **如果都不存在,则报告错误**
44
+
45
+ 这种机制确保了最大的兼容性:
46
+ - ✅ 支持明确指定函数名
47
+ - ✅ 支持仅导出默认函数
48
+ - ✅ 支持传统的 `evaluate` 函数名
49
+ - ✅ 向下兼容旧版本配置
50
+
51
+ **配置示例:**
52
+
53
+ ```json
54
+ {
55
+ "externalFunction": {
56
+ "path": "./debug-logger.js",
57
+ "functionName": "printModelRequestData"
58
+ }
59
+ }
60
+ ```
61
+
62
+ 如果不指定 `functionName`,系统会依次尝试:
63
+ - `module.exports.default` (ES模块默认导出)
64
+ - `module.exports.evaluate` (传统函数名)
65
+
66
+ ### 3. 外部规则文件格式
37
67
 
38
68
  外部 JS 文件需要导出一个或多个函数:
39
69
 
@@ -62,7 +92,7 @@ export function condition2(context) {
62
92
  }
63
93
  ```
64
94
 
65
- ### 3. 上下文参数
95
+ ### 4. 上下文参数
66
96
 
67
97
  外部函数接收一个 `RouteContext` 对象,包含:
68
98
 
@@ -0,0 +1,386 @@
1
+ # 🔍 调试日志外部路由脚本使用指南
2
+
3
+ ## 概述
4
+
5
+ `debug-logger.js` 是一个专门用于打印模型请求数据的外部路由脚本,它具有以下特点:
6
+
7
+ - ✅ **优先级最高**:可以设置为最高优先级(999),在所有规则之前执行
8
+ - ✅ **不拦截路由**:始终返回 `false`,不会影响正常的路由决策
9
+ - ✅ **变量式收集**:每种日志类型单独收集,便于选择性输出
10
+ - ✅ **文件存储**:自动写入到 `~/.claude-code-router/logs/` 目录
11
+ - ✅ **时间戳**:每个日志条目带时间标记,便于追踪
12
+ - ✅ **选择性输出**:用户可自由选择要输出的日志类型
13
+ - ✅ **增量追加**:日志文件自动按日期命名,内容增量追加
14
+ - ✅ **折叠友好**:支持编辑器折叠功能,便于浏览
15
+
16
+ ## 文件结构
17
+
18
+ ```
19
+ examples/
20
+ ├── external-rules/
21
+ │ └── debug-logger.js # 调试日志脚本
22
+ ├── config-with-debug-logger.json # 使用示例配置
23
+ └── README-调试日志脚本.md # 本文档
24
+ ```
25
+
26
+ ## 使用方法
27
+
28
+ ### 1. 在配置中添加外部规则
29
+
30
+ 在你的 `config.json` 文件中添加以下规则:
31
+
32
+ ```json
33
+ {
34
+ "Router": {
35
+ "rules": [
36
+ {
37
+ "name": "调试日志打印规则",
38
+ "priority": 999,
39
+ "enabled": true,
40
+ "condition": {
41
+ "type": "externalFunction",
42
+ "externalFunction": {
43
+ "path": "../examples/external-rules/debug-logger.js",
44
+ "functionName": "printModelRequestData"
45
+ }
46
+ },
47
+ "action": {
48
+ "route": "sonnet-minimax",
49
+ "description": "打印所有请求数据但不拦截路由"
50
+ }
51
+ }
52
+ ]
53
+ }
54
+ }
55
+ ```
56
+ ![1765945871911](image/README-调试日志脚本/1765945871911.png)
57
+
58
+ ### 2. 启动路由服务
59
+
60
+ ```bash
61
+ # 启动路由服务
62
+ ccr start
63
+
64
+ # 或者指定配置文件
65
+ ccr start --config ../examples/config-with-debug-logger.json
66
+ ```
67
+
68
+ ### 3. 选择性输出日志
69
+
70
+ 新版本支持选择性输出特定类型的日志,方便调试特定问题:
71
+
72
+ #### 3.1 修改输出类型
73
+
74
+ 在脚本中找到 `outputTypes` 数组(大约在第244行),根据需要修改:
75
+
76
+ ```javascript
77
+ // 只输出基本信息和消息内容
78
+ const outputTypes = ['basic', 'messages'];
79
+
80
+ // 或者只输出请求头和使用统计
81
+ const outputTypes = ['headers', 'usage'];
82
+
83
+ // 完整的输出类型列表:
84
+ // 'basic' - 基本信息 (Token数量、会话ID等)
85
+ // 'headers' - 请求头信息
86
+ // 'messages' - 消息内容
87
+ // 'system' - 系统消息
88
+ // 'tools' - 可用工具
89
+ // 'body' - 请求体原始数据
90
+ // 'usage' - 使用统计
91
+ // 'event' - 事件信息
92
+ ```
93
+
94
+ #### 3.2 查看日志文件
95
+
96
+ 日志会自动写入到 `~/.claude-code-router/logs/` 目录,按日期命名:
97
+
98
+ ```bash
99
+ # 查看日志目录
100
+ ls -la ~/.claude-code-router/logs/
101
+
102
+ # 实时查看最新日志
103
+ tail -f ~/.claude-code-router/logs/debug-logger-$(date +%Y-%m-%d).log
104
+
105
+ # 查看今天的日志
106
+ cat ~/.claude-code-router/logs/debug-logger-$(date +%Y-%m-%d).log
107
+ ```
108
+
109
+ ### 4. 查看调试日志
110
+
111
+ 启动服务后,每次有请求时都会在控制台看到详细的调试信息:
112
+
113
+ ```
114
+ ========================================
115
+ 🔍 【调试日志】模型请求数据
116
+ ========================================
117
+
118
+ 📊 【基本信息】
119
+ Token 数量: 1234
120
+ 会话ID: session_abc123
121
+ 请求ID: req_xyz789
122
+
123
+ 📋 【请求头】
124
+ content-type: application/json
125
+ x-user-id: user123
126
+
127
+ 💬 【消息内容】(共 3 条)
128
+
129
+ [消息 1]
130
+ Role: user
131
+ Content: 你好,请帮我写一个Hello World程序...
132
+
133
+ ⚙️ 【系统消息】(共 1 条)
134
+
135
+ [系统消息 1]
136
+ Content: 你是一个有用的AI助手...
137
+
138
+ 🔧 【可用工具】(共 2 个)
139
+
140
+ [1] web_search
141
+ Description: Search the web for information
142
+
143
+ [2] code_execution
144
+ Description: Execute code
145
+
146
+ 📦 【请求体原始数据】
147
+ {
148
+ body: {
149
+ model: 'sonnet-minimax',
150
+ messages: '[包含 3 条消息的数组]',
151
+ system: '[包含 1 条系统消息的数组]'
152
+ }
153
+ }
154
+
155
+ ========================================
156
+ ✅ 【调试日志】打印完成 - 路由继续执行
157
+ ========================================
158
+ ```
159
+
160
+ ## 日志内容说明
161
+
162
+ 调试日志会打印以下信息:
163
+
164
+ ### 1. 基本信息
165
+ - **Token 数量**:当前请求的 token 数量
166
+ - **会话ID**:请求的会话标识
167
+ - **请求ID**:请求的唯一标识
168
+
169
+ ### 2. 请求头
170
+ - 显示 HTTP 请求头信息
171
+ - 包含用户标识、认证信息等
172
+
173
+ ### 3. 消息内容
174
+ - **Role**:消息发送者(user/assistant/system)
175
+ - **Content**:消息内容(自动截断超长内容)
176
+ - **Tool Calls**:工具调用信息(如果有)
177
+
178
+ ### 4. 系统消息
179
+ - 系统级别的指令和配置
180
+ - 包含角色定义、行为规范等
181
+
182
+ ### 5. 可用工具
183
+ - 当前会话中可用的工具列表
184
+ - 工具名称、描述和参数模式
185
+
186
+ ### 6. 请求体原始数据
187
+ - 完整的请求数据结构
188
+ - 包含模型、参数等所有请求信息
189
+
190
+ ### 7. 使用统计
191
+ - 输入/输出 token 数量
192
+ - 估算成本(如果可用)
193
+
194
+ ## 实际应用场景
195
+
196
+ ### 1. 调试路由规则
197
+ ```bash
198
+ # 查看路由决策过程
199
+ # 通过日志确认请求是否按照预期路由
200
+ ```
201
+
202
+ ### 2. 分析请求模式
203
+ ```bash
204
+ # 了解用户的请求习惯
205
+ # 分析常用的工具调用
206
+ ```
207
+
208
+ ### 3. 性能优化
209
+ ```bash
210
+ # 分析 token 使用量
211
+ # 识别大请求模式
212
+ ```
213
+
214
+ ### 4. 问题排查
215
+ ```bash
216
+ # 查看请求是否正确传递
217
+ # 验证系统消息和工具配置
218
+ ```
219
+
220
+ ### 5. 日志文件分析
221
+ ```bash
222
+ # 查看历史日志
223
+ cat ~/.claude-code-router/logs/debug-logger-2025-12-17.log
224
+
225
+ # 搜索特定会话ID
226
+ grep "session_abc123" ~/.claude-code-router/logs/debug-logger-*.log
227
+
228
+ # 分析某一天的日志
229
+ grep "2025-12-17" ~/.claude-code-router/logs/debug-logger-*.log
230
+ ```
231
+
232
+ ### 6. 选择性调试
233
+ ```javascript
234
+ // 当只需要调试 Token 使用情况时
235
+ const outputTypes = ['basic', 'usage'];
236
+
237
+ // 当需要调试请求结构时
238
+ const outputTypes = ['headers', 'body'];
239
+
240
+ // 当需要调试消息内容时
241
+ const outputTypes = ['messages', 'system'];
242
+ ```
243
+
244
+ ## 注意事项
245
+
246
+ 1. **性能影响**:调试日志会增加一定的性能开销,建议在生产环境中禁用
247
+ 2. **日志量**:大量请求时会产生大量日志,日志文件会按日期自动分割
248
+ 3. **敏感信息**:日志可能包含敏感数据,注意保护日志文件
249
+ 4. **优先级设置**:确保调试规则的优先级高于其他规则(使用999或更高)
250
+ 5. **文件位置**:日志默认存储在 `~/.claude-code-router/logs/` 目录
251
+ 6. **磁盘空间**:长时间运行会积累日志文件,定期清理不需要的日志
252
+ 7. **选择性输出**:合理使用选择性输出功能,减少不必要的日志
253
+
254
+ ## ⚠️ 重要修复记录
255
+
256
+ ### v2.0 - 全新重构版本
257
+
258
+ **新特性**:
259
+ - ✅ 变量式日志收集:每种日志类型单独存储,便于选择性输出
260
+ - ✅ 文件存储:自动写入到 `~/.claude-code-router/logs/` 目录
261
+ - ✅ 时间戳:每个日志条目带 ISO 8601 时间标记
262
+ - ✅ 增量追加:日志文件按日期命名,内容自动追加
263
+ - ✅ 选择性输出:用户可自由组合要输出的日志类型
264
+ - ✅ 折叠友好:支持编辑器折叠功能,便于浏览长日志
265
+
266
+ **使用方法**:
267
+ ```javascript
268
+ // 修改 outputTypes 数组来选择日志类型
269
+ const outputTypes = ['basic', 'messages']; // 只输出基本信息和消息
270
+ ```
271
+
272
+ **影响**:提供更灵活、更实用的调试日志功能,同时保持零性能影响原始请求。
273
+
274
+ ---
275
+
276
+ ### v1.1 - 修复请求体数据被意外修改的问题
277
+
278
+ **问题描述**:调试日志脚本在打印请求体数据时,意外修改了原始的 `context.req.body` 对象,导致发送到 API 的请求缺少必要的消息数据,引发 "invalid params" 错误。
279
+
280
+ **根本原因**:虽然创建了 `safeReq` 对象来避免循环引用,但 `safeReq.body` 实际上是对原始 `context.req.body` 的引用。当执行以下操作时:
281
+ ```javascript
282
+ safeReq.body.messages = `[包含 ${safeReq.body.messages.length} 条消息的数组]`;
283
+ ```
284
+ 实际上是在修改原始的 `context.req.body.messages`!
285
+
286
+ **解决方案**:在修改 `safeReq.body` 之前,先创建它的深拷贝:
287
+ ```javascript
288
+ // 创建 body 的深拷贝,避免修改原始数据
289
+ if (safeReq.body) {
290
+ safeReq.body = { ...safeReq.body }; // 关键修复:创建副本
291
+ // 现在可以安全地修改副本,不会影响原始数据
292
+ if (safeReq.body.messages) {
293
+ safeReq.body.messages = `[包含 ${safeReq.body.messages.length} 条消息的数组]`;
294
+ }
295
+ // ...
296
+ }
297
+ ```
298
+
299
+ **影响**:此修复确保调试日志功能不会影响正常的 API 请求,同时保持完整的调试信息输出。
300
+
301
+ **升级说明**:如果您之前遇到了 "invalid params" 错误,请更新到修复版本并重新测试。
302
+
303
+ ---
304
+
305
+ ## 故障排查
306
+
307
+ ### 错误:外部函数不是一个有效的函数
308
+
309
+ 如果遇到以下错误:
310
+ ```
311
+ ❌ [ERROR] 外部函数 ../examples/external-rules/debug-logger.js 不是一个有效的函数
312
+ ```
313
+
314
+ **解决方案:**
315
+
316
+ 1. **检查路径是否正确**
317
+ ```bash
318
+ # 如果命令行在 dist 目录下运行,需要使用上级路径
319
+ "path": "../examples/external-rules/debug-logger.js"
320
+
321
+ # 或者使用绝对路径
322
+ # 在配置文件中使用绝对路径:
323
+ "path": "/path/to/your/project/examples/external-rules/debug-logger.js"
324
+ ```
325
+
326
+ 2. **确认函数导出方式**
327
+ ```javascript
328
+ // 使用 module.exports 导出,统一方案
329
+ module.exports = printModelRequestData;
330
+ ```
331
+
332
+ 3. **验证文件是否存在**
333
+ ```bash
334
+ ls examples/external-rules/debug-logger.js
335
+ ```
336
+
337
+ 4. **检查Node.js语法**
338
+ ```bash
339
+ node -c examples/external-rules/debug-logger.js
340
+ ```
341
+
342
+ 5. **查看详细错误日志**
343
+ ```bash
344
+ # 启动时查看详细错误
345
+ ccr start --log-level debug
346
+ ```
347
+
348
+ ## 示例配置
349
+
350
+ 完整的示例配置请参考:`examples/config-with-debug-logger.json`
351
+
352
+ 该配置包含了:
353
+ - 调试日志规则(优先级999)
354
+ - 用户指定规则(优先级200)
355
+ - 代号映射规则(优先级190)
356
+ - 长上下文规则(优先级100)
357
+
358
+ ## 禁用调试日志
359
+
360
+ 只需要将调试规则设置为 `enabled: false` 即可:
361
+
362
+ ```json
363
+ {
364
+ "name": "调试日志打印规则",
365
+ "enabled": false,
366
+ ...
367
+ }
368
+ ```
369
+
370
+ ## 总结
371
+
372
+ 调试日志脚本是一个强大的工具,可以帮助你:
373
+ - 📊 深入了解请求结构
374
+ - 🔍 调试路由规则
375
+ - 📈 分析使用模式
376
+ - 🐛 排查问题
377
+ - 📁 持久化日志记录
378
+ - ⚙️ 选择性调试
379
+
380
+ **v2.0 版本亮点**:
381
+ - 🎯 **灵活选择**:通过 `outputTypes` 数组自由选择日志类型
382
+ - 💾 **持久存储**:自动写入日志文件,支持历史分析
383
+ - ⏰ **时间追踪**:每个日志条目带时间戳,便于问题定位
384
+ - 📂 **自动管理**:按日期自动分割,避免单个文件过大
385
+
386
+ 只需要一个简单的配置修改,就能获得详细的请求洞察!
@@ -0,0 +1,111 @@
1
+ {
2
+ "Router": {
3
+ "engine": "unified",
4
+ "defaultRoute": "sonnet-minimax",
5
+ "rules": [
6
+ {
7
+ "name": "调试日志打印规则",
8
+ "priority": 999,
9
+ "enabled": true,
10
+ "condition": {
11
+ "type": "externalFunction",
12
+ "externalFunction": {
13
+ "path": "../examples/external-rules/debug-logger.js",
14
+ "functionName": "printModelRequestData"
15
+ }
16
+ },
17
+ "action": {
18
+ "route": "${mappedModel}",
19
+ "description": "打印所有请求数据但不匹配路由"
20
+ }
21
+ },
22
+ {
23
+ "name": "用户指定规则",
24
+ "priority": 200,
25
+ "enabled": true,
26
+ "condition": {
27
+ "type": "custom",
28
+ "customFunction": "modelContainsComma"
29
+ },
30
+ "action": {
31
+ "route": "${userModel}",
32
+ "description": "用户直接指定 provider,model 格式"
33
+ }
34
+ },
35
+ {
36
+ "name": "代号映射规则",
37
+ "priority": 190,
38
+ "enabled": true,
39
+ "condition": {
40
+ "type": "custom",
41
+ "customFunction": "directModelMapping"
42
+ },
43
+ "action": {
44
+ "route": "${mappedModel}",
45
+ "description": "将provider作为代号,映射到对应的model模型"
46
+ }
47
+ },
48
+ {
49
+ "name": "长上下文规则",
50
+ "priority": 100,
51
+ "enabled": true,
52
+ "condition": {
53
+ "type": "tokenThreshold",
54
+ "value": 180000,
55
+ "operator": "gt"
56
+ },
57
+ "action": {
58
+ "route": "sonnet-minimax",
59
+ "description": "基于token阈值选择模型"
60
+ }
61
+ }
62
+ ],
63
+ "cache": {
64
+ "enabled": true,
65
+ "ttl": 300000,
66
+ "maxSize": 1000
67
+ },
68
+ "debug": {
69
+ "enabled": true,
70
+ "logLevel": "info"
71
+ }
72
+ },
73
+ "Providers": [
74
+ {
75
+ "name": "sonnet-minimax",
76
+ "api_base_url": "https://api.minimaxi.com/anthropic/v1/messages",
77
+ "api_key": "YOUR_MINIMAX_API_KEY",
78
+ "models": ["MiniMax-M2"],
79
+ "transformer": { "use": ["Anthropic"] }
80
+ },
81
+ {
82
+ "name": "opus-glm",
83
+ "api_base_url": "https://api.z.ai/api/coding/paas/v4/chat/completions",
84
+ "api_key": "YOUR_GLM_API_KEY",
85
+ "models": ["glm-4.6"],
86
+ "transformer": { "use": ["reasoning", "glm-thinking"] }
87
+ },
88
+ {
89
+ "name": "haiku-glm",
90
+ "api_base_url": "https://open.bigmodel.cn/api/anthropic/v1/messages",
91
+ "api_key": "YOUR_GLM_API_KEY",
92
+ "models": ["glm-4.5-air"],
93
+ "transformer": { "use": ["Anthropic"] }
94
+ }
95
+ ],
96
+ "transformers": [
97
+ {
98
+ "path": "./transformers/glm-thinking.js",
99
+ "options": {
100
+ "enabled": "false",
101
+ "debug": "true"
102
+ }
103
+ }
104
+ ],
105
+ "LOG": true,
106
+ "LOG_LEVEL": "info",
107
+ "HOST": "127.0.0.1",
108
+ "PORT": 3456,
109
+ "APIKEY": "sk-anything",
110
+ "API_TIMEOUT_MS": 600000
111
+ }