@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.
@@ -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
- // Run 15-dimension weighted scorer
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
- ### Weighted Scorer
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
- The routing engine uses a 15-dimension weighted scorer that runs entirely locally:
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
- ### Tier Selection
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
- ```typescript
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
- if (confidence < 0.7) {
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
- if (score < 0.3) return "SIMPLE";
288
- if (score < 0.6) return "MEDIUM";
289
- if (score < 0.8) return "COMPLEX";
290
- return "REASONING";
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
- ### Overrides
293
+ Capability errors never reach the preference stage — the router fails closed rather than optimistically cheap.
295
294
 
296
- Certain conditions force tier assignment:
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 > 100000) {
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) → min MEDIUM
305
- if (systemPrompt?.includes("json") || systemPrompt?.includes("yaml")) {
306
- return { tier: Math.max(tier, "MEDIUM"), method: "override:structured" };
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 # route() entry point
542
- ├── rules.ts # 15-dimension weighted scorer (9-language)
543
- ├── selector.ts # Tier → model selection + fallback
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/rules.ts` | 15-dimension weighted scorer, 9-language keyword sets |
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 |
@@ -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: "deepseek/deepseek-reasoner",
310
+ // model: "xai/grok-4-1-fast-reasoning",
311
311
  // tier: "REASONING",
312
+ // taskType: "reasoning_math",
312
313
  // confidence: 0.97,
313
- // method: "rules",
314
- // savings: 0.994,
315
- // costEstimate: 0.002,
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
- # Override tier assignments
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-4.6"
391
- fallback: ["openai/gpt-4o"]
392
- REASONING:
393
- primary: "deepseek/deepseek-reasoner"
394
- fallback: ["openai/o3-mini"]
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 parameters
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
- largeContextTokens: 100000 # Force COMPLEX above this
410
- structuredOutput: true # Bump to min MEDIUM for JSON/YAML
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 | Fallback Chain |
420
- | --------- | ----------------------------- | ----------------------------------------------- |
421
- | SIMPLE | `google/gemini-2.5-flash` | `deepseek/deepseek-chat` |
422
- | MEDIUM | `deepseek/deepseek-chat` | `openai/gpt-4o-mini`, `google/gemini-2.5-flash` |
423
- | COMPLEX | `anthropic/claude-sonnet-4.6` | `openai/gpt-4o`, `google/gemini-2.5-pro` |
424
- | REASONING | `deepseek/deepseek-reasoner` | `openai/o3-mini`, `anthropic/claude-sonnet-4.6` |
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 primary model fails (rate limits, billing errors, provider outages), ClawRouter tries the next model in the fallback chain:
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-2.5-flash (rate limited)
432
- → deepseek-chat (billing error)
433
- → gpt-4o-mini (success)
453
+ Request → gemini-3.1-pro (503)
454
+ → gemini-3-flash-preview (rate limited)
455
+ → grok-4-0709 (success)
434
456
  ```
435
457
 
436
- Max fallback attempts: 3 models per request.
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-4o" # Use GPT-4o instead of Claude
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-4.6"
447
- - "google/gemini-2.5-pro"
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
- - `k = 8` — steepness of the sigmoid curve
506
- - `midpoint = 0.5` — score at which confidence = 50%
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
  ---
@@ -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). Tables show each tier's **primary** model — every tier also carries a benchmark-ordered fallback chain (see `src/router/config.ts`).
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
- ## ECO (Absolute Cheapest)
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
- Use `blockrun/eco` for maximum cost savings.
18
+ ## AUTO (Balanced — Default)
8
19
 
9
- | Tier | Primary Model | Input | Output |
10
- | --------- | ---------------------------- | ----- | ------ |
11
- | SIMPLE | free/gpt-oss-120b | $0.00 | $0.00 |
12
- | MEDIUM | google/gemini-3.1-flash-lite | $0.25 | $1.50 |
13
- | COMPLEX | google/gemini-3.1-flash-lite | $0.25 | $1.50 |
14
- | REASONING | xai/grok-4-1-fast-reasoning | $0.20 | $0.50 |
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
- ## AUTO (Balanced - Default)
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
- Use `blockrun/auto` for the best quality/price balance.
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
- | Tier | Primary Model | Input | Output |
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
- | Tier | Primary Model | Input | Output |
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
- ## AGENTIC (Multi-Step Tasks)
84
+ ## Profile weights
45
85
 
46
- ClawRouter auto-detects agentic patterns (tool use, multi-step autonomy) and switches to agent-tuned primaries.
86
+ How survivors are ranked, per profile (router-core `DEFAULT_ROUTING_CONFIG.portfolio`):
47
87
 
48
- | Tier | Primary Model | Input | Output |
49
- | --------- | ------------------ | ----- | ------ |
50
- | SIMPLE | openai/gpt-4o-mini | $0.15 | $0.60 |
51
- | MEDIUM | moonshot/kimi-k2.6 | $0.95 | $4.00 |
52
- | COMPLEX | claude-sonnet-4.6 | $3.00 | $15.00 |
53
- | REASONING | claude-sonnet-4.6 | $3.00 | $15.00 |
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
- ClawRouter automatically classifies your query into one of four tiers:
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
- - **SIMPLE**: Basic questions, short responses, simple lookups
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
- The router picks the cheapest model capable of handling your query's tier.
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
- There is also a `blockrun/free` pin that routes exclusively across the free NVIDIA-hosted fleet (gpt-oss-120b default) — no USDC required.
130
+ See [configuration.md](./configuration.md#routing-configuration) for the YAML.
82
131
 
83
132
  ---
84
133
 
85
- _Last updated: v0.12.201_
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.249",
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/d7bc10ce184b3daa40bcc115b523fd629d847a52",
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 default four-tier router. |
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
- ClawRouter classifies each request into one of four tiers:
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
- Prices are per 1M input/output tokens, on the default `auto` profile. Per-tier
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]).