@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/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((model2) => typeof model2 === "string" && model2.length > 0);
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
- ] : features.taskType === "tool_agent" || features.taskType === "tool_agent_parallel" && features.agentDomain !== "other" ? [
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
- "free/gpt-oss-120b"
37968
- // 1,252ms, FREE fallback (hidden from /v1/models but direct calls work)
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: "free/gpt-oss-120b",
38042
- // FREE! $0.00/$0.00 — heavy user default
38054
+ primary: "nvidia/step-3.7-flash",
38055
+ // FREE! $0.00/$0.00 — new NVIDIA free tier flagship
38043
38056
  fallback: [
38044
- "free/gpt-oss-20b",
38045
- // FREE — smaller, faster
38046
- // deepseek-v4-flash and seed-oss-36b sat here until NVIDIA EOL'd them
38047
- // (410; 2026-08-12 and 2026-08-03 respectively). gpt-oss-120b/20b already
38048
- // head this chain, so the rungs are dropped, not retargeted.
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
- "free/gpt-oss-120b"
38166
- // NVIDIA free ultimate backstop (was seed-oss-36b; EOL'd 2026-08-03)
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
- "free/gpt-oss-120b"
38256
- // NVIDIA free ultimate backstop (was seed-oss-36b; EOL'd 2026-08-03)
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
- const IMAGE_MODEL_ALIASES = {
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
- const imageResult = await imageResponse.json();
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 (!imageResponse.ok || imageResult.error) {
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
- sizes: { "1024x1024": 0.045, "2048x1024": 0.045, "2048x2048": 0.09 }
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: "8 image models (DALL-E, Flux, Grok, ...)",
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/dall-e-3, black-forest/flux-1.1-pro, xai/grok-imagine-image, xai/grok-imagine-image-pro, zai/cogview-4. Returns a local http://localhost:8402/images/<file>.png URL.",
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/dall-e-3'). Default: google/nano-banana.",
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/dall-e-3",
225855
- "black-forest/flux-1.1-pro",
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
- "1216x832",
225991
+ "1024x1536",
225992
+ "1280x720",
225877
225993
  "1344x768",
225878
225994
  "1440x1440",
225879
225995
  "1536x1024",
225880
- "1024x1536",
225881
- "1792x1024",
225882
- "1024x1792",
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,
@@ -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((model2) => typeof model2 === "string" && model2.length > 0);
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
- ] : features.taskType === "tool_agent" || features.taskType === "tool_agent_parallel" && features.agentDomain !== "other" ? [
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
- "free/gpt-oss-120b"
2933
- // 1,252ms, FREE fallback (hidden from /v1/models but direct calls work)
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: "free/gpt-oss-120b",
3007
- // FREE! $0.00/$0.00 — heavy user default
3019
+ primary: "nvidia/step-3.7-flash",
3020
+ // FREE! $0.00/$0.00 — new NVIDIA free tier flagship
3008
3021
  fallback: [
3009
- "free/gpt-oss-20b",
3010
- // FREE — smaller, faster
3011
- // deepseek-v4-flash and seed-oss-36b sat here until NVIDIA EOL'd them
3012
- // (410; 2026-08-12 and 2026-08-03 respectively). gpt-oss-120b/20b already
3013
- // head this chain, so the rungs are dropped, not retargeted.
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
- "free/gpt-oss-120b"
3131
- // NVIDIA free ultimate backstop (was seed-oss-36b; EOL'd 2026-08-03)
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
- "free/gpt-oss-120b"
3221
- // NVIDIA free ultimate backstop (was seed-oss-36b; EOL'd 2026-08-03)
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 -->70<!-- /br:models.chatVisible --> AI models. It saves you money in three ways: **smart routing**, **token optimization**, and **response caching**.
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 -->70<!-- /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.
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 -->70<!-- /br:models.chatVisible --> models, switch anytime
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 -->70<!-- /br:models.chatVisible --> models, balance hits zero and the valve shuts cleanly" width="720"></p>
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