@blockrun/clawrouter 0.12.39 โ†’ 0.12.40

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 CHANGED
@@ -2,17 +2,19 @@
2
2
 
3
3
  <img src="assets/banner.png" alt="ClawRouter Banner" width="600">
4
4
 
5
- <h3>The agent-native LLM router for <a href="https://openclaw.ai">OpenClaw</a></h3>
5
+ <h1>The LLM router built for autonomous agents</h1>
6
6
 
7
- Route every request to the right model at the right price.<br>
8
- 15-dimension scoring, <1ms local routing, optimized for autonomous agents.<br>
9
- One wallet, 41+ models, zero API keys.
7
+ <p>Agents can't sign up for accounts. Agents can't enter credit cards.<br>
8
+ Agents can only sign transactions.<br><br>
9
+ <strong>ClawRouter is the only LLM router that lets agents operate independently.</strong></p>
10
10
 
11
- <img src="https://img.shields.io/badge/๐Ÿš€_92%25_Cost_Savings-success?style=for-the-badge" alt="92% savings">&nbsp;
11
+ <br>
12
+
13
+ <img src="https://img.shields.io/badge/๐Ÿค–_Agent--Native-black?style=for-the-badge" alt="Agent native">&nbsp;
12
14
  <img src="https://img.shields.io/badge/๐Ÿ”‘_Zero_API_Keys-blue?style=for-the-badge" alt="No API keys">&nbsp;
13
- <img src="https://img.shields.io/badge/๐Ÿค–_41+_Models-purple?style=for-the-badge" alt="41+ models">&nbsp;
14
- <img src="https://img.shields.io/badge/๐Ÿ’ฐ_Non--Custodial-orange?style=for-the-badge" alt="Non-custodial">&nbsp;
15
- <img src="https://img.shields.io/badge/โšก_<1ms_Routing-yellow?style=for-the-badge" alt="Fast routing">
15
+ <img src="https://img.shields.io/badge/โšก_Local_Routing-yellow?style=for-the-badge" alt="Local routing">&nbsp;
16
+ <img src="https://img.shields.io/badge/๐Ÿ’ฐ_x402_USDC-purple?style=for-the-badge" alt="x402 USDC">&nbsp;
17
+ <img src="https://img.shields.io/badge/๐Ÿ”“_Open_Source-green?style=for-the-badge" alt="Open source">
16
18
 
17
19
  [![npm version](https://img.shields.io/npm/v/@blockrun/clawrouter.svg?style=flat-square&color=cb3837)](https://npmjs.com/package/@blockrun/clawrouter)
18
20
  [![npm downloads](https://img.shields.io/npm/dm/@blockrun/clawrouter.svg?style=flat-square&color=blue)](https://npmjs.com/package/@blockrun/clawrouter)
@@ -32,27 +34,43 @@ One wallet, 41+ models, zero API keys.
32
34
 
33
35
  ---
34
36
 
35
- ## ๐Ÿ“‘ Quick Navigation
37
+ ## Why ClawRouter exists
38
+
39
+ Every other LLM router was built for **human developers** โ€” create an account, get an API key, pick a model from a dashboard, pay with a credit card.
40
+
41
+ **Agents can't do any of that.**
42
+
43
+ ClawRouter is built for the agent-first world:
44
+
45
+ - **No accounts** โ€” a wallet is generated locally, no signup
46
+ - **No API keys** โ€” your wallet signature IS authentication
47
+ - **No model selection** โ€” 15-dimension scoring picks the right model automatically
48
+ - **No credit cards** โ€” agents pay per-request with USDC via [x402](https://x402.org)
49
+ - **No trust required** โ€” runs locally, <1ms routing, zero external dependencies
50
+
51
+ This is the stack that lets agents operate autonomously: **x402 + USDC + local routing**.
52
+
53
+ ---
54
+
55
+ ## How it compares
36
56
 
37
- | Section | Description |
38
- | ----------------------------------------- | ------------------------------- |
39
- | [Quick Start](#-quick-start) | Install in 2 minutes |
40
- | [Routing Profiles](#-routing-profiles) | eco / auto / premium / free |
41
- | [Image Generation](#-image-generation) | /imagegen with 5 models |
42
- | [How It Works](#-how-it-works) | 15-dimension local routing |
43
- | [Models & Pricing](#-models--pricing) | 41+ models, full price list |
44
- | [Screenshots](#-screenshots) | See it in action |
45
- | [Payment](#-payment) | x402 non-custodial USDC |
46
- | [Configuration](#%EF%B8%8F-configuration) | Environment variables |
47
- | [Troubleshooting](#-troubleshooting) | `doctor` AI-powered diagnostics |
48
- | [vs OpenRouter](#-vs-openrouter) | Why ClawRouter wins |
49
- | [Support](#-support) | Telegram, X, founders |
57
+ | | OpenRouter | LiteLLM | Martian | Portkey | **ClawRouter** |
58
+ | ---------------- | ----------------- | ---------------- | ----------------- | ----------------- | ----------------------- |
59
+ | **Models** | 200+ | 100+ | Smart routing | Gateway | **41+** |
60
+ | **Routing** | Manual selection | Manual selection | Smart (closed) | Observability | **Smart (open source)** |
61
+ | **Auth** | Account + API key | Your API keys | Account + API key | Account + API key | **Wallet signature** |
62
+ | **Payment** | Credit card | BYO keys | Credit card | $49-499/mo | **USDC per-request** |
63
+ | **Runs locally** | No | Yes | No | No | **Yes** |
64
+ | **Open source** | No | Yes | No | Partial | **Yes** |
65
+ | **Agent-ready** | No | No | No | No | **Yes** |
50
66
 
51
- **API Docs:** [Image Generation & Editing](docs/image-generation.md) ยท [Architecture](docs/architecture.md) ยท [Configuration](docs/configuration.md)
67
+ โœ“ Open source ยท โœ“ Smart routing ยท โœ“ Runs locally ยท โœ“ Crypto native ยท โœ“ Agent ready
68
+
69
+ **We're the only one that checks all five boxes.**
52
70
 
53
71
  ---
54
72
 
55
- ## ๐Ÿš€ Quick Start
73
+ ## Quick Start
56
74
 
57
75
  ```bash
58
76
  # 1. Install with smart routing enabled
@@ -63,11 +81,11 @@ openclaw gateway restart
63
81
  # $5 is enough for thousands of requests
64
82
  ```
65
83
 
66
- Done! Smart routing (`blockrun/auto`) is now your default model.
84
+ Done. Smart routing (`blockrun/auto`) is now your default model.
67
85
 
68
86
  ---
69
87
 
70
- ## ๐ŸŽฏ Routing Profiles
88
+ ## Routing Profiles
71
89
 
72
90
  Choose your routing strategy with `/model <profile>`:
73
91
 
@@ -82,7 +100,26 @@ Choose your routing strategy with `/model <profile>`:
82
100
 
83
101
  ---
84
102
 
85
- ## ๐ŸŽจ Image Generation
103
+ ## How It Works
104
+
105
+ **100% local routing. <1ms latency. Zero external API calls.**
106
+
107
+ ```
108
+ Request โ†’ Weighted Scorer (15 dimensions) โ†’ Tier โ†’ Best Model โ†’ Response
109
+ ```
110
+
111
+ | Tier | ECO Model | AUTO Model | PREMIUM Model |
112
+ | --------- | ----------------------------------- | ---------------------------- | ---------------------------- |
113
+ | SIMPLE | nvidia/gpt-oss-120b (FREE) | kimi-k2.5 ($0.60/$3.00) | kimi-k2.5 |
114
+ | MEDIUM | gemini-2.5-flash-lite ($0.10/$0.40) | grok-code-fast ($0.20/$1.50) | gpt-5.2-codex ($1.75/$14.00) |
115
+ | COMPLEX | gemini-2.5-flash-lite ($0.10/$0.40) | gemini-3.1-pro ($2/$12) | claude-opus-4.6 ($5/$25) |
116
+ | REASONING | grok-4-fast ($0.20/$0.50) | grok-4-fast ($0.20/$0.50) | claude-sonnet-4.6 ($3/$15) |
117
+
118
+ **Blended average: $2.05/M** vs $25/M for Claude Opus = **92% savings**
119
+
120
+ ---
121
+
122
+ ## Image Generation
86
123
 
87
124
  Generate images directly from chat with `/imagegen`:
88
125
 
@@ -100,16 +137,13 @@ Generate images directly from chat with `/imagegen`:
100
137
  | `gpt-image` | OpenAI GPT Image 1 | $0.02/image | 1536x1024 |
101
138
  | `flux` | Black Forest Flux 1.1 | $0.04/image | 1024x1024 |
102
139
 
103
- Default model: `nano-banana`. Images are returned as hosted URLs for compatibility with Telegram, Discord, and other clients.
104
-
105
- ## โœ๏ธ Image Editing (img2img)
140
+ ## Image Editing (img2img)
106
141
 
107
- Edit existing images with `/img2img` โ€” pass a local file and describe what to change:
142
+ Edit existing images with `/img2img`:
108
143
 
109
144
  ```
110
145
  /img2img --image ~/photo.png change the background to a starry sky
111
146
  /img2img --image ./cat.jpg --mask ./mask.png remove the background
112
- /img2img --image /tmp/portrait.png --size 1536x1024 add a hat
113
147
  ```
114
148
 
115
149
  | Option | Required | Description |
@@ -119,40 +153,11 @@ Edit existing images with `/img2img` โ€” pass a local file and describe what to
119
153
  | `--model <model>` | No | Model to use (default: `gpt-image-1`) |
120
154
  | `--size <WxH>` | No | Output size (default: `1024x1024`) |
121
155
 
122
- Supported model: `gpt-image-1` (OpenAI GPT Image 1, $0.02/image).
123
-
124
- **API endpoint:** `POST http://localhost:8402/v1/images/image2image` โ€” accepts local file paths, URLs, or base64 data URIs:
125
-
126
- ```bash
127
- curl -X POST http://localhost:8402/v1/images/image2image \
128
- -H "Content-Type: application/json" \
129
- -d '{"prompt":"add sunglasses","image":"~/photo.png"}'
130
- ```
131
-
132
- See [Image Generation & Editing docs](docs/image-generation.md#post-v1imagesimage2image) for full API reference and code examples.
156
+ **API endpoint:** `POST http://localhost:8402/v1/images/image2image` โ€” see [full docs](docs/image-generation.md#post-v1imagesimage2image).
133
157
 
134
158
  ---
135
159
 
136
- ## โšก How It Works
137
-
138
- **100% local routing. <1ms latency. Zero external API calls.**
139
-
140
- ```
141
- Request โ†’ Weighted Scorer (15 dimensions) โ†’ Tier โ†’ Cheapest Model โ†’ Response
142
- ```
143
-
144
- | Tier | ECO Model | AUTO Model | PREMIUM Model |
145
- | --------- | ----------------------------------- | ---------------------------- | ---------------------------- |
146
- | SIMPLE | nvidia/gpt-oss-120b (FREE) | kimi-k2.5 ($0.60/$3.00) | kimi-k2.5 |
147
- | MEDIUM | gemini-2.5-flash-lite ($0.10/$0.40) | grok-code-fast ($0.20/$1.50) | gpt-5.2-codex ($1.75/$14.00) |
148
- | COMPLEX | gemini-2.5-flash-lite ($0.10/$0.40) | gemini-3.1-pro ($2/$12) | claude-opus-4.6 ($5/$25) |
149
- | REASONING | grok-4-fast ($0.20/$0.50) | grok-4-fast ($0.20/$0.50) | claude-sonnet-4.6 ($3/$15) |
150
-
151
- **Blended average: $2.05/M** vs $25/M for Claude Opus = **92% savings**
152
-
153
- ---
154
-
155
- ## ๐Ÿ’ฐ Models & Pricing
160
+ ## Models & Pricing
156
161
 
157
162
  41+ models across 7 providers, one wallet:
158
163
 
@@ -199,31 +204,7 @@ Request โ†’ Weighted Scorer (15 dimensions) โ†’ Tier โ†’ Cheapest Model โ†’ Resp
199
204
 
200
205
  ---
201
206
 
202
- ## ๐Ÿ“ธ Screenshots
203
-
204
- <table>
205
- <tr>
206
- <td width="50%" align="center">
207
- <strong>Smart Routing in Action</strong><br><br>
208
- <img src="docs/clawrouter-savings.png" alt="ClawRouter savings" width="400">
209
- </td>
210
- <td width="50%" align="center">
211
- <strong>Telegram Integration</strong><br><br>
212
- <img src="assets/telegram-demo.png" alt="Telegram demo" width="400">
213
- </td>
214
- </tr>
215
- </table>
216
-
217
- **The flow:**
218
-
219
- 1. **Wallet auto-generated** on Base (L2) โ€” saved at `~/.openclaw/blockrun/wallet.key`
220
- 2. **Fund with $1 USDC** โ€” enough for hundreds of requests
221
- 3. **Request any model** โ€” ClawRouter picks the cheapest capable one
222
- 4. **Pay per request** โ€” non-custodial, you hold your keys
223
-
224
- ---
225
-
226
- ## ๐Ÿ’ณ Payment
207
+ ## Payment
227
208
 
228
209
  No account. No API key. **Payment IS authentication** via [x402](https://x402.org).
229
210
 
@@ -231,9 +212,9 @@ No account. No API key. **Payment IS authentication** via [x402](https://x402.or
231
212
  Request โ†’ 402 (price: $0.003) โ†’ wallet signs USDC โ†’ retry โ†’ response
232
213
  ```
233
214
 
234
- USDC stays in your wallet until spent - non-custodial. Price is visible in the 402 header before signing.
215
+ USDC stays in your wallet until spent โ€” non-custodial. Price is visible in the 402 header before signing.
235
216
 
236
- **Dual-chain support:** Pay with **USDC** on **Base (EVM)** or **USDC on Solana** โ€” no SOL token accepted. Both wallets are derived from a single BIP-39 mnemonic on first run.
217
+ **Dual-chain support:** Pay with **USDC** on **Base (EVM)** or **USDC on Solana**. Both wallets are derived from a single BIP-39 mnemonic on first run.
237
218
 
238
219
  ```bash
239
220
  /wallet # Check balance and address (both chains)
@@ -251,11 +232,28 @@ USDC stays in your wallet until spent - non-custodial. Price is visible in the 4
251
232
  - **Base (EVM):** Send USDC on Base to your EVM address
252
233
  - **Solana:** Send USDC on Solana to your Solana address
253
234
  - **Coinbase/CEX:** Withdraw USDC to either network
254
- - **Credit card:** Don't have USDC? Reach out to [@bc1max on Telegram](https://t.me/bc1max) โ€” we accept credit card payments
235
+ - **Credit card:** Reach out to [@bc1max on Telegram](https://t.me/bc1max)
255
236
 
256
237
  ---
257
238
 
258
- ## โš™๏ธ Configuration
239
+ ## Screenshots
240
+
241
+ <table>
242
+ <tr>
243
+ <td width="50%" align="center">
244
+ <strong>Smart Routing in Action</strong><br><br>
245
+ <img src="docs/clawrouter-savings.png" alt="ClawRouter savings" width="400">
246
+ </td>
247
+ <td width="50%" align="center">
248
+ <strong>Telegram Integration</strong><br><br>
249
+ <img src="assets/telegram-demo.png" alt="Telegram demo" width="400">
250
+ </td>
251
+ </tr>
252
+ </table>
253
+
254
+ ---
255
+
256
+ ## Configuration
259
257
 
260
258
  For basic usage, no configuration needed. For advanced options:
261
259
 
@@ -270,22 +268,7 @@ For basic usage, no configuration needed. For advanced options:
270
268
 
271
269
  ---
272
270
 
273
- ## ๐ŸฅŠ vs OpenRouter
274
-
275
- | | OpenRouter / LiteLLM | ClawRouter |
276
- | --------------- | --------------------------- | -------------------------------- |
277
- | **Setup** | Human creates account | Agent generates wallet |
278
- | **Auth** | API key (shared secret) | Wallet signature (cryptographic) |
279
- | **Payment** | Prepaid balance (custodial) | Per-request (non-custodial) |
280
- | **Routing** | Proprietary / closed | Open source, client-side |
281
- | **Rate limits** | Per-key quotas | None (your wallet, your limits) |
282
- | **Cost** | $25/M (Opus equivalent) | $2.05/M blended average |
283
-
284
- **[Full comparison โ†’](docs/vs-openrouter.md)**
285
-
286
- ---
287
-
288
- ## ๐Ÿฉบ Troubleshooting
271
+ ## Troubleshooting
289
272
 
290
273
  **When things go wrong, run the doctor:**
291
274
 
@@ -333,7 +316,7 @@ npx @blockrun/clawrouter doctor opus "ๆทฑๅบฆๅˆ†ๆžๆˆ‘็š„้…็ฝฎ"
333
316
 
334
317
  ---
335
318
 
336
- ## ๐Ÿ›  Development
319
+ ## Development
337
320
 
338
321
  ```bash
339
322
  git clone https://github.com/BlockRunAI/ClawRouter.git
@@ -345,7 +328,7 @@ npm test
345
328
 
346
329
  ---
347
330
 
348
- ## ๐Ÿ“ž Support
331
+ ## Support
349
332
 
350
333
  | Channel | Link |
351
334
  | --------------------- | ------------------------------------------------------------------ |
@@ -357,7 +340,40 @@ npm test
357
340
 
358
341
  ---
359
342
 
360
- ## ๐Ÿ“š More Resources
343
+ ## From the BlockRun Ecosystem
344
+
345
+ <table>
346
+ <tr>
347
+ <td width="50%">
348
+
349
+ ### โšก ClawRouter
350
+
351
+ **The LLM router built for autonomous agents**
352
+
353
+ You're here. 41+ models, local smart routing, x402 USDC payments โ€” the only stack that lets agents operate independently.
354
+
355
+ `curl -fsSL https://blockrun.ai/ClawRouter-update | bash`
356
+
357
+ </td>
358
+ <td width="50%">
359
+
360
+ ### ๐Ÿฆž [SocialClaw](https://github.com/BlockRunAI/socialclaw)
361
+
362
+ **Intelligence-as-a-function for X/Twitter**
363
+
364
+ The first X analytics an agent can call. One function call = one intelligence report. $0.08, not $49/month. No dashboard, no login, no subscription.
365
+
366
+ `pip install blockrun-llm[solana]`
367
+
368
+ [![GitHub](https://img.shields.io/github/stars/BlockRunAI/socialclaw?style=flat-square)](https://github.com/BlockRunAI/socialclaw)
369
+
370
+ </td>
371
+ </tr>
372
+ </table>
373
+
374
+ ---
375
+
376
+ ## More Resources
361
377
 
362
378
  | Resource | Description |
363
379
  | ------------------------------------------------------ | ------------------------ |
@@ -367,16 +383,14 @@ npm test
367
383
  | [Routing Profiles](docs/routing-profiles.md) | ECO/AUTO/PREMIUM details |
368
384
  | [Architecture](docs/architecture.md) | Technical deep dive |
369
385
  | [Configuration](docs/configuration.md) | Environment variables |
370
- | [vs OpenRouter](docs/vs-openrouter.md) | Why ClawRouter wins |
371
- | [Features](docs/features.md) | All features |
372
386
  | [Troubleshooting](docs/troubleshooting.md) | Common issues |
373
387
 
374
388
  ---
375
389
 
376
390
  <div align="center">
377
391
 
378
- **MIT License** ยท [BlockRun](https://blockrun.ai) โ€” Pay-per-request AI infrastructure
392
+ **MIT License** ยท [BlockRun](https://blockrun.ai) โ€” Agent-native AI infrastructure
379
393
 
380
- โญ If ClawRouter saves you money, consider starring the repo!
394
+ โญ If ClawRouter powers your agents, consider starring the repo!
381
395
 
382
396
  </div>
package/dist/cli.d.ts ADDED
@@ -0,0 +1 @@
1
+ #!/usr/bin/env node
package/dist/cli.js CHANGED
@@ -525,6 +525,99 @@ function getFallbackChainFiltered(tier, tierConfigs, estimatedTotalTokens, getCo
525
525
  return filtered;
526
526
  }
527
527
 
528
+ // src/router/strategy.ts
529
+ var RulesStrategy = class {
530
+ name = "rules";
531
+ route(prompt, systemPrompt, maxOutputTokens, options) {
532
+ const { config, modelPricing } = options;
533
+ const fullText = `${systemPrompt ?? ""} ${prompt}`;
534
+ const estimatedTokens = Math.ceil(fullText.length / 4);
535
+ const ruleResult = classifyByRules(prompt, systemPrompt, estimatedTokens, config.scoring);
536
+ const { routingProfile } = options;
537
+ let tierConfigs;
538
+ let profileSuffix;
539
+ let profile;
540
+ if (routingProfile === "eco" && config.ecoTiers) {
541
+ tierConfigs = config.ecoTiers;
542
+ profileSuffix = " | eco";
543
+ profile = "eco";
544
+ } else if (routingProfile === "premium" && config.premiumTiers) {
545
+ tierConfigs = config.premiumTiers;
546
+ profileSuffix = " | premium";
547
+ profile = "premium";
548
+ } else {
549
+ const agenticScore = ruleResult.agenticScore ?? 0;
550
+ const isAutoAgentic = agenticScore >= 0.5;
551
+ const isExplicitAgentic = config.overrides.agenticMode ?? false;
552
+ const hasToolsInRequest = options.hasTools ?? false;
553
+ const useAgenticTiers = (hasToolsInRequest || isAutoAgentic || isExplicitAgentic) && config.agenticTiers != null;
554
+ tierConfigs = useAgenticTiers ? config.agenticTiers : config.tiers;
555
+ profileSuffix = useAgenticTiers ? ` | agentic${hasToolsInRequest ? " (tools)" : ""}` : "";
556
+ profile = useAgenticTiers ? "agentic" : "auto";
557
+ }
558
+ const agenticScoreValue = ruleResult.agenticScore;
559
+ if (estimatedTokens > config.overrides.maxTokensForceComplex) {
560
+ const decision2 = selectModel(
561
+ "COMPLEX",
562
+ 0.95,
563
+ "rules",
564
+ `Input exceeds ${config.overrides.maxTokensForceComplex} tokens${profileSuffix}`,
565
+ tierConfigs,
566
+ modelPricing,
567
+ estimatedTokens,
568
+ maxOutputTokens,
569
+ routingProfile,
570
+ agenticScoreValue
571
+ );
572
+ return { ...decision2, tierConfigs, profile };
573
+ }
574
+ const hasStructuredOutput = systemPrompt ? /json|structured|schema/i.test(systemPrompt) : false;
575
+ let tier;
576
+ let confidence;
577
+ const method = "rules";
578
+ let reasoning = `score=${ruleResult.score.toFixed(2)} | ${ruleResult.signals.join(", ")}`;
579
+ if (ruleResult.tier !== null) {
580
+ tier = ruleResult.tier;
581
+ confidence = ruleResult.confidence;
582
+ } else {
583
+ tier = config.overrides.ambiguousDefaultTier;
584
+ confidence = 0.5;
585
+ reasoning += ` | ambiguous -> default: ${tier}`;
586
+ }
587
+ if (hasStructuredOutput) {
588
+ const tierRank = { SIMPLE: 0, MEDIUM: 1, COMPLEX: 2, REASONING: 3 };
589
+ const minTier = config.overrides.structuredOutputMinTier;
590
+ if (tierRank[tier] < tierRank[minTier]) {
591
+ reasoning += ` | upgraded to ${minTier} (structured output)`;
592
+ tier = minTier;
593
+ }
594
+ }
595
+ reasoning += profileSuffix;
596
+ const decision = selectModel(
597
+ tier,
598
+ confidence,
599
+ method,
600
+ reasoning,
601
+ tierConfigs,
602
+ modelPricing,
603
+ estimatedTokens,
604
+ maxOutputTokens,
605
+ routingProfile,
606
+ agenticScoreValue
607
+ );
608
+ return { ...decision, tierConfigs, profile };
609
+ }
610
+ };
611
+ var registry = /* @__PURE__ */ new Map();
612
+ registry.set("rules", new RulesStrategy());
613
+ function getStrategy(name) {
614
+ const strategy = registry.get(name);
615
+ if (!strategy) {
616
+ throw new Error(`Unknown routing strategy: ${name}`);
617
+ }
618
+ return strategy;
619
+ }
620
+
528
621
  // src/router/config.ts
529
622
  var DEFAULT_ROUTING_CONFIG = {
530
623
  version: "2.0",
@@ -1617,7 +1710,11 @@ var DEFAULT_ROUTING_CONFIG = {
1617
1710
  SIMPLE: {
1618
1711
  primary: "nvidia/gpt-oss-120b",
1619
1712
  // FREE! $0.00/$0.00
1620
- fallback: ["google/gemini-2.5-flash-lite", "google/gemini-2.5-flash", "deepseek/deepseek-chat"]
1713
+ fallback: [
1714
+ "google/gemini-2.5-flash-lite",
1715
+ "google/gemini-2.5-flash",
1716
+ "deepseek/deepseek-chat"
1717
+ ]
1621
1718
  },
1622
1719
  MEDIUM: {
1623
1720
  primary: "google/gemini-2.5-flash-lite",
@@ -1742,77 +1839,8 @@ var DEFAULT_ROUTING_CONFIG = {
1742
1839
 
1743
1840
  // src/router/index.ts
1744
1841
  function route(prompt, systemPrompt, maxOutputTokens, options) {
1745
- const { config, modelPricing } = options;
1746
- const fullText = `${systemPrompt ?? ""} ${prompt}`;
1747
- const estimatedTokens = Math.ceil(fullText.length / 4);
1748
- const ruleResult = classifyByRules(prompt, systemPrompt, estimatedTokens, config.scoring);
1749
- const { routingProfile } = options;
1750
- let tierConfigs;
1751
- let profileSuffix;
1752
- if (routingProfile === "eco" && config.ecoTiers) {
1753
- tierConfigs = config.ecoTiers;
1754
- profileSuffix = " | eco";
1755
- } else if (routingProfile === "premium" && config.premiumTiers) {
1756
- tierConfigs = config.premiumTiers;
1757
- profileSuffix = " | premium";
1758
- } else {
1759
- const agenticScore = ruleResult.agenticScore ?? 0;
1760
- const isAutoAgentic = agenticScore >= 0.5;
1761
- const isExplicitAgentic = config.overrides.agenticMode ?? false;
1762
- const hasToolsInRequest = options.hasTools ?? false;
1763
- const useAgenticTiers = (hasToolsInRequest || isAutoAgentic || isExplicitAgentic) && config.agenticTiers != null;
1764
- tierConfigs = useAgenticTiers ? config.agenticTiers : config.tiers;
1765
- profileSuffix = useAgenticTiers ? ` | agentic${hasToolsInRequest ? " (tools)" : ""}` : "";
1766
- }
1767
- const agenticScoreValue = ruleResult.agenticScore;
1768
- if (estimatedTokens > config.overrides.maxTokensForceComplex) {
1769
- return selectModel(
1770
- "COMPLEX",
1771
- 0.95,
1772
- "rules",
1773
- `Input exceeds ${config.overrides.maxTokensForceComplex} tokens${profileSuffix}`,
1774
- tierConfigs,
1775
- modelPricing,
1776
- estimatedTokens,
1777
- maxOutputTokens,
1778
- routingProfile,
1779
- agenticScoreValue
1780
- );
1781
- }
1782
- const hasStructuredOutput = systemPrompt ? /json|structured|schema/i.test(systemPrompt) : false;
1783
- let tier;
1784
- let confidence;
1785
- const method = "rules";
1786
- let reasoning = `score=${ruleResult.score.toFixed(2)} | ${ruleResult.signals.join(", ")}`;
1787
- if (ruleResult.tier !== null) {
1788
- tier = ruleResult.tier;
1789
- confidence = ruleResult.confidence;
1790
- } else {
1791
- tier = config.overrides.ambiguousDefaultTier;
1792
- confidence = 0.5;
1793
- reasoning += ` | ambiguous -> default: ${tier}`;
1794
- }
1795
- if (hasStructuredOutput) {
1796
- const tierRank = { SIMPLE: 0, MEDIUM: 1, COMPLEX: 2, REASONING: 3 };
1797
- const minTier = config.overrides.structuredOutputMinTier;
1798
- if (tierRank[tier] < tierRank[minTier]) {
1799
- reasoning += ` | upgraded to ${minTier} (structured output)`;
1800
- tier = minTier;
1801
- }
1802
- }
1803
- reasoning += profileSuffix;
1804
- return selectModel(
1805
- tier,
1806
- confidence,
1807
- method,
1808
- reasoning,
1809
- tierConfigs,
1810
- modelPricing,
1811
- estimatedTokens,
1812
- maxOutputTokens,
1813
- routingProfile,
1814
- agenticScoreValue
1815
- );
1842
+ const strategy = getStrategy("rules");
1843
+ return strategy.route(prompt, systemPrompt, maxOutputTokens, options);
1816
1844
  }
1817
1845
 
1818
1846
  // src/models.ts
@@ -5026,6 +5054,12 @@ var ROUTING_PROFILES = /* @__PURE__ */ new Set([
5026
5054
  "premium"
5027
5055
  ]);
5028
5056
  var FREE_MODEL = "nvidia/gpt-oss-120b";
5057
+ var FREE_TIER_CONFIGS = {
5058
+ SIMPLE: { primary: FREE_MODEL, fallback: [] },
5059
+ MEDIUM: { primary: FREE_MODEL, fallback: [] },
5060
+ COMPLEX: { primary: FREE_MODEL, fallback: [] },
5061
+ REASONING: { primary: FREE_MODEL, fallback: [] }
5062
+ };
5029
5063
  var freeRequestCount = 0;
5030
5064
  var MAX_MESSAGES = 200;
5031
5065
  var CONTEXT_LIMIT_KB = 5120;
@@ -6900,7 +6934,17 @@ async function proxyRequest(req, res, apiBase, payFetch, options, routerOpts, de
6900
6934
 
6901
6935
  `;
6902
6936
  }
6903
- routingDecision = { model: freeModel, tier: "SIMPLE", confidence: 1, method: "rules", reasoning: "free profile" };
6937
+ routingDecision = {
6938
+ model: freeModel,
6939
+ tier: "SIMPLE",
6940
+ confidence: 1,
6941
+ method: "rules",
6942
+ reasoning: "free profile",
6943
+ costEstimate: 0,
6944
+ baselineCost: 0,
6945
+ savings: 1,
6946
+ tierConfigs: FREE_TIER_CONFIGS
6947
+ };
6904
6948
  } else {
6905
6949
  effectiveSessionId = getSessionId(req.headers) ?? deriveSessionId(parsedMessages);
6906
6950
  const existingSession = effectiveSessionId ? sessionStore.getSession(effectiveSessionId) : void 0;
@@ -6991,18 +7035,7 @@ async function proxyRequest(req, res, apiBase, payFetch, options, routerOpts, de
6991
7035
  const contentHash = hashRequestContent(prompt, toolCallNames);
6992
7036
  const shouldEscalate = sessionStore.recordRequestHash(effectiveSessionId, contentHash);
6993
7037
  if (shouldEscalate) {
6994
- const activeTierConfigs = (() => {
6995
- if (routingDecision.reasoning?.includes("agentic") && routerOpts.config.agenticTiers) {
6996
- return routerOpts.config.agenticTiers;
6997
- }
6998
- if (routingProfile === "eco" && routerOpts.config.ecoTiers) {
6999
- return routerOpts.config.ecoTiers;
7000
- }
7001
- if (routingProfile === "premium" && routerOpts.config.premiumTiers) {
7002
- return routerOpts.config.premiumTiers;
7003
- }
7004
- return routerOpts.config.tiers;
7005
- })();
7038
+ const activeTierConfigs = routingDecision.tierConfigs ?? routerOpts.config.tiers;
7006
7039
  const escalation = sessionStore.escalateSession(
7007
7040
  effectiveSessionId,
7008
7041
  activeTierConfigs
@@ -7218,18 +7251,7 @@ async function proxyRequest(req, res, apiBase, payFetch, options, routerOpts, de
7218
7251
  if (routingDecision) {
7219
7252
  const estimatedInputTokens = Math.ceil(body.length / 4);
7220
7253
  const estimatedTotalTokens = estimatedInputTokens + maxTokens;
7221
- const tierConfigs = (() => {
7222
- if (routingDecision.reasoning?.includes("agentic") && routerOpts.config.agenticTiers) {
7223
- return routerOpts.config.agenticTiers;
7224
- }
7225
- if (routingProfile === "eco" && routerOpts.config.ecoTiers) {
7226
- return routerOpts.config.ecoTiers;
7227
- }
7228
- if (routingProfile === "premium" && routerOpts.config.premiumTiers) {
7229
- return routerOpts.config.premiumTiers;
7230
- }
7231
- return routerOpts.config.tiers;
7232
- })();
7254
+ const tierConfigs = routingDecision.tierConfigs ?? routerOpts.config.tiers;
7233
7255
  const fullChain = getFallbackChain(routingDecision.tier, tierConfigs);
7234
7256
  const contextFiltered = getFallbackChainFiltered(
7235
7257
  routingDecision.tier,
@@ -7309,6 +7331,14 @@ async function proxyRequest(req, res, apiBase, payFetch, options, routerOpts, de
7309
7331
  status: result.errorStatus || 500
7310
7332
  };
7311
7333
  if (result.isProviderError && !isLastAttempt) {
7334
+ const isExplicitModelError = !routingDecision;
7335
+ const isUnknownExplicitModel = isExplicitModelError && /unknown.*model|invalid.*model/i.test(result.errorBody || "");
7336
+ if (isUnknownExplicitModel) {
7337
+ console.log(
7338
+ `[ClawRouter] Explicit model error from ${tryModel}, not falling back: ${result.errorBody?.slice(0, 100)}`
7339
+ );
7340
+ break;
7341
+ }
7312
7342
  if (result.errorStatus === 429) {
7313
7343
  markRateLimited(tryModel);
7314
7344
  try {
@@ -8084,8 +8114,8 @@ Commands:
8084
8114
  partners List available partner APIs with pricing
8085
8115
  partners test Test partner API endpoints (expect 402 = alive)
8086
8116
  wallet recover Restore wallet.key from mnemonic (if generated by ClawRouter)
8087
- chain solana Switch payment chain to Solana (persists across restarts)
8088
- chain base Switch payment chain to Base EVM (persists across restarts)
8117
+ chain solana Switch to Solana (persists). Aliases: /wallet solana, wallet solana
8118
+ chain base Switch to Base EVM (persists). Aliases: /wallet base, wallet base
8089
8119
 
8090
8120
  Examples:
8091
8121
  # Start standalone proxy
@@ -8155,7 +8185,7 @@ function parseArgs(args) {
8155
8185
  } else if (arg === "wallet" && args[i + 1] === "recover") {
8156
8186
  result.walletRecover = true;
8157
8187
  i++;
8158
- } else if (arg === "chain" && (args[i + 1] === "solana" || args[i + 1] === "base")) {
8188
+ } else if ((arg === "chain" || arg === "/wallet" || arg === "wallet") && (args[i + 1] === "solana" || args[i + 1] === "base")) {
8159
8189
  result.chain = args[i + 1];
8160
8190
  i++;
8161
8191
  } else if (arg === "--port" && args[i + 1]) {