@blockrun/clawrouter 0.12.39 → 0.12.41

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/cli.js CHANGED
@@ -525,6 +525,99 @@ function getFallbackChainFiltered(tier, tierConfigs, estimatedTotalTokens, getCo
525
525
  return filtered;
526
526
  }
527
527
 
528
+ // src/router/strategy.ts
529
+ var RulesStrategy = class {
530
+ name = "rules";
531
+ route(prompt, systemPrompt, maxOutputTokens, options) {
532
+ const { config, modelPricing } = options;
533
+ const fullText = `${systemPrompt ?? ""} ${prompt}`;
534
+ const estimatedTokens = Math.ceil(fullText.length / 4);
535
+ const ruleResult = classifyByRules(prompt, systemPrompt, estimatedTokens, config.scoring);
536
+ const { routingProfile } = options;
537
+ let tierConfigs;
538
+ let profileSuffix;
539
+ let profile;
540
+ if (routingProfile === "eco" && config.ecoTiers) {
541
+ tierConfigs = config.ecoTiers;
542
+ profileSuffix = " | eco";
543
+ profile = "eco";
544
+ } else if (routingProfile === "premium" && config.premiumTiers) {
545
+ tierConfigs = config.premiumTiers;
546
+ profileSuffix = " | premium";
547
+ profile = "premium";
548
+ } else {
549
+ const agenticScore = ruleResult.agenticScore ?? 0;
550
+ const isAutoAgentic = agenticScore >= 0.5;
551
+ const isExplicitAgentic = config.overrides.agenticMode ?? false;
552
+ const hasToolsInRequest = options.hasTools ?? false;
553
+ const useAgenticTiers = (hasToolsInRequest || isAutoAgentic || isExplicitAgentic) && config.agenticTiers != null;
554
+ tierConfigs = useAgenticTiers ? config.agenticTiers : config.tiers;
555
+ profileSuffix = useAgenticTiers ? ` | agentic${hasToolsInRequest ? " (tools)" : ""}` : "";
556
+ profile = useAgenticTiers ? "agentic" : "auto";
557
+ }
558
+ const agenticScoreValue = ruleResult.agenticScore;
559
+ if (estimatedTokens > config.overrides.maxTokensForceComplex) {
560
+ const decision2 = selectModel(
561
+ "COMPLEX",
562
+ 0.95,
563
+ "rules",
564
+ `Input exceeds ${config.overrides.maxTokensForceComplex} tokens${profileSuffix}`,
565
+ tierConfigs,
566
+ modelPricing,
567
+ estimatedTokens,
568
+ maxOutputTokens,
569
+ routingProfile,
570
+ agenticScoreValue
571
+ );
572
+ return { ...decision2, tierConfigs, profile };
573
+ }
574
+ const hasStructuredOutput = systemPrompt ? /json|structured|schema/i.test(systemPrompt) : false;
575
+ let tier;
576
+ let confidence;
577
+ const method = "rules";
578
+ let reasoning = `score=${ruleResult.score.toFixed(2)} | ${ruleResult.signals.join(", ")}`;
579
+ if (ruleResult.tier !== null) {
580
+ tier = ruleResult.tier;
581
+ confidence = ruleResult.confidence;
582
+ } else {
583
+ tier = config.overrides.ambiguousDefaultTier;
584
+ confidence = 0.5;
585
+ reasoning += ` | ambiguous -> default: ${tier}`;
586
+ }
587
+ if (hasStructuredOutput) {
588
+ const tierRank = { SIMPLE: 0, MEDIUM: 1, COMPLEX: 2, REASONING: 3 };
589
+ const minTier = config.overrides.structuredOutputMinTier;
590
+ if (tierRank[tier] < tierRank[minTier]) {
591
+ reasoning += ` | upgraded to ${minTier} (structured output)`;
592
+ tier = minTier;
593
+ }
594
+ }
595
+ reasoning += profileSuffix;
596
+ const decision = selectModel(
597
+ tier,
598
+ confidence,
599
+ method,
600
+ reasoning,
601
+ tierConfigs,
602
+ modelPricing,
603
+ estimatedTokens,
604
+ maxOutputTokens,
605
+ routingProfile,
606
+ agenticScoreValue
607
+ );
608
+ return { ...decision, tierConfigs, profile };
609
+ }
610
+ };
611
+ var registry = /* @__PURE__ */ new Map();
612
+ registry.set("rules", new RulesStrategy());
613
+ function getStrategy(name) {
614
+ const strategy = registry.get(name);
615
+ if (!strategy) {
616
+ throw new Error(`Unknown routing strategy: ${name}`);
617
+ }
618
+ return strategy;
619
+ }
620
+
528
621
  // src/router/config.ts
529
622
  var DEFAULT_ROUTING_CONFIG = {
530
623
  version: "2.0",
@@ -1617,7 +1710,11 @@ var DEFAULT_ROUTING_CONFIG = {
1617
1710
  SIMPLE: {
1618
1711
  primary: "nvidia/gpt-oss-120b",
1619
1712
  // FREE! $0.00/$0.00
1620
- fallback: ["google/gemini-2.5-flash-lite", "google/gemini-2.5-flash", "deepseek/deepseek-chat"]
1713
+ fallback: [
1714
+ "google/gemini-2.5-flash-lite",
1715
+ "google/gemini-2.5-flash",
1716
+ "deepseek/deepseek-chat"
1717
+ ]
1621
1718
  },
1622
1719
  MEDIUM: {
1623
1720
  primary: "google/gemini-2.5-flash-lite",
@@ -1650,8 +1747,8 @@ var DEFAULT_ROUTING_CONFIG = {
1650
1747
  ]
1651
1748
  },
1652
1749
  MEDIUM: {
1653
- primary: "openai/gpt-5.2-codex",
1654
- // $2.50/$10 - strong coding for medium tasks
1750
+ primary: "openai/gpt-5.3-codex",
1751
+ // $1.75/$14 - 400K context, 128K output, replaces 5.2
1655
1752
  fallback: [
1656
1753
  "moonshot/kimi-k2.5",
1657
1754
  "google/gemini-2.5-flash",
@@ -1667,7 +1764,7 @@ var DEFAULT_ROUTING_CONFIG = {
1667
1764
  fallback: [
1668
1765
  "openai/gpt-5.4",
1669
1766
  // Newest flagship
1670
- "openai/gpt-5.2-codex",
1767
+ "openai/gpt-5.3-codex",
1671
1768
  "anthropic/claude-opus-4.6",
1672
1769
  "anthropic/claude-sonnet-4.6",
1673
1770
  "google/gemini-3.1-pro",
@@ -1742,77 +1839,8 @@ var DEFAULT_ROUTING_CONFIG = {
1742
1839
 
1743
1840
  // src/router/index.ts
1744
1841
  function route(prompt, systemPrompt, maxOutputTokens, options) {
1745
- const { config, modelPricing } = options;
1746
- const fullText = `${systemPrompt ?? ""} ${prompt}`;
1747
- const estimatedTokens = Math.ceil(fullText.length / 4);
1748
- const ruleResult = classifyByRules(prompt, systemPrompt, estimatedTokens, config.scoring);
1749
- const { routingProfile } = options;
1750
- let tierConfigs;
1751
- let profileSuffix;
1752
- if (routingProfile === "eco" && config.ecoTiers) {
1753
- tierConfigs = config.ecoTiers;
1754
- profileSuffix = " | eco";
1755
- } else if (routingProfile === "premium" && config.premiumTiers) {
1756
- tierConfigs = config.premiumTiers;
1757
- profileSuffix = " | premium";
1758
- } else {
1759
- const agenticScore = ruleResult.agenticScore ?? 0;
1760
- const isAutoAgentic = agenticScore >= 0.5;
1761
- const isExplicitAgentic = config.overrides.agenticMode ?? false;
1762
- const hasToolsInRequest = options.hasTools ?? false;
1763
- const useAgenticTiers = (hasToolsInRequest || isAutoAgentic || isExplicitAgentic) && config.agenticTiers != null;
1764
- tierConfigs = useAgenticTiers ? config.agenticTiers : config.tiers;
1765
- profileSuffix = useAgenticTiers ? ` | agentic${hasToolsInRequest ? " (tools)" : ""}` : "";
1766
- }
1767
- const agenticScoreValue = ruleResult.agenticScore;
1768
- if (estimatedTokens > config.overrides.maxTokensForceComplex) {
1769
- return selectModel(
1770
- "COMPLEX",
1771
- 0.95,
1772
- "rules",
1773
- `Input exceeds ${config.overrides.maxTokensForceComplex} tokens${profileSuffix}`,
1774
- tierConfigs,
1775
- modelPricing,
1776
- estimatedTokens,
1777
- maxOutputTokens,
1778
- routingProfile,
1779
- agenticScoreValue
1780
- );
1781
- }
1782
- const hasStructuredOutput = systemPrompt ? /json|structured|schema/i.test(systemPrompt) : false;
1783
- let tier;
1784
- let confidence;
1785
- const method = "rules";
1786
- let reasoning = `score=${ruleResult.score.toFixed(2)} | ${ruleResult.signals.join(", ")}`;
1787
- if (ruleResult.tier !== null) {
1788
- tier = ruleResult.tier;
1789
- confidence = ruleResult.confidence;
1790
- } else {
1791
- tier = config.overrides.ambiguousDefaultTier;
1792
- confidence = 0.5;
1793
- reasoning += ` | ambiguous -> default: ${tier}`;
1794
- }
1795
- if (hasStructuredOutput) {
1796
- const tierRank = { SIMPLE: 0, MEDIUM: 1, COMPLEX: 2, REASONING: 3 };
1797
- const minTier = config.overrides.structuredOutputMinTier;
1798
- if (tierRank[tier] < tierRank[minTier]) {
1799
- reasoning += ` | upgraded to ${minTier} (structured output)`;
1800
- tier = minTier;
1801
- }
1802
- }
1803
- reasoning += profileSuffix;
1804
- return selectModel(
1805
- tier,
1806
- confidence,
1807
- method,
1808
- reasoning,
1809
- tierConfigs,
1810
- modelPricing,
1811
- estimatedTokens,
1812
- maxOutputTokens,
1813
- routingProfile,
1814
- agenticScoreValue
1815
- );
1842
+ const strategy = getStrategy("rules");
1843
+ return strategy.route(prompt, systemPrompt, maxOutputTokens, options);
1816
1844
  }
1817
1845
 
1818
1846
  // src/models.ts
@@ -1847,7 +1875,7 @@ var MODEL_ALIASES = {
1847
1875
  gpt5: "openai/gpt-5.4",
1848
1876
  "gpt-5.4": "openai/gpt-5.4",
1849
1877
  "gpt-5.4-pro": "openai/gpt-5.4-pro",
1850
- codex: "openai/gpt-5.2-codex",
1878
+ codex: "openai/gpt-5.3-codex",
1851
1879
  mini: "openai/gpt-4o-mini",
1852
1880
  o1: "openai/o1",
1853
1881
  o3: "openai/o3",
@@ -2003,15 +2031,29 @@ var BLOCKRUN_MODELS = [
2003
2031
  reasoning: true,
2004
2032
  toolCalling: true
2005
2033
  },
2006
- // OpenAI Codex Family
2034
+ // OpenAI GPT-5.3 Family
2007
2035
  {
2008
- id: "openai/gpt-5.2-codex",
2009
- name: "GPT-5.2 Codex",
2010
- version: "5.2",
2036
+ id: "openai/gpt-5.3",
2037
+ name: "GPT-5.3",
2038
+ version: "5.3",
2011
2039
  inputPrice: 1.75,
2012
2040
  outputPrice: 14,
2013
2041
  contextWindow: 128e3,
2014
- maxOutput: 32e3,
2042
+ maxOutput: 16e3,
2043
+ reasoning: true,
2044
+ vision: true,
2045
+ agentic: true,
2046
+ toolCalling: true
2047
+ },
2048
+ // OpenAI Codex Family
2049
+ {
2050
+ id: "openai/gpt-5.3-codex",
2051
+ name: "GPT-5.3 Codex",
2052
+ version: "5.3",
2053
+ inputPrice: 1.75,
2054
+ outputPrice: 14,
2055
+ contextWindow: 4e5,
2056
+ maxOutput: 128e3,
2015
2057
  agentic: true,
2016
2058
  toolCalling: true
2017
2059
  },
@@ -5026,6 +5068,12 @@ var ROUTING_PROFILES = /* @__PURE__ */ new Set([
5026
5068
  "premium"
5027
5069
  ]);
5028
5070
  var FREE_MODEL = "nvidia/gpt-oss-120b";
5071
+ var FREE_TIER_CONFIGS = {
5072
+ SIMPLE: { primary: FREE_MODEL, fallback: [] },
5073
+ MEDIUM: { primary: FREE_MODEL, fallback: [] },
5074
+ COMPLEX: { primary: FREE_MODEL, fallback: [] },
5075
+ REASONING: { primary: FREE_MODEL, fallback: [] }
5076
+ };
5029
5077
  var freeRequestCount = 0;
5030
5078
  var MAX_MESSAGES = 200;
5031
5079
  var CONTEXT_LIMIT_KB = 5120;
@@ -6900,7 +6948,17 @@ async function proxyRequest(req, res, apiBase, payFetch, options, routerOpts, de
6900
6948
 
6901
6949
  `;
6902
6950
  }
6903
- routingDecision = { model: freeModel, tier: "SIMPLE", confidence: 1, method: "rules", reasoning: "free profile" };
6951
+ routingDecision = {
6952
+ model: freeModel,
6953
+ tier: "SIMPLE",
6954
+ confidence: 1,
6955
+ method: "rules",
6956
+ reasoning: "free profile",
6957
+ costEstimate: 0,
6958
+ baselineCost: 0,
6959
+ savings: 1,
6960
+ tierConfigs: FREE_TIER_CONFIGS
6961
+ };
6904
6962
  } else {
6905
6963
  effectiveSessionId = getSessionId(req.headers) ?? deriveSessionId(parsedMessages);
6906
6964
  const existingSession = effectiveSessionId ? sessionStore.getSession(effectiveSessionId) : void 0;
@@ -6991,18 +7049,7 @@ async function proxyRequest(req, res, apiBase, payFetch, options, routerOpts, de
6991
7049
  const contentHash = hashRequestContent(prompt, toolCallNames);
6992
7050
  const shouldEscalate = sessionStore.recordRequestHash(effectiveSessionId, contentHash);
6993
7051
  if (shouldEscalate) {
6994
- const activeTierConfigs = (() => {
6995
- if (routingDecision.reasoning?.includes("agentic") && routerOpts.config.agenticTiers) {
6996
- return routerOpts.config.agenticTiers;
6997
- }
6998
- if (routingProfile === "eco" && routerOpts.config.ecoTiers) {
6999
- return routerOpts.config.ecoTiers;
7000
- }
7001
- if (routingProfile === "premium" && routerOpts.config.premiumTiers) {
7002
- return routerOpts.config.premiumTiers;
7003
- }
7004
- return routerOpts.config.tiers;
7005
- })();
7052
+ const activeTierConfigs = routingDecision.tierConfigs ?? routerOpts.config.tiers;
7006
7053
  const escalation = sessionStore.escalateSession(
7007
7054
  effectiveSessionId,
7008
7055
  activeTierConfigs
@@ -7218,18 +7265,7 @@ async function proxyRequest(req, res, apiBase, payFetch, options, routerOpts, de
7218
7265
  if (routingDecision) {
7219
7266
  const estimatedInputTokens = Math.ceil(body.length / 4);
7220
7267
  const estimatedTotalTokens = estimatedInputTokens + maxTokens;
7221
- const tierConfigs = (() => {
7222
- if (routingDecision.reasoning?.includes("agentic") && routerOpts.config.agenticTiers) {
7223
- return routerOpts.config.agenticTiers;
7224
- }
7225
- if (routingProfile === "eco" && routerOpts.config.ecoTiers) {
7226
- return routerOpts.config.ecoTiers;
7227
- }
7228
- if (routingProfile === "premium" && routerOpts.config.premiumTiers) {
7229
- return routerOpts.config.premiumTiers;
7230
- }
7231
- return routerOpts.config.tiers;
7232
- })();
7268
+ const tierConfigs = routingDecision.tierConfigs ?? routerOpts.config.tiers;
7233
7269
  const fullChain = getFallbackChain(routingDecision.tier, tierConfigs);
7234
7270
  const contextFiltered = getFallbackChainFiltered(
7235
7271
  routingDecision.tier,
@@ -7309,6 +7345,14 @@ async function proxyRequest(req, res, apiBase, payFetch, options, routerOpts, de
7309
7345
  status: result.errorStatus || 500
7310
7346
  };
7311
7347
  if (result.isProviderError && !isLastAttempt) {
7348
+ const isExplicitModelError = !routingDecision;
7349
+ const isUnknownExplicitModel = isExplicitModelError && /unknown.*model|invalid.*model/i.test(result.errorBody || "");
7350
+ if (isUnknownExplicitModel) {
7351
+ console.log(
7352
+ `[ClawRouter] Explicit model error from ${tryModel}, not falling back: ${result.errorBody?.slice(0, 100)}`
7353
+ );
7354
+ break;
7355
+ }
7312
7356
  if (result.errorStatus === 429) {
7313
7357
  markRateLimited(tryModel);
7314
7358
  try {
@@ -8084,8 +8128,8 @@ Commands:
8084
8128
  partners List available partner APIs with pricing
8085
8129
  partners test Test partner API endpoints (expect 402 = alive)
8086
8130
  wallet recover Restore wallet.key from mnemonic (if generated by ClawRouter)
8087
- chain solana Switch payment chain to Solana (persists across restarts)
8088
- chain base Switch payment chain to Base EVM (persists across restarts)
8131
+ chain solana Switch to Solana (persists). Aliases: /wallet solana, wallet solana
8132
+ chain base Switch to Base EVM (persists). Aliases: /wallet base, wallet base
8089
8133
 
8090
8134
  Examples:
8091
8135
  # Start standalone proxy
@@ -8155,7 +8199,7 @@ function parseArgs(args) {
8155
8199
  } else if (arg === "wallet" && args[i + 1] === "recover") {
8156
8200
  result.walletRecover = true;
8157
8201
  i++;
8158
- } else if (arg === "chain" && (args[i + 1] === "solana" || args[i + 1] === "base")) {
8202
+ } else if ((arg === "chain" || arg === "/wallet" || arg === "wallet") && (args[i + 1] === "solana" || args[i + 1] === "base")) {
8159
8203
  result.chain = args[i + 1];
8160
8204
  i++;
8161
8205
  } else if (arg === "--port" && args[i + 1]) {