@blockrun/clawrouter 0.12.245 → 0.12.247
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 +11 -11
- package/dist/cli.js +189 -70
- package/dist/index.d.ts +16 -3
- package/dist/index.js +189 -70
- package/dist/router/index.js +48 -33
- package/docs/anthropic-cost-savings.md +1 -1
- package/docs/anthropic-third-party-harness-changes.md +2 -2
- package/docs/clawrouter-cuts-llm-api-costs-500x.md +1 -1
- package/docs/clawrouter-vs-openrouter-llm-routing-comparison.md +3 -3
- package/docs/configuration.md +2 -9
- package/docs/image-generation.md +34 -23
- package/package.json +3 -3
- package/scripts/reinstall.sh +1 -1
- package/skills/clawrouter/SKILL.md +5 -5
- package/skills/imagegen/SKILL.md +9 -7
package/dist/index.js
CHANGED
|
@@ -35385,6 +35385,21 @@ function applyPromotions(tierConfigs, promotions, profile, now2 = /* @__PURE__ *
|
|
|
35385
35385
|
}
|
|
35386
35386
|
return result;
|
|
35387
35387
|
}
|
|
35388
|
+
function applyUnavailableModels(tierConfigs, unavailableModels) {
|
|
35389
|
+
if (!unavailableModels || unavailableModels.length === 0) return tierConfigs;
|
|
35390
|
+
const dead = new Set(unavailableModels);
|
|
35391
|
+
let result = tierConfigs;
|
|
35392
|
+
for (const tier of Object.keys(tierConfigs)) {
|
|
35393
|
+
const config = tierConfigs[tier];
|
|
35394
|
+
const alive = [config.primary, ...config.fallback].filter((model) => !dead.has(model));
|
|
35395
|
+
if (alive.length === 0 || alive[0] === config.primary && alive.length === config.fallback.length + 1) {
|
|
35396
|
+
continue;
|
|
35397
|
+
}
|
|
35398
|
+
if (result === tierConfigs) result = { ...tierConfigs };
|
|
35399
|
+
result[tier] = { primary: alive[0], fallback: alive.slice(1) };
|
|
35400
|
+
}
|
|
35401
|
+
return result;
|
|
35402
|
+
}
|
|
35388
35403
|
function getStrategy(name) {
|
|
35389
35404
|
const strategy = registry.get(name);
|
|
35390
35405
|
if (!strategy) {
|
|
@@ -36082,6 +36097,7 @@ ${value.slice(-(scanLimit - prefixLength))}`;
|
|
|
36082
36097
|
profile = useAgenticTiers ? "agentic" : "auto";
|
|
36083
36098
|
}
|
|
36084
36099
|
tierConfigs = applyPromotions(tierConfigs, config.promotions, profile, options.now);
|
|
36100
|
+
tierConfigs = applyUnavailableModels(tierConfigs, options.unavailableModels);
|
|
36085
36101
|
const agenticScoreValue = ruleResult.agenticScore;
|
|
36086
36102
|
if (estimatedTokens > config.overrides.maxTokensForceComplex) {
|
|
36087
36103
|
const decision2 = selectModel(
|
|
@@ -36210,18 +36226,6 @@ ${value.slice(-(scanLimit - prefixLength))}`;
|
|
|
36210
36226
|
supportsTools: false,
|
|
36211
36227
|
supportsVision: false
|
|
36212
36228
|
},
|
|
36213
|
-
"free/gpt-oss-120b": {
|
|
36214
|
-
contextWindow: 128e3,
|
|
36215
|
-
maxOutputTokens: 16384,
|
|
36216
|
-
supportsTools: false,
|
|
36217
|
-
supportsVision: false
|
|
36218
|
-
},
|
|
36219
|
-
"free/gpt-oss-20b": {
|
|
36220
|
-
contextWindow: 128e3,
|
|
36221
|
-
maxOutputTokens: 16384,
|
|
36222
|
-
supportsTools: false,
|
|
36223
|
-
supportsVision: false
|
|
36224
|
-
},
|
|
36225
36229
|
"free/seed-oss-36b": {
|
|
36226
36230
|
contextWindow: 131072,
|
|
36227
36231
|
maxOutputTokens: 16384,
|
|
@@ -36294,6 +36298,18 @@ ${value.slice(-(scanLimit - prefixLength))}`;
|
|
|
36294
36298
|
supportsTools: true,
|
|
36295
36299
|
supportsVision: true
|
|
36296
36300
|
},
|
|
36301
|
+
"nvidia/nemotron-nano-9b-v2": {
|
|
36302
|
+
contextWindow: 131072,
|
|
36303
|
+
maxOutputTokens: 16384,
|
|
36304
|
+
supportsTools: false,
|
|
36305
|
+
supportsVision: false
|
|
36306
|
+
},
|
|
36307
|
+
"nvidia/step-3.7-flash": {
|
|
36308
|
+
contextWindow: 131072,
|
|
36309
|
+
maxOutputTokens: 16384,
|
|
36310
|
+
supportsTools: false,
|
|
36311
|
+
supportsVision: false
|
|
36312
|
+
},
|
|
36297
36313
|
"openai/gpt-4.1": {
|
|
36298
36314
|
contextWindow: 128e3,
|
|
36299
36315
|
maxOutputTokens: 16384,
|
|
@@ -36767,9 +36783,12 @@ ${value.slice(-(scanLimit - prefixLength))}`;
|
|
|
36767
36783
|
const targetTier = (features.taskType === "reasoning_mcq" || features.taskType === "reasoning_math") && (base3.tier === "SIMPLE" || base3.tier === "MEDIUM") ? "REASONING" : base3.tier;
|
|
36768
36784
|
const tierConfig = tierConfigs[targetTier];
|
|
36769
36785
|
const configuredCandidates = tierConfig ? getFallbackChain(targetTier, tierConfigs) : [];
|
|
36786
|
+
const unavailable = new Set(options.unavailableModels ?? []);
|
|
36770
36787
|
const chain3 = [
|
|
36771
36788
|
.../* @__PURE__ */ new Set([...configuredCandidates, ...evidenceCandidates(features.taskType)])
|
|
36772
|
-
].filter(
|
|
36789
|
+
].filter(
|
|
36790
|
+
(model2) => typeof model2 === "string" && model2.length > 0 && !unavailable.has(model2)
|
|
36791
|
+
);
|
|
36773
36792
|
const eligible = chain3.filter(
|
|
36774
36793
|
(model2) => isEligible(model2, features, maxOutputTokens, options)
|
|
36775
36794
|
);
|
|
@@ -36846,13 +36865,7 @@ ${value.slice(-(scanLimit - prefixLength))}`;
|
|
|
36846
36865
|
...eligibleCandidates.filter(
|
|
36847
36866
|
(model2) => !scoredModels.includes(model2) && !webResearchFallbackOrder.includes(model2)
|
|
36848
36867
|
)
|
|
36849
|
-
] :
|
|
36850
|
-
...scoredModels,
|
|
36851
|
-
...eligibleCandidates.filter((model2) => !scoredModels.includes(model2))
|
|
36852
|
-
] : [
|
|
36853
|
-
...scoredModels,
|
|
36854
|
-
...eligibleCandidates.filter((model2) => !scoredModels.includes(model2))
|
|
36855
|
-
];
|
|
36868
|
+
] : [...scoredModels, ...eligibleCandidates.filter((model2) => !scoredModels.includes(model2))];
|
|
36856
36869
|
const model = ranked[0] ?? base3.model;
|
|
36857
36870
|
const selectedTierConfigs = {
|
|
36858
36871
|
...tierConfigs,
|
|
@@ -37964,8 +37977,8 @@ ${value.slice(-(scanLimit - prefixLength))}`;
|
|
|
37964
37977
|
// $0.20/$1.25, 1M context
|
|
37965
37978
|
"xai/grok-4-fast-non-reasoning",
|
|
37966
37979
|
// 1,143ms, $0.20/$0.50 — fast fallback
|
|
37967
|
-
"
|
|
37968
|
-
//
|
|
37980
|
+
"nvidia/step-3.7-flash"
|
|
37981
|
+
// FREE backstop — new NVIDIA free tier (gpt-oss-120b now 400s; probed 2026-08-21)
|
|
37969
37982
|
]
|
|
37970
37983
|
},
|
|
37971
37984
|
MEDIUM: {
|
|
@@ -38038,14 +38051,15 @@ ${value.slice(-(scanLimit - prefixLength))}`;
|
|
|
38038
38051
|
// Eco tier configs - absolute cheapest (blockrun/eco)
|
|
38039
38052
|
ecoTiers: {
|
|
38040
38053
|
SIMPLE: {
|
|
38041
|
-
primary: "
|
|
38042
|
-
// FREE! $0.00/$0.00 —
|
|
38054
|
+
primary: "nvidia/step-3.7-flash",
|
|
38055
|
+
// FREE! $0.00/$0.00 — new NVIDIA free tier flagship
|
|
38043
38056
|
fallback: [
|
|
38044
|
-
"
|
|
38045
|
-
// FREE —
|
|
38046
|
-
//
|
|
38047
|
-
// (410
|
|
38048
|
-
//
|
|
38057
|
+
"nvidia/nemotron-nano-9b-v2",
|
|
38058
|
+
// FREE — compact + fast (~0.7s), high-volume light tasks
|
|
38059
|
+
// This head keeps rotting with NVIDIA's free hosting: deepseek-v4-flash
|
|
38060
|
+
// (410, 2026-08-12), seed-oss-36b (410, 2026-08-03), then gpt-oss-120b/20b
|
|
38061
|
+
// (400 Unknown model, probed 2026-08-21). Each retirement retargets the
|
|
38062
|
+
// two free rungs to the current free tier; the paid rungs below never move.
|
|
38049
38063
|
"google/gemini-3.1-flash-lite",
|
|
38050
38064
|
// $0.25/$1.50 — newest flash-lite
|
|
38051
38065
|
"openai/gpt-5.4-nano",
|
|
@@ -38162,8 +38176,8 @@ ${value.slice(-(scanLimit - prefixLength))}`;
|
|
|
38162
38176
|
"openai/gpt-5.3-codex",
|
|
38163
38177
|
"deepseek/deepseek-chat",
|
|
38164
38178
|
// Cheap, reliable
|
|
38165
|
-
"
|
|
38166
|
-
// NVIDIA free ultimate backstop (was
|
|
38179
|
+
"nvidia/step-3.7-flash"
|
|
38180
|
+
// NVIDIA free ultimate backstop (was gpt-oss-120b; 400s since ~2026-08)
|
|
38167
38181
|
]
|
|
38168
38182
|
},
|
|
38169
38183
|
REASONING: {
|
|
@@ -38252,8 +38266,8 @@ ${value.slice(-(scanLimit - prefixLength))}`;
|
|
|
38252
38266
|
// Previous flagship — 6,213ms, reliable
|
|
38253
38267
|
"deepseek/deepseek-chat",
|
|
38254
38268
|
// 1,431ms — cheap, reliable
|
|
38255
|
-
"
|
|
38256
|
-
// NVIDIA free ultimate backstop (was
|
|
38269
|
+
"nvidia/step-3.7-flash"
|
|
38270
|
+
// NVIDIA free ultimate backstop (was gpt-oss-120b; 400s since ~2026-08)
|
|
38257
38271
|
]
|
|
38258
38272
|
},
|
|
38259
38273
|
REASONING: {
|
|
@@ -57791,6 +57805,14 @@ Then run: npx @blockrun/clawrouter`
|
|
|
57791
57805
|
solanaAddress = await getSolanaAddress(derived.solanaPrivateKeyBytes);
|
|
57792
57806
|
} catch {
|
|
57793
57807
|
}
|
|
57808
|
+
let solanaDefaultSaved = false;
|
|
57809
|
+
if (solanaAddress) {
|
|
57810
|
+
try {
|
|
57811
|
+
await savePaymentChain("solana");
|
|
57812
|
+
solanaDefaultSaved = true;
|
|
57813
|
+
} catch {
|
|
57814
|
+
}
|
|
57815
|
+
}
|
|
57794
57816
|
console.log(`[ClawRouter]`);
|
|
57795
57817
|
console.log(`[ClawRouter] \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550`);
|
|
57796
57818
|
console.log(`[ClawRouter] NEW WALLET GENERATED \u2014 BACK UP YOUR KEY NOW`);
|
|
@@ -57803,6 +57825,12 @@ Then run: npx @blockrun/clawrouter`
|
|
|
57803
57825
|
console.log(`[ClawRouter] Mnemonic : ${MNEMONIC_FILE}`);
|
|
57804
57826
|
console.log(`[ClawRouter]`);
|
|
57805
57827
|
console.log(`[ClawRouter] Both EVM (Base) and Solana wallets are ready.`);
|
|
57828
|
+
if (solanaDefaultSaved) {
|
|
57829
|
+
console.log(
|
|
57830
|
+
`[ClawRouter] Default payment chain: Solana \u2014 fund the Solana address above with USDC.`
|
|
57831
|
+
);
|
|
57832
|
+
console.log(`[ClawRouter] To switch to Base, run in OpenClaw: /wallet base`);
|
|
57833
|
+
}
|
|
57806
57834
|
console.log(`[ClawRouter] To back up, run in OpenClaw:`);
|
|
57807
57835
|
console.log(`[ClawRouter] /wallet export`);
|
|
57808
57836
|
console.log(`[ClawRouter]`);
|
|
@@ -90608,25 +90636,7 @@ async function proxyRequest(req, res, apiBase, payFetch, options, routerOpts, de
|
|
|
90608
90636
|
const modelMatch = imageArgs.match(/--model\s+(\S+)/);
|
|
90609
90637
|
if (modelMatch) {
|
|
90610
90638
|
const raw = modelMatch[1];
|
|
90611
|
-
|
|
90612
|
-
// dall-e-3 delisted upstream 2026-05-25 — legacy aliases route to
|
|
90613
|
-
// the OpenAI successor instead of a guaranteed 400.
|
|
90614
|
-
"dall-e-3": "openai/gpt-image-2",
|
|
90615
|
-
dalle3: "openai/gpt-image-2",
|
|
90616
|
-
dalle: "openai/gpt-image-2",
|
|
90617
|
-
"gpt-image": "openai/gpt-image-1",
|
|
90618
|
-
"gpt-image-1": "openai/gpt-image-1",
|
|
90619
|
-
"gpt-image-2": "openai/gpt-image-2",
|
|
90620
|
-
seedream: "bytedance/seedream-5-pro",
|
|
90621
|
-
banana: "google/nano-banana",
|
|
90622
|
-
"nano-banana": "google/nano-banana",
|
|
90623
|
-
"banana-pro": "google/nano-banana-pro",
|
|
90624
|
-
"nano-banana-pro": "google/nano-banana-pro",
|
|
90625
|
-
"grok-imagine": "xai/grok-imagine-image",
|
|
90626
|
-
"grok-imagine-pro": "xai/grok-imagine-image-pro",
|
|
90627
|
-
cogview: "zai/cogview-4"
|
|
90628
|
-
};
|
|
90629
|
-
imageModel = IMAGE_MODEL_ALIASES[raw] ?? raw;
|
|
90639
|
+
imageModel = Object.prototype.hasOwnProperty.call(IMAGE_MODEL_ALIASES, raw) ? IMAGE_MODEL_ALIASES[raw] : raw;
|
|
90630
90640
|
imagePrompt = imagePrompt.replace(/--model\s+\S+/, "").trim();
|
|
90631
90641
|
}
|
|
90632
90642
|
const sizeMatch = imageArgs.match(/--size\s+(\d+x\d+)/);
|
|
@@ -90644,11 +90654,13 @@ async function proxyRequest(req, res, apiBase, payFetch, options, routerOpts, de
|
|
|
90644
90654
|
"",
|
|
90645
90655
|
"Models:",
|
|
90646
90656
|
" nano-banana Google Gemini Flash \u2014 $0.05/image",
|
|
90657
|
+
" banana-2 Google Nano Banana 2 \u2014 $0.09/image",
|
|
90647
90658
|
" banana-pro Google Gemini Pro \u2014 $0.10/image (up to 4K)",
|
|
90648
90659
|
" gpt-image OpenAI GPT Image 1 \u2014 $0.02/image",
|
|
90649
90660
|
" gpt-image-2 OpenAI GPT Image 2 \u2014 $0.06/image",
|
|
90650
90661
|
" seedream ByteDance Seedream 5 Pro \u2014 $0.045/image",
|
|
90651
90662
|
" grok-imagine xAI Grok Imagine \u2014 $0.02/image",
|
|
90663
|
+
" grok-imagine-pro xAI Grok Imagine Pro \u2014 $0.07/image",
|
|
90652
90664
|
" cogview Zhipu CogView-4 \u2014 $0.015/image",
|
|
90653
90665
|
"",
|
|
90654
90666
|
"Examples:",
|
|
@@ -90711,14 +90723,68 @@ async function proxyRequest(req, res, apiBase, payFetch, options, routerOpts, de
|
|
|
90711
90723
|
size: imageSize,
|
|
90712
90724
|
n: 1
|
|
90713
90725
|
});
|
|
90726
|
+
const imagegenAbort = new AbortController();
|
|
90727
|
+
res.on("close", () => {
|
|
90728
|
+
if (!res.writableEnded) imagegenAbort.abort();
|
|
90729
|
+
});
|
|
90714
90730
|
const imageResponse = await payFetch(imageUpstreamUrl, {
|
|
90715
90731
|
method: "POST",
|
|
90716
90732
|
headers: { "content-type": "application/json", "user-agent": USER_AGENT },
|
|
90717
|
-
body: imageBody
|
|
90733
|
+
body: imageBody,
|
|
90734
|
+
signal: imagegenAbort.signal
|
|
90718
90735
|
});
|
|
90719
|
-
|
|
90736
|
+
let imageResult = await imageResponse.json();
|
|
90737
|
+
let imageFailure;
|
|
90738
|
+
if (imageResponse.ok && imageResult.poll_url && imageResult.id && !imageResult.data?.length) {
|
|
90739
|
+
const apiOrigin = new URL(apiBase).origin;
|
|
90740
|
+
const pollUrl = imageResult.poll_url.startsWith("http") ? imageResult.poll_url : `${apiOrigin}${imageResult.poll_url}`;
|
|
90741
|
+
console.log(
|
|
90742
|
+
`[ClawRouter] /imagegen job submitted (id=${imageResult.id}), polling upstream \u2014 typical 30\u2013120s...`
|
|
90743
|
+
);
|
|
90744
|
+
const pollDeadline = Date.now() + 3e5;
|
|
90745
|
+
await new Promise((r2) => setTimeout(r2, 2e3));
|
|
90746
|
+
let completed2 = false;
|
|
90747
|
+
while (Date.now() < pollDeadline) {
|
|
90748
|
+
if (imagegenAbort.signal.aborted) {
|
|
90749
|
+
console.log(
|
|
90750
|
+
`[ClawRouter] Chat client disconnected \u2014 abandoning image poll (id=${imageResult.id})`
|
|
90751
|
+
);
|
|
90752
|
+
return;
|
|
90753
|
+
}
|
|
90754
|
+
const pollResp = await payFetch(pollUrl, {
|
|
90755
|
+
method: "GET",
|
|
90756
|
+
headers: { "user-agent": USER_AGENT },
|
|
90757
|
+
signal: imagegenAbort.signal
|
|
90758
|
+
});
|
|
90759
|
+
const pollText = await pollResp.text();
|
|
90760
|
+
let pollBody = {};
|
|
90761
|
+
try {
|
|
90762
|
+
pollBody = JSON.parse(pollText);
|
|
90763
|
+
} catch {
|
|
90764
|
+
imageFailure = `Non-JSON poll response (${pollResp.status}): ${pollText.slice(0, 200)}`;
|
|
90765
|
+
break;
|
|
90766
|
+
}
|
|
90767
|
+
if (pollResp.status === 202 || pollBody.status === "queued" || pollBody.status === "in_progress") {
|
|
90768
|
+
await new Promise((r2) => setTimeout(r2, 3e3));
|
|
90769
|
+
continue;
|
|
90770
|
+
}
|
|
90771
|
+
if (pollBody.status === "failed" || !pollResp.ok) {
|
|
90772
|
+
imageFailure = typeof pollBody.error === "string" ? pollBody.error : pollBody.error?.message ?? `Upstream image generation failed (HTTP ${pollResp.status})`;
|
|
90773
|
+
break;
|
|
90774
|
+
}
|
|
90775
|
+
imageResult = pollBody;
|
|
90776
|
+
completed2 = true;
|
|
90777
|
+
break;
|
|
90778
|
+
}
|
|
90779
|
+
if (!completed2 && !imageFailure) {
|
|
90780
|
+
imageFailure = "Image generation timed out after 5 minutes \u2014 the job may still complete upstream.";
|
|
90781
|
+
}
|
|
90782
|
+
}
|
|
90720
90783
|
let responseText;
|
|
90721
|
-
if (
|
|
90784
|
+
if (imageFailure) {
|
|
90785
|
+
responseText = `Image generation failed: ${imageFailure}`;
|
|
90786
|
+
console.log(`[ClawRouter] /imagegen error: ${imageFailure}`);
|
|
90787
|
+
} else if (!imageResponse.ok || imageResult.error) {
|
|
90722
90788
|
const errMsg = typeof imageResult.error === "string" ? imageResult.error : imageResult.error?.message ?? `HTTP ${imageResponse.status}`;
|
|
90723
90789
|
responseText = `Image generation failed: ${errMsg}`;
|
|
90724
90790
|
console.log(`[ClawRouter] /imagegen error: ${errMsg}`);
|
|
@@ -90738,9 +90804,7 @@ async function proxyRequest(req, res, apiBase, payFetch, options, routerOpts, de
|
|
|
90738
90804
|
console.error(
|
|
90739
90805
|
`[ClawRouter] /imagegen: failed to upload data URI: ${uploadErr instanceof Error ? uploadErr.message : String(uploadErr)}`
|
|
90740
90806
|
);
|
|
90741
|
-
lines.push(
|
|
90742
|
-
"Image generated but upload failed. Try again or use --model dall-e-3."
|
|
90743
|
-
);
|
|
90807
|
+
lines.push("Image generated but upload failed. Try again.");
|
|
90744
90808
|
}
|
|
90745
90809
|
} else {
|
|
90746
90810
|
lines.push(img.url);
|
|
@@ -92524,7 +92588,7 @@ data: [DONE]
|
|
|
92524
92588
|
});
|
|
92525
92589
|
}
|
|
92526
92590
|
}
|
|
92527
|
-
var paymentStore, BLOCKRUN_API, BLOCKRUN_SOLANA_API, IMAGE_DIR, AUDIO_DIR, VIDEO_DIR, AUTO_MODEL, ROUTING_PROFILES, FREE_MODELS, FREE_MODEL, 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, 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, VIDEO_PRICING, PHONE_PRICING;
|
|
92591
|
+
var paymentStore, BLOCKRUN_API, BLOCKRUN_SOLANA_API, IMAGE_DIR, AUDIO_DIR, VIDEO_DIR, AUTO_MODEL, ROUTING_PROFILES, FREE_MODELS, FREE_MODEL, 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, 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;
|
|
92528
92592
|
var init_proxy = __esm({
|
|
92529
92593
|
"src/proxy.ts"() {
|
|
92530
92594
|
"use strict";
|
|
@@ -92669,9 +92733,20 @@ var init_proxy = __esm({
|
|
|
92669
92733
|
},
|
|
92670
92734
|
"bytedance/seedream-5-pro": {
|
|
92671
92735
|
default: 0.045,
|
|
92672
|
-
|
|
92736
|
+
// Full size list live-probed 2026-08-23 (gateway 402 quotes, base price):
|
|
92737
|
+
// the 2K portrait/landscape tiers bill at the 2048x2048 rate.
|
|
92738
|
+
sizes: {
|
|
92739
|
+
"1024x1024": 0.045,
|
|
92740
|
+
"1280x720": 0.045,
|
|
92741
|
+
"2048x1024": 0.045,
|
|
92742
|
+
"2048x2048": 0.09,
|
|
92743
|
+
"2304x1728": 0.09,
|
|
92744
|
+
"1728x2304": 0.09,
|
|
92745
|
+
"2848x1600": 0.09,
|
|
92746
|
+
"1600x2848": 0.09
|
|
92747
|
+
}
|
|
92673
92748
|
},
|
|
92674
|
-
"google/nano-banana": { default: 0.05 },
|
|
92749
|
+
"google/nano-banana": { default: 0.05, sizes: { "1024x1024": 0.05 } },
|
|
92675
92750
|
// Nano Banana 2 (Gemini 3.1 Flash imagegen, blockrun #329): $0.09/image at 1K.
|
|
92676
92751
|
"google/nano-banana-2": { default: 0.09, sizes: { "1024x1024": 0.09 } },
|
|
92677
92752
|
"google/nano-banana-pro": {
|
|
@@ -92692,6 +92767,30 @@ var init_proxy = __esm({
|
|
|
92692
92767
|
}
|
|
92693
92768
|
}
|
|
92694
92769
|
};
|
|
92770
|
+
IMAGE_MODEL_IDS = Object.freeze(Object.keys(IMAGE_PRICING));
|
|
92771
|
+
IMAGE_MODEL_SIZES = Object.freeze(
|
|
92772
|
+
[...new Set(Object.values(IMAGE_PRICING).flatMap((p) => Object.keys(p.sizes ?? {})))].sort()
|
|
92773
|
+
);
|
|
92774
|
+
IMAGE_MODEL_ALIASES = Object.freeze({
|
|
92775
|
+
// dall-e-3 delisted upstream 2026-05-25 — legacy aliases route to
|
|
92776
|
+
// the OpenAI successor instead of a guaranteed 400.
|
|
92777
|
+
"dall-e-3": "openai/gpt-image-2",
|
|
92778
|
+
dalle3: "openai/gpt-image-2",
|
|
92779
|
+
dalle: "openai/gpt-image-2",
|
|
92780
|
+
"gpt-image": "openai/gpt-image-1",
|
|
92781
|
+
"gpt-image-1": "openai/gpt-image-1",
|
|
92782
|
+
"gpt-image-2": "openai/gpt-image-2",
|
|
92783
|
+
seedream: "bytedance/seedream-5-pro",
|
|
92784
|
+
banana: "google/nano-banana",
|
|
92785
|
+
"nano-banana": "google/nano-banana",
|
|
92786
|
+
"banana-2": "google/nano-banana-2",
|
|
92787
|
+
"nano-banana-2": "google/nano-banana-2",
|
|
92788
|
+
"banana-pro": "google/nano-banana-pro",
|
|
92789
|
+
"nano-banana-pro": "google/nano-banana-pro",
|
|
92790
|
+
"grok-imagine": "xai/grok-imagine-image",
|
|
92791
|
+
"grok-imagine-pro": "xai/grok-imagine-image-pro",
|
|
92792
|
+
cogview: "zai/cogview-4"
|
|
92793
|
+
});
|
|
92695
92794
|
VIDEO_PRICING = {
|
|
92696
92795
|
"xai/grok-imagine-video": { pricePerSecond: 0.05, defaultDurationSeconds: 8 },
|
|
92697
92796
|
// Seedance rates re-synced 2026-08-08 from blockrun's models.ts after the
|
|
@@ -93465,8 +93564,8 @@ var init_registry = __esm({
|
|
|
93465
93564
|
name: "Image Generation",
|
|
93466
93565
|
partner: "BlockRun",
|
|
93467
93566
|
category: "Image & Video",
|
|
93468
|
-
shortDescription: "
|
|
93469
|
-
description: "Generate an image from a text prompt. Models available: google/nano-banana (default), google/nano-banana-pro (up to 4K), openai/gpt-image-1, openai/
|
|
93567
|
+
shortDescription: "9 image models (Nano Banana, GPT Image, ...)",
|
|
93568
|
+
description: "Generate an image from a text prompt. Models available: google/nano-banana (default), google/nano-banana-2, google/nano-banana-pro (up to 4K), openai/gpt-image-1, openai/gpt-image-2, bytedance/seedream-5-pro, xai/grok-imagine-image, xai/grok-imagine-image-pro, zai/cogview-4. Returns a local http://localhost:8402/images/<file>.png URL.",
|
|
93470
93569
|
proxyPath: "/images/generations",
|
|
93471
93570
|
method: "POST",
|
|
93472
93571
|
params: [
|
|
@@ -93479,7 +93578,7 @@ var init_registry = __esm({
|
|
|
93479
93578
|
{
|
|
93480
93579
|
name: "model",
|
|
93481
93580
|
type: "string",
|
|
93482
|
-
description: "Full model ID (e.g. 'google/nano-banana', 'openai/
|
|
93581
|
+
description: "Full model ID (e.g. 'google/nano-banana', 'openai/gpt-image-2'). Default: google/nano-banana.",
|
|
93483
93582
|
required: false
|
|
93484
93583
|
},
|
|
93485
93584
|
{
|
|
@@ -225847,12 +225946,23 @@ function buildImageGenerationProvider() {
|
|
|
225847
225946
|
id: "blockrun",
|
|
225848
225947
|
label: "BlockRun",
|
|
225849
225948
|
defaultModel: "google/nano-banana",
|
|
225949
|
+
// Must stay in sync with IMAGE_PRICING (proxy.ts). OpenClaw sends the
|
|
225950
|
+
// picked id straight to /v1/images/generations, which forwards the body
|
|
225951
|
+
// verbatim with no alias resolution, so a retired id here is a guaranteed
|
|
225952
|
+
// upstream 400. dall-e-3 (delisted 2026-05-25) and flux-1.1-pro (no
|
|
225953
|
+
// gateway entry) were dropped in v0.12.227 and had lingered here.
|
|
225954
|
+
// Kept as a hand-written array (not spread from IMAGE_MODEL_IDS) because
|
|
225955
|
+
// this is the picker's curated display order — default model first, which
|
|
225956
|
+
// IMAGE_PRICING declaration order does not give — and because the
|
|
225957
|
+
// lifecycle tests fully mock ./proxy.js. Set-equality is enforced by
|
|
225958
|
+
// src/index.image-provider.test.ts, which pins the two lists together.
|
|
225850
225959
|
models: [
|
|
225851
225960
|
"google/nano-banana",
|
|
225961
|
+
"google/nano-banana-2",
|
|
225852
225962
|
"google/nano-banana-pro",
|
|
225853
225963
|
"openai/gpt-image-1",
|
|
225854
|
-
"openai/
|
|
225855
|
-
"
|
|
225964
|
+
"openai/gpt-image-2",
|
|
225965
|
+
"bytedance/seedream-5-pro",
|
|
225856
225966
|
"xai/grok-imagine-image",
|
|
225857
225967
|
"xai/grok-imagine-image-pro",
|
|
225858
225968
|
"zai/cogview-4"
|
|
@@ -225867,20 +225977,28 @@ function buildImageGenerationProvider() {
|
|
|
225867
225977
|
// Only openai/gpt-image-1 supports edit server-side; OpenClaw's UI picks a
|
|
225868
225978
|
// compatible model at edit time via /v1/images/image2image.
|
|
225869
225979
|
edit: { enabled: true },
|
|
225980
|
+
// Union of every size the gateway accepts across the models above,
|
|
225981
|
+
// live-probed 2026-08-23 (the gateway validates size per-model BEFORE
|
|
225982
|
+
// payment and 400s unknown ones — 1216x832 / 1792x1024 / 1024x1792 were
|
|
225983
|
+
// accepted by no model and are gone with dall-e-3). Pinned against
|
|
225984
|
+
// IMAGE_MODEL_SIZES (proxy.ts) by src/index.image-provider.test.ts.
|
|
225870
225985
|
geometry: {
|
|
225871
225986
|
sizes: [
|
|
225872
225987
|
"512x512",
|
|
225873
225988
|
"768x768",
|
|
225874
225989
|
"768x1344",
|
|
225875
225990
|
"1024x1024",
|
|
225876
|
-
"
|
|
225991
|
+
"1024x1536",
|
|
225992
|
+
"1280x720",
|
|
225877
225993
|
"1344x768",
|
|
225878
225994
|
"1440x1440",
|
|
225879
225995
|
"1536x1024",
|
|
225880
|
-
"
|
|
225881
|
-
"
|
|
225882
|
-
"
|
|
225996
|
+
"1600x2848",
|
|
225997
|
+
"1728x2304",
|
|
225998
|
+
"2048x1024",
|
|
225883
225999
|
"2048x2048",
|
|
226000
|
+
"2304x1728",
|
|
226001
|
+
"2848x1600",
|
|
225884
226002
|
"4096x4096"
|
|
225885
226003
|
]
|
|
225886
226004
|
}
|
|
@@ -226846,6 +226964,7 @@ export {
|
|
|
226846
226964
|
SpendControl,
|
|
226847
226965
|
VISIBLE_OPENCLAW_MODELS,
|
|
226848
226966
|
blockrunProvider,
|
|
226967
|
+
buildImageGenerationProvider,
|
|
226849
226968
|
buildPartnerTools,
|
|
226850
226969
|
buildProviderModels,
|
|
226851
226970
|
calculateModelCost,
|
package/dist/router/index.js
CHANGED
|
@@ -363,6 +363,21 @@ function applyPromotions(tierConfigs, promotions, profile, now = /* @__PURE__ */
|
|
|
363
363
|
}
|
|
364
364
|
return result;
|
|
365
365
|
}
|
|
366
|
+
function applyUnavailableModels(tierConfigs, unavailableModels) {
|
|
367
|
+
if (!unavailableModels || unavailableModels.length === 0) return tierConfigs;
|
|
368
|
+
const dead = new Set(unavailableModels);
|
|
369
|
+
let result = tierConfigs;
|
|
370
|
+
for (const tier of Object.keys(tierConfigs)) {
|
|
371
|
+
const config = tierConfigs[tier];
|
|
372
|
+
const alive = [config.primary, ...config.fallback].filter((model) => !dead.has(model));
|
|
373
|
+
if (alive.length === 0 || alive[0] === config.primary && alive.length === config.fallback.length + 1) {
|
|
374
|
+
continue;
|
|
375
|
+
}
|
|
376
|
+
if (result === tierConfigs) result = { ...tierConfigs };
|
|
377
|
+
result[tier] = { primary: alive[0], fallback: alive.slice(1) };
|
|
378
|
+
}
|
|
379
|
+
return result;
|
|
380
|
+
}
|
|
366
381
|
var RulesStrategy = class {
|
|
367
382
|
name = "rules";
|
|
368
383
|
route(prompt, systemPrompt, maxOutputTokens, options) {
|
|
@@ -414,6 +429,7 @@ ${value.slice(-(scanLimit - prefixLength))}`;
|
|
|
414
429
|
profile = useAgenticTiers ? "agentic" : "auto";
|
|
415
430
|
}
|
|
416
431
|
tierConfigs = applyPromotions(tierConfigs, config.promotions, profile, options.now);
|
|
432
|
+
tierConfigs = applyUnavailableModels(tierConfigs, options.unavailableModels);
|
|
417
433
|
const agenticScoreValue = ruleResult.agenticScore;
|
|
418
434
|
if (estimatedTokens > config.overrides.maxTokensForceComplex) {
|
|
419
435
|
const decision2 = selectModel(
|
|
@@ -552,18 +568,6 @@ var DEFAULT_MODEL_CAPABILITIES = Object.freeze({
|
|
|
552
568
|
supportsTools: false,
|
|
553
569
|
supportsVision: false
|
|
554
570
|
},
|
|
555
|
-
"free/gpt-oss-120b": {
|
|
556
|
-
contextWindow: 128e3,
|
|
557
|
-
maxOutputTokens: 16384,
|
|
558
|
-
supportsTools: false,
|
|
559
|
-
supportsVision: false
|
|
560
|
-
},
|
|
561
|
-
"free/gpt-oss-20b": {
|
|
562
|
-
contextWindow: 128e3,
|
|
563
|
-
maxOutputTokens: 16384,
|
|
564
|
-
supportsTools: false,
|
|
565
|
-
supportsVision: false
|
|
566
|
-
},
|
|
567
571
|
"free/seed-oss-36b": {
|
|
568
572
|
contextWindow: 131072,
|
|
569
573
|
maxOutputTokens: 16384,
|
|
@@ -636,6 +640,18 @@ var DEFAULT_MODEL_CAPABILITIES = Object.freeze({
|
|
|
636
640
|
supportsTools: true,
|
|
637
641
|
supportsVision: true
|
|
638
642
|
},
|
|
643
|
+
"nvidia/nemotron-nano-9b-v2": {
|
|
644
|
+
contextWindow: 131072,
|
|
645
|
+
maxOutputTokens: 16384,
|
|
646
|
+
supportsTools: false,
|
|
647
|
+
supportsVision: false
|
|
648
|
+
},
|
|
649
|
+
"nvidia/step-3.7-flash": {
|
|
650
|
+
contextWindow: 131072,
|
|
651
|
+
maxOutputTokens: 16384,
|
|
652
|
+
supportsTools: false,
|
|
653
|
+
supportsVision: false
|
|
654
|
+
},
|
|
639
655
|
"openai/gpt-4.1": {
|
|
640
656
|
contextWindow: 128e3,
|
|
641
657
|
maxOutputTokens: 16384,
|
|
@@ -1732,9 +1748,12 @@ var PortfolioStrategy = class {
|
|
|
1732
1748
|
const targetTier = (features.taskType === "reasoning_mcq" || features.taskType === "reasoning_math") && (base.tier === "SIMPLE" || base.tier === "MEDIUM") ? "REASONING" : base.tier;
|
|
1733
1749
|
const tierConfig = tierConfigs[targetTier];
|
|
1734
1750
|
const configuredCandidates = tierConfig ? getFallbackChain(targetTier, tierConfigs) : [];
|
|
1751
|
+
const unavailable = new Set(options.unavailableModels ?? []);
|
|
1735
1752
|
const chain = [
|
|
1736
1753
|
.../* @__PURE__ */ new Set([...configuredCandidates, ...evidenceCandidates(features.taskType)])
|
|
1737
|
-
].filter(
|
|
1754
|
+
].filter(
|
|
1755
|
+
(model2) => typeof model2 === "string" && model2.length > 0 && !unavailable.has(model2)
|
|
1756
|
+
);
|
|
1738
1757
|
const eligible = chain.filter(
|
|
1739
1758
|
(model2) => isEligible(model2, features, maxOutputTokens, options)
|
|
1740
1759
|
);
|
|
@@ -1811,13 +1830,7 @@ var PortfolioStrategy = class {
|
|
|
1811
1830
|
...eligibleCandidates.filter(
|
|
1812
1831
|
(model2) => !scoredModels.includes(model2) && !webResearchFallbackOrder.includes(model2)
|
|
1813
1832
|
)
|
|
1814
|
-
] :
|
|
1815
|
-
...scoredModels,
|
|
1816
|
-
...eligibleCandidates.filter((model2) => !scoredModels.includes(model2))
|
|
1817
|
-
] : [
|
|
1818
|
-
...scoredModels,
|
|
1819
|
-
...eligibleCandidates.filter((model2) => !scoredModels.includes(model2))
|
|
1820
|
-
];
|
|
1833
|
+
] : [...scoredModels, ...eligibleCandidates.filter((model2) => !scoredModels.includes(model2))];
|
|
1821
1834
|
const model = ranked[0] ?? base.model;
|
|
1822
1835
|
const selectedTierConfigs = {
|
|
1823
1836
|
...tierConfigs,
|
|
@@ -2929,8 +2942,8 @@ var DEFAULT_ROUTING_CONFIG = {
|
|
|
2929
2942
|
// $0.20/$1.25, 1M context
|
|
2930
2943
|
"xai/grok-4-fast-non-reasoning",
|
|
2931
2944
|
// 1,143ms, $0.20/$0.50 — fast fallback
|
|
2932
|
-
"
|
|
2933
|
-
//
|
|
2945
|
+
"nvidia/step-3.7-flash"
|
|
2946
|
+
// FREE backstop — new NVIDIA free tier (gpt-oss-120b now 400s; probed 2026-08-21)
|
|
2934
2947
|
]
|
|
2935
2948
|
},
|
|
2936
2949
|
MEDIUM: {
|
|
@@ -3003,14 +3016,15 @@ var DEFAULT_ROUTING_CONFIG = {
|
|
|
3003
3016
|
// Eco tier configs - absolute cheapest (blockrun/eco)
|
|
3004
3017
|
ecoTiers: {
|
|
3005
3018
|
SIMPLE: {
|
|
3006
|
-
primary: "
|
|
3007
|
-
// FREE! $0.00/$0.00 —
|
|
3019
|
+
primary: "nvidia/step-3.7-flash",
|
|
3020
|
+
// FREE! $0.00/$0.00 — new NVIDIA free tier flagship
|
|
3008
3021
|
fallback: [
|
|
3009
|
-
"
|
|
3010
|
-
// FREE —
|
|
3011
|
-
//
|
|
3012
|
-
// (410
|
|
3013
|
-
//
|
|
3022
|
+
"nvidia/nemotron-nano-9b-v2",
|
|
3023
|
+
// FREE — compact + fast (~0.7s), high-volume light tasks
|
|
3024
|
+
// This head keeps rotting with NVIDIA's free hosting: deepseek-v4-flash
|
|
3025
|
+
// (410, 2026-08-12), seed-oss-36b (410, 2026-08-03), then gpt-oss-120b/20b
|
|
3026
|
+
// (400 Unknown model, probed 2026-08-21). Each retirement retargets the
|
|
3027
|
+
// two free rungs to the current free tier; the paid rungs below never move.
|
|
3014
3028
|
"google/gemini-3.1-flash-lite",
|
|
3015
3029
|
// $0.25/$1.50 — newest flash-lite
|
|
3016
3030
|
"openai/gpt-5.4-nano",
|
|
@@ -3127,8 +3141,8 @@ var DEFAULT_ROUTING_CONFIG = {
|
|
|
3127
3141
|
"openai/gpt-5.3-codex",
|
|
3128
3142
|
"deepseek/deepseek-chat",
|
|
3129
3143
|
// Cheap, reliable
|
|
3130
|
-
"
|
|
3131
|
-
// NVIDIA free ultimate backstop (was
|
|
3144
|
+
"nvidia/step-3.7-flash"
|
|
3145
|
+
// NVIDIA free ultimate backstop (was gpt-oss-120b; 400s since ~2026-08)
|
|
3132
3146
|
]
|
|
3133
3147
|
},
|
|
3134
3148
|
REASONING: {
|
|
@@ -3217,8 +3231,8 @@ var DEFAULT_ROUTING_CONFIG = {
|
|
|
3217
3231
|
// Previous flagship — 6,213ms, reliable
|
|
3218
3232
|
"deepseek/deepseek-chat",
|
|
3219
3233
|
// 1,431ms — cheap, reliable
|
|
3220
|
-
"
|
|
3221
|
-
// NVIDIA free ultimate backstop (was
|
|
3234
|
+
"nvidia/step-3.7-flash"
|
|
3235
|
+
// NVIDIA free ultimate backstop (was gpt-oss-120b; 400s since ~2026-08)
|
|
3222
3236
|
]
|
|
3223
3237
|
},
|
|
3224
3238
|
REASONING: {
|
|
@@ -3275,6 +3289,7 @@ export {
|
|
|
3275
3289
|
LIVE_MODEL_PROFILES,
|
|
3276
3290
|
PortfolioStrategy,
|
|
3277
3291
|
RulesStrategy,
|
|
3292
|
+
applyUnavailableModels,
|
|
3278
3293
|
calculateModelCost,
|
|
3279
3294
|
classifyByRules,
|
|
3280
3295
|
filterByExcludeList,
|
|
@@ -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 -->71<!-- /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 -->71<!-- /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
|
|
@@ -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 -->71<!-- /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 -->71<!-- /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
|
|