@blockrun/clawrouter 0.10.13 → 0.10.15
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/dist/cli.js +219 -59
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +7 -0
- package/dist/index.js +219 -59
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -694,6 +694,13 @@ type BlockRunModel = {
|
|
|
694
694
|
vision?: boolean;
|
|
695
695
|
/** Models optimized for agentic workflows (multi-step autonomous tasks) */
|
|
696
696
|
agentic?: boolean;
|
|
697
|
+
/**
|
|
698
|
+
* Model supports OpenAI-compatible structured function/tool calling.
|
|
699
|
+
* Models without this flag output tool invocations as plain text JSON,
|
|
700
|
+
* which leaks raw {"command":"..."} into visible chat messages.
|
|
701
|
+
* Default: false (must opt-in to prevent silent regressions on new models).
|
|
702
|
+
*/
|
|
703
|
+
toolCalling?: boolean;
|
|
697
704
|
};
|
|
698
705
|
declare const BLOCKRUN_MODELS: BlockRunModel[];
|
|
699
706
|
/**
|
package/dist/index.js
CHANGED
|
@@ -115,7 +115,8 @@ var BLOCKRUN_MODELS = [
|
|
|
115
115
|
maxOutput: 128e3,
|
|
116
116
|
reasoning: true,
|
|
117
117
|
vision: true,
|
|
118
|
-
agentic: true
|
|
118
|
+
agentic: true,
|
|
119
|
+
toolCalling: true
|
|
119
120
|
},
|
|
120
121
|
{
|
|
121
122
|
id: "openai/gpt-5-mini",
|
|
@@ -124,7 +125,8 @@ var BLOCKRUN_MODELS = [
|
|
|
124
125
|
inputPrice: 0.25,
|
|
125
126
|
outputPrice: 2,
|
|
126
127
|
contextWindow: 2e5,
|
|
127
|
-
maxOutput: 65536
|
|
128
|
+
maxOutput: 65536,
|
|
129
|
+
toolCalling: true
|
|
128
130
|
},
|
|
129
131
|
{
|
|
130
132
|
id: "openai/gpt-5-nano",
|
|
@@ -133,7 +135,8 @@ var BLOCKRUN_MODELS = [
|
|
|
133
135
|
inputPrice: 0.05,
|
|
134
136
|
outputPrice: 0.4,
|
|
135
137
|
contextWindow: 128e3,
|
|
136
|
-
maxOutput: 32768
|
|
138
|
+
maxOutput: 32768,
|
|
139
|
+
toolCalling: true
|
|
137
140
|
},
|
|
138
141
|
{
|
|
139
142
|
id: "openai/gpt-5.2-pro",
|
|
@@ -143,7 +146,8 @@ var BLOCKRUN_MODELS = [
|
|
|
143
146
|
outputPrice: 168,
|
|
144
147
|
contextWindow: 4e5,
|
|
145
148
|
maxOutput: 128e3,
|
|
146
|
-
reasoning: true
|
|
149
|
+
reasoning: true,
|
|
150
|
+
toolCalling: true
|
|
147
151
|
},
|
|
148
152
|
// OpenAI Codex Family
|
|
149
153
|
{
|
|
@@ -154,7 +158,8 @@ var BLOCKRUN_MODELS = [
|
|
|
154
158
|
outputPrice: 14,
|
|
155
159
|
contextWindow: 128e3,
|
|
156
160
|
maxOutput: 32e3,
|
|
157
|
-
agentic: true
|
|
161
|
+
agentic: true,
|
|
162
|
+
toolCalling: true
|
|
158
163
|
},
|
|
159
164
|
// OpenAI GPT-4 Family
|
|
160
165
|
{
|
|
@@ -165,7 +170,8 @@ var BLOCKRUN_MODELS = [
|
|
|
165
170
|
outputPrice: 8,
|
|
166
171
|
contextWindow: 128e3,
|
|
167
172
|
maxOutput: 16384,
|
|
168
|
-
vision: true
|
|
173
|
+
vision: true,
|
|
174
|
+
toolCalling: true
|
|
169
175
|
},
|
|
170
176
|
{
|
|
171
177
|
id: "openai/gpt-4.1-mini",
|
|
@@ -174,7 +180,8 @@ var BLOCKRUN_MODELS = [
|
|
|
174
180
|
inputPrice: 0.4,
|
|
175
181
|
outputPrice: 1.6,
|
|
176
182
|
contextWindow: 128e3,
|
|
177
|
-
maxOutput: 16384
|
|
183
|
+
maxOutput: 16384,
|
|
184
|
+
toolCalling: true
|
|
178
185
|
},
|
|
179
186
|
{
|
|
180
187
|
id: "openai/gpt-4.1-nano",
|
|
@@ -183,7 +190,8 @@ var BLOCKRUN_MODELS = [
|
|
|
183
190
|
inputPrice: 0.1,
|
|
184
191
|
outputPrice: 0.4,
|
|
185
192
|
contextWindow: 128e3,
|
|
186
|
-
maxOutput: 16384
|
|
193
|
+
maxOutput: 16384,
|
|
194
|
+
toolCalling: true
|
|
187
195
|
},
|
|
188
196
|
{
|
|
189
197
|
id: "openai/gpt-4o",
|
|
@@ -194,7 +202,8 @@ var BLOCKRUN_MODELS = [
|
|
|
194
202
|
contextWindow: 128e3,
|
|
195
203
|
maxOutput: 16384,
|
|
196
204
|
vision: true,
|
|
197
|
-
agentic: true
|
|
205
|
+
agentic: true,
|
|
206
|
+
toolCalling: true
|
|
198
207
|
},
|
|
199
208
|
{
|
|
200
209
|
id: "openai/gpt-4o-mini",
|
|
@@ -203,7 +212,8 @@ var BLOCKRUN_MODELS = [
|
|
|
203
212
|
inputPrice: 0.15,
|
|
204
213
|
outputPrice: 0.6,
|
|
205
214
|
contextWindow: 128e3,
|
|
206
|
-
maxOutput: 16384
|
|
215
|
+
maxOutput: 16384,
|
|
216
|
+
toolCalling: true
|
|
207
217
|
},
|
|
208
218
|
// OpenAI O-series (Reasoning)
|
|
209
219
|
{
|
|
@@ -214,7 +224,8 @@ var BLOCKRUN_MODELS = [
|
|
|
214
224
|
outputPrice: 60,
|
|
215
225
|
contextWindow: 2e5,
|
|
216
226
|
maxOutput: 1e5,
|
|
217
|
-
reasoning: true
|
|
227
|
+
reasoning: true,
|
|
228
|
+
toolCalling: true
|
|
218
229
|
},
|
|
219
230
|
{
|
|
220
231
|
id: "openai/o1-mini",
|
|
@@ -224,7 +235,8 @@ var BLOCKRUN_MODELS = [
|
|
|
224
235
|
outputPrice: 4.4,
|
|
225
236
|
contextWindow: 128e3,
|
|
226
237
|
maxOutput: 65536,
|
|
227
|
-
reasoning: true
|
|
238
|
+
reasoning: true,
|
|
239
|
+
toolCalling: true
|
|
228
240
|
},
|
|
229
241
|
{
|
|
230
242
|
id: "openai/o3",
|
|
@@ -234,7 +246,8 @@ var BLOCKRUN_MODELS = [
|
|
|
234
246
|
outputPrice: 8,
|
|
235
247
|
contextWindow: 2e5,
|
|
236
248
|
maxOutput: 1e5,
|
|
237
|
-
reasoning: true
|
|
249
|
+
reasoning: true,
|
|
250
|
+
toolCalling: true
|
|
238
251
|
},
|
|
239
252
|
{
|
|
240
253
|
id: "openai/o3-mini",
|
|
@@ -244,7 +257,8 @@ var BLOCKRUN_MODELS = [
|
|
|
244
257
|
outputPrice: 4.4,
|
|
245
258
|
contextWindow: 128e3,
|
|
246
259
|
maxOutput: 65536,
|
|
247
|
-
reasoning: true
|
|
260
|
+
reasoning: true,
|
|
261
|
+
toolCalling: true
|
|
248
262
|
},
|
|
249
263
|
{
|
|
250
264
|
id: "openai/o4-mini",
|
|
@@ -254,7 +268,8 @@ var BLOCKRUN_MODELS = [
|
|
|
254
268
|
outputPrice: 4.4,
|
|
255
269
|
contextWindow: 128e3,
|
|
256
270
|
maxOutput: 65536,
|
|
257
|
-
reasoning: true
|
|
271
|
+
reasoning: true,
|
|
272
|
+
toolCalling: true
|
|
258
273
|
},
|
|
259
274
|
// Anthropic - all Claude models excel at agentic workflows
|
|
260
275
|
// Use newest versions (4.6) with full provider prefix
|
|
@@ -266,7 +281,8 @@ var BLOCKRUN_MODELS = [
|
|
|
266
281
|
outputPrice: 5,
|
|
267
282
|
contextWindow: 2e5,
|
|
268
283
|
maxOutput: 8192,
|
|
269
|
-
agentic: true
|
|
284
|
+
agentic: true,
|
|
285
|
+
toolCalling: true
|
|
270
286
|
},
|
|
271
287
|
{
|
|
272
288
|
id: "anthropic/claude-sonnet-4.6",
|
|
@@ -277,7 +293,8 @@ var BLOCKRUN_MODELS = [
|
|
|
277
293
|
contextWindow: 2e5,
|
|
278
294
|
maxOutput: 64e3,
|
|
279
295
|
reasoning: true,
|
|
280
|
-
agentic: true
|
|
296
|
+
agentic: true,
|
|
297
|
+
toolCalling: true
|
|
281
298
|
},
|
|
282
299
|
{
|
|
283
300
|
id: "anthropic/claude-opus-4.6",
|
|
@@ -288,7 +305,8 @@ var BLOCKRUN_MODELS = [
|
|
|
288
305
|
contextWindow: 2e5,
|
|
289
306
|
maxOutput: 32e3,
|
|
290
307
|
reasoning: true,
|
|
291
|
-
agentic: true
|
|
308
|
+
agentic: true,
|
|
309
|
+
toolCalling: true
|
|
292
310
|
},
|
|
293
311
|
// Google
|
|
294
312
|
{
|
|
@@ -300,7 +318,8 @@ var BLOCKRUN_MODELS = [
|
|
|
300
318
|
contextWindow: 105e4,
|
|
301
319
|
maxOutput: 65536,
|
|
302
320
|
reasoning: true,
|
|
303
|
-
vision: true
|
|
321
|
+
vision: true,
|
|
322
|
+
toolCalling: true
|
|
304
323
|
},
|
|
305
324
|
{
|
|
306
325
|
id: "google/gemini-3-pro-preview",
|
|
@@ -311,7 +330,8 @@ var BLOCKRUN_MODELS = [
|
|
|
311
330
|
contextWindow: 105e4,
|
|
312
331
|
maxOutput: 65536,
|
|
313
332
|
reasoning: true,
|
|
314
|
-
vision: true
|
|
333
|
+
vision: true,
|
|
334
|
+
toolCalling: true
|
|
315
335
|
},
|
|
316
336
|
{
|
|
317
337
|
id: "google/gemini-3-flash-preview",
|
|
@@ -321,7 +341,8 @@ var BLOCKRUN_MODELS = [
|
|
|
321
341
|
outputPrice: 3,
|
|
322
342
|
contextWindow: 1e6,
|
|
323
343
|
maxOutput: 65536,
|
|
324
|
-
vision: true
|
|
344
|
+
vision: true,
|
|
345
|
+
toolCalling: true
|
|
325
346
|
},
|
|
326
347
|
{
|
|
327
348
|
id: "google/gemini-2.5-pro",
|
|
@@ -332,7 +353,8 @@ var BLOCKRUN_MODELS = [
|
|
|
332
353
|
contextWindow: 105e4,
|
|
333
354
|
maxOutput: 65536,
|
|
334
355
|
reasoning: true,
|
|
335
|
-
vision: true
|
|
356
|
+
vision: true,
|
|
357
|
+
toolCalling: true
|
|
336
358
|
},
|
|
337
359
|
{
|
|
338
360
|
id: "google/gemini-2.5-flash",
|
|
@@ -341,7 +363,8 @@ var BLOCKRUN_MODELS = [
|
|
|
341
363
|
inputPrice: 0.3,
|
|
342
364
|
outputPrice: 2.5,
|
|
343
365
|
contextWindow: 1e6,
|
|
344
|
-
maxOutput: 65536
|
|
366
|
+
maxOutput: 65536,
|
|
367
|
+
toolCalling: true
|
|
345
368
|
},
|
|
346
369
|
{
|
|
347
370
|
id: "google/gemini-2.5-flash-lite",
|
|
@@ -350,7 +373,8 @@ var BLOCKRUN_MODELS = [
|
|
|
350
373
|
inputPrice: 0.1,
|
|
351
374
|
outputPrice: 0.4,
|
|
352
375
|
contextWindow: 1e6,
|
|
353
|
-
maxOutput: 65536
|
|
376
|
+
maxOutput: 65536,
|
|
377
|
+
toolCalling: true
|
|
354
378
|
},
|
|
355
379
|
// DeepSeek
|
|
356
380
|
{
|
|
@@ -360,7 +384,8 @@ var BLOCKRUN_MODELS = [
|
|
|
360
384
|
inputPrice: 0.28,
|
|
361
385
|
outputPrice: 0.42,
|
|
362
386
|
contextWindow: 128e3,
|
|
363
|
-
maxOutput: 8192
|
|
387
|
+
maxOutput: 8192,
|
|
388
|
+
toolCalling: true
|
|
364
389
|
},
|
|
365
390
|
{
|
|
366
391
|
id: "deepseek/deepseek-reasoner",
|
|
@@ -370,7 +395,8 @@ var BLOCKRUN_MODELS = [
|
|
|
370
395
|
outputPrice: 0.42,
|
|
371
396
|
contextWindow: 128e3,
|
|
372
397
|
maxOutput: 8192,
|
|
373
|
-
reasoning: true
|
|
398
|
+
reasoning: true,
|
|
399
|
+
toolCalling: true
|
|
374
400
|
},
|
|
375
401
|
// Moonshot / Kimi - optimized for agentic workflows
|
|
376
402
|
{
|
|
@@ -383,7 +409,8 @@ var BLOCKRUN_MODELS = [
|
|
|
383
409
|
maxOutput: 8192,
|
|
384
410
|
reasoning: true,
|
|
385
411
|
vision: true,
|
|
386
|
-
agentic: true
|
|
412
|
+
agentic: true,
|
|
413
|
+
toolCalling: true
|
|
387
414
|
},
|
|
388
415
|
// xAI / Grok
|
|
389
416
|
{
|
|
@@ -394,7 +421,8 @@ var BLOCKRUN_MODELS = [
|
|
|
394
421
|
outputPrice: 15,
|
|
395
422
|
contextWindow: 131072,
|
|
396
423
|
maxOutput: 16384,
|
|
397
|
-
reasoning: true
|
|
424
|
+
reasoning: true,
|
|
425
|
+
toolCalling: true
|
|
398
426
|
},
|
|
399
427
|
// grok-3-fast removed - too expensive ($5/$25), use grok-4-fast instead
|
|
400
428
|
{
|
|
@@ -404,7 +432,8 @@ var BLOCKRUN_MODELS = [
|
|
|
404
432
|
inputPrice: 0.3,
|
|
405
433
|
outputPrice: 0.5,
|
|
406
434
|
contextWindow: 131072,
|
|
407
|
-
maxOutput: 16384
|
|
435
|
+
maxOutput: 16384,
|
|
436
|
+
toolCalling: true
|
|
408
437
|
},
|
|
409
438
|
// xAI Grok 4 Family - Ultra-cheap fast models
|
|
410
439
|
{
|
|
@@ -415,7 +444,8 @@ var BLOCKRUN_MODELS = [
|
|
|
415
444
|
outputPrice: 0.5,
|
|
416
445
|
contextWindow: 131072,
|
|
417
446
|
maxOutput: 16384,
|
|
418
|
-
reasoning: true
|
|
447
|
+
reasoning: true,
|
|
448
|
+
toolCalling: true
|
|
419
449
|
},
|
|
420
450
|
{
|
|
421
451
|
id: "xai/grok-4-fast-non-reasoning",
|
|
@@ -424,7 +454,8 @@ var BLOCKRUN_MODELS = [
|
|
|
424
454
|
inputPrice: 0.2,
|
|
425
455
|
outputPrice: 0.5,
|
|
426
456
|
contextWindow: 131072,
|
|
427
|
-
maxOutput: 16384
|
|
457
|
+
maxOutput: 16384,
|
|
458
|
+
toolCalling: true
|
|
428
459
|
},
|
|
429
460
|
{
|
|
430
461
|
id: "xai/grok-4-1-fast-reasoning",
|
|
@@ -434,7 +465,8 @@ var BLOCKRUN_MODELS = [
|
|
|
434
465
|
outputPrice: 0.5,
|
|
435
466
|
contextWindow: 131072,
|
|
436
467
|
maxOutput: 16384,
|
|
437
|
-
reasoning: true
|
|
468
|
+
reasoning: true,
|
|
469
|
+
toolCalling: true
|
|
438
470
|
},
|
|
439
471
|
{
|
|
440
472
|
id: "xai/grok-4-1-fast-non-reasoning",
|
|
@@ -443,7 +475,8 @@ var BLOCKRUN_MODELS = [
|
|
|
443
475
|
inputPrice: 0.2,
|
|
444
476
|
outputPrice: 0.5,
|
|
445
477
|
contextWindow: 131072,
|
|
446
|
-
maxOutput: 16384
|
|
478
|
+
maxOutput: 16384,
|
|
479
|
+
toolCalling: true
|
|
447
480
|
},
|
|
448
481
|
{
|
|
449
482
|
id: "xai/grok-code-fast-1",
|
|
@@ -452,9 +485,10 @@ var BLOCKRUN_MODELS = [
|
|
|
452
485
|
inputPrice: 0.2,
|
|
453
486
|
outputPrice: 1.5,
|
|
454
487
|
contextWindow: 131072,
|
|
455
|
-
maxOutput: 16384
|
|
456
|
-
|
|
457
|
-
//
|
|
488
|
+
maxOutput: 16384
|
|
489
|
+
// toolCalling intentionally omitted: outputs tool calls as plain text JSON,
|
|
490
|
+
// not OpenAI-compatible structured function calls. Will be skipped when
|
|
491
|
+
// request has tools to prevent the "talking to itself" bug.
|
|
458
492
|
},
|
|
459
493
|
{
|
|
460
494
|
id: "xai/grok-4-0709",
|
|
@@ -464,7 +498,8 @@ var BLOCKRUN_MODELS = [
|
|
|
464
498
|
outputPrice: 1.5,
|
|
465
499
|
contextWindow: 131072,
|
|
466
500
|
maxOutput: 16384,
|
|
467
|
-
reasoning: true
|
|
501
|
+
reasoning: true,
|
|
502
|
+
toolCalling: true
|
|
468
503
|
},
|
|
469
504
|
{
|
|
470
505
|
id: "xai/grok-2-vision",
|
|
@@ -474,7 +509,8 @@ var BLOCKRUN_MODELS = [
|
|
|
474
509
|
outputPrice: 10,
|
|
475
510
|
contextWindow: 131072,
|
|
476
511
|
maxOutput: 16384,
|
|
477
|
-
vision: true
|
|
512
|
+
vision: true,
|
|
513
|
+
toolCalling: true
|
|
478
514
|
},
|
|
479
515
|
// MiniMax
|
|
480
516
|
{
|
|
@@ -486,7 +522,8 @@ var BLOCKRUN_MODELS = [
|
|
|
486
522
|
contextWindow: 204800,
|
|
487
523
|
maxOutput: 16384,
|
|
488
524
|
reasoning: true,
|
|
489
|
-
agentic: true
|
|
525
|
+
agentic: true,
|
|
526
|
+
toolCalling: true
|
|
490
527
|
},
|
|
491
528
|
// NVIDIA - Free/cheap models
|
|
492
529
|
{
|
|
@@ -497,6 +534,8 @@ var BLOCKRUN_MODELS = [
|
|
|
497
534
|
outputPrice: 0,
|
|
498
535
|
contextWindow: 128e3,
|
|
499
536
|
maxOutput: 16384
|
|
537
|
+
// toolCalling intentionally omitted: free model, structured function
|
|
538
|
+
// calling support unverified. Excluded from tool-heavy routing paths.
|
|
500
539
|
},
|
|
501
540
|
{
|
|
502
541
|
id: "nvidia/kimi-k2.5",
|
|
@@ -505,7 +544,8 @@ var BLOCKRUN_MODELS = [
|
|
|
505
544
|
inputPrice: 0.55,
|
|
506
545
|
outputPrice: 2.5,
|
|
507
546
|
contextWindow: 262144,
|
|
508
|
-
maxOutput: 16384
|
|
547
|
+
maxOutput: 16384,
|
|
548
|
+
toolCalling: true
|
|
509
549
|
}
|
|
510
550
|
];
|
|
511
551
|
function toOpenClawModel(m) {
|
|
@@ -550,6 +590,11 @@ function isAgenticModel(modelId) {
|
|
|
550
590
|
function getAgenticModels() {
|
|
551
591
|
return BLOCKRUN_MODELS.filter((m) => m.agentic).map((m) => m.id);
|
|
552
592
|
}
|
|
593
|
+
function supportsToolCalling(modelId) {
|
|
594
|
+
const normalized = modelId.replace("blockrun/", "");
|
|
595
|
+
const model = BLOCKRUN_MODELS.find((m) => m.id === normalized);
|
|
596
|
+
return model?.toolCalling ?? false;
|
|
597
|
+
}
|
|
553
598
|
function getModelContextWindow(modelId) {
|
|
554
599
|
const normalized = modelId.replace("blockrun/", "");
|
|
555
600
|
const model = BLOCKRUN_MODELS.find((m) => m.id === normalized);
|
|
@@ -1061,7 +1106,8 @@ function classifyByRules(prompt, systemPrompt, estimatedTokens, config) {
|
|
|
1061
1106
|
tier: "REASONING",
|
|
1062
1107
|
confidence: Math.max(confidence2, 0.85),
|
|
1063
1108
|
signals,
|
|
1064
|
-
agenticScore
|
|
1109
|
+
agenticScore,
|
|
1110
|
+
dimensions
|
|
1065
1111
|
};
|
|
1066
1112
|
}
|
|
1067
1113
|
const { simpleMedium, mediumComplex, complexReasoning } = config.tierBoundaries;
|
|
@@ -1085,9 +1131,9 @@ function classifyByRules(prompt, systemPrompt, estimatedTokens, config) {
|
|
|
1085
1131
|
}
|
|
1086
1132
|
const confidence = calibrateConfidence(distanceFromBoundary, config.confidenceSteepness);
|
|
1087
1133
|
if (confidence < config.confidenceThreshold) {
|
|
1088
|
-
return { score: weightedScore, tier: null, confidence, signals, agenticScore };
|
|
1134
|
+
return { score: weightedScore, tier: null, confidence, signals, agenticScore, dimensions };
|
|
1089
1135
|
}
|
|
1090
|
-
return { score: weightedScore, tier, confidence, signals, agenticScore };
|
|
1136
|
+
return { score: weightedScore, tier, confidence, signals, agenticScore, dimensions };
|
|
1091
1137
|
}
|
|
1092
1138
|
function calibrateConfidence(distance, steepness) {
|
|
1093
1139
|
return 1 / (1 + Math.exp(-steepness * distance));
|
|
@@ -1143,6 +1189,11 @@ function calculateModelCost(model, modelPricing, estimatedInputTokens, maxOutput
|
|
|
1143
1189
|
const savings = routingProfile === "premium" ? 0 : baselineCost > 0 ? Math.max(0, (baselineCost - costEstimate) / baselineCost) : 0;
|
|
1144
1190
|
return { costEstimate, baselineCost, savings };
|
|
1145
1191
|
}
|
|
1192
|
+
function filterByToolCalling(models, hasTools, supportsToolCalling2) {
|
|
1193
|
+
if (!hasTools) return models;
|
|
1194
|
+
const filtered = models.filter(supportsToolCalling2);
|
|
1195
|
+
return filtered.length > 0 ? filtered : models;
|
|
1196
|
+
}
|
|
1146
1197
|
function getFallbackChainFiltered(tier, tierConfigs, estimatedTotalTokens, getContextWindow) {
|
|
1147
1198
|
const fullChain = getFallbackChain(tier, tierConfigs);
|
|
1148
1199
|
const filtered = fullChain.filter((modelId) => {
|
|
@@ -2198,12 +2249,12 @@ var DEFAULT_ROUTING_CONFIG = {
|
|
|
2198
2249
|
]
|
|
2199
2250
|
},
|
|
2200
2251
|
MEDIUM: {
|
|
2201
|
-
primary: "
|
|
2202
|
-
//
|
|
2252
|
+
primary: "moonshot/kimi-k2.5",
|
|
2253
|
+
// $0.50/$2.40 - strong tool use, proper function call format
|
|
2203
2254
|
fallback: [
|
|
2255
|
+
"deepseek/deepseek-chat",
|
|
2204
2256
|
"google/gemini-2.5-flash-lite",
|
|
2205
2257
|
// 1M context, ultra cheap ($0.10/$0.40)
|
|
2206
|
-
"deepseek/deepseek-chat",
|
|
2207
2258
|
"xai/grok-4-1-fast-non-reasoning"
|
|
2208
2259
|
// Upgraded Grok 4.1
|
|
2209
2260
|
]
|
|
@@ -2269,7 +2320,7 @@ var DEFAULT_ROUTING_CONFIG = {
|
|
|
2269
2320
|
fallback: [
|
|
2270
2321
|
"anthropic/claude-haiku-4.5",
|
|
2271
2322
|
"google/gemini-2.5-flash-lite",
|
|
2272
|
-
"
|
|
2323
|
+
"deepseek/deepseek-chat"
|
|
2273
2324
|
]
|
|
2274
2325
|
},
|
|
2275
2326
|
MEDIUM: {
|
|
@@ -2320,9 +2371,9 @@ var DEFAULT_ROUTING_CONFIG = {
|
|
|
2320
2371
|
]
|
|
2321
2372
|
},
|
|
2322
2373
|
MEDIUM: {
|
|
2323
|
-
primary: "
|
|
2324
|
-
//
|
|
2325
|
-
fallback: ["
|
|
2374
|
+
primary: "moonshot/kimi-k2.5",
|
|
2375
|
+
// $0.50/$2.40 - strong tool use, handles function calls correctly
|
|
2376
|
+
fallback: ["anthropic/claude-haiku-4.5", "deepseek/deepseek-chat", "xai/grok-4-1-fast-non-reasoning"]
|
|
2326
2377
|
},
|
|
2327
2378
|
COMPLEX: {
|
|
2328
2379
|
primary: "anthropic/claude-sonnet-4.6",
|
|
@@ -5182,6 +5233,7 @@ async function proxyRequest(req, res, apiBase, payFetch, options, routerOpts, de
|
|
|
5182
5233
|
const originalContextSizeKB = Math.ceil(body.length / 1024);
|
|
5183
5234
|
const debugMode = req.headers["x-clawrouter-debug"] !== "false";
|
|
5184
5235
|
let routingDecision;
|
|
5236
|
+
let hasTools = false;
|
|
5185
5237
|
let isStreaming = false;
|
|
5186
5238
|
let modelId = "";
|
|
5187
5239
|
let maxTokens = 4096;
|
|
@@ -5196,10 +5248,11 @@ async function proxyRequest(req, res, apiBase, payFetch, options, routerOpts, de
|
|
|
5196
5248
|
modelId = parsed.model || "";
|
|
5197
5249
|
maxTokens = parsed.max_tokens || 4096;
|
|
5198
5250
|
let bodyModified = false;
|
|
5199
|
-
|
|
5200
|
-
|
|
5201
|
-
|
|
5202
|
-
|
|
5251
|
+
const parsedMessages = Array.isArray(parsed.messages) ? parsed.messages : [];
|
|
5252
|
+
const lastUserMsg = [...parsedMessages].reverse().find((m) => m.role === "user");
|
|
5253
|
+
const lastContent = typeof lastUserMsg?.content === "string" ? lastUserMsg.content : "";
|
|
5254
|
+
if (sessionId && parsedMessages.length > 0) {
|
|
5255
|
+
const messages = parsedMessages;
|
|
5203
5256
|
if (sessionJournal.needsContext(lastContent)) {
|
|
5204
5257
|
const journalText = sessionJournal.format(sessionId);
|
|
5205
5258
|
if (journalText) {
|
|
@@ -5220,6 +5273,106 @@ async function proxyRequest(req, res, apiBase, payFetch, options, routerOpts, de
|
|
|
5220
5273
|
}
|
|
5221
5274
|
}
|
|
5222
5275
|
}
|
|
5276
|
+
if (lastContent.startsWith("/debug")) {
|
|
5277
|
+
const debugPrompt = lastContent.slice("/debug".length).trim() || "hello";
|
|
5278
|
+
const messages = parsed.messages;
|
|
5279
|
+
const systemMsg = messages?.find((m) => m.role === "system");
|
|
5280
|
+
const systemPrompt = typeof systemMsg?.content === "string" ? systemMsg.content : void 0;
|
|
5281
|
+
const fullText = `${systemPrompt ?? ""} ${debugPrompt}`;
|
|
5282
|
+
const estimatedTokens = Math.ceil(fullText.length / 4);
|
|
5283
|
+
const normalizedModel2 = typeof parsed.model === "string" ? parsed.model.trim().toLowerCase() : "";
|
|
5284
|
+
const profileName = normalizedModel2.replace("blockrun/", "");
|
|
5285
|
+
const debugProfile = ["free", "eco", "auto", "premium"].includes(profileName) ? profileName : "auto";
|
|
5286
|
+
const scoring = classifyByRules(
|
|
5287
|
+
debugPrompt,
|
|
5288
|
+
systemPrompt,
|
|
5289
|
+
estimatedTokens,
|
|
5290
|
+
DEFAULT_ROUTING_CONFIG.scoring
|
|
5291
|
+
);
|
|
5292
|
+
const debugRouting = route(debugPrompt, systemPrompt, maxTokens, {
|
|
5293
|
+
...routerOpts,
|
|
5294
|
+
routingProfile: debugProfile
|
|
5295
|
+
});
|
|
5296
|
+
const dimLines = (scoring.dimensions ?? []).map((d) => {
|
|
5297
|
+
const nameStr = (d.name + ":").padEnd(24);
|
|
5298
|
+
const scoreStr = d.score.toFixed(2).padStart(6);
|
|
5299
|
+
const sigStr = d.signal ? ` [${d.signal}]` : "";
|
|
5300
|
+
return ` ${nameStr}${scoreStr}${sigStr}`;
|
|
5301
|
+
}).join("\n");
|
|
5302
|
+
const sess = sessionId ? sessionStore.getSession(sessionId) : void 0;
|
|
5303
|
+
const sessLine = sess ? `Session: ${sessionId.slice(0, 8)}... \u2192 pinned: ${sess.model} (${sess.requestCount} requests)` : sessionId ? `Session: ${sessionId.slice(0, 8)}... \u2192 no pinned model` : "Session: none";
|
|
5304
|
+
const { simpleMedium, mediumComplex, complexReasoning } = DEFAULT_ROUTING_CONFIG.scoring.tierBoundaries;
|
|
5305
|
+
const debugText = [
|
|
5306
|
+
"ClawRouter Debug",
|
|
5307
|
+
"",
|
|
5308
|
+
`Profile: ${debugProfile} | Tier: ${debugRouting.tier} | Model: ${debugRouting.model}`,
|
|
5309
|
+
`Confidence: ${debugRouting.confidence.toFixed(2)} | Cost: $${debugRouting.costEstimate.toFixed(4)} | Savings: ${(debugRouting.savings * 100).toFixed(0)}%`,
|
|
5310
|
+
`Reasoning: ${debugRouting.reasoning}`,
|
|
5311
|
+
"",
|
|
5312
|
+
`Scoring (weighted: ${scoring.score.toFixed(3)})`,
|
|
5313
|
+
dimLines,
|
|
5314
|
+
"",
|
|
5315
|
+
`Tier Boundaries: SIMPLE <${simpleMedium.toFixed(2)} | MEDIUM <${mediumComplex.toFixed(2)} | COMPLEX <${complexReasoning.toFixed(2)} | REASONING >=${complexReasoning.toFixed(2)}`,
|
|
5316
|
+
"",
|
|
5317
|
+
sessLine
|
|
5318
|
+
].join("\n");
|
|
5319
|
+
const completionId = `chatcmpl-debug-${Date.now()}`;
|
|
5320
|
+
const timestamp = Math.floor(Date.now() / 1e3);
|
|
5321
|
+
const syntheticResponse = {
|
|
5322
|
+
id: completionId,
|
|
5323
|
+
object: "chat.completion",
|
|
5324
|
+
created: timestamp,
|
|
5325
|
+
model: "clawrouter/debug",
|
|
5326
|
+
choices: [
|
|
5327
|
+
{
|
|
5328
|
+
index: 0,
|
|
5329
|
+
message: { role: "assistant", content: debugText },
|
|
5330
|
+
finish_reason: "stop"
|
|
5331
|
+
}
|
|
5332
|
+
],
|
|
5333
|
+
usage: { prompt_tokens: 0, completion_tokens: 0, total_tokens: 0 }
|
|
5334
|
+
};
|
|
5335
|
+
if (isStreaming) {
|
|
5336
|
+
res.writeHead(200, {
|
|
5337
|
+
"Content-Type": "text/event-stream",
|
|
5338
|
+
"Cache-Control": "no-cache",
|
|
5339
|
+
Connection: "keep-alive"
|
|
5340
|
+
});
|
|
5341
|
+
const sseChunk = {
|
|
5342
|
+
id: completionId,
|
|
5343
|
+
object: "chat.completion.chunk",
|
|
5344
|
+
created: timestamp,
|
|
5345
|
+
model: "clawrouter/debug",
|
|
5346
|
+
choices: [
|
|
5347
|
+
{
|
|
5348
|
+
index: 0,
|
|
5349
|
+
delta: { role: "assistant", content: debugText },
|
|
5350
|
+
finish_reason: null
|
|
5351
|
+
}
|
|
5352
|
+
]
|
|
5353
|
+
};
|
|
5354
|
+
const sseDone = {
|
|
5355
|
+
id: completionId,
|
|
5356
|
+
object: "chat.completion.chunk",
|
|
5357
|
+
created: timestamp,
|
|
5358
|
+
model: "clawrouter/debug",
|
|
5359
|
+
choices: [{ index: 0, delta: {}, finish_reason: "stop" }]
|
|
5360
|
+
};
|
|
5361
|
+
res.write(`data: ${JSON.stringify(sseChunk)}
|
|
5362
|
+
|
|
5363
|
+
`);
|
|
5364
|
+
res.write(`data: ${JSON.stringify(sseDone)}
|
|
5365
|
+
|
|
5366
|
+
`);
|
|
5367
|
+
res.write("data: [DONE]\n\n");
|
|
5368
|
+
res.end();
|
|
5369
|
+
} else {
|
|
5370
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
5371
|
+
res.end(JSON.stringify(syntheticResponse));
|
|
5372
|
+
}
|
|
5373
|
+
console.log(`[ClawRouter] /debug command \u2192 ${debugRouting.tier} | ${debugRouting.model}`);
|
|
5374
|
+
return;
|
|
5375
|
+
}
|
|
5223
5376
|
if (parsed.stream === true) {
|
|
5224
5377
|
parsed.stream = false;
|
|
5225
5378
|
bodyModified = true;
|
|
@@ -5274,20 +5427,20 @@ async function proxyRequest(req, res, apiBase, payFetch, options, routerOpts, de
|
|
|
5274
5427
|
sessionStore.touchSession(sessionId2);
|
|
5275
5428
|
} else {
|
|
5276
5429
|
const messages = parsed.messages;
|
|
5277
|
-
let
|
|
5430
|
+
let lastUserMsg2;
|
|
5278
5431
|
if (messages) {
|
|
5279
5432
|
for (let i = messages.length - 1; i >= 0; i--) {
|
|
5280
5433
|
if (messages[i].role === "user") {
|
|
5281
|
-
|
|
5434
|
+
lastUserMsg2 = messages[i];
|
|
5282
5435
|
break;
|
|
5283
5436
|
}
|
|
5284
5437
|
}
|
|
5285
5438
|
}
|
|
5286
5439
|
const systemMsg = messages?.find((m) => m.role === "system");
|
|
5287
|
-
const prompt = typeof
|
|
5440
|
+
const prompt = typeof lastUserMsg2?.content === "string" ? lastUserMsg2.content : "";
|
|
5288
5441
|
const systemPrompt = typeof systemMsg?.content === "string" ? systemMsg.content : void 0;
|
|
5289
5442
|
const tools = parsed.tools;
|
|
5290
|
-
|
|
5443
|
+
hasTools = Array.isArray(tools) && tools.length > 0;
|
|
5291
5444
|
if (hasTools && tools) {
|
|
5292
5445
|
console.log(
|
|
5293
5446
|
`[ClawRouter] Tools detected (${tools.length}), agentic mode via keywords`
|
|
@@ -5504,7 +5657,14 @@ async function proxyRequest(req, res, apiBase, payFetch, options, routerOpts, de
|
|
|
5504
5657
|
`[ClawRouter] Context filter (~${estimatedTotalTokens} tokens): excluded ${contextExcluded.join(", ")}`
|
|
5505
5658
|
);
|
|
5506
5659
|
}
|
|
5507
|
-
|
|
5660
|
+
const toolFiltered = filterByToolCalling(contextFiltered, hasTools, supportsToolCalling);
|
|
5661
|
+
const toolExcluded = contextFiltered.filter((m) => !toolFiltered.includes(m));
|
|
5662
|
+
if (toolExcluded.length > 0) {
|
|
5663
|
+
console.log(
|
|
5664
|
+
`[ClawRouter] Tool-calling filter: excluded ${toolExcluded.join(", ")} (no structured function call support)`
|
|
5665
|
+
);
|
|
5666
|
+
}
|
|
5667
|
+
modelsToTry = toolFiltered.slice(0, MAX_FALLBACK_ATTEMPTS);
|
|
5508
5668
|
modelsToTry = prioritizeNonRateLimited(modelsToTry);
|
|
5509
5669
|
} else {
|
|
5510
5670
|
if (modelId && modelId !== FREE_MODEL) {
|