@blockrun/clawrouter 0.12.249 → 0.12.251
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/README.md +34 -21
- package/dist/cli.js +946 -451
- package/dist/index.js +946 -451
- package/dist/router/index.js +910 -422
- package/docs/architecture.md +64 -50
- package/docs/configuration.md +63 -42
- package/docs/routing-profiles.md +90 -41
- package/package.json +2 -2
- package/skills/clawrouter/SKILL.md +11 -5
package/docs/architecture.md
CHANGED
|
@@ -96,16 +96,28 @@ if (inflight) {
|
|
|
96
96
|
// Extract user's last message
|
|
97
97
|
const prompt = messages.findLast((m) => m.role === "user")?.content;
|
|
98
98
|
|
|
99
|
-
//
|
|
99
|
+
// Router Core V3.5 (@blockrun/router-core): 15-dimension scorer → hard
|
|
100
|
+
// capability filters → portfolio ranking. Model capabilities come from the
|
|
101
|
+
// live catalog, injected at proxy startup.
|
|
100
102
|
const decision = route(prompt, systemPrompt, maxTokens, {
|
|
101
103
|
config: DEFAULT_ROUTING_CONFIG,
|
|
102
104
|
modelPricing,
|
|
105
|
+
modelCapabilities,
|
|
106
|
+
routingProfile: "auto",
|
|
107
|
+
hasTools,
|
|
108
|
+
toolCount,
|
|
109
|
+
toolNames,
|
|
110
|
+
hasVision,
|
|
103
111
|
});
|
|
104
112
|
|
|
105
113
|
// decision = {
|
|
106
114
|
// model: "google/gemini-2.5-flash",
|
|
107
115
|
// tier: "SIMPLE",
|
|
116
|
+
// taskType: "chat",
|
|
108
117
|
// confidence: 0.92,
|
|
118
|
+
// method: "portfolio",
|
|
119
|
+
// routerVersion: "v3-portfolio",
|
|
120
|
+
// candidates: ["google/gemini-2.5-flash", "google/gemini-3-flash-preview", ...],
|
|
109
121
|
// savings: 0.99,
|
|
110
122
|
// costEstimate: 0.0012,
|
|
111
123
|
// }
|
|
@@ -235,17 +247,12 @@ data: [DONE]
|
|
|
235
247
|
|
|
236
248
|
## Routing Engine
|
|
237
249
|
|
|
238
|
-
|
|
250
|
+
The routing engine lives in [`@blockrun/router-core`](https://github.com/BlockRunAI/router-core) (Router Core V3.5), a product-neutral package shared by ClawRouter, Franklin, the `@blockrun/llm` SDKs and ClawRouter-Hermes. `src/router/index.ts` is a single `export * from "@blockrun/router-core"`; the package is a `devDependency` inlined by tsup at build time and pinned to an immutable commit SHA. Nothing in the decision path touches the network.
|
|
239
251
|
|
|
240
|
-
|
|
252
|
+
### 1. Classify — 15-dimension weighted scorer
|
|
241
253
|
|
|
242
254
|
```typescript
|
|
243
|
-
function classifyByRules(
|
|
244
|
-
prompt: string,
|
|
245
|
-
systemPrompt: string | undefined,
|
|
246
|
-
tokenCount: number,
|
|
247
|
-
config: ScoringConfig,
|
|
248
|
-
): ClassificationResult {
|
|
255
|
+
function classifyByRules(prompt, systemPrompt, tokenCount, config): ClassificationResult {
|
|
249
256
|
let score = 0;
|
|
250
257
|
const signals: string[] = [];
|
|
251
258
|
|
|
@@ -262,51 +269,60 @@ function classifyByRules(
|
|
|
262
269
|
signals.push("code");
|
|
263
270
|
}
|
|
264
271
|
|
|
265
|
-
// ... 13 more dimensions
|
|
266
|
-
|
|
267
|
-
// Sigmoid calibration
|
|
268
|
-
const confidence = sigmoid(score, (k = 8), (midpoint = 0.5));
|
|
272
|
+
// ... 13 more dimensions (multiStepPatterns, technicalTerms, tokenCount,
|
|
273
|
+
// creativeMarkers, questionComplexity, constraintCount, agenticTask, ...)
|
|
269
274
|
|
|
275
|
+
// Sigmoid calibration (steepness 12), ambiguous below 0.7
|
|
276
|
+
const confidence = sigmoid(score, config.confidenceSteepness);
|
|
270
277
|
return { score, confidence, tier: selectTier(score, confidence), signals };
|
|
271
278
|
}
|
|
272
279
|
```
|
|
273
280
|
|
|
274
|
-
|
|
281
|
+
Tier boundaries: `< 0.3` SIMPLE, `< 0.5` COMPLEX, else REASONING (2+ reasoning markers short-circuit to REASONING). Alongside the tier, a task classifier derives the _shape_ of the work from the prompt, the visible tool names/count, requested output size and language: `chat`, `extraction`, `code_edit`, `code_agent`, `tool_agent`, `tool_agent_parallel`, `debug`, `reasoning`, `reasoning_mcq`, `reasoning_math`, `long_context`, `vision`.
|
|
275
282
|
|
|
276
|
-
|
|
277
|
-
function selectTier(score: number, confidence: number): Tier | null {
|
|
278
|
-
// Special case: 2+ reasoning markers → REASONING at high confidence
|
|
279
|
-
if (signals.includes("reasoning") && reasoningCount >= 2) {
|
|
280
|
-
return "REASONING";
|
|
281
|
-
}
|
|
283
|
+
### 2. Filter — hard eligibility
|
|
282
284
|
|
|
283
|
-
|
|
284
|
-
return null; // Ambiguous → default to MEDIUM
|
|
285
|
-
}
|
|
285
|
+
The tier's curated chain (primary + fallbacks) is the candidate pool. Before anything is scored, candidates are removed that:
|
|
286
286
|
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
```
|
|
287
|
+
- lack tool calling on a turn that requires tools (`inferToolRequirement` — `tool_choice: "none"` is authoritative; host tool descriptions alone never create a requirement)
|
|
288
|
+
- lack vision on image input
|
|
289
|
+
- have too small a context window for the conversation, or too small a max-output for the requested length
|
|
290
|
+
- take an incompatible structured-output path
|
|
291
|
+
- are absent from the live catalog injected by the proxy (`modelCapabilities`)
|
|
293
292
|
|
|
294
|
-
|
|
293
|
+
Capability errors never reach the preference stage — the router fails closed rather than optimistically cheap.
|
|
295
294
|
|
|
296
|
-
|
|
295
|
+
### 3. Rank — portfolio scoring
|
|
296
|
+
|
|
297
|
+
Survivors are scored on six bounded factors with per-profile weights (auto: quality 0.47 · capability 0.20 · cost 0.18 · speed 0.07 · reliability 0.03 · curated order 0.05; eco raises cost to 0.28, premium raises quality to 0.58). High-stakes turns boost quality and reliability, latency-sensitive turns boost speed; an `affinityFloorGap` stops a candidate far below the best task affinity from winning on price. Speed and reliability priors come from `model-profiles.generated.json` (BlockRun's gateway benchmark), decayed on a 30-day half-life.
|
|
298
|
+
|
|
299
|
+
### 4. Recover — the fallback chain
|
|
300
|
+
|
|
301
|
+
The full ranked list is returned as `decision.candidates`; the proxy walks it on timeouts and 5xx. The winner is chosen once per request — no mid-task drift, no auxiliary routing call.
|
|
302
|
+
|
|
303
|
+
### Overrides
|
|
297
304
|
|
|
298
305
|
```typescript
|
|
299
306
|
// Large context → COMPLEX
|
|
300
|
-
if (tokenCount >
|
|
307
|
+
if (tokenCount > config.overrides.maxTokensForceComplex /* 100_000 */) {
|
|
301
308
|
return { tier: "COMPLEX", method: "override:large_context" };
|
|
302
309
|
}
|
|
303
310
|
|
|
304
|
-
// Structured output (JSON/YAML) →
|
|
305
|
-
if (
|
|
306
|
-
return {
|
|
311
|
+
// Structured output (JSON/YAML) → at least MEDIUM
|
|
312
|
+
if (requiresStructuredOutput) {
|
|
313
|
+
return {
|
|
314
|
+
tier: max(tier, config.overrides.structuredOutputMinTier),
|
|
315
|
+
method: "override:structured",
|
|
316
|
+
};
|
|
307
317
|
}
|
|
308
318
|
```
|
|
309
319
|
|
|
320
|
+
### Escape hatches
|
|
321
|
+
|
|
322
|
+
- `routing.strategy = "rules"` — one-line rollback to the V2 primary-first selector.
|
|
323
|
+
- `routing.shadow = { strategy: "rules", sampleRate }` — recompute a comparison decision locally; reported on debug headers, never a second paid call.
|
|
324
|
+
- `unavailableModels` — the host can hard-remove models it observed dead at the gateway from every chain before selection (router-core API; not yet wired in the proxy — free-model liveness is enforced at build time by `src/router/free-model-liveness.test.ts` instead).
|
|
325
|
+
|
|
310
326
|
---
|
|
311
327
|
|
|
312
328
|
## Payment System
|
|
@@ -538,22 +554,20 @@ src/
|
|
|
538
554
|
├── retry.ts # Fetch retry with exponential backoff
|
|
539
555
|
├── version.ts # Version from package.json
|
|
540
556
|
└── router/
|
|
541
|
-
├── index.ts
|
|
542
|
-
├──
|
|
543
|
-
|
|
544
|
-
├── config.ts # Default routing configuration (ECO/AUTO/PREMIUM/AGENTIC)
|
|
545
|
-
└── types.ts # TypeScript type definitions
|
|
557
|
+
├── index.ts # export * from "@blockrun/router-core" (Router Core V3.5)
|
|
558
|
+
├── free-model-liveness.test.ts # build-time guard: no chain names a dead free model
|
|
559
|
+
└── brand-numbers.test.ts # README/SKILL brand markers stay in sync
|
|
546
560
|
```
|
|
547
561
|
|
|
548
562
|
### Key Files
|
|
549
563
|
|
|
550
|
-
| File | Purpose
|
|
551
|
-
| -------------------- |
|
|
552
|
-
| `proxy.ts` | Core request handling, SSE simulation, fallback chain
|
|
553
|
-
| `wallet.ts` | BIP-39 mnemonic generation, EVM + Solana (SLIP-10) derivation
|
|
554
|
-
| `router/
|
|
555
|
-
| `x402.ts` | EIP-712 typed data signing, payment header formatting
|
|
556
|
-
| `balance.ts` | USDC balance via Base RPC (EVM), caching, thresholds
|
|
557
|
-
| `solana-balance.ts` | USDC balance via Solana RPC (SPL Token), caching, retries
|
|
558
|
-
| `payment-preauth.ts` | Pre-authorization cache (EVM; skipped for Solana)
|
|
559
|
-
| `dedup.ts` | SHA-256 hashing, 30s response cache
|
|
564
|
+
| File | Purpose |
|
|
565
|
+
| -------------------- | ----------------------------------------------------------------------------------- |
|
|
566
|
+
| `proxy.ts` | Core request handling, SSE simulation, fallback chain |
|
|
567
|
+
| `wallet.ts` | BIP-39 mnemonic generation, EVM + Solana (SLIP-10) derivation |
|
|
568
|
+
| `router/index.ts` | Re-exports `@blockrun/router-core` (scorer, filters, portfolio ranker, tier config) |
|
|
569
|
+
| `x402.ts` | EIP-712 typed data signing, payment header formatting |
|
|
570
|
+
| `balance.ts` | USDC balance via Base RPC (EVM), caching, thresholds |
|
|
571
|
+
| `solana-balance.ts` | USDC balance via Solana RPC (SPL Token), caching, retries |
|
|
572
|
+
| `payment-preauth.ts` | Pre-authorization cache (EVM; skipped for Solana) |
|
|
573
|
+
| `dedup.ts` | SHA-256 hashing, 30s response cache |
|
package/docs/configuration.md
CHANGED
|
@@ -307,12 +307,18 @@ const decision = route("Prove sqrt(2) is irrational", undefined, 4096, {
|
|
|
307
307
|
|
|
308
308
|
console.log(decision);
|
|
309
309
|
// {
|
|
310
|
-
// model: "
|
|
310
|
+
// model: "xai/grok-4-1-fast-reasoning",
|
|
311
311
|
// tier: "REASONING",
|
|
312
|
+
// taskType: "reasoning_math",
|
|
312
313
|
// confidence: 0.97,
|
|
313
|
-
// method: "
|
|
314
|
-
//
|
|
315
|
-
//
|
|
314
|
+
// method: "portfolio",
|
|
315
|
+
// routerVersion: "v3-portfolio",
|
|
316
|
+
// profile: "auto",
|
|
317
|
+
// candidates: ["xai/grok-4-1-fast-reasoning", "xai/grok-4-fast-reasoning", "deepseek/deepseek-reasoner", ...],
|
|
318
|
+
// candidateScores: [{ model, score, quality, cost, speed, reliability }, ...],
|
|
319
|
+
// savings: 0.99,
|
|
320
|
+
// costEstimate: 0.0007,
|
|
321
|
+
// reasoning: "…",
|
|
316
322
|
// }
|
|
317
323
|
```
|
|
318
324
|
|
|
@@ -354,6 +360,8 @@ const proxy = await startProxy({
|
|
|
354
360
|
|
|
355
361
|
## Routing Configuration
|
|
356
362
|
|
|
363
|
+
Routing decisions are made by [`@blockrun/router-core`](https://github.com/BlockRunAI/router-core) (Router Core V3.4). The `routing` block is merged over router-core's `DEFAULT_ROUTING_CONFIG`: tier maps are merged per tier (override just `COMPLEX` without redefining the other three), `classifier` / `scoring` / `overrides` are merged per key, and `null` disables a tier set.
|
|
364
|
+
|
|
357
365
|
### Via openclaw.yaml
|
|
358
366
|
|
|
359
367
|
```yaml
|
|
@@ -378,22 +386,33 @@ plugins:
|
|
|
378
386
|
# Their cost is charged via x402 micropayment directly and is not tracked per-session.
|
|
379
387
|
|
|
380
388
|
routing:
|
|
381
|
-
#
|
|
389
|
+
# Strategy. Default: portfolio (Router Core V3.4 — constraint-first ranking
|
|
390
|
+
# over the tier's chain). "rules" is the one-line rollback to the V2
|
|
391
|
+
# primary-first selector.
|
|
392
|
+
strategy: portfolio
|
|
393
|
+
|
|
394
|
+
# Optional shadow evaluation: recompute a comparison decision locally on a
|
|
395
|
+
# sample of requests and report it on the x-clawrouter-* debug headers.
|
|
396
|
+
# Never issues a second paid completion, never persists prompt content.
|
|
397
|
+
# shadow:
|
|
398
|
+
# strategy: rules
|
|
399
|
+
# sampleRate: 0.1
|
|
400
|
+
|
|
401
|
+
# Override tier chains (auto profile). Each tier is merged individually,
|
|
402
|
+
# so you can override just COMPLEX. Under the portfolio strategy the
|
|
403
|
+
# chain is the candidate pool: primary is the curated head, the ranker
|
|
404
|
+
# still enforces tool/vision/context constraints and may pick a fallback.
|
|
382
405
|
tiers:
|
|
383
|
-
SIMPLE:
|
|
384
|
-
primary: "google/gemini-2.5-flash"
|
|
385
|
-
fallback: ["deepseek/deepseek-chat"]
|
|
386
|
-
MEDIUM:
|
|
387
|
-
primary: "deepseek/deepseek-chat"
|
|
388
|
-
fallback: ["openai/gpt-4o-mini"]
|
|
389
406
|
COMPLEX:
|
|
390
|
-
primary: "anthropic/claude-sonnet-
|
|
391
|
-
fallback: ["openai/gpt-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
407
|
+
primary: "anthropic/claude-sonnet-5"
|
|
408
|
+
fallback: ["google/gemini-3.1-pro", "openai/gpt-5.6-terra"]
|
|
409
|
+
|
|
410
|
+
# Same shape for the other tier sets:
|
|
411
|
+
# ecoTiers: { ... }
|
|
412
|
+
# premiumTiers: { ... }
|
|
413
|
+
# agenticTiers: { ... } # or `null` to disable agentic switching entirely
|
|
395
414
|
|
|
396
|
-
# Override scoring
|
|
415
|
+
# Override scoring keywords
|
|
397
416
|
scoring:
|
|
398
417
|
reasoningKeywords: ["prove", "theorem", "formal", "derive"]
|
|
399
418
|
codeKeywords: ["function", "class", "async", "import"]
|
|
@@ -402,38 +421,41 @@ plugins:
|
|
|
402
421
|
# Override thresholds
|
|
403
422
|
classifier:
|
|
404
423
|
confidenceThreshold: 0.7
|
|
405
|
-
reasoningConfidence: 0.97
|
|
406
424
|
|
|
407
425
|
# Context-based overrides
|
|
408
426
|
overrides:
|
|
409
|
-
|
|
410
|
-
|
|
427
|
+
maxTokensForceComplex: 100000 # Force COMPLEX above this many tokens
|
|
428
|
+
structuredOutputMinTier: MEDIUM # Bump to at least MEDIUM for JSON/YAML
|
|
429
|
+
ambiguousDefaultTier: MEDIUM # Where low-confidence requests land
|
|
430
|
+
# agenticMode: true | false # force / disable the agentic tier set (default: auto-detect)
|
|
411
431
|
```
|
|
412
432
|
|
|
413
433
|
---
|
|
414
434
|
|
|
415
435
|
## Tier Overrides
|
|
416
436
|
|
|
417
|
-
### Default Tier Mappings
|
|
437
|
+
### Default Tier Mappings (auto profile)
|
|
438
|
+
|
|
439
|
+
Curated primaries from router-core's `DEFAULT_ROUTING_CONFIG.tiers`; chains truncated. The full chains for every profile — and the eco / premium / agentic tier sets — are in [routing-profiles.md](./routing-profiles.md).
|
|
418
440
|
|
|
419
|
-
| Tier | Primary Model
|
|
420
|
-
| --------- |
|
|
421
|
-
| SIMPLE | `google/gemini-2.5-flash`
|
|
422
|
-
| MEDIUM | `
|
|
423
|
-
| COMPLEX | `
|
|
424
|
-
| REASONING | `deepseek/deepseek-reasoner`
|
|
441
|
+
| Tier | Primary Model | Fallback Chain (head) |
|
|
442
|
+
| --------- | ---------------------------- | ------------------------------------------------------------------ |
|
|
443
|
+
| SIMPLE | `google/gemini-2.5-flash` | `google/gemini-3-flash-preview`, `google/gemini-3.5-flash-lite`, … |
|
|
444
|
+
| MEDIUM | `google/gemini-3.5-flash` | `google/gemini-3.6-flash`, `zai/glm-5.3-flash`, … |
|
|
445
|
+
| COMPLEX | `google/gemini-3.1-pro` | `google/gemini-3.6-flash`, `google/gemini-3.5-flash`, … |
|
|
446
|
+
| REASONING | `deepseek/deepseek-reasoner` | `deepseek/deepseek-v4-pro`, `xai/grok-4.3`, … |
|
|
425
447
|
|
|
426
448
|
### Fallback Chain
|
|
427
449
|
|
|
428
|
-
When the
|
|
450
|
+
The ranked candidate list is returned on every decision (`decision.candidates`). When the selected model fails (rate limits, billing errors, provider outages, timeouts), ClawRouter tries the next candidate:
|
|
429
451
|
|
|
430
452
|
```
|
|
431
|
-
Request → gemini-
|
|
432
|
-
→
|
|
433
|
-
→
|
|
453
|
+
Request → gemini-3.1-pro (503)
|
|
454
|
+
→ gemini-3-flash-preview (rate limited)
|
|
455
|
+
→ grok-4-0709 (success)
|
|
434
456
|
```
|
|
435
457
|
|
|
436
|
-
|
|
458
|
+
Candidates that fail a hard constraint (no tool calling on a tool turn, no vision on image input, too small a context window) are removed before ranking, so a fallback never lands on a model that cannot serve the request.
|
|
437
459
|
|
|
438
460
|
### Custom Tier Configuration
|
|
439
461
|
|
|
@@ -441,10 +463,10 @@ Max fallback attempts: 3 models per request.
|
|
|
441
463
|
routing:
|
|
442
464
|
tiers:
|
|
443
465
|
COMPLEX:
|
|
444
|
-
primary: "openai/gpt-
|
|
466
|
+
primary: "openai/gpt-5.6-terra" # Use GPT-5.6 Terra instead of Gemini 3.1 Pro
|
|
445
467
|
fallback:
|
|
446
|
-
- "anthropic/claude-sonnet-
|
|
447
|
-
- "google/gemini-
|
|
468
|
+
- "anthropic/claude-sonnet-5"
|
|
469
|
+
- "google/gemini-3.1-pro"
|
|
448
470
|
```
|
|
449
471
|
|
|
450
472
|
---
|
|
@@ -458,12 +480,12 @@ The 15-dimension weighted scorer determines query complexity:
|
|
|
458
480
|
| `reasoningMarkers` | 0.18 | "prove", "theorem", "step by step" |
|
|
459
481
|
| `codePresence` | 0.15 | "function", "async", "import", "```" |
|
|
460
482
|
| `multiStepPatterns` | 0.12 | "first...then", "step 1", numbered lists |
|
|
461
|
-
| `agenticTask` | 0.10 | "run", "test", "fix", "deploy", "edit" |
|
|
462
483
|
| `technicalTerms` | 0.10 | "algorithm", "kubernetes", "distributed" |
|
|
463
484
|
| `tokenCount` | 0.08 | short (<50) vs long (>500) |
|
|
464
485
|
| `creativeMarkers` | 0.05 | "story", "poem", "brainstorm" |
|
|
465
486
|
| `questionComplexity` | 0.05 | Multiple question marks |
|
|
466
487
|
| `constraintCount` | 0.04 | "at most", "O(n)", "maximum" |
|
|
488
|
+
| `agenticTask` | 0.04 | "run", "test", "fix", "deploy", "edit" |
|
|
467
489
|
| `imperativeVerbs` | 0.03 | "build", "create", "implement" |
|
|
468
490
|
| `outputFormat` | 0.03 | "json", "yaml", "schema" |
|
|
469
491
|
| `simpleIndicators` | 0.02 | "what is", "define", "translate" |
|
|
@@ -500,10 +522,12 @@ The classifier uses sigmoid calibration to convert raw scores to confidence valu
|
|
|
500
522
|
confidence = 1 / (1 + exp(-k * (score - midpoint)))
|
|
501
523
|
```
|
|
502
524
|
|
|
503
|
-
Parameters:
|
|
525
|
+
Parameters (router-core `classifier`):
|
|
504
526
|
|
|
505
|
-
- `
|
|
506
|
-
- `
|
|
527
|
+
- `confidenceSteepness = 12` — steepness of the sigmoid curve
|
|
528
|
+
- `confidenceThreshold = 0.7` — below this the request is ambiguous and lands on `overrides.ambiguousDefaultTier` (MEDIUM)
|
|
529
|
+
|
|
530
|
+
Tier boundaries on the weighted-score axis: `mediumComplex = 0.3`, `complexReasoning = 0.5`.
|
|
507
531
|
|
|
508
532
|
### Override Thresholds
|
|
509
533
|
|
|
@@ -512,9 +536,6 @@ routing:
|
|
|
512
536
|
classifier:
|
|
513
537
|
# Require higher confidence for tier assignment
|
|
514
538
|
confidenceThreshold: 0.8 # Default: 0.7
|
|
515
|
-
|
|
516
|
-
# Force REASONING tier at lower confidence
|
|
517
|
-
reasoningConfidence: 0.90 # Default: 0.97
|
|
518
539
|
```
|
|
519
540
|
|
|
520
541
|
---
|
package/docs/routing-profiles.md
CHANGED
|
@@ -1,62 +1,106 @@
|
|
|
1
1
|
# Routing Profiles & Pricing
|
|
2
2
|
|
|
3
|
-
ClawRouter offers four routing profiles to balance cost vs quality. Prices are in **$/M tokens** (input/output)
|
|
3
|
+
ClawRouter offers four routing profiles to balance cost vs quality. Prices are in **$/M tokens** (input/output), taken from `src/models.ts` (which mirrors the live BlockRun catalog).
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Routing decisions are made by [`@blockrun/router-core`](https://github.com/BlockRunAI/router-core) (Router Core **V3.4**, the constraint-first portfolio router), which ClawRouter inlines at build time and pins by commit SHA. `src/router/index.ts` simply re-exports it. Nothing below calls a network or a second model: classification, eligibility filtering and ranking all run locally in about a quarter of a millisecond.
|
|
6
|
+
|
|
7
|
+
## How a request is routed
|
|
8
|
+
|
|
9
|
+
1. **Classify.** A 15-dimension weighted scorer maps the request onto a capability tier — `SIMPLE`, `MEDIUM`, `COMPLEX` or `REASONING` — and a task classifier labels the _shape_ of the work (`chat`, `extraction`, `code_edit`, `code_agent`, `tool_agent`, `tool_agent_parallel`, `debug`, `reasoning`, `reasoning_math`, `long_context`, `vision`, …). Turns that actually need their attached tools switch to the **agentic** tier set automatically.
|
|
10
|
+
2. **Filter.** The tier's curated chain (primary + fallbacks, below) is the candidate pool. Every model that cannot satisfy the request is removed **before** scoring: no tool calling on a tool-required turn, no vision on image input, too small a context window, too small a max-output, an incompatible structured-output path, or absent from the live catalog. Being cheap never compensates for failing the contract.
|
|
11
|
+
3. **Rank.** Survivors are scored on task quality, capability, estimated cost, speed, reliability and a small curated-order prior. The weights differ per profile (see [Profile weights](#profile-weights)).
|
|
12
|
+
4. **Recover.** The full ranked list stays on the decision as `candidates`. The proxy walks it on a timeout or 5xx, so a provider outage costs a retry, not the task.
|
|
13
|
+
|
|
14
|
+
The tables show each tier's **curated primary** and its fallback chain as configured in router-core. Under the portfolio strategy the primary is the head of the candidate pool and carries the curated-order prior; it is the usual winner, not a guarantee — a request that needs vision or a 1M context can legitimately land on a fallback.
|
|
15
|
+
|
|
16
|
+
---
|
|
6
17
|
|
|
7
|
-
|
|
18
|
+
## AUTO (Balanced — Default)
|
|
8
19
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
|
12
|
-
|
|
|
13
|
-
|
|
|
14
|
-
|
|
|
20
|
+
Use `blockrun/auto` (or `/model auto`) for the best quality/price balance.
|
|
21
|
+
|
|
22
|
+
| Tier | Primary Model | Input | Output | Fallback chain (in order) |
|
|
23
|
+
| --------- | -------------------------- | ----- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
24
|
+
| SIMPLE | google/gemini-2.5-flash | $0.30 | $2.50 | gemini-3-flash-preview → gemini-3.5-flash-lite → deepseek-chat → gemini-3.1-flash-lite → gpt-5.6-luna → gpt-5.4-nano → gemini-2.5-flash-lite → step-3.7-flash (free) |
|
|
25
|
+
| MEDIUM | google/gemini-3.5-flash | $1.50 | $9.00 | gemini-3.6-flash → glm-5.3-flash → gpt-5.6-terra → gemini-3-flash-preview → deepseek-chat → gemini-2.5-flash → minimax-m3 → gemini-3.1-flash-lite → gpt-5.6-luna → gemini-2.5-flash-lite |
|
|
26
|
+
| COMPLEX | google/gemini-3.1-pro | $2.00 | $12.00 | gemini-3.6-flash → gemini-3.5-flash → claude-sonnet-5 → grok-4.5 → gemini-2.5-pro → claude-sonnet-4.6 → gpt-5.6-terra → gpt-5.5 → gpt-5.4 → glm-5.3 → kimi-k3 → deepseek-v4-pro → deepseek-chat → gemini-2.5-flash |
|
|
27
|
+
| REASONING | deepseek/deepseek-reasoner | $0.14 | $0.28 | deepseek-v4-pro → grok-4.3 → qwen3.7-plus → gemini-3.5-flash → o4-mini → o3 |
|
|
15
28
|
|
|
16
29
|
---
|
|
17
30
|
|
|
18
|
-
##
|
|
31
|
+
## ECO (Absolute Cheapest)
|
|
32
|
+
|
|
33
|
+
Use `blockrun/eco` for maximum cost savings. The first stop is the free tier, so simple requests can cost $0.00.
|
|
19
34
|
|
|
20
|
-
|
|
35
|
+
| Tier | Primary Model | Input | Output | Fallback chain (in order) |
|
|
36
|
+
| --------- | -------------------------- | ----- | ------ | ------------------------------------------------------------------------------------------------------------------------ |
|
|
37
|
+
| SIMPLE | free/step-3.7-flash | $0.00 | $0.00 | nemotron-nano-9b-v2 (free) → gemini-2.5-flash-lite → glm-5.3-flash → gpt-5.6-luna → gpt-5.4-nano → gemini-3.1-flash-lite |
|
|
38
|
+
| MEDIUM | zai/glm-5.3-flash | $0.15 | $0.50 | deepseek-chat → gemini-3.1-flash-lite → gpt-5.6-luna → gpt-5.4-nano → gemini-2.5-flash-lite → gemini-2.5-flash |
|
|
39
|
+
| COMPLEX | zai/glm-5.3-flash | $0.15 | $0.50 | deepseek-chat → minimax-m3 → deepseek-v4-pro → gemini-3.1-flash-lite → gemini-2.5-flash |
|
|
40
|
+
| REASONING | deepseek/deepseek-reasoner | $0.14 | $0.28 | deepseek-v4-pro → qwen3.7-plus → minimax-m3 → glm-5.3-flash |
|
|
21
41
|
|
|
22
|
-
|
|
23
|
-
| --------- | --------------------------- | ----- | ------ |
|
|
24
|
-
| SIMPLE | google/gemini-2.5-flash | $0.30 | $2.50 |
|
|
25
|
-
| MEDIUM | moonshot/kimi-k2.6 | $0.95 | $4.00 |
|
|
26
|
-
| COMPLEX | google/gemini-3.1-pro | $2.00 | $12.00 |
|
|
27
|
-
| REASONING | xai/grok-4-1-fast-reasoning | $0.20 | $0.50 |
|
|
42
|
+
The two free rungs at the head of ECO SIMPLE follow NVIDIA's free hosting, which retires models without notice (deepseek-v4-flash 410'd 2026-08-12, seed-oss-36b 2026-08-03, gpt-oss-120b hung 2026-08-16). Each retirement retargets the free rungs to the current free tier; the paid rungs never move. `src/router/free-model-liveness.test.ts` fails the build if a chain names a free model the picker no longer lists.
|
|
28
43
|
|
|
29
44
|
---
|
|
30
45
|
|
|
31
46
|
## PREMIUM (Best Quality)
|
|
32
47
|
|
|
33
|
-
Use `blockrun/premium` for maximum quality.
|
|
48
|
+
Use `blockrun/premium` for maximum quality. Codex for complex coding, Gemini 3.5 Flash for simple work, Sonnet 5 for reasoning/instructions, Fable/Opus for architecture, audits and PM-grade work.
|
|
49
|
+
|
|
50
|
+
| Tier | Primary Model | Input | Output | Fallback chain (in order) |
|
|
51
|
+
| --------- | ------------------------- | ------ | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
52
|
+
| SIMPLE | google/gemini-3.5-flash | $1.50 | $9.00 | gemini-3.6-flash → claude-haiku-4.5 → glm-5.3 → gemini-2.5-flash → gemini-3.5-flash-lite → deepseek-chat |
|
|
53
|
+
| MEDIUM | openai/gpt-5.3-codex | $1.75 | $14.00 | claude-sonnet-5 → kimi-k3 → glm-5.3 → gemini-3.6-flash → gemini-3.5-flash → gemini-2.5-pro → grok-4.5 → claude-sonnet-4.6 → gpt-5.6-terra |
|
|
54
|
+
| COMPLEX | anthropic/claude-fable-5 | $10.00 | $50.00 | claude-opus-5 → claude-opus-4.8 → claude-opus-4.7 → claude-sonnet-5 → claude-sonnet-4.6 → grok-4.5 → kimi-k3 → gpt-5.6-terra → gpt-5.5 → gpt-5.4 → gpt-5.3-codex → glm-5.3 → deepseek-v4-pro → deepseek-chat → step-3.7-flash (free) |
|
|
55
|
+
| REASONING | anthropic/claude-sonnet-5 | $3.00 | $15.00 | claude-sonnet-4.6 → claude-opus-5 → claude-opus-4.8 → claude-opus-4.7 → grok-4.5 → deepseek-v4-pro → grok-4.3 → o4-mini → o3 |
|
|
56
|
+
|
|
57
|
+
The premium COMPLEX chain is deliberately de-Gemini'd: Google's "high demand" 503s correlate with Anthropic outages (everyone falls back to Google at the same time), so the chain prefers the in-family Opus hot swaps, then xAI, Moonshot, OpenAI and Z.AI — providers on independent infrastructure.
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## AGENTIC (Multi-Step Tool Use)
|
|
62
|
+
|
|
63
|
+
Not a profile you pick — router-core switches to these tiers when the turn actually needs its attached tools (`inferToolRequirement`: `tool_choice: "none"` is authoritative, and host tool _descriptions_ alone do not trigger it). Primaries favour models that keep going instead of stopping to ask.
|
|
64
|
+
|
|
65
|
+
| Tier | Primary Model | Input | Output | Fallback chain (in order) |
|
|
66
|
+
| --------- | ------------------------- | ----- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
67
|
+
| SIMPLE | openai/gpt-4o-mini | $0.15 | $0.60 | gpt-5.6-luna → glm-5.3-flash → claude-haiku-4.5 → gemini-2.5-flash |
|
|
68
|
+
| MEDIUM | openai/gpt-5-mini | $0.25 | $2.00 | gemini-3.5-flash → glm-5.3-flash → gpt-5.6-terra → gpt-4o-mini → claude-haiku-4.5 → deepseek-chat → kimi-k3 |
|
|
69
|
+
| COMPLEX | anthropic/claude-sonnet-5 | $3.00 | $15.00 | claude-sonnet-4.6 → claude-opus-5 → claude-opus-4.8 → claude-opus-4.7 → grok-4.5 → kimi-k3 → gpt-5.6-terra → gpt-5.5 → gpt-5.4 → gpt-5.3-codex → glm-5.3 → deepseek-v4-pro → deepseek-chat → step-3.7-flash (free) |
|
|
70
|
+
| REASONING | anthropic/claude-sonnet-5 | $3.00 | $15.00 | claude-sonnet-4.6 → claude-opus-5 → claude-opus-4.8 → claude-opus-4.7 → grok-4.5 → deepseek-v4-pro → deepseek-reasoner |
|
|
71
|
+
|
|
72
|
+
Set `routing.overrides.agenticMode: false` to disable the agentic tier set, or `true` to force it.
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## FREE (`/model free`)
|
|
77
|
+
|
|
78
|
+
`free` is an alias, not a routed profile: it pins the free-tier default, currently **`free/step-3.7-flash`** — the same model that opens ECO SIMPLE. If that model is excluded (`/exclude add step-flash`) or the budget cap forces a free fallback, the proxy walks the free cascade in this order: step-3.7-flash → nemotron-nano-9b-v2 → mistral-nemotron → nemotron-3-nano-omni-30b-a3b-reasoning (vision) → nemotron-nano-12b-v2-vl (vision). All five are NVIDIA-hosted, $0.00, and need no USDC.
|
|
34
79
|
|
|
35
|
-
|
|
36
|
-
| --------- | -------------------- | ------ | ------ |
|
|
37
|
-
| SIMPLE | moonshot/kimi-k2.6 | $0.95 | $4.00 |
|
|
38
|
-
| MEDIUM | openai/gpt-5.3-codex | $1.75 | $14.00 |
|
|
39
|
-
| COMPLEX | claude-fable-5 | $10.00 | $50.00 |
|
|
40
|
-
| REASONING | claude-sonnet-4.6 | $3.00 | $15.00 |
|
|
80
|
+
Pin any of them directly with `/model step-flash`, `/model nemotron-nano`, `/model mistral-nemotron`, `/model nemotron-omni` (vision) or `/model nano-vl` (vision).
|
|
41
81
|
|
|
42
82
|
---
|
|
43
83
|
|
|
44
|
-
##
|
|
84
|
+
## Profile weights
|
|
45
85
|
|
|
46
|
-
|
|
86
|
+
How survivors are ranked, per profile (router-core `DEFAULT_ROUTING_CONFIG.portfolio`):
|
|
47
87
|
|
|
48
|
-
|
|
|
49
|
-
|
|
|
50
|
-
|
|
|
51
|
-
|
|
|
52
|
-
|
|
|
53
|
-
|
|
|
88
|
+
| Component | AUTO | ECO | PREMIUM | Role |
|
|
89
|
+
| ------------- | ---: | ---: | ------: | ------------------------------------------------------- |
|
|
90
|
+
| Task quality | 0.47 | 0.36 | 0.58 | Prefer models validated for the detected task shape |
|
|
91
|
+
| Capability | 0.20 | 0.20 | 0.20 | Preserve the request contract after hard filtering |
|
|
92
|
+
| Cost | 0.18 | 0.28 | 0.08 | Reward efficient qualified candidates |
|
|
93
|
+
| Speed | 0.07 | 0.10 | 0.06 | Ordinary interactive latency |
|
|
94
|
+
| Reliability | 0.03 | 0.04 | 0.06 | Prefer stable candidates |
|
|
95
|
+
| Curated order | 0.05 | 0.02 | 0.02 | A small, explainable prior toward the chain order above |
|
|
96
|
+
|
|
97
|
+
High-stakes turns add `+0.08` quality / `+0.05` reliability; latency-sensitive turns add `+0.08` speed. An `affinityFloorGap` (auto 0.10, eco 0.22, premium 0.05) stops a candidate materially below the best task affinity from winning on price alone — which is why ECO can still climb to a paid model for work the free tier would botch.
|
|
54
98
|
|
|
55
99
|
---
|
|
56
100
|
|
|
57
101
|
## ECO vs AUTO Savings
|
|
58
102
|
|
|
59
|
-
Combined input + output rate per 1M tokens:
|
|
103
|
+
Combined input + output rate per 1M tokens, primaries only:
|
|
60
104
|
|
|
61
105
|
| Tier | ECO | AUTO | Savings |
|
|
62
106
|
| --------- | ----- | ------ | -------- |
|
|
@@ -65,21 +109,26 @@ Combined input + output rate per 1M tokens:
|
|
|
65
109
|
| COMPLEX | $1.75 | $14.00 | **88%** |
|
|
66
110
|
| REASONING | $0.70 | $0.70 | 0% |
|
|
67
111
|
|
|
112
|
+
The published savings claim (**88%** on `auto`, **98%** on `eco`, against pinning Claude Opus 5) is blended across a stated workload mix and priced on the live catalog — see [`savings-mix.json`](https://github.com/BlockRunAI/blockrun/blob/main/src/brand/savings-mix.json). Per-tier numbers above are illustrative; the blended figure is the one to quote.
|
|
113
|
+
|
|
68
114
|
---
|
|
69
115
|
|
|
70
116
|
## How Tiers Work
|
|
71
117
|
|
|
72
|
-
|
|
118
|
+
- **SIMPLE**: factual lookups, greetings, translations, short responses
|
|
119
|
+
- **MEDIUM**: summaries, explanations, data extraction, moderate code
|
|
120
|
+
- **COMPLEX**: large context, multi-step analysis, substantial code generation
|
|
121
|
+
- **REASONING**: proofs, formal logic, multi-step math, chain-of-thought
|
|
122
|
+
|
|
123
|
+
Two overrides apply on top of the scorer: conversations above 100K tokens are forced to COMPLEX, and structured-output requests (JSON/YAML) are lifted to at least MEDIUM. Ambiguous requests (confidence < 0.7) default to MEDIUM.
|
|
73
124
|
|
|
74
|
-
|
|
75
|
-
- **MEDIUM**: Code generation, moderate complexity tasks
|
|
76
|
-
- **COMPLEX**: Large context, multi-step reasoning, complex code
|
|
77
|
-
- **REASONING**: Logic puzzles, math, chain-of-thought tasks
|
|
125
|
+
## Rollback and shadow mode
|
|
78
126
|
|
|
79
|
-
|
|
127
|
+
- `routing.strategy: "rules"` reverts to the V2 tier selector (primary-first, no portfolio ranking) without a code change.
|
|
128
|
+
- `routing.shadow: { strategy: "rules", sampleRate: 0.1 }` recomputes a comparison decision locally on a sample of requests and reports it on `x-clawrouter-*` debug headers. It never issues a second paid completion and never persists prompt content.
|
|
80
129
|
|
|
81
|
-
|
|
130
|
+
See [configuration.md](./configuration.md#routing-configuration) for the YAML.
|
|
82
131
|
|
|
83
132
|
---
|
|
84
133
|
|
|
85
|
-
_Last updated: v0.12.
|
|
134
|
+
_Last updated: v0.12.250 — router-core V3.4 (commit `d7bc10c`)_
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@blockrun/clawrouter",
|
|
3
|
-
"version": "0.12.
|
|
3
|
+
"version": "0.12.251",
|
|
4
4
|
"description": "Smart LLM router — save 88% on inference costs. 71 models (5 free), one wallet, x402 micropayments.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -111,7 +111,7 @@
|
|
|
111
111
|
}
|
|
112
112
|
},
|
|
113
113
|
"devDependencies": {
|
|
114
|
-
"@blockrun/router-core": "https://codeload.github.com/BlockRunAI/router-core/tar.gz/
|
|
114
|
+
"@blockrun/router-core": "https://codeload.github.com/BlockRunAI/router-core/tar.gz/5d911879d7f1eddf93d513b08798998320272cc8",
|
|
115
115
|
"@eslint/js": "^10.0.1",
|
|
116
116
|
"eslint": "^10.2.0",
|
|
117
117
|
"openclaw": "^2026.7.2-beta.7",
|
|
@@ -86,7 +86,7 @@ ClawRouter does **not** collect or forward third-party provider API keys. You do
|
|
|
86
86
|
| `walletKey` | Yes | EVM private key used to sign USDC micropayments via x402. **Auto-generated locally on first run** — no user input required. Never transmitted over the network; only detached payment signatures are sent. |
|
|
87
87
|
| `solanaKey` | Yes | Solana keypair (BIP-44 `m/44'/501'/0'/0'`). Auto-derived from the same local mnemonic via `@scure/bip32` + `@scure/bip39`. |
|
|
88
88
|
| `gateway` | No | Gateway URL. Defaults: `https://sol.blockrun.ai/api` (Solana, default chain for new installs) · `https://blockrun.ai/api` (Base, default for pre-existing installs). |
|
|
89
|
-
| `routing` | No | Optional override of the
|
|
89
|
+
| `routing` | No | Optional override of the router-core config (tier chains, `strategy: "rules"` rollback, `shadow` comparison, scorer keywords). |
|
|
90
90
|
|
|
91
91
|
**How and where keys are stored:**
|
|
92
92
|
|
|
@@ -124,21 +124,27 @@ openclaw models set openai/gpt-4o
|
|
|
124
124
|
|
|
125
125
|
## How Routing Works
|
|
126
126
|
|
|
127
|
-
|
|
127
|
+
Routing is done locally by [`@blockrun/router-core`](https://github.com/BlockRunAI/router-core) (Router Core V3.4, constraint-first), inlined into ClawRouter and pinned by commit. No network call, no second model — about a quarter of a millisecond per request.
|
|
128
|
+
|
|
129
|
+
1. A 15-dimension weighted scorer classifies each request into one of four tiers, and a task classifier labels the shape of the work (chat, extraction, code_edit, code_agent, tool_agent, reasoning_math, long_context, vision, …).
|
|
130
|
+
2. Models that cannot satisfy the request — no tool calling, no vision, too small a context window or max-output, incompatible structured output — are removed before anything is scored.
|
|
131
|
+
3. Survivors are ranked on task quality, capability, estimated cost, speed and reliability; the full ranked list is kept as the fallback chain for timeouts and 5xx.
|
|
132
|
+
|
|
133
|
+
Curated primaries on the default `auto` profile:
|
|
128
134
|
|
|
129
135
|
- **SIMPLE** — factual lookups, greetings, translations → gemini-2.5-flash ($0.30/$2.50)
|
|
130
136
|
- **MEDIUM** — summaries, explanations, data extraction → kimi-k2.7 ($0.95/$4.00)
|
|
131
137
|
- **COMPLEX** — code generation, multi-step analysis → gemini-3.1-pro ($2/$12)
|
|
132
138
|
- **REASONING** — proofs, formal logic, multi-step math → grok-4-1-fast-reasoning ($0.20/$0.50)
|
|
133
139
|
|
|
134
|
-
|
|
140
|
+
Turns that actually need their attached tools switch to agent-tuned tiers (gpt-4o-mini → kimi-k2.7 → claude-sonnet-4.6). `eco` opens on the free tier (step-3.7-flash); `premium` climbs to gpt-5.3-codex / claude-fable-5 / claude-sonnet-4.6. Full chains: [docs/routing-profiles.md](../../docs/routing-profiles.md).
|
|
141
|
+
|
|
142
|
+
Prices are per 1M input/output tokens. Per-tier
|
|
135
143
|
savings percentages are deliberately not quoted here: the published figure is
|
|
136
144
|
blended across a stated workload mix, and a per-tier number invites comparing
|
|
137
145
|
it against a baseline nobody wrote down. See
|
|
138
146
|
[savings-mix.json](https://github.com/BlockRunAI/blockrun/blob/main/src/brand/savings-mix.json).
|
|
139
147
|
|
|
140
|
-
Rules handle ~~80% of requests in <1ms. Only ambiguous queries hit the LLM classifier (~~$0.00003 per classification).
|
|
141
|
-
|
|
142
148
|
## Available Models
|
|
143
149
|
|
|
144
150
|
<!-- br:models.chatVisible -->71<!-- /br:models.chatVisible --> models including: gpt-5.6-terra [balanced, stable default], gpt-5.6-sol [flagship], gpt-5.6-luna [cost-efficient], gpt-5.6-sol/terra/luna-pro [pro reasoning tiers], gpt-5.5, gpt-5.5-pro [max compute], chat-latest [ChatGPT Instant], gpt-5.4, gpt-4o, o3, claude-fable-5, claude-opus-5 [Anthropic flagship, 1M ctx], claude-opus-4.8, claude-opus-4.7, claude-opus-4.5, claude-sonnet-5, claude-sonnet-4.6, gemini-3.1-pro, gemini-3.6-flash, gemini-3.5-flash-lite, gemini-2.5-flash, deepseek-v4-pro, deepseek-chat, grok-4.5, grok-4.3, grok-build-0.1, kimi-k3 [1M ctx flagship], kimi-k2.7, qwen3.7-max [Qwen flagship, 1M ctx], qwen3.7-plus, qwen3.7-flash, hy3 [Tencent], mimo [Xiaomi MiMo-V2.5 Pro, 1M ctx], and 5 free NVIDIA models (nemotron-3-nano-omni-30b-a3b-reasoning [vision], mistral-nemotron, step-3.7-flash, nemotron-nano-9b-v2, nemotron-nano-12b-v2-vl [vision]).
|