@blockrun/clawrouter 0.12.258 → 0.12.260
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 +17 -15
- package/dist/cli.js +194 -15
- package/dist/index.d.ts +15 -2
- package/dist/index.js +194 -15
- package/docs/9-free-ai-models-zero-cost-blockrun.md +17 -11
- package/docs/anthropic-cost-savings.md +1 -1
- package/docs/anthropic-third-party-harness-changes.md +3 -3
- package/docs/clawrouter-cuts-llm-api-costs-500x.md +1 -1
- package/docs/clawrouter-vs-openrouter-llm-routing-comparison.md +4 -4
- package/docs/routing-profiles.md +5 -3
- package/package.json +2 -2
- package/skills/clawrouter/SKILL.md +3 -3
- package/src/top-models.json +3 -0
package/README.md
CHANGED
|
@@ -34,7 +34,7 @@ Agents can only sign transactions.<br><br>
|
|
|
34
34
|
|
|
35
35
|
</div>
|
|
36
36
|
|
|
37
|
-
> **ClawRouter** is an open-source smart LLM router that reduces AI API costs by up to <!-- br:savings.autoVsBaselinePct -->
|
|
37
|
+
> **ClawRouter** is an open-source smart LLM router that reduces AI API costs by up to <!-- br:savings.autoVsBaselinePct -->84<!-- /br:savings.autoVsBaselinePct -->%. It analyzes each request across <!-- br:clawrouter.dimensions -->15<!-- /br:clawrouter.dimensions --> dimensions and routes to the cheapest capable model in under 1ms, entirely locally. ClawRouter is the only LLM router built for autonomous AI agents — it uses wallet signatures for authentication (no API keys) and USDC micropayments via the x402 protocol (no credit cards). <!-- br:models.chatVisible -->76<!-- /br:models.chatVisible --> models from OpenAI, Anthropic, Google, xAI, DeepSeek, and more. MIT licensed.
|
|
38
38
|
|
|
39
39
|
---
|
|
40
40
|
|
|
@@ -46,7 +46,7 @@ Every other LLM router was built for **human developers** — create an account,
|
|
|
46
46
|
|
|
47
47
|
ClawRouter is built for the agent-first world:
|
|
48
48
|
|
|
49
|
-
- **Starts at $0** — <!-- br:models.free -->7<!-- /br:models.free --> open-weight models are free forever (incl. a 1M-context reasoner
|
|
49
|
+
- **Starts at $0** — <!-- br:models.free -->7<!-- /br:models.free --> open-weight models are free forever (incl. a 1M-context reasoner and two sub-second coders). Image turns route to paid models — see the free-tier note below.
|
|
50
50
|
- **No accounts** — a wallet is generated locally, no signup
|
|
51
51
|
- **No API keys** — your wallet signature IS authentication
|
|
52
52
|
- **No model selection** — <!-- br:clawrouter.dimensions -->15<!-- /br:clawrouter.dimensions -->-dimension scoring + constraint-first ranking ([router-core](https://github.com/BlockRunAI/router-core)) picks the right model automatically
|
|
@@ -61,7 +61,7 @@ This is the stack that lets agents operate autonomously: **x402 + USDC + local r
|
|
|
61
61
|
|
|
62
62
|
| | OpenRouter | LiteLLM | Martian | Portkey | **ClawRouter** |
|
|
63
63
|
| ---------------- | ----------------- | ---------------- | ----------------- | ----------------- | ---------------------------------------------------------------------- |
|
|
64
|
-
| **Models** | 200+ | 100+ | Smart routing | Gateway | **<!-- br:models.chatVisible -->
|
|
64
|
+
| **Models** | 200+ | 100+ | Smart routing | Gateway | **<!-- br:models.chatVisible -->76<!-- /br:models.chatVisible -->** |
|
|
65
65
|
| **Free tier** | Rate-limited | BYO keys | No | No | **<!-- br:models.free -->7<!-- /br:models.free --> models, no signup** |
|
|
66
66
|
| **Routing** | Manual selection | Manual selection | Smart (closed) | Observability | **Smart (open source)** |
|
|
67
67
|
| **Auth** | Account + API key | Your API keys | Account + API key | Account + API key | **Wallet signature** |
|
|
@@ -107,7 +107,7 @@ openclaw gateway restart
|
|
|
107
107
|
|
|
108
108
|
> **Using Claude Code?** Check out [BRCC](https://github.com/BlockRunAI/brcc) — it's purpose-built for Claude Code with the same smart routing and x402 payments.
|
|
109
109
|
>
|
|
110
|
-
> **Using NousResearch Hermes?** See [ClawRouter-Hermes](https://github.com/BlockRunAI/ClawRouter-Hermes) — a Python plugin that wires Hermes into the ClawRouter proxy. Same wallet, same <!-- br:models.chatVisible -->
|
|
110
|
+
> **Using NousResearch Hermes?** See [ClawRouter-Hermes](https://github.com/BlockRunAI/ClawRouter-Hermes) — a Python plugin that wires Hermes into the ClawRouter proxy. Same wallet, same <!-- br:models.chatVisible -->76<!-- /br:models.chatVisible --> models, same x402 USDC settlement on Base & Solana.
|
|
111
111
|
|
|
112
112
|
No OpenClaw required. ClawRouter runs as a local proxy on port 8402.
|
|
113
113
|
|
|
@@ -191,7 +191,7 @@ Choose your routing strategy with `/model <profile>`:
|
|
|
191
191
|
| Profile | Strategy | Savings | Best For |
|
|
192
192
|
| ---------------- | ------------------ | ---------------------------------------------------------------------------------- | -------------------- |
|
|
193
193
|
| `/model free` | Free NVIDIA models | **100%** | $0 balance, learning |
|
|
194
|
-
| `/model auto` | Balanced (default) | **<!-- br:savings.autoVsBaselinePct -->
|
|
194
|
+
| `/model auto` | Balanced (default) | **<!-- br:savings.autoVsBaselinePct -->84<!-- /br:savings.autoVsBaselinePct -->%** | General use |
|
|
195
195
|
| `/model eco` | Cheapest possible | **<!-- br:savings.ecoVsBaselinePct -->98<!-- /br:savings.ecoVsBaselinePct -->%** | Maximum savings |
|
|
196
196
|
| `/model premium` | Best quality | 0% | Mission-critical |
|
|
197
197
|
|
|
@@ -229,7 +229,7 @@ Request → 15-dimension scorer → tier + task shape
|
|
|
229
229
|
|
|
230
230
|
These are the curated primaries; every tier carries a benchmark-ordered fallback chain — full chains and per-profile ranking weights in [docs/routing-profiles.md](docs/routing-profiles.md). On router-core's frozen three-arm agent benchmark (τ-bench, BrowseComp, Terminal-Bench) the V3.4 policy (the last one benchmarked; V3.5 is a catalog refresh on the same scorer and weights) completed **57%** of tasks vs **49%** for the previous rules router, at **6.4%** lower cost per successful task — and spent **8.9%** of the tokens a pinned flagship would have.
|
|
231
231
|
|
|
232
|
-
**<!-- br:savings.autoVsBaselinePct -->
|
|
232
|
+
**<!-- br:savings.autoVsBaselinePct -->84<!-- /br:savings.autoVsBaselinePct -->% cheaper than pinning Claude Opus 5** for the same traffic, on `auto`; **<!-- br:savings.ecoVsBaselinePct -->98<!-- /br:savings.ecoVsBaselinePct -->%** on `eco`.
|
|
233
233
|
|
|
234
234
|
Not an "up to" figure. The baseline, the workload mix and the token ratio are
|
|
235
235
|
published in [`savings-mix.json`](https://github.com/BlockRunAI/blockrun/blob/main/src/brand/savings-mix.json),
|
|
@@ -407,7 +407,7 @@ No Surf account, no API key — settles directly to Surf's Base treasury in USDC
|
|
|
407
407
|
|
|
408
408
|
## Models & Pricing
|
|
409
409
|
|
|
410
|
-
<!-- br:models.chatVisible -->
|
|
410
|
+
<!-- br:models.chatVisible -->76<!-- /br:models.chatVisible --> models across 9 providers, one wallet. **<!-- br:models.free -->7<!-- /br:models.free --> models are $0 — paid models start at fractions of a cent.**
|
|
411
411
|
|
|
412
412
|
> **💡 "Cost per request"** = estimated cost for a typical chat message (~500 input + 500 output tokens). Paid requests also carry a flat **$0.001/tx settlement fee** (covers on-chain gas; already included in the price the gateway quotes). Free models never pay it.
|
|
413
413
|
|
|
@@ -419,9 +419,9 @@ No Surf account, no API key — settles directly to Surf's Base treasury in USDC
|
|
|
419
419
|
| free/nemotron-3-nano-30b | **FREE** | **FREE** | **$0** | 131K | fastest free model (~121 tok/s) |
|
|
420
420
|
| free/laguna-xs-2.1 | **FREE** | **FREE** | **$0** | 131K | coding (Poolside, ~161 tok/s) |
|
|
421
421
|
| free/north-mini-code | **FREE** | **FREE** | **$0** | 256K | coding (Cohere, sub-second) |
|
|
422
|
-
| free/nemotron-3-nano-omni-30b-a3b-reasoning | **FREE** | **FREE** | **$0** | 256K | reasoning
|
|
422
|
+
| free/nemotron-3-nano-omni-30b-a3b-reasoning | **FREE** | **FREE** | **$0** | 256K | reasoning (text only — see note) |
|
|
423
423
|
| free/nemotron-3-ultra-550b | **FREE** | **FREE** | **$0** | 1M | largest free model (550B/55B MoE) |
|
|
424
|
-
| free/llama-3.2-11b-vision | **FREE** | **FREE** | **$0** | 128K | Meta Llama
|
|
424
|
+
| free/llama-3.2-11b-vision | **FREE** | **FREE** | **$0** | 128K | Meta Llama (text only — see note) |
|
|
425
425
|
| qwen/qwen3.7-flash | $0.03 | $0.13 | $0.0001 | 1M | reasoning, tools (fastest Qwen tier) |
|
|
426
426
|
| openai/gpt-5-nano | $0.05 | $0.40 | $0.0002 | 128K | tools |
|
|
427
427
|
| openai/gpt-5.6-luna-pro | $0.10 | $0.60 | $0.0004 | 1M | reasoning, vision, agentic, tools |
|
|
@@ -499,7 +499,9 @@ No Surf account, no API key — settles directly to Surf's Base treasury in USDC
|
|
|
499
499
|
| openai/gpt-5.4-pro | $30.00 | $180.00 | $0.1050 | 400K | reasoning, tools |
|
|
500
500
|
| openai/gpt-5.5-pro | $30.00 | $180.00 | $0.1050 | 1M | reasoning, vision, tools |
|
|
501
501
|
|
|
502
|
-
> **Free tier:** <!-- br:models.free -->7<!-- /br:models.free --> open-weight models cost nothing — `/model free` pins the free default (`nemotron-3.5-lightning`, with the other six as fallbacks), `/model eco` opens on it, or pick one directly (e.g., `/model
|
|
502
|
+
> **Free tier:** <!-- br:models.free -->7<!-- /br:models.free --> open-weight models cost nothing — `/model free` pins the free default (`nemotron-3.5-lightning`, with the other six as fallbacks), `/model eco` opens on it, or pick one directly (e.g., `/model lightning` for 1M-context reasoning, `/model north-mini` or `/model laguna` for fast coding, `/model nano-30b` for the fastest).
|
|
503
|
+
>
|
|
504
|
+
> **No free vision.** Two free models are catalogued as vision-capable and neither reliably is: on a 64×64 solid-colour probe `nemotron-3-nano-omni` was right 1 of 4 times on Base and answered "white" for red on Solana, and `llama-3.2-11b-vision` replied "I'm unable to see the image" 3 of 3 while answering text fine. Both return HTTP 200, so a wrong answer arrives with no error to branch on. ClawRouter therefore does not flag them for vision, and requests carrying an `image_url` route to a paid vision model instead.
|
|
503
505
|
> **Best value:** `gpt-5-nano` and `gemini-2.5-flash-lite` deliver strong results at ~$0.0003/request.
|
|
504
506
|
|
|
505
507
|
---
|
|
@@ -669,7 +671,7 @@ npm test
|
|
|
669
671
|
|
|
670
672
|
**The LLM router built for autonomous agents**
|
|
671
673
|
|
|
672
|
-
You're here. <!-- br:models.chatVisible -->
|
|
674
|
+
You're here. <!-- br:models.chatVisible -->76<!-- /br:models.chatVisible --> models, local smart routing, x402 USDC payments — the only stack that lets agents operate independently.
|
|
673
675
|
|
|
674
676
|
`curl -fsSL https://blockrun.ai/ClawRouter-update | bash`
|
|
675
677
|
|
|
@@ -680,7 +682,7 @@ You're here. <!-- br:models.chatVisible -->73<!-- /br:models.chatVisible --> mod
|
|
|
680
682
|
|
|
681
683
|
**BlockRun for Claude Code**
|
|
682
684
|
|
|
683
|
-
Run Claude Code with <!-- br:models.chatVisible -->
|
|
685
|
+
Run Claude Code with <!-- br:models.chatVisible -->76<!-- /br:models.chatVisible --> models, no rate limits, no Anthropic account, no phone verification. Pay per request with USDC — your wallet is your identity.
|
|
684
686
|
|
|
685
687
|
`curl -fsSL https://blockrun.ai/brcc-install | bash`
|
|
686
688
|
|
|
@@ -693,7 +695,7 @@ Run Claude Code with <!-- br:models.chatVisible -->73<!-- /br:models.chatVisible
|
|
|
693
695
|
|
|
694
696
|
**ClawRouter for NousResearch Hermes**
|
|
695
697
|
|
|
696
|
-
Python plugin that wraps the ClawRouter proxy for `hermes-agent`. Same <!-- br:models.chatVisible -->
|
|
698
|
+
Python plugin that wraps the ClawRouter proxy for `hermes-agent`. Same <!-- br:models.chatVisible -->76<!-- /br:models.chatVisible --> models, same x402 USDC payments on Base & Solana, native Hermes ergonomics.
|
|
697
699
|
|
|
698
700
|
`pip install hermes-plugin-clawrouter`
|
|
699
701
|
|
|
@@ -741,7 +743,7 @@ ClawRouter is an open-source (MIT licensed) smart LLM router built for autonomou
|
|
|
741
743
|
|
|
742
744
|
### How much can ClawRouter save on LLM costs?
|
|
743
745
|
|
|
744
|
-
On the `auto` profile ClawRouter costs <!-- br:savings.autoVsBaselinePct -->
|
|
746
|
+
On the `auto` profile ClawRouter costs <!-- br:savings.autoVsBaselinePct -->84<!-- /br:savings.autoVsBaselinePct -->% less than pinning Claude Opus 5 for every request, and <!-- br:savings.ecoVsBaselinePct -->98<!-- /br:savings.ecoVsBaselinePct -->% less on `eco`. That is computed from a published workload mix rather than estimated — see [savings-mix.json](https://github.com/BlockRunAI/blockrun/blob/main/src/brand/savings-mix.json) for the baseline and assumptions. Actual savings depend on your workload — simple queries are routed to free models ($0/request), while complex tasks get premium models.
|
|
745
747
|
|
|
746
748
|
### How does ClawRouter compare to OpenRouter?
|
|
747
749
|
|
|
@@ -757,7 +759,7 @@ ClawRouter works with any tool that makes OpenAI-compatible API calls — point
|
|
|
757
759
|
|
|
758
760
|
### Is ClawRouter free?
|
|
759
761
|
|
|
760
|
-
ClawRouter itself is free and MIT licensed. You pay only for the LLM API calls routed through it — and several open-weight models (`nemotron-3.5-lightning`, `nemotron-3-nano-30b`, `laguna-xs-2.1`, `north-mini-code`, `nemotron-3-nano-omni-30b-a3b-reasoning`, `nemotron-3-ultra-550b`, `llama-3.2-11b-vision`) are completely free. Use `/model free` to smart-route across them, or pick any by name.
|
|
762
|
+
ClawRouter itself is free and MIT licensed. You pay only for the LLM API calls routed through it — and several open-weight models (`nemotron-3.5-lightning`, `nemotron-3-nano-30b`, `laguna-xs-2.1`, `north-mini-code`, `nemotron-3-nano-omni-30b-a3b-reasoning`, `nemotron-3-ultra-550b`, `llama-3.2-11b-vision`) are completely free (text only). Use `/model free` to smart-route across them, or pick any by name.
|
|
761
763
|
|
|
762
764
|
---
|
|
763
765
|
|
package/dist/cli.js
CHANGED
|
@@ -37684,10 +37684,13 @@ var init_top_models = __esm({
|
|
|
37684
37684
|
"zai/glm-5.1",
|
|
37685
37685
|
"zai/glm-5-turbo",
|
|
37686
37686
|
"zai/glm-5",
|
|
37687
|
+
"xiaomi/mimo-v2.5",
|
|
37687
37688
|
"minimax/minimax-m3",
|
|
37688
37689
|
"minimax/minimax-m2.7",
|
|
37689
37690
|
"moonshot/kimi-k3",
|
|
37690
37691
|
"qwen/qwen3.7-max",
|
|
37692
|
+
"qwen/qwen3.8-flash",
|
|
37693
|
+
"deepseek/deepseek-v4-flash-vision-exp",
|
|
37691
37694
|
"deepseek/deepseek-v4-pro",
|
|
37692
37695
|
"deepseek/deepseek-chat",
|
|
37693
37696
|
"deepseek/deepseek-reasoner",
|
|
@@ -37949,6 +37952,19 @@ var init_models = __esm({
|
|
|
37949
37952
|
// `kimi` on K2.7. (`grok` WAS promoted to 4.5, but only after the cost
|
|
37950
37953
|
// tradeoff was argued explicitly; there's no such case for qwen yet.)
|
|
37951
37954
|
"qwen3.7-max": "qwen/qwen3.7-max",
|
|
37955
|
+
// Qwen3.8 Flash — newer generation than the whole 3.7 line, and cheaper than
|
|
37956
|
+
// the 3.7-plus tier it beats. Bare `qwen` stays UNBOUND (every other qwen*
|
|
37957
|
+
// shorthand resolves to a free model, so binding the short name to a paid
|
|
37958
|
+
// flagship would bill callers expecting free).
|
|
37959
|
+
"qwen3.8-flash": "qwen/qwen3.8-flash",
|
|
37960
|
+
"qwen3-8-flash": "qwen/qwen3.8-flash",
|
|
37961
|
+
"qwen-vision": "qwen/qwen3.8-flash",
|
|
37962
|
+
// DeepSeek's first image-capable SKU. Bare `deepseek` stays on deepseek-chat.
|
|
37963
|
+
"deepseek-vision": "deepseek/deepseek-v4-flash-vision-exp",
|
|
37964
|
+
"v4-flash-vision": "deepseek/deepseek-v4-flash-vision-exp",
|
|
37965
|
+
// Xiaomi MiMo V2.5 — the natively multimodal SKU, distinct from mimo-v2.5-pro
|
|
37966
|
+
// (text-only upstream). `mimo` stays on the Pro entry it has always named.
|
|
37967
|
+
"mimo-vision": "xiaomi/mimo-v2.5",
|
|
37952
37968
|
"qwen-3.7-max": "qwen/qwen3.7-max",
|
|
37953
37969
|
"qwen3-7-max": "qwen/qwen3.7-max",
|
|
37954
37970
|
// Plus/Flash tiers (2026-08-03) — explicit pins, same rule as Max.
|
|
@@ -37963,7 +37979,15 @@ var init_models = __esm({
|
|
|
37963
37979
|
hunyuan: "tencent/hy3",
|
|
37964
37980
|
mimo: "xiaomi/mimo-v2.5-pro",
|
|
37965
37981
|
"mimo-v2.5-pro": "xiaomi/mimo-v2.5-pro",
|
|
37966
|
-
|
|
37982
|
+
// RETARGETED 2026-08-30, Pro -> the real thing. This key used to point at
|
|
37983
|
+
// `xiaomi/mimo-v2.5-pro`, which was harmless while no model owned the name —
|
|
37984
|
+
// but blockrun then listed an actual `xiaomi/mimo-v2.5`, a DIFFERENT and
|
|
37985
|
+
// natively-multimodal SKU at $0.14/$0.28 against Pro's $0.435/$0.87. Leaving
|
|
37986
|
+
// it would have billed 3x for the text-only model when the caller named the
|
|
37987
|
+
// cheaper multimodal one. (The key itself is safe: it is not equal to the
|
|
37988
|
+
// catalog id, so it shadows nothing — the rule that bans `opus-5`-style keys
|
|
37989
|
+
// does not apply to a bare shorthand.)
|
|
37990
|
+
"mimo-v2.5": "xiaomi/mimo-v2.5",
|
|
37967
37991
|
xiaomi: "xiaomi/mimo-v2.5-pro",
|
|
37968
37992
|
// Google
|
|
37969
37993
|
// gemini-3-pro-preview delisted by Google 2026-06-06 — mirror the gateway
|
|
@@ -38138,6 +38162,10 @@ var init_models = __esm({
|
|
|
38138
38162
|
// Vision-capable free models
|
|
38139
38163
|
"nemotron-omni": "free/nemotron-3-nano-omni-30b-a3b-reasoning",
|
|
38140
38164
|
"nano-omni": "free/nemotron-3-nano-omni-30b-a3b-reasoning",
|
|
38165
|
+
// `vision-free` kept for backward compatibility ONLY — it still resolves to
|
|
38166
|
+
// nano-omni, which is the strongest free model, but the free tier no longer
|
|
38167
|
+
// claims working image input on either chain (see the catalog note). Do not
|
|
38168
|
+
// advertise this alias as a way to get free vision.
|
|
38141
38169
|
"vision-free": "free/nemotron-3-nano-omni-30b-a3b-reasoning",
|
|
38142
38170
|
// Retired shorthand aliases redirect to live successors. The catch-all target
|
|
38143
38171
|
// moved llama-4-maverick → gpt-oss-120b (2026-07-17) → step-3.7-flash
|
|
@@ -38403,8 +38431,8 @@ var init_models = __esm({
|
|
|
38403
38431
|
id: "openai/gpt-5.6-terra-pro",
|
|
38404
38432
|
name: "GPT-5.6 Terra Pro",
|
|
38405
38433
|
version: "5.6",
|
|
38406
|
-
inputPrice:
|
|
38407
|
-
outputPrice:
|
|
38434
|
+
inputPrice: 2,
|
|
38435
|
+
outputPrice: 12,
|
|
38408
38436
|
contextWindow: 105e4,
|
|
38409
38437
|
maxOutput: 128e3,
|
|
38410
38438
|
reasoning: true,
|
|
@@ -38416,8 +38444,8 @@ var init_models = __esm({
|
|
|
38416
38444
|
id: "openai/gpt-5.6-luna-pro",
|
|
38417
38445
|
name: "GPT-5.6 Luna Pro",
|
|
38418
38446
|
version: "5.6",
|
|
38419
|
-
inputPrice: 0.
|
|
38420
|
-
outputPrice:
|
|
38447
|
+
inputPrice: 0.2,
|
|
38448
|
+
outputPrice: 1.2,
|
|
38421
38449
|
contextWindow: 105e4,
|
|
38422
38450
|
maxOutput: 128e3,
|
|
38423
38451
|
reasoning: true,
|
|
@@ -38950,8 +38978,8 @@ var init_models = __esm({
|
|
|
38950
38978
|
id: "deepseek/deepseek-v4-pro",
|
|
38951
38979
|
name: "DeepSeek V4 Pro",
|
|
38952
38980
|
version: "4-pro",
|
|
38953
|
-
inputPrice:
|
|
38954
|
-
outputPrice:
|
|
38981
|
+
inputPrice: 1.32,
|
|
38982
|
+
outputPrice: 3.96,
|
|
38955
38983
|
contextWindow: 1048576,
|
|
38956
38984
|
maxOutput: 65536,
|
|
38957
38985
|
reasoning: true,
|
|
@@ -39409,8 +39437,21 @@ var init_models = __esm({
|
|
|
39409
39437
|
outputPrice: 0,
|
|
39410
39438
|
contextWindow: 256e3,
|
|
39411
39439
|
maxOutput: 16384,
|
|
39412
|
-
reasoning: true
|
|
39413
|
-
vision: true
|
|
39440
|
+
reasoning: true
|
|
39441
|
+
// NO `vision: true` — 2026-08-31. Both catalogs advertise vision on this
|
|
39442
|
+
// model and blockrun #448 cites an 8x8 PNG answering "Red", but a 64x64
|
|
39443
|
+
// solid-red probe does not hold up: 1 of 4 correct on Base (the others
|
|
39444
|
+
// "I'm not able to view the image" or leaked reasoning), and on sol it
|
|
39445
|
+
// answered "white" twice, once with the response's own `model` field
|
|
39446
|
+
// reading `nemotron-3-super-120b (fallback: ...nano-omni)` — the image is
|
|
39447
|
+
// silently dropped and a text model answers.
|
|
39448
|
+
//
|
|
39449
|
+
// `vision: true` is what makes filterByVision() route real image turns
|
|
39450
|
+
// here, so the flag does not merely describe the model, it aims traffic at
|
|
39451
|
+
// it. HTTP 200 with a confident wrong colour is worse than no free vision:
|
|
39452
|
+
// there is no error for a caller to branch on. Image turns go to paid
|
|
39453
|
+
// vision models until a correctly-sized probe comes back right on both
|
|
39454
|
+
// chains. Independently confirmed on Solana by the blockrun-sol owner.
|
|
39414
39455
|
},
|
|
39415
39456
|
// 2026-06-14: BlockRun re-featured these two as free flagships (catalog sweep).
|
|
39416
39457
|
// Added to the auto-pick set behind gpt-oss to strengthen the mid/back of the
|
|
@@ -39532,8 +39573,11 @@ var init_models = __esm({
|
|
|
39532
39573
|
outputPrice: 0,
|
|
39533
39574
|
contextWindow: 131072,
|
|
39534
39575
|
maxOutput: 16384,
|
|
39535
|
-
reasoning: true
|
|
39536
|
-
|
|
39576
|
+
reasoning: true
|
|
39577
|
+
// Vision flag dropped 2026-08-31 with the rest of the free tier: this id is
|
|
39578
|
+
// 410 Gone and the gateway redirects it to nano-omni, whose image path does
|
|
39579
|
+
// not work either (see above). A pinned caller sending an image would have
|
|
39580
|
+
// been told, by the flag, that it would be seen.
|
|
39537
39581
|
},
|
|
39538
39582
|
// ── 2026-08-30 free-tier rebuild (blockrun #448) ─────────────────────────
|
|
39539
39583
|
// NVIDIA retired FOUR of the five VISIBLE free models in one sweep. blockrun
|
|
@@ -39606,8 +39650,13 @@ var init_models = __esm({
|
|
|
39606
39650
|
inputPrice: 0,
|
|
39607
39651
|
outputPrice: 0,
|
|
39608
39652
|
contextWindow: 128e3,
|
|
39609
|
-
maxOutput: 16384
|
|
39610
|
-
vision: true
|
|
39653
|
+
maxOutput: 16384
|
|
39654
|
+
// NO `vision: true` despite the name and blockrun's `categories:
|
|
39655
|
+
// ["chat","vision"]` — 2026-08-31, three consecutive 64x64 PNG probes came
|
|
39656
|
+
// back "I'm unable to see the image" / "you haven't provided an image",
|
|
39657
|
+
// while a plain-text control on the same id answered fine. The model is
|
|
39658
|
+
// alive; the image path is not. Mirroring the catalog's claim here would
|
|
39659
|
+
// have routed image turns to it. See the nano-omni note above.
|
|
39611
39660
|
},
|
|
39612
39661
|
{
|
|
39613
39662
|
// Cohere North Mini Code, on OpenRouter's $0 pool — 607ms median, the
|
|
@@ -39637,6 +39686,57 @@ var init_models = __esm({
|
|
|
39637
39686
|
contextWindow: 131072,
|
|
39638
39687
|
maxOutput: 16384
|
|
39639
39688
|
},
|
|
39689
|
+
// ── 2026-08-30 paid catalog refresh (blockrun #449) ─────────────────────
|
|
39690
|
+
// Three additions, each probe-verified upstream with a real completion AND a
|
|
39691
|
+
// real image before listing. All three carry `vision: true` on that evidence
|
|
39692
|
+
// — unlike the free tier, where the same claim did not survive a probe.
|
|
39693
|
+
{
|
|
39694
|
+
// Alibaba's 3.8 generation: 125B MoE, one tier above the whole 3.7 line and
|
|
39695
|
+
// cheaper than the qwen3.7-plus ($0.32/$1.28) it outperforms.
|
|
39696
|
+
// Vision took two probes to establish upstream: the first 400'd with
|
|
39697
|
+
// `invalid_parameter_error` on an 8x8 PNG because the model requires >10px
|
|
39698
|
+
// per side; 64x64 answered correctly. A single 400 is not a capability gap.
|
|
39699
|
+
id: "qwen/qwen3.8-flash",
|
|
39700
|
+
name: "Qwen3.8 Flash",
|
|
39701
|
+
version: "3.8-flash",
|
|
39702
|
+
inputPrice: 0.15,
|
|
39703
|
+
outputPrice: 0.47,
|
|
39704
|
+
contextWindow: 1e6,
|
|
39705
|
+
maxOutput: 131072,
|
|
39706
|
+
reasoning: true,
|
|
39707
|
+
vision: true,
|
|
39708
|
+
toolCalling: true
|
|
39709
|
+
},
|
|
39710
|
+
{
|
|
39711
|
+
// The first DeepSeek SKU that takes images. Priced at DeepSeek's PEAK rate
|
|
39712
|
+
// on purpose: they now split peak/off-peak and off-peak is half, so listing
|
|
39713
|
+
// the lower number would sell under cost for seven hours every weekday.
|
|
39714
|
+
id: "deepseek/deepseek-v4-flash-vision-exp",
|
|
39715
|
+
name: "DeepSeek V4 Flash Vision",
|
|
39716
|
+
version: "v4-flash-vision-exp",
|
|
39717
|
+
inputPrice: 0.44,
|
|
39718
|
+
outputPrice: 1.32,
|
|
39719
|
+
contextWindow: 1048576,
|
|
39720
|
+
maxOutput: 65536,
|
|
39721
|
+
reasoning: true,
|
|
39722
|
+
vision: true,
|
|
39723
|
+
toolCalling: true
|
|
39724
|
+
},
|
|
39725
|
+
{
|
|
39726
|
+
// NOT a cheaper mimo-v2.5-pro — a different, natively multimodal SKU. The
|
|
39727
|
+
// Pro entry is text-only upstream while this one takes images, at a third
|
|
39728
|
+
// of the price. Keep both.
|
|
39729
|
+
id: "xiaomi/mimo-v2.5",
|
|
39730
|
+
name: "Xiaomi MiMo V2.5",
|
|
39731
|
+
version: "2.5",
|
|
39732
|
+
inputPrice: 0.14,
|
|
39733
|
+
outputPrice: 0.28,
|
|
39734
|
+
contextWindow: 1048576,
|
|
39735
|
+
maxOutput: 131072,
|
|
39736
|
+
reasoning: true,
|
|
39737
|
+
vision: true,
|
|
39738
|
+
toolCalling: true
|
|
39739
|
+
},
|
|
39640
39740
|
// Z.AI GLM-5 Models
|
|
39641
39741
|
{
|
|
39642
39742
|
// Z.AI's flagship, live-probed by blockrun 2026-08-19 against api.z.ai
|
|
@@ -89923,7 +90023,36 @@ import { homedir as homedir7 } from "os";
|
|
|
89923
90023
|
import { join as join10 } from "path";
|
|
89924
90024
|
import { mkdir as mkdir4, writeFile as writeFile2, readFile as readFile2, stat as fsStat } from "fs/promises";
|
|
89925
90025
|
import { readFileSync as readFileSync2, existsSync as existsSync2 } from "fs";
|
|
90026
|
+
async function loadGatewayCatalog(apiBase) {
|
|
90027
|
+
try {
|
|
90028
|
+
const controller = new AbortController();
|
|
90029
|
+
const timer2 = setTimeout(() => controller.abort(), GATEWAY_CATALOG_TIMEOUT_MS);
|
|
90030
|
+
const res = await fetch(`${apiBase}/v1/models`, { signal: controller.signal });
|
|
90031
|
+
clearTimeout(timer2);
|
|
90032
|
+
if (!res.ok) return;
|
|
90033
|
+
const body = await res.json();
|
|
90034
|
+
const ids = (body.data ?? []).map((m) => m.id).filter((id2) => !!id2);
|
|
90035
|
+
if (ids.length === 0) return;
|
|
90036
|
+
gatewayModelIds = new Set(ids);
|
|
90037
|
+
const unserved = [...FREE_MODELS].filter((m) => !gatewayModelIds.has(toUpstreamModelId(m)));
|
|
90038
|
+
if (unserved.length > 0) {
|
|
90039
|
+
console.log(
|
|
90040
|
+
`[ClawRouter] Free models not served by this gateway (skipped in the cascade): ${unserved.join(", ")}`
|
|
90041
|
+
);
|
|
90042
|
+
}
|
|
90043
|
+
} catch {
|
|
90044
|
+
}
|
|
90045
|
+
}
|
|
90046
|
+
function isServedByGateway(modelId) {
|
|
90047
|
+
if (!gatewayModelIds) return true;
|
|
90048
|
+
return gatewayModelIds.has(toUpstreamModelId(modelId));
|
|
90049
|
+
}
|
|
89926
90050
|
function pickFreeModel(excludeList) {
|
|
90051
|
+
for (const m of FREE_MODELS) {
|
|
90052
|
+
if (excludeList?.has(m)) continue;
|
|
90053
|
+
if (!isServedByGateway(m)) continue;
|
|
90054
|
+
return m;
|
|
90055
|
+
}
|
|
89927
90056
|
for (const m of FREE_MODELS) {
|
|
89928
90057
|
if (!excludeList?.has(m)) return m;
|
|
89929
90058
|
}
|
|
@@ -90263,6 +90392,9 @@ function detectDegradedSuccessResponse(body) {
|
|
|
90263
90392
|
return `degraded response: ${errorText.slice(0, 120)}`;
|
|
90264
90393
|
}
|
|
90265
90394
|
const choices = parsed.choices;
|
|
90395
|
+
if (Array.isArray(choices) && choices.length === 0) {
|
|
90396
|
+
return "degraded response: no choices returned";
|
|
90397
|
+
}
|
|
90266
90398
|
if (Array.isArray(choices) && choices.length > 0) {
|
|
90267
90399
|
const choice = choices[0];
|
|
90268
90400
|
const msg = choice.message ?? choice.delta;
|
|
@@ -90753,6 +90885,7 @@ async function startProxy(options) {
|
|
|
90753
90885
|
} else if (paymentChain === "solana") {
|
|
90754
90886
|
console.log(`[ClawRouter] Payment chain: Solana (${BLOCKRUN_SOLANA_API})`);
|
|
90755
90887
|
}
|
|
90888
|
+
void loadGatewayCatalog(apiBase);
|
|
90756
90889
|
const listenPort = options.port ?? getProxyPort();
|
|
90757
90890
|
const existingProxy = await checkExistingProxy(listenPort);
|
|
90758
90891
|
if (existingProxy) {
|
|
@@ -93286,6 +93419,22 @@ data: [DONE]
|
|
|
93286
93419
|
} else {
|
|
93287
93420
|
modelsToTry = modelId ? [modelId] : [];
|
|
93288
93421
|
}
|
|
93422
|
+
if (modelsToTry.length > 0) {
|
|
93423
|
+
const unservedFree = modelsToTry.filter((m) => FREE_MODELS.has(m) && !isServedByGateway(m));
|
|
93424
|
+
if (unservedFree.length > 0) {
|
|
93425
|
+
const servedFree = [...FREE_MODELS].filter(
|
|
93426
|
+
(m) => isServedByGateway(m) && !excludeList?.has(m)
|
|
93427
|
+
);
|
|
93428
|
+
const replacement = servedFree[0];
|
|
93429
|
+
if (replacement) {
|
|
93430
|
+
modelsToTry = modelsToTry.map((m) => unservedFree.includes(m) ? replacement : m);
|
|
93431
|
+
modelsToTry = modelsToTry.filter((m, i) => modelsToTry.indexOf(m) === i);
|
|
93432
|
+
console.log(
|
|
93433
|
+
`[ClawRouter] ${unservedFree.join(", ")} not served on this chain \u2014 using ${replacement}`
|
|
93434
|
+
);
|
|
93435
|
+
}
|
|
93436
|
+
}
|
|
93437
|
+
}
|
|
93289
93438
|
if (!hasTools && routingDecision) {
|
|
93290
93439
|
const freeFallback = pickFreeModel(excludeList);
|
|
93291
93440
|
if (freeFallback && !modelsToTry.includes(freeFallback)) {
|
|
@@ -94166,7 +94315,7 @@ data: [DONE]
|
|
|
94166
94315
|
});
|
|
94167
94316
|
}
|
|
94168
94317
|
}
|
|
94169
|
-
var paymentStore, BLOCKRUN_API, BLOCKRUN_SOLANA_API, IMAGE_DIR, AUDIO_DIR, VIDEO_DIR, AUTO_MODEL, ROUTING_PROFILES, FREE_MODELS, FREE_MODEL, FREE_UPSTREAM_OVERRIDES, MAX_MESSAGES, CONTEXT_LIMIT_KB, HEARTBEAT_INTERVAL_MS, BALANCE_CHECK_TIMEOUT_MS, DEFAULT_REQUEST_TIMEOUT_MS, PER_MODEL_TIMEOUT_MS, REASONING_MODEL_TIMEOUT_MS, REASONING_MODEL_IDS, MAX_FALLBACK_ATTEMPTS, HEALTH_CHECK_TIMEOUT_MS, RATE_LIMIT_COOLDOWN_MS, OVERLOAD_COOLDOWN_MS, PORT_RETRY_ATTEMPTS, PORT_RETRY_DELAY_MS, MODEL_BODY_READ_TIMEOUT_MS, ERROR_BODY_READ_TIMEOUT_MS, ClientDisconnectedError, rateLimitedModels, overloadedModels, perProviderErrors, BALANCE_CHECK_BUFFER, BALANCE_PREFLIGHT_OUTPUT_TOKEN_CAP, PROVIDER_ERROR_PATTERNS, DEGRADED_RESPONSE_PATTERNS, DEGRADED_LOOP_PATTERNS, VALID_ROLES, ROLE_MAPPINGS, VALID_TOOL_ID_PATTERN, KIMI_BLOCK_RE, KIMI_TOKEN_RE, THINKING_TAG_RE, THINKING_BLOCK_RE, BLOCKRUN_MODEL_BY_ID, IMAGE_PRICING, IMAGE_MODEL_IDS, IMAGE_MODEL_SIZES, IMAGE_MODEL_ALIASES, VIDEO_PRICING, PHONE_PRICING;
|
|
94318
|
+
var paymentStore, BLOCKRUN_API, BLOCKRUN_SOLANA_API, IMAGE_DIR, AUDIO_DIR, VIDEO_DIR, AUTO_MODEL, ROUTING_PROFILES, FREE_MODELS, gatewayModelIds, FREE_MODEL, FREE_UPSTREAM_OVERRIDES, MAX_MESSAGES, CONTEXT_LIMIT_KB, HEARTBEAT_INTERVAL_MS, BALANCE_CHECK_TIMEOUT_MS, GATEWAY_CATALOG_TIMEOUT_MS, DEFAULT_REQUEST_TIMEOUT_MS, PER_MODEL_TIMEOUT_MS, REASONING_MODEL_TIMEOUT_MS, REASONING_MODEL_IDS, MAX_FALLBACK_ATTEMPTS, HEALTH_CHECK_TIMEOUT_MS, RATE_LIMIT_COOLDOWN_MS, OVERLOAD_COOLDOWN_MS, PORT_RETRY_ATTEMPTS, PORT_RETRY_DELAY_MS, MODEL_BODY_READ_TIMEOUT_MS, ERROR_BODY_READ_TIMEOUT_MS, ClientDisconnectedError, rateLimitedModels, overloadedModels, perProviderErrors, BALANCE_CHECK_BUFFER, BALANCE_PREFLIGHT_OUTPUT_TOKEN_CAP, PROVIDER_ERROR_PATTERNS, DEGRADED_RESPONSE_PATTERNS, DEGRADED_LOOP_PATTERNS, VALID_ROLES, ROLE_MAPPINGS, VALID_TOOL_ID_PATTERN, KIMI_BLOCK_RE, KIMI_TOKEN_RE, THINKING_TAG_RE, THINKING_BLOCK_RE, BLOCKRUN_MODEL_BY_ID, IMAGE_PRICING, IMAGE_MODEL_IDS, IMAGE_MODEL_SIZES, IMAGE_MODEL_ALIASES, VIDEO_PRICING, PHONE_PRICING;
|
|
94170
94319
|
var init_proxy = __esm({
|
|
94171
94320
|
"src/proxy.ts"() {
|
|
94172
94321
|
"use strict";
|
|
@@ -94241,6 +94390,7 @@ var init_proxy = __esm({
|
|
|
94241
94390
|
CONTEXT_LIMIT_KB = 5120;
|
|
94242
94391
|
HEARTBEAT_INTERVAL_MS = 2e3;
|
|
94243
94392
|
BALANCE_CHECK_TIMEOUT_MS = 2500;
|
|
94393
|
+
GATEWAY_CATALOG_TIMEOUT_MS = 5e3;
|
|
94244
94394
|
DEFAULT_REQUEST_TIMEOUT_MS = 3e5;
|
|
94245
94395
|
PER_MODEL_TIMEOUT_MS = 6e4;
|
|
94246
94396
|
REASONING_MODEL_TIMEOUT_MS = 18e4;
|
|
@@ -226642,7 +226792,8 @@ import {
|
|
|
226642
226792
|
readdirSync,
|
|
226643
226793
|
mkdirSync as mkdirSync3,
|
|
226644
226794
|
copyFileSync,
|
|
226645
|
-
renameSync as renameSync2
|
|
226795
|
+
renameSync as renameSync2,
|
|
226796
|
+
unlinkSync
|
|
226646
226797
|
} from "fs";
|
|
226647
226798
|
import { readFile as readFileAsync } from "fs/promises";
|
|
226648
226799
|
import { homedir as homedir13 } from "os";
|
|
@@ -226987,6 +227138,15 @@ function injectAuthProfile(logger48) {
|
|
|
226987
227138
|
for (const agentId of agents) {
|
|
226988
227139
|
const authDir = join16(agentsDir, agentId, "agent");
|
|
226989
227140
|
const authPath = join16(authDir, "auth-profiles.json");
|
|
227141
|
+
const sqlitePath = join16(authDir, "openclaw-agent.sqlite");
|
|
227142
|
+
if (existsSync4(sqlitePath)) {
|
|
227143
|
+
removeInjectedAuthPlaceholder(authPath, logger48, agentId);
|
|
227144
|
+
continue;
|
|
227145
|
+
}
|
|
227146
|
+
if (agentId === "main") {
|
|
227147
|
+
removeInjectedAuthPlaceholder(authPath, logger48, agentId);
|
|
227148
|
+
continue;
|
|
227149
|
+
}
|
|
226990
227150
|
if (!existsSync4(authDir)) {
|
|
226991
227151
|
try {
|
|
226992
227152
|
mkdirSync3(authDir, { recursive: true });
|
|
@@ -227029,6 +227189,25 @@ function injectAuthProfile(logger48) {
|
|
|
227029
227189
|
logger48.info(`Auth injection failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
227030
227190
|
}
|
|
227031
227191
|
}
|
|
227192
|
+
function removeInjectedAuthPlaceholder(authPath, logger48, agentId) {
|
|
227193
|
+
try {
|
|
227194
|
+
if (!existsSync4(authPath)) return;
|
|
227195
|
+
const parsed = JSON.parse(readTextFileSync(authPath));
|
|
227196
|
+
const profiles = parsed?.profiles;
|
|
227197
|
+
if (!profiles || typeof profiles !== "object" || Array.isArray(profiles)) return;
|
|
227198
|
+
const keys = Object.keys(profiles);
|
|
227199
|
+
if (keys.length !== 1 || keys[0] !== "blockrun:default") return;
|
|
227200
|
+
const entry = profiles["blockrun:default"];
|
|
227201
|
+
if (!entry || typeof entry !== "object") return;
|
|
227202
|
+
const profile = entry;
|
|
227203
|
+
if (profile.type !== "api_key" || profile.provider !== "blockrun" || profile.key !== "x402-proxy-handles-auth") {
|
|
227204
|
+
return;
|
|
227205
|
+
}
|
|
227206
|
+
unlinkSync(authPath);
|
|
227207
|
+
logger48.info(`Removed legacy BlockRun auth placeholder for agent: ${agentId}`);
|
|
227208
|
+
} catch {
|
|
227209
|
+
}
|
|
227210
|
+
}
|
|
227032
227211
|
function clearDeferredProxyStartTimer(proc = process) {
|
|
227033
227212
|
if (!proc.__clawrouterDeferredStartTimer) return false;
|
|
227034
227213
|
clearTimeout(proc.__clawrouterDeferredStartTimer);
|
package/dist/index.d.ts
CHANGED
|
@@ -1692,8 +1692,21 @@ declare function syncAgentModelCache(logger: {
|
|
|
1692
1692
|
}): void;
|
|
1693
1693
|
/**
|
|
1694
1694
|
* Inject dummy auth profile for BlockRun into agent auth stores.
|
|
1695
|
-
*
|
|
1696
|
-
*
|
|
1695
|
+
*
|
|
1696
|
+
* The legacy ``auth-profiles.json`` write is now deliberately narrow:
|
|
1697
|
+
*
|
|
1698
|
+
* - Wherever ``openclaw-agent.sqlite`` exists, the SQLite auth store is
|
|
1699
|
+
* authoritative. Writing the legacy JSON beside it is at best ignored, at
|
|
1700
|
+
* worst a failed-closed migration trigger: since OpenClaw 2026.8.1 a
|
|
1701
|
+
* leftover legacy file beside a store that holds no profiles fails auth
|
|
1702
|
+
* migration for the whole agent fleet. So we never write there, and we
|
|
1703
|
+
* clean up the placeholder we previously injected.
|
|
1704
|
+
* - The shared auth-owner directory (``main``) is managed by OpenClaw
|
|
1705
|
+
* itself; a placeholder written there can shadow that state. The
|
|
1706
|
+
* provider's real auth comes from the x402 proxy (and the apiKey
|
|
1707
|
+
* injectModelsConfig writes into openclaw.json), so nothing is lost.
|
|
1708
|
+
* - Only on very old installs with no SQLite store at all do we keep the
|
|
1709
|
+
* original JSON bootstrap, which those releases import.
|
|
1697
1710
|
*/
|
|
1698
1711
|
declare function injectAuthProfile(logger: {
|
|
1699
1712
|
info: (msg: string) => void;
|
package/dist/index.js
CHANGED
|
@@ -87,10 +87,13 @@ var init_top_models = __esm({
|
|
|
87
87
|
"zai/glm-5.1",
|
|
88
88
|
"zai/glm-5-turbo",
|
|
89
89
|
"zai/glm-5",
|
|
90
|
+
"xiaomi/mimo-v2.5",
|
|
90
91
|
"minimax/minimax-m3",
|
|
91
92
|
"minimax/minimax-m2.7",
|
|
92
93
|
"moonshot/kimi-k3",
|
|
93
94
|
"qwen/qwen3.7-max",
|
|
95
|
+
"qwen/qwen3.8-flash",
|
|
96
|
+
"deepseek/deepseek-v4-flash-vision-exp",
|
|
94
97
|
"deepseek/deepseek-v4-pro",
|
|
95
98
|
"deepseek/deepseek-chat",
|
|
96
99
|
"deepseek/deepseek-reasoner",
|
|
@@ -352,6 +355,19 @@ var init_models = __esm({
|
|
|
352
355
|
// `kimi` on K2.7. (`grok` WAS promoted to 4.5, but only after the cost
|
|
353
356
|
// tradeoff was argued explicitly; there's no such case for qwen yet.)
|
|
354
357
|
"qwen3.7-max": "qwen/qwen3.7-max",
|
|
358
|
+
// Qwen3.8 Flash — newer generation than the whole 3.7 line, and cheaper than
|
|
359
|
+
// the 3.7-plus tier it beats. Bare `qwen` stays UNBOUND (every other qwen*
|
|
360
|
+
// shorthand resolves to a free model, so binding the short name to a paid
|
|
361
|
+
// flagship would bill callers expecting free).
|
|
362
|
+
"qwen3.8-flash": "qwen/qwen3.8-flash",
|
|
363
|
+
"qwen3-8-flash": "qwen/qwen3.8-flash",
|
|
364
|
+
"qwen-vision": "qwen/qwen3.8-flash",
|
|
365
|
+
// DeepSeek's first image-capable SKU. Bare `deepseek` stays on deepseek-chat.
|
|
366
|
+
"deepseek-vision": "deepseek/deepseek-v4-flash-vision-exp",
|
|
367
|
+
"v4-flash-vision": "deepseek/deepseek-v4-flash-vision-exp",
|
|
368
|
+
// Xiaomi MiMo V2.5 — the natively multimodal SKU, distinct from mimo-v2.5-pro
|
|
369
|
+
// (text-only upstream). `mimo` stays on the Pro entry it has always named.
|
|
370
|
+
"mimo-vision": "xiaomi/mimo-v2.5",
|
|
355
371
|
"qwen-3.7-max": "qwen/qwen3.7-max",
|
|
356
372
|
"qwen3-7-max": "qwen/qwen3.7-max",
|
|
357
373
|
// Plus/Flash tiers (2026-08-03) — explicit pins, same rule as Max.
|
|
@@ -366,7 +382,15 @@ var init_models = __esm({
|
|
|
366
382
|
hunyuan: "tencent/hy3",
|
|
367
383
|
mimo: "xiaomi/mimo-v2.5-pro",
|
|
368
384
|
"mimo-v2.5-pro": "xiaomi/mimo-v2.5-pro",
|
|
369
|
-
|
|
385
|
+
// RETARGETED 2026-08-30, Pro -> the real thing. This key used to point at
|
|
386
|
+
// `xiaomi/mimo-v2.5-pro`, which was harmless while no model owned the name —
|
|
387
|
+
// but blockrun then listed an actual `xiaomi/mimo-v2.5`, a DIFFERENT and
|
|
388
|
+
// natively-multimodal SKU at $0.14/$0.28 against Pro's $0.435/$0.87. Leaving
|
|
389
|
+
// it would have billed 3x for the text-only model when the caller named the
|
|
390
|
+
// cheaper multimodal one. (The key itself is safe: it is not equal to the
|
|
391
|
+
// catalog id, so it shadows nothing — the rule that bans `opus-5`-style keys
|
|
392
|
+
// does not apply to a bare shorthand.)
|
|
393
|
+
"mimo-v2.5": "xiaomi/mimo-v2.5",
|
|
370
394
|
xiaomi: "xiaomi/mimo-v2.5-pro",
|
|
371
395
|
// Google
|
|
372
396
|
// gemini-3-pro-preview delisted by Google 2026-06-06 — mirror the gateway
|
|
@@ -541,6 +565,10 @@ var init_models = __esm({
|
|
|
541
565
|
// Vision-capable free models
|
|
542
566
|
"nemotron-omni": "free/nemotron-3-nano-omni-30b-a3b-reasoning",
|
|
543
567
|
"nano-omni": "free/nemotron-3-nano-omni-30b-a3b-reasoning",
|
|
568
|
+
// `vision-free` kept for backward compatibility ONLY — it still resolves to
|
|
569
|
+
// nano-omni, which is the strongest free model, but the free tier no longer
|
|
570
|
+
// claims working image input on either chain (see the catalog note). Do not
|
|
571
|
+
// advertise this alias as a way to get free vision.
|
|
544
572
|
"vision-free": "free/nemotron-3-nano-omni-30b-a3b-reasoning",
|
|
545
573
|
// Retired shorthand aliases redirect to live successors. The catch-all target
|
|
546
574
|
// moved llama-4-maverick → gpt-oss-120b (2026-07-17) → step-3.7-flash
|
|
@@ -806,8 +834,8 @@ var init_models = __esm({
|
|
|
806
834
|
id: "openai/gpt-5.6-terra-pro",
|
|
807
835
|
name: "GPT-5.6 Terra Pro",
|
|
808
836
|
version: "5.6",
|
|
809
|
-
inputPrice:
|
|
810
|
-
outputPrice:
|
|
837
|
+
inputPrice: 2,
|
|
838
|
+
outputPrice: 12,
|
|
811
839
|
contextWindow: 105e4,
|
|
812
840
|
maxOutput: 128e3,
|
|
813
841
|
reasoning: true,
|
|
@@ -819,8 +847,8 @@ var init_models = __esm({
|
|
|
819
847
|
id: "openai/gpt-5.6-luna-pro",
|
|
820
848
|
name: "GPT-5.6 Luna Pro",
|
|
821
849
|
version: "5.6",
|
|
822
|
-
inputPrice: 0.
|
|
823
|
-
outputPrice:
|
|
850
|
+
inputPrice: 0.2,
|
|
851
|
+
outputPrice: 1.2,
|
|
824
852
|
contextWindow: 105e4,
|
|
825
853
|
maxOutput: 128e3,
|
|
826
854
|
reasoning: true,
|
|
@@ -1353,8 +1381,8 @@ var init_models = __esm({
|
|
|
1353
1381
|
id: "deepseek/deepseek-v4-pro",
|
|
1354
1382
|
name: "DeepSeek V4 Pro",
|
|
1355
1383
|
version: "4-pro",
|
|
1356
|
-
inputPrice:
|
|
1357
|
-
outputPrice:
|
|
1384
|
+
inputPrice: 1.32,
|
|
1385
|
+
outputPrice: 3.96,
|
|
1358
1386
|
contextWindow: 1048576,
|
|
1359
1387
|
maxOutput: 65536,
|
|
1360
1388
|
reasoning: true,
|
|
@@ -1812,8 +1840,21 @@ var init_models = __esm({
|
|
|
1812
1840
|
outputPrice: 0,
|
|
1813
1841
|
contextWindow: 256e3,
|
|
1814
1842
|
maxOutput: 16384,
|
|
1815
|
-
reasoning: true
|
|
1816
|
-
vision: true
|
|
1843
|
+
reasoning: true
|
|
1844
|
+
// NO `vision: true` — 2026-08-31. Both catalogs advertise vision on this
|
|
1845
|
+
// model and blockrun #448 cites an 8x8 PNG answering "Red", but a 64x64
|
|
1846
|
+
// solid-red probe does not hold up: 1 of 4 correct on Base (the others
|
|
1847
|
+
// "I'm not able to view the image" or leaked reasoning), and on sol it
|
|
1848
|
+
// answered "white" twice, once with the response's own `model` field
|
|
1849
|
+
// reading `nemotron-3-super-120b (fallback: ...nano-omni)` — the image is
|
|
1850
|
+
// silently dropped and a text model answers.
|
|
1851
|
+
//
|
|
1852
|
+
// `vision: true` is what makes filterByVision() route real image turns
|
|
1853
|
+
// here, so the flag does not merely describe the model, it aims traffic at
|
|
1854
|
+
// it. HTTP 200 with a confident wrong colour is worse than no free vision:
|
|
1855
|
+
// there is no error for a caller to branch on. Image turns go to paid
|
|
1856
|
+
// vision models until a correctly-sized probe comes back right on both
|
|
1857
|
+
// chains. Independently confirmed on Solana by the blockrun-sol owner.
|
|
1817
1858
|
},
|
|
1818
1859
|
// 2026-06-14: BlockRun re-featured these two as free flagships (catalog sweep).
|
|
1819
1860
|
// Added to the auto-pick set behind gpt-oss to strengthen the mid/back of the
|
|
@@ -1935,8 +1976,11 @@ var init_models = __esm({
|
|
|
1935
1976
|
outputPrice: 0,
|
|
1936
1977
|
contextWindow: 131072,
|
|
1937
1978
|
maxOutput: 16384,
|
|
1938
|
-
reasoning: true
|
|
1939
|
-
|
|
1979
|
+
reasoning: true
|
|
1980
|
+
// Vision flag dropped 2026-08-31 with the rest of the free tier: this id is
|
|
1981
|
+
// 410 Gone and the gateway redirects it to nano-omni, whose image path does
|
|
1982
|
+
// not work either (see above). A pinned caller sending an image would have
|
|
1983
|
+
// been told, by the flag, that it would be seen.
|
|
1940
1984
|
},
|
|
1941
1985
|
// ── 2026-08-30 free-tier rebuild (blockrun #448) ─────────────────────────
|
|
1942
1986
|
// NVIDIA retired FOUR of the five VISIBLE free models in one sweep. blockrun
|
|
@@ -2009,8 +2053,13 @@ var init_models = __esm({
|
|
|
2009
2053
|
inputPrice: 0,
|
|
2010
2054
|
outputPrice: 0,
|
|
2011
2055
|
contextWindow: 128e3,
|
|
2012
|
-
maxOutput: 16384
|
|
2013
|
-
vision: true
|
|
2056
|
+
maxOutput: 16384
|
|
2057
|
+
// NO `vision: true` despite the name and blockrun's `categories:
|
|
2058
|
+
// ["chat","vision"]` — 2026-08-31, three consecutive 64x64 PNG probes came
|
|
2059
|
+
// back "I'm unable to see the image" / "you haven't provided an image",
|
|
2060
|
+
// while a plain-text control on the same id answered fine. The model is
|
|
2061
|
+
// alive; the image path is not. Mirroring the catalog's claim here would
|
|
2062
|
+
// have routed image turns to it. See the nano-omni note above.
|
|
2014
2063
|
},
|
|
2015
2064
|
{
|
|
2016
2065
|
// Cohere North Mini Code, on OpenRouter's $0 pool — 607ms median, the
|
|
@@ -2040,6 +2089,57 @@ var init_models = __esm({
|
|
|
2040
2089
|
contextWindow: 131072,
|
|
2041
2090
|
maxOutput: 16384
|
|
2042
2091
|
},
|
|
2092
|
+
// ── 2026-08-30 paid catalog refresh (blockrun #449) ─────────────────────
|
|
2093
|
+
// Three additions, each probe-verified upstream with a real completion AND a
|
|
2094
|
+
// real image before listing. All three carry `vision: true` on that evidence
|
|
2095
|
+
// — unlike the free tier, where the same claim did not survive a probe.
|
|
2096
|
+
{
|
|
2097
|
+
// Alibaba's 3.8 generation: 125B MoE, one tier above the whole 3.7 line and
|
|
2098
|
+
// cheaper than the qwen3.7-plus ($0.32/$1.28) it outperforms.
|
|
2099
|
+
// Vision took two probes to establish upstream: the first 400'd with
|
|
2100
|
+
// `invalid_parameter_error` on an 8x8 PNG because the model requires >10px
|
|
2101
|
+
// per side; 64x64 answered correctly. A single 400 is not a capability gap.
|
|
2102
|
+
id: "qwen/qwen3.8-flash",
|
|
2103
|
+
name: "Qwen3.8 Flash",
|
|
2104
|
+
version: "3.8-flash",
|
|
2105
|
+
inputPrice: 0.15,
|
|
2106
|
+
outputPrice: 0.47,
|
|
2107
|
+
contextWindow: 1e6,
|
|
2108
|
+
maxOutput: 131072,
|
|
2109
|
+
reasoning: true,
|
|
2110
|
+
vision: true,
|
|
2111
|
+
toolCalling: true
|
|
2112
|
+
},
|
|
2113
|
+
{
|
|
2114
|
+
// The first DeepSeek SKU that takes images. Priced at DeepSeek's PEAK rate
|
|
2115
|
+
// on purpose: they now split peak/off-peak and off-peak is half, so listing
|
|
2116
|
+
// the lower number would sell under cost for seven hours every weekday.
|
|
2117
|
+
id: "deepseek/deepseek-v4-flash-vision-exp",
|
|
2118
|
+
name: "DeepSeek V4 Flash Vision",
|
|
2119
|
+
version: "v4-flash-vision-exp",
|
|
2120
|
+
inputPrice: 0.44,
|
|
2121
|
+
outputPrice: 1.32,
|
|
2122
|
+
contextWindow: 1048576,
|
|
2123
|
+
maxOutput: 65536,
|
|
2124
|
+
reasoning: true,
|
|
2125
|
+
vision: true,
|
|
2126
|
+
toolCalling: true
|
|
2127
|
+
},
|
|
2128
|
+
{
|
|
2129
|
+
// NOT a cheaper mimo-v2.5-pro — a different, natively multimodal SKU. The
|
|
2130
|
+
// Pro entry is text-only upstream while this one takes images, at a third
|
|
2131
|
+
// of the price. Keep both.
|
|
2132
|
+
id: "xiaomi/mimo-v2.5",
|
|
2133
|
+
name: "Xiaomi MiMo V2.5",
|
|
2134
|
+
version: "2.5",
|
|
2135
|
+
inputPrice: 0.14,
|
|
2136
|
+
outputPrice: 0.28,
|
|
2137
|
+
contextWindow: 1048576,
|
|
2138
|
+
maxOutput: 131072,
|
|
2139
|
+
reasoning: true,
|
|
2140
|
+
vision: true,
|
|
2141
|
+
toolCalling: true
|
|
2142
|
+
},
|
|
2043
2143
|
// Z.AI GLM-5 Models
|
|
2044
2144
|
{
|
|
2045
2145
|
// Z.AI's flagship, live-probed by blockrun 2026-08-19 against api.z.ai
|
|
@@ -89743,7 +89843,36 @@ import { homedir as homedir7 } from "os";
|
|
|
89743
89843
|
import { join as join10 } from "path";
|
|
89744
89844
|
import { mkdir as mkdir4, writeFile as writeFile2, readFile as readFile2, stat as fsStat } from "fs/promises";
|
|
89745
89845
|
import { readFileSync as readFileSync2, existsSync as existsSync2 } from "fs";
|
|
89846
|
+
async function loadGatewayCatalog(apiBase) {
|
|
89847
|
+
try {
|
|
89848
|
+
const controller = new AbortController();
|
|
89849
|
+
const timer2 = setTimeout(() => controller.abort(), GATEWAY_CATALOG_TIMEOUT_MS);
|
|
89850
|
+
const res = await fetch(`${apiBase}/v1/models`, { signal: controller.signal });
|
|
89851
|
+
clearTimeout(timer2);
|
|
89852
|
+
if (!res.ok) return;
|
|
89853
|
+
const body = await res.json();
|
|
89854
|
+
const ids = (body.data ?? []).map((m) => m.id).filter((id2) => !!id2);
|
|
89855
|
+
if (ids.length === 0) return;
|
|
89856
|
+
gatewayModelIds = new Set(ids);
|
|
89857
|
+
const unserved = [...FREE_MODELS].filter((m) => !gatewayModelIds.has(toUpstreamModelId(m)));
|
|
89858
|
+
if (unserved.length > 0) {
|
|
89859
|
+
console.log(
|
|
89860
|
+
`[ClawRouter] Free models not served by this gateway (skipped in the cascade): ${unserved.join(", ")}`
|
|
89861
|
+
);
|
|
89862
|
+
}
|
|
89863
|
+
} catch {
|
|
89864
|
+
}
|
|
89865
|
+
}
|
|
89866
|
+
function isServedByGateway(modelId) {
|
|
89867
|
+
if (!gatewayModelIds) return true;
|
|
89868
|
+
return gatewayModelIds.has(toUpstreamModelId(modelId));
|
|
89869
|
+
}
|
|
89746
89870
|
function pickFreeModel(excludeList) {
|
|
89871
|
+
for (const m of FREE_MODELS) {
|
|
89872
|
+
if (excludeList?.has(m)) continue;
|
|
89873
|
+
if (!isServedByGateway(m)) continue;
|
|
89874
|
+
return m;
|
|
89875
|
+
}
|
|
89747
89876
|
for (const m of FREE_MODELS) {
|
|
89748
89877
|
if (!excludeList?.has(m)) return m;
|
|
89749
89878
|
}
|
|
@@ -90083,6 +90212,9 @@ function detectDegradedSuccessResponse(body) {
|
|
|
90083
90212
|
return `degraded response: ${errorText.slice(0, 120)}`;
|
|
90084
90213
|
}
|
|
90085
90214
|
const choices = parsed.choices;
|
|
90215
|
+
if (Array.isArray(choices) && choices.length === 0) {
|
|
90216
|
+
return "degraded response: no choices returned";
|
|
90217
|
+
}
|
|
90086
90218
|
if (Array.isArray(choices) && choices.length > 0) {
|
|
90087
90219
|
const choice = choices[0];
|
|
90088
90220
|
const msg = choice.message ?? choice.delta;
|
|
@@ -90573,6 +90705,7 @@ async function startProxy(options) {
|
|
|
90573
90705
|
} else if (paymentChain === "solana") {
|
|
90574
90706
|
console.log(`[ClawRouter] Payment chain: Solana (${BLOCKRUN_SOLANA_API})`);
|
|
90575
90707
|
}
|
|
90708
|
+
void loadGatewayCatalog(apiBase);
|
|
90576
90709
|
const listenPort = options.port ?? getProxyPort();
|
|
90577
90710
|
const existingProxy = await checkExistingProxy(listenPort);
|
|
90578
90711
|
if (existingProxy) {
|
|
@@ -93106,6 +93239,22 @@ data: [DONE]
|
|
|
93106
93239
|
} else {
|
|
93107
93240
|
modelsToTry = modelId ? [modelId] : [];
|
|
93108
93241
|
}
|
|
93242
|
+
if (modelsToTry.length > 0) {
|
|
93243
|
+
const unservedFree = modelsToTry.filter((m) => FREE_MODELS.has(m) && !isServedByGateway(m));
|
|
93244
|
+
if (unservedFree.length > 0) {
|
|
93245
|
+
const servedFree = [...FREE_MODELS].filter(
|
|
93246
|
+
(m) => isServedByGateway(m) && !excludeList?.has(m)
|
|
93247
|
+
);
|
|
93248
|
+
const replacement = servedFree[0];
|
|
93249
|
+
if (replacement) {
|
|
93250
|
+
modelsToTry = modelsToTry.map((m) => unservedFree.includes(m) ? replacement : m);
|
|
93251
|
+
modelsToTry = modelsToTry.filter((m, i) => modelsToTry.indexOf(m) === i);
|
|
93252
|
+
console.log(
|
|
93253
|
+
`[ClawRouter] ${unservedFree.join(", ")} not served on this chain \u2014 using ${replacement}`
|
|
93254
|
+
);
|
|
93255
|
+
}
|
|
93256
|
+
}
|
|
93257
|
+
}
|
|
93109
93258
|
if (!hasTools && routingDecision) {
|
|
93110
93259
|
const freeFallback = pickFreeModel(excludeList);
|
|
93111
93260
|
if (freeFallback && !modelsToTry.includes(freeFallback)) {
|
|
@@ -93986,7 +94135,7 @@ data: [DONE]
|
|
|
93986
94135
|
});
|
|
93987
94136
|
}
|
|
93988
94137
|
}
|
|
93989
|
-
var paymentStore, BLOCKRUN_API, BLOCKRUN_SOLANA_API, IMAGE_DIR, AUDIO_DIR, VIDEO_DIR, AUTO_MODEL, ROUTING_PROFILES, FREE_MODELS, FREE_MODEL, FREE_UPSTREAM_OVERRIDES, MAX_MESSAGES, CONTEXT_LIMIT_KB, HEARTBEAT_INTERVAL_MS, BALANCE_CHECK_TIMEOUT_MS, DEFAULT_REQUEST_TIMEOUT_MS, PER_MODEL_TIMEOUT_MS, REASONING_MODEL_TIMEOUT_MS, REASONING_MODEL_IDS, MAX_FALLBACK_ATTEMPTS, HEALTH_CHECK_TIMEOUT_MS, RATE_LIMIT_COOLDOWN_MS, OVERLOAD_COOLDOWN_MS, PORT_RETRY_ATTEMPTS, PORT_RETRY_DELAY_MS, MODEL_BODY_READ_TIMEOUT_MS, ERROR_BODY_READ_TIMEOUT_MS, ClientDisconnectedError, rateLimitedModels, overloadedModels, perProviderErrors, BALANCE_CHECK_BUFFER, BALANCE_PREFLIGHT_OUTPUT_TOKEN_CAP, PROVIDER_ERROR_PATTERNS, DEGRADED_RESPONSE_PATTERNS, DEGRADED_LOOP_PATTERNS, VALID_ROLES, ROLE_MAPPINGS, VALID_TOOL_ID_PATTERN, KIMI_BLOCK_RE, KIMI_TOKEN_RE, THINKING_TAG_RE, THINKING_BLOCK_RE, BLOCKRUN_MODEL_BY_ID, IMAGE_PRICING, IMAGE_MODEL_IDS, IMAGE_MODEL_SIZES, IMAGE_MODEL_ALIASES, VIDEO_PRICING, PHONE_PRICING;
|
|
94138
|
+
var paymentStore, BLOCKRUN_API, BLOCKRUN_SOLANA_API, IMAGE_DIR, AUDIO_DIR, VIDEO_DIR, AUTO_MODEL, ROUTING_PROFILES, FREE_MODELS, gatewayModelIds, FREE_MODEL, FREE_UPSTREAM_OVERRIDES, MAX_MESSAGES, CONTEXT_LIMIT_KB, HEARTBEAT_INTERVAL_MS, BALANCE_CHECK_TIMEOUT_MS, GATEWAY_CATALOG_TIMEOUT_MS, DEFAULT_REQUEST_TIMEOUT_MS, PER_MODEL_TIMEOUT_MS, REASONING_MODEL_TIMEOUT_MS, REASONING_MODEL_IDS, MAX_FALLBACK_ATTEMPTS, HEALTH_CHECK_TIMEOUT_MS, RATE_LIMIT_COOLDOWN_MS, OVERLOAD_COOLDOWN_MS, PORT_RETRY_ATTEMPTS, PORT_RETRY_DELAY_MS, MODEL_BODY_READ_TIMEOUT_MS, ERROR_BODY_READ_TIMEOUT_MS, ClientDisconnectedError, rateLimitedModels, overloadedModels, perProviderErrors, BALANCE_CHECK_BUFFER, BALANCE_PREFLIGHT_OUTPUT_TOKEN_CAP, PROVIDER_ERROR_PATTERNS, DEGRADED_RESPONSE_PATTERNS, DEGRADED_LOOP_PATTERNS, VALID_ROLES, ROLE_MAPPINGS, VALID_TOOL_ID_PATTERN, KIMI_BLOCK_RE, KIMI_TOKEN_RE, THINKING_TAG_RE, THINKING_BLOCK_RE, BLOCKRUN_MODEL_BY_ID, IMAGE_PRICING, IMAGE_MODEL_IDS, IMAGE_MODEL_SIZES, IMAGE_MODEL_ALIASES, VIDEO_PRICING, PHONE_PRICING;
|
|
93990
94139
|
var init_proxy = __esm({
|
|
93991
94140
|
"src/proxy.ts"() {
|
|
93992
94141
|
"use strict";
|
|
@@ -94061,6 +94210,7 @@ var init_proxy = __esm({
|
|
|
94061
94210
|
CONTEXT_LIMIT_KB = 5120;
|
|
94062
94211
|
HEARTBEAT_INTERVAL_MS = 2e3;
|
|
94063
94212
|
BALANCE_CHECK_TIMEOUT_MS = 2500;
|
|
94213
|
+
GATEWAY_CATALOG_TIMEOUT_MS = 5e3;
|
|
94064
94214
|
DEFAULT_REQUEST_TIMEOUT_MS = 3e5;
|
|
94065
94215
|
PER_MODEL_TIMEOUT_MS = 6e4;
|
|
94066
94216
|
REASONING_MODEL_TIMEOUT_MS = 18e4;
|
|
@@ -226389,7 +226539,8 @@ import {
|
|
|
226389
226539
|
readdirSync,
|
|
226390
226540
|
mkdirSync as mkdirSync3,
|
|
226391
226541
|
copyFileSync,
|
|
226392
|
-
renameSync as renameSync2
|
|
226542
|
+
renameSync as renameSync2,
|
|
226543
|
+
unlinkSync
|
|
226393
226544
|
} from "fs";
|
|
226394
226545
|
import { readFile as readFileAsync } from "fs/promises";
|
|
226395
226546
|
import { homedir as homedir13 } from "os";
|
|
@@ -226734,6 +226885,15 @@ function injectAuthProfile(logger48) {
|
|
|
226734
226885
|
for (const agentId of agents) {
|
|
226735
226886
|
const authDir = join16(agentsDir, agentId, "agent");
|
|
226736
226887
|
const authPath = join16(authDir, "auth-profiles.json");
|
|
226888
|
+
const sqlitePath = join16(authDir, "openclaw-agent.sqlite");
|
|
226889
|
+
if (existsSync3(sqlitePath)) {
|
|
226890
|
+
removeInjectedAuthPlaceholder(authPath, logger48, agentId);
|
|
226891
|
+
continue;
|
|
226892
|
+
}
|
|
226893
|
+
if (agentId === "main") {
|
|
226894
|
+
removeInjectedAuthPlaceholder(authPath, logger48, agentId);
|
|
226895
|
+
continue;
|
|
226896
|
+
}
|
|
226737
226897
|
if (!existsSync3(authDir)) {
|
|
226738
226898
|
try {
|
|
226739
226899
|
mkdirSync3(authDir, { recursive: true });
|
|
@@ -226776,6 +226936,25 @@ function injectAuthProfile(logger48) {
|
|
|
226776
226936
|
logger48.info(`Auth injection failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
226777
226937
|
}
|
|
226778
226938
|
}
|
|
226939
|
+
function removeInjectedAuthPlaceholder(authPath, logger48, agentId) {
|
|
226940
|
+
try {
|
|
226941
|
+
if (!existsSync3(authPath)) return;
|
|
226942
|
+
const parsed = JSON.parse(readTextFileSync(authPath));
|
|
226943
|
+
const profiles = parsed?.profiles;
|
|
226944
|
+
if (!profiles || typeof profiles !== "object" || Array.isArray(profiles)) return;
|
|
226945
|
+
const keys = Object.keys(profiles);
|
|
226946
|
+
if (keys.length !== 1 || keys[0] !== "blockrun:default") return;
|
|
226947
|
+
const entry = profiles["blockrun:default"];
|
|
226948
|
+
if (!entry || typeof entry !== "object") return;
|
|
226949
|
+
const profile = entry;
|
|
226950
|
+
if (profile.type !== "api_key" || profile.provider !== "blockrun" || profile.key !== "x402-proxy-handles-auth") {
|
|
226951
|
+
return;
|
|
226952
|
+
}
|
|
226953
|
+
unlinkSync(authPath);
|
|
226954
|
+
logger48.info(`Removed legacy BlockRun auth placeholder for agent: ${agentId}`);
|
|
226955
|
+
} catch {
|
|
226956
|
+
}
|
|
226957
|
+
}
|
|
226779
226958
|
function clearDeferredProxyStartTimer(proc = process) {
|
|
226780
226959
|
if (!proc.__clawrouterDeferredStartTimer) return false;
|
|
226781
226960
|
clearTimeout(proc.__clawrouterDeferredStartTimer);
|
|
@@ -32,8 +32,8 @@ Through [ClawRouter](https://github.com/BlockRunAI/ClawRouter) — BlockRun's lo
|
|
|
32
32
|
| **Nemotron 3.5 Lightning** | 1M | ✅ | The free default — thinking-mode reasoning |
|
|
33
33
|
| **Nemotron 3 Nano 30B** | 131K | ✅ | Fastest free model (~121 tok/s) |
|
|
34
34
|
| **Nemotron 3 Ultra 550B** | 1M | ✅ | Largest free model — 550B / 55B active MoE |
|
|
35
|
-
| **Nemotron 3 Nano Omni 30B** | 256K | ✅ |
|
|
36
|
-
| **Llama 3.2 11B Vision** | 128K | — | Meta Llama
|
|
35
|
+
| **Nemotron 3 Nano Omni 30B** | 256K | ✅ | Strong generalist (text only in practice) |
|
|
36
|
+
| **Llama 3.2 11B Vision** | 128K | — | Meta Llama (text only in practice) |
|
|
37
37
|
| **Cohere North Mini Code** | 256K | ✅ | Coding, sub-second responses |
|
|
38
38
|
| **Poolside Laguna XS 2.1** | 131K | — | Coding, ~161 tok/s |
|
|
39
39
|
|
|
@@ -111,17 +111,17 @@ The **fastest free model in the catalog** — around 121 tokens/second on realis
|
|
|
111
111
|
|
|
112
112
|
**Best for:** Complex analysis and deep reasoning where you would otherwise pay.
|
|
113
113
|
|
|
114
|
-
### Nemotron 3 Nano Omni 30B —
|
|
114
|
+
### Nemotron 3 Nano Omni 30B — Strong, and Text-Only in Practice
|
|
115
115
|
|
|
116
|
-
31B / 3.2B active MoE, 256K context
|
|
116
|
+
31B / 3.2B active MoE, 256K context. Both gateways catalogue it as vision-capable and its benchmark card is real (ChartQA 90.3, DocVQA 95.6, MMMU 70.8) — but **the image path does not work through either gateway**, so ClawRouter treats it as text-only. See "There Is No Working Free Vision" below.
|
|
117
117
|
|
|
118
|
-
**Best for:**
|
|
118
|
+
**Best for:** General reasoning at 256K context, for free.
|
|
119
119
|
|
|
120
120
|
### Llama 3.2 11B Vision — The Free Llama
|
|
121
121
|
|
|
122
|
-
Meta's Llama 3.2 11B with
|
|
122
|
+
Meta's Llama 3.2 11B with a 128K window. It is older than everything else here, and that is the point: a 12-model sweep of what NVIDIA still serves free found this was the only Llama that actually finishes a real completion. The name promises image input; the gateway does not deliver it (see below).
|
|
123
123
|
|
|
124
|
-
**Best for:** Anyone who needs a Llama specifically
|
|
124
|
+
**Best for:** Anyone who needs a Llama specifically.
|
|
125
125
|
|
|
126
126
|
### Cohere North Mini Code — The Fast Coder
|
|
127
127
|
|
|
@@ -178,8 +178,8 @@ If you're using Claude Code, one command switches you to any free model:
|
|
|
178
178
|
/model free → Nemotron 3.5 Lightning (1M ctx, the default)
|
|
179
179
|
/model nano-30b → Nemotron 3 Nano 30B (fastest)
|
|
180
180
|
/model ultra-550b → Nemotron 3 Ultra 550B (largest)
|
|
181
|
-
/model vision-free → Nemotron 3 Nano Omni (
|
|
182
|
-
/model llama-vision → Llama 3.2 11B Vision
|
|
181
|
+
/model vision-free → Nemotron 3 Nano Omni (text only, see below)
|
|
182
|
+
/model llama-vision → Llama 3.2 11B Vision (text only, see below)
|
|
183
183
|
/model north-mini → Cohere North Mini Code
|
|
184
184
|
/model laguna → Poolside Laguna XS 2.1
|
|
185
185
|
```
|
|
@@ -200,7 +200,13 @@ The gateway will return structured tool calls from these models, but ClawRouter
|
|
|
200
200
|
|
|
201
201
|
Five of the seven are reasoning-capable and handle most tasks well. On the hardest problems — competition-level math, formal proofs, deep multi-step planning — they don't match Claude Opus 5 or Sonnet 5. That's why ClawRouter's REASONING tier doesn't use free models.
|
|
202
202
|
|
|
203
|
-
### 3.
|
|
203
|
+
### 3. There Is No Working Free Vision
|
|
204
|
+
|
|
205
|
+
Two of the seven are catalogued as vision-capable, and neither survives a real probe. On a 64×64 solid-red PNG, `nemotron-3-nano-omni` answered correctly 1 time in 4 on Base and returned "white" on Solana — where the response's own `model` field revealed a silent fallback to a text model. `llama-3.2-11b-vision` replied "I'm unable to see the image" on 3 of 3 attempts while answering plain text fine. Every one of those failures is an **HTTP 200**: the image is dropped and a confident wrong answer comes back with no error to branch on.
|
|
206
|
+
|
|
207
|
+
ClawRouter therefore ships no `vision` flag on any free model, so requests carrying an image route to a paid vision model instead. The general lesson is worth more than the specific finding: **a catalog's capability list is a claim, not a measurement** — and one passing sample is not a measurement either. The first probe here returned the right colour; it took four to see that was luck.
|
|
208
|
+
|
|
209
|
+
### 4. Free Hosting Is Volatile
|
|
204
210
|
|
|
205
211
|
This is the real limitation, and it is worth more than the other two. On 2026-08-30 NVIDIA retired four of the five visible free models in one sweep, and none of the nine models this article originally listed is still in the tier. Free capacity comes from whatever a provider is willing to give away this quarter. Pin a free model if you like — but build so that losing it costs you a config line, not a rewrite. That is the entire argument for putting a router in front of them.
|
|
206
212
|
|
|
@@ -217,7 +223,7 @@ Quick chat, formatting → Nemotron 3 Nano 30B (fastest)
|
|
|
217
223
|
Code generation → North Mini Code or Laguna XS 2.1
|
|
218
224
|
Reasoning required → Nemotron 3.5 Lightning (1M ctx)
|
|
219
225
|
Hardest free reasoning → Nemotron 3 Ultra 550B
|
|
220
|
-
|
|
226
|
+
Long-context reasoning → Nemotron 3.5 Lightning (1M)
|
|
221
227
|
A Llama specifically → Llama 3.2 11B Vision
|
|
222
228
|
```
|
|
223
229
|
|
|
@@ -50,7 +50,7 @@ This is where you're paying for real value:
|
|
|
50
50
|
|
|
51
51
|
## The Solution: ClawRouter
|
|
52
52
|
|
|
53
|
-
[ClawRouter](https://github.com/BlockRunAI/ClawRouter) is an open-source local proxy that sits between your app and <!-- br:models.chatVisible -->
|
|
53
|
+
[ClawRouter](https://github.com/BlockRunAI/ClawRouter) is an open-source local proxy that sits between your app and <!-- br:models.chatVisible -->76<!-- /br:models.chatVisible --> AI models. It saves you money in three ways: **smart routing**, **token optimization**, and **response caching**.
|
|
54
54
|
|
|
55
55
|
```
|
|
56
56
|
┌─────────────┐ ┌──────────────────────────────┐ ┌──────────────────┐
|
|
@@ -31,7 +31,7 @@ This is exactly the problem [ClawRouter](https://github.com/BlockRunAI/ClawRoute
|
|
|
31
31
|
|
|
32
32
|
## ClawRouter: Smart Routing for Agents
|
|
33
33
|
|
|
34
|
-
ClawRouter is an open-source local proxy that sits between your agent and <!-- br:models.chatVisible -->
|
|
34
|
+
ClawRouter is an open-source local proxy that sits between your agent and <!-- br:models.chatVisible -->76<!-- /br:models.chatVisible --> LLM models across 9 providers. It analyzes every request across 15 dimensions and routes it to the cheapest model that can handle it — in under 1ms, entirely locally.
|
|
35
35
|
|
|
36
36
|
```
|
|
37
37
|
Your Agent → ClawRouter (localhost:8402) → Best model for the job
|
|
@@ -56,7 +56,7 @@ From 20,000+ production requests:
|
|
|
56
56
|
| Free models (trivial tasks) | 12.8% | $0.00 |
|
|
57
57
|
| Others | 13.8% | varies |
|
|
58
58
|
|
|
59
|
-
**Result: <!-- br:savings.autoVsBaselinePct -->
|
|
59
|
+
**Result: <!-- br:savings.autoVsBaselinePct -->84<!-- /br:savings.autoVsBaselinePct -->% cheaper than pinning Claude Opus 5 for every request** — the published figure, priced on a stated workload mix rather than estimated.
|
|
60
60
|
|
|
61
61
|
A typical user running 10K mixed requests/month:
|
|
62
62
|
|
|
@@ -74,7 +74,7 @@ Then point your agent at `http://localhost:8402/v1/` with any OpenAI-compatible
|
|
|
74
74
|
|
|
75
75
|
- **No API keys to manage** — wallet-based cryptographic auth
|
|
76
76
|
- **No subscriptions** — pay per request in USDC (Base or Solana)
|
|
77
|
-
- **No vendor lock-in** — <!-- br:models.chatVisible -->
|
|
77
|
+
- **No vendor lock-in** — <!-- br:models.chatVisible -->76<!-- /br:models.chatVisible --> models, switch anytime
|
|
78
78
|
- **You control your wallet** — non-custodial, funds never held by a third party
|
|
79
79
|
- **Budget caps** — set a max spend per session, ClawRouter gracefully downgrades when budget runs low
|
|
80
80
|
- **Token compression** — 7-layer pipeline reduces token costs by 7–40% before they hit any provider
|
|
@@ -135,7 +135,7 @@ Less context repeated = fewer tokens = lower cost. Agents that need to recall ea
|
|
|
135
135
|
|
|
136
136
|
### 7. x402 Micropayments — Wallet-Based Budget Control
|
|
137
137
|
|
|
138
|
-
<p align="center"><img src="assets/blockrun-clawrouter-x402-usdc-micropayment-wallet-budget-control.png" alt="Budget limits enforced by physical construction — wallet loaded via Base/Solana, pay per call across <!-- br:models.chatVisible -->
|
|
138
|
+
<p align="center"><img src="assets/blockrun-clawrouter-x402-usdc-micropayment-wallet-budget-control.png" alt="Budget limits enforced by physical construction — wallet loaded via Base/Solana, pay per call across <!-- br:models.chatVisible -->76<!-- /br:models.chatVisible --> models, balance hits zero and the valve shuts cleanly" width="720"></p>
|
|
139
139
|
|
|
140
140
|
ClawRouter pays for inference via [x402](https://x402.org/) USDC micropayments (Base or Solana). You load a wallet. Each inference call costs exactly what it costs. When the wallet runs low, requests stop cleanly.
|
|
141
141
|
|
|
@@ -222,7 +222,7 @@ OpenRouter doesn't always pass through provider-specific features correctly. Ima
|
|
|
222
222
|
|
|
223
223
|
**Direct provider routing.** ClawRouter routes through BlockRun's API directly to providers — not through a second aggregator. One hop, not two. Provider-specific features work because there's no middleman translating them.
|
|
224
224
|
|
|
225
|
-

|
|
226
226
|
|
|
227
227
|
---
|
|
228
228
|
|
|
@@ -240,7 +240,7 @@ When new models launch, OpenRouter's catalog lags. Users configure a model that
|
|
|
240
240
|
|
|
241
241
|
### How ClawRouter Solves This
|
|
242
242
|
|
|
243
|
-
ClawRouter maintains a curated catalog of <!-- br:models.chatVisible -->
|
|
243
|
+
ClawRouter maintains a curated catalog of <!-- br:models.chatVisible -->76<!-- /br:models.chatVisible --> models across 9 providers (including <!-- br:models.free -->7<!-- /br:models.free --> free models), updated with each release. Delisted models have automatic redirect aliases:
|
|
244
244
|
|
|
245
245
|
```typescript
|
|
246
246
|
// Delisted models redirect automatically
|
|
@@ -268,10 +268,10 @@ No silent drops. No stale catalog. Models are benchmarked for speed, quality, an
|
|
|
268
268
|
| **Rate limits** | Per-key, shared | Per-wallet, independent |
|
|
269
269
|
| **Vision support** | Images sometimes dropped | Auto-detected, vision-only fallback |
|
|
270
270
|
| **Tool calling** | Silent failures with some models | Flag-based filtering, guaranteed support |
|
|
271
|
-
| **Model catalog** | Laggy, silent drops | Curated <!-- br:models.chatVisible -->
|
|
271
|
+
| **Model catalog** | Laggy, silent drops | Curated <!-- br:models.chatVisible -->76<!-- /br:models.chatVisible --> models, redirect aliases |
|
|
272
272
|
| **Budget control** | Monthly invoice | Per-session cap (`maxCostPerRun`) |
|
|
273
273
|
| **Setup** | Create account, paste key | Agent generates wallet, auto-configured |
|
|
274
|
-
| **Average cost** | $25/M tokens (Opus direct) | auto-routed = **<!-- br:savings.autoVsBaselinePct -->
|
|
274
|
+
| **Average cost** | $25/M tokens (Opus direct) | auto-routed = **<!-- br:savings.autoVsBaselinePct -->84<!-- /br:savings.autoVsBaselinePct -->% savings** |
|
|
275
275
|
|
|
276
276
|

|
|
277
277
|
|
package/docs/routing-profiles.md
CHANGED
|
@@ -75,11 +75,13 @@ Set `routing.overrides.agenticMode: false` to disable the agentic tier set, or `
|
|
|
75
75
|
|
|
76
76
|
## FREE (`/model free`)
|
|
77
77
|
|
|
78
|
-
`free` is an alias, not a routed profile: it pins the free-tier default, currently **`free/nemotron-3.5-lightning`** — the same model that opens ECO SIMPLE. If that model is excluded (`/exclude add lightning`) or the budget cap forces a free fallback, the proxy walks the free cascade in this order: nemotron-3.5-lightning → nemotron-3-nano-30b → laguna-xs-2.1 → north-mini-code → nemotron-3-nano-omni-30b-a3b-reasoning
|
|
78
|
+
`free` is an alias, not a routed profile: it pins the free-tier default, currently **`free/nemotron-3.5-lightning`** — the same model that opens ECO SIMPLE. If that model is excluded (`/exclude add lightning`) or the budget cap forces a free fallback, the proxy walks the free cascade in this order: nemotron-3.5-lightning → nemotron-3-nano-30b → laguna-xs-2.1 → north-mini-code → nemotron-3-nano-omni-30b-a3b-reasoning → nemotron-3-ultra-550b → llama-3.2-11b-vision. All seven are $0.00 and need no USDC, and all seven are treated as **text-only** — see the vision note below.
|
|
79
79
|
|
|
80
80
|
The order is not arbitrary. The head is whatever the gateway itself redirects the previous head to, so the proxy and the gateway never name different models. After it comes the fastest rung, then the two sub-second coders — adjacent on purpose, because they sit on _different_ capacity pools (our own NVIDIA key vs OpenRouter's $0 pool), so one pool's outage cannot take both. The vision model sits mid-chain, and the two slowest rungs go last. The tier stopped being NVIDIA-only on 2026-08-30: two of the seven come from Cohere and Poolside.
|
|
81
81
|
|
|
82
|
-
Pin any of them directly with `/model lightning`, `/model nano-30b`, `/model laguna`, `/model north-mini`, `/model nemotron-omni
|
|
82
|
+
Pin any of them directly with `/model lightning`, `/model nano-30b`, `/model laguna`, `/model north-mini`, `/model nemotron-omni`, `/model ultra-550b` or `/model llama-vision`.
|
|
83
|
+
|
|
84
|
+
**No free model carries the `vision` flag,** even the two the upstream catalogs advertise as vision-capable. A 64×64 solid-colour probe on 2026-08-31 got the right answer 1 time in 4 from `nemotron-3-nano-omni` on Base, and "white" for red on Solana — where the response's own `model` field showed a silent fallback to a text model. `llama-3.2-11b-vision`, despite the name, said "I'm unable to see the image" on 3 of 3 while a plain-text control passed. Every one of those is an HTTP 200, so the caller gets a confident wrong answer with nothing to branch on. Since `vision` is what `filterByVision()` uses to _aim_ image turns at a model, flagging them would route real traffic into that. Requests carrying an `image_url` go to a paid vision model.
|
|
83
85
|
|
|
84
86
|
---
|
|
85
87
|
|
|
@@ -111,7 +113,7 @@ Combined input + output rate per 1M tokens, primaries only:
|
|
|
111
113
|
| COMPLEX | $1.75 | $14.00 | **88%** |
|
|
112
114
|
| REASONING | $0.70 | $0.70 | 0% |
|
|
113
115
|
|
|
114
|
-
The published savings claim (**
|
|
116
|
+
The published savings claim (**84%** 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.
|
|
115
117
|
|
|
116
118
|
---
|
|
117
119
|
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@blockrun/clawrouter",
|
|
3
|
-
"version": "0.12.
|
|
4
|
-
"description": "Smart LLM router — save
|
|
3
|
+
"version": "0.12.260",
|
|
4
|
+
"description": "Smart LLM router — save 84% on inference costs. 76 models (7 free), one wallet, x402 micropayments.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"types": "dist/index.d.ts",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: clawrouter
|
|
3
|
-
description: Hosted-gateway LLM router — save
|
|
3
|
+
description: Hosted-gateway LLM router — save 84% on inference costs. A local proxy that forwards each request to the blockrun.ai gateway, which routes to the cheapest capable model across 76 models from OpenAI, Anthropic, Google, DeepSeek, xAI, Z.AI, and more. 7 free open-weight models included. Also exposes realtime market data (global stocks, crypto, FX, commodities), Twitter/X intelligence, prediction-market data across Polymarket, Kalshi, Limitless, Opinion, Predict.Fun, dFlow + UMA oracle resolution + wallet identity & clustering, phone-number intelligence (carrier + SIM-swap fraud detection) plus AI-powered outbound voice calls (Twilio + Bland.ai), AND the Surf unified crypto data API (84 endpoints — CEX/DEX, on-chain SQL over 80+ ClickHouse tables, 100M+ labeled wallets, prediction markets, social/CT mindshare, news, VC fund intel) as built-in agent tools. Not a local-inference tool — prompts are sent to the blockrun.ai gateway.
|
|
4
4
|
triggers:
|
|
5
5
|
- "clawrouter"
|
|
6
6
|
- "claw router"
|
|
@@ -53,7 +53,7 @@ metadata:
|
|
|
53
53
|
|
|
54
54
|
# ClawRouter
|
|
55
55
|
|
|
56
|
-
Hosted-gateway LLM router that saves <!-- br:savings.autoVsBaselinePct -->
|
|
56
|
+
Hosted-gateway LLM router that saves <!-- br:savings.autoVsBaselinePct -->84<!-- /br:savings.autoVsBaselinePct -->% on inference costs by forwarding each request to the blockrun.ai gateway, which picks the cheapest model capable of handling it across <!-- br:models.chatVisible -->76<!-- /br:models.chatVisible --> models from 9 providers (<!-- br:models.free -->7<!-- /br:models.free --> free open-weight models). All billing flows through one USDC wallet; you do not hold provider API keys.
|
|
57
57
|
|
|
58
58
|
**This is not a local-inference tool.** ClawRouter is a thin local proxy. Your prompts are sent over HTTPS to the blockrun.ai gateway for model execution. If your workload requires inference that never leaves your machine, use a local runtime like Ollama — ClawRouter is not the right tool for that use case.
|
|
59
59
|
|
|
@@ -147,7 +147,7 @@ it against a baseline nobody wrote down. See
|
|
|
147
147
|
|
|
148
148
|
## Available Models
|
|
149
149
|
|
|
150
|
-
<!-- br:models.chatVisible -->
|
|
150
|
+
<!-- br:models.chatVisible -->76<!-- /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, glm-5.3 [Z.AI flagship, 1M ctx], glm-5.3-flash [natively multimodal, 1M ctx — $0.15/$0.50], glm-5.2, minimax-m3, 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 7 free open-weight models (nemotron-3.5-lightning [1M ctx, thinking mode — the free default], nemotron-3-nano-30b [fastest, ~121 tok/s], nemotron-3-ultra-550b [550B/55B MoE, 1M ctx — the largest free model], nemotron-3-nano-omni-30b-a3b-reasoning [256K ctx], llama-3.2-11b-vision [Meta Llama], north-mini-code [Cohere, coding, sub-second], laguna-xs-2.1 [Poolside, coding, ~161 tok/s]). The free tier is text-only — image turns route to a paid vision model, because the two free models the catalogs advertise as vision-capable fail a solid-colour probe on both chains and do so with an HTTP 200.
|
|
151
151
|
|
|
152
152
|
## Built-in Agent Tools
|
|
153
153
|
|
package/src/top-models.json
CHANGED
|
@@ -33,10 +33,13 @@
|
|
|
33
33
|
"zai/glm-5.1",
|
|
34
34
|
"zai/glm-5-turbo",
|
|
35
35
|
"zai/glm-5",
|
|
36
|
+
"xiaomi/mimo-v2.5",
|
|
36
37
|
"minimax/minimax-m3",
|
|
37
38
|
"minimax/minimax-m2.7",
|
|
38
39
|
"moonshot/kimi-k3",
|
|
39
40
|
"qwen/qwen3.7-max",
|
|
41
|
+
"qwen/qwen3.8-flash",
|
|
42
|
+
"deepseek/deepseek-v4-flash-vision-exp",
|
|
40
43
|
"deepseek/deepseek-v4-pro",
|
|
41
44
|
"deepseek/deepseek-chat",
|
|
42
45
|
"deepseek/deepseek-reasoner",
|