@blockrun/clawrouter 0.9.26 → 0.9.28

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
@@ -511,6 +511,7 @@ function calibrateConfidence(distance, steepness) {
511
511
  }
512
512
 
513
513
  // src/router/selector.ts
514
+ var BASELINE_MODEL_ID = "anthropic/claude-opus-4-5";
514
515
  function selectModel(tier, confidence, method, reasoning, tierConfigs, modelPricing, estimatedInputTokens, maxOutputTokens, routingProfile) {
515
516
  const tierConfig = tierConfigs[tier];
516
517
  const model = tierConfig.primary;
@@ -520,7 +521,7 @@ function selectModel(tier, confidence, method, reasoning, tierConfigs, modelPric
520
521
  const inputCost = estimatedInputTokens / 1e6 * inputPrice;
521
522
  const outputCost = maxOutputTokens / 1e6 * outputPrice;
522
523
  const costEstimate = inputCost + outputCost;
523
- const opusPricing = modelPricing.get("anthropic/claude-opus-4.5");
524
+ const opusPricing = modelPricing.get(BASELINE_MODEL_ID);
524
525
  const opusInputPrice = opusPricing?.inputPrice ?? 0;
525
526
  const opusOutputPrice = opusPricing?.outputPrice ?? 0;
526
527
  const baselineInput = estimatedInputTokens / 1e6 * opusInputPrice;
@@ -549,7 +550,7 @@ function calculateModelCost(model, modelPricing, estimatedInputTokens, maxOutput
549
550
  const inputCost = estimatedInputTokens / 1e6 * inputPrice;
550
551
  const outputCost = maxOutputTokens / 1e6 * outputPrice;
551
552
  const costEstimate = inputCost + outputCost;
552
- const opusPricing = modelPricing.get("anthropic/claude-opus-4.5");
553
+ const opusPricing = modelPricing.get(BASELINE_MODEL_ID);
553
554
  const opusInputPrice = opusPricing?.inputPrice ?? 0;
554
555
  const opusOutputPrice = opusPricing?.outputPrice ?? 0;
555
556
  const baselineInput = estimatedInputTokens / 1e6 * opusInputPrice;
@@ -1237,7 +1238,7 @@ var DEFAULT_ROUTING_CONFIG = {
1237
1238
  "openai/gpt-5.2",
1238
1239
  // Newer and cheaper input than gpt-4o
1239
1240
  "openai/gpt-4o",
1240
- "anthropic/claude-sonnet-4.6"
1241
+ "anthropic/claude-sonnet-4-6"
1241
1242
  ]
1242
1243
  },
1243
1244
  REASONING: {
@@ -1300,7 +1301,7 @@ var DEFAULT_ROUTING_CONFIG = {
1300
1301
  SIMPLE: {
1301
1302
  primary: "moonshot/kimi-k2.5",
1302
1303
  // $0.50/$2.40 - good for simple coding
1303
- fallback: ["anthropic/claude-haiku-4.5", "google/gemini-2.5-flash", "xai/grok-code-fast-1"]
1304
+ fallback: ["anthropic/claude-haiku-4-5", "google/gemini-2.5-flash", "xai/grok-code-fast-1"]
1304
1305
  },
1305
1306
  MEDIUM: {
1306
1307
  primary: "openai/gpt-5.2-codex",
@@ -1309,26 +1310,26 @@ var DEFAULT_ROUTING_CONFIG = {
1309
1310
  "moonshot/kimi-k2.5",
1310
1311
  "google/gemini-2.5-pro",
1311
1312
  "xai/grok-4-0709",
1312
- "anthropic/claude-sonnet-4.6"
1313
+ "anthropic/claude-sonnet-4-6"
1313
1314
  ]
1314
1315
  },
1315
1316
  COMPLEX: {
1316
- primary: "anthropic/claude-opus-4.6",
1317
+ primary: "anthropic/claude-opus-4-6",
1317
1318
  // Best quality for complex tasks
1318
1319
  fallback: [
1319
1320
  "openai/gpt-5.2-codex",
1320
- "anthropic/claude-opus-4.5",
1321
- "anthropic/claude-sonnet-4.6",
1321
+ "anthropic/claude-opus-4-5",
1322
+ "anthropic/claude-sonnet-4-6",
1322
1323
  "google/gemini-3-pro-preview",
1323
1324
  "moonshot/kimi-k2.5"
1324
1325
  ]
1325
1326
  },
1326
1327
  REASONING: {
1327
- primary: "anthropic/claude-sonnet-4.6",
1328
+ primary: "anthropic/claude-sonnet-4-6",
1328
1329
  // $3/$15 - best for reasoning/instructions
1329
1330
  fallback: [
1330
- "anthropic/claude-opus-4.6",
1331
- "anthropic/claude-opus-4.5",
1331
+ "anthropic/claude-opus-4-6",
1332
+ "anthropic/claude-opus-4-5",
1332
1333
  "openai/o4-mini",
1333
1334
  // Newer and cheaper than o3 ($1.10 vs $2.00)
1334
1335
  "openai/o3",
@@ -1344,7 +1345,7 @@ var DEFAULT_ROUTING_CONFIG = {
1344
1345
  fallback: [
1345
1346
  "minimax/minimax-m2.5",
1346
1347
  // $0.30/$1.20 - agentic capable, cheaper than kimi
1347
- "anthropic/claude-haiku-4.5",
1348
+ "anthropic/claude-haiku-4-5",
1348
1349
  "xai/grok-4-1-fast-non-reasoning",
1349
1350
  "openai/gpt-4o-mini"
1350
1351
  ]
@@ -1356,14 +1357,14 @@ var DEFAULT_ROUTING_CONFIG = {
1356
1357
  "minimax/minimax-m2.5",
1357
1358
  // $0.30/$1.20 - agentic capable
1358
1359
  "moonshot/kimi-k2.5",
1359
- "anthropic/claude-haiku-4.5",
1360
- "anthropic/claude-sonnet-4.6"
1360
+ "anthropic/claude-haiku-4-5",
1361
+ "anthropic/claude-sonnet-4-6"
1361
1362
  ]
1362
1363
  },
1363
1364
  COMPLEX: {
1364
- primary: "anthropic/claude-sonnet-4.6",
1365
+ primary: "anthropic/claude-sonnet-4-6",
1365
1366
  fallback: [
1366
- "anthropic/claude-opus-4.6",
1367
+ "anthropic/claude-opus-4-6",
1367
1368
  // Latest Opus - best agentic
1368
1369
  "minimax/minimax-m2.5",
1369
1370
  // $0.30/$1.20 - cheap agentic fallback
@@ -1373,10 +1374,10 @@ var DEFAULT_ROUTING_CONFIG = {
1373
1374
  ]
1374
1375
  },
1375
1376
  REASONING: {
1376
- primary: "anthropic/claude-sonnet-4.6",
1377
+ primary: "anthropic/claude-sonnet-4-6",
1377
1378
  // Strong tool use + reasoning for agentic tasks
1378
1379
  fallback: [
1379
- "anthropic/claude-opus-4.6",
1380
+ "anthropic/claude-opus-4-6",
1380
1381
  "minimax/minimax-m2.5",
1381
1382
  // $0.30/$1.20 - reasoning + agentic
1382
1383
  "xai/grok-4-1-fast-reasoning",
@@ -1465,19 +1466,23 @@ function route(prompt, systemPrompt, maxOutputTokens, options) {
1465
1466
 
1466
1467
  // src/models.ts
1467
1468
  var MODEL_ALIASES = {
1468
- // Claude - short names
1469
- claude: "anthropic/claude-sonnet-4.6",
1470
- sonnet: "anthropic/claude-sonnet-4.6",
1471
- opus: "anthropic/claude-opus-4.6",
1472
- // Updated to latest Opus 4.6
1473
- "opus-46": "anthropic/claude-opus-4.6",
1474
- "opus-45": "anthropic/claude-opus-4.5",
1475
- haiku: "anthropic/claude-haiku-4.5",
1469
+ // Claude - short names (use dashes in version, not dots - Anthropic API format)
1470
+ claude: "anthropic/claude-sonnet-4-6",
1471
+ sonnet: "anthropic/claude-sonnet-4-6",
1472
+ opus: "anthropic/claude-opus-4-6",
1473
+ "opus-46": "anthropic/claude-opus-4-6",
1474
+ "opus-45": "anthropic/claude-opus-4-5",
1475
+ haiku: "anthropic/claude-haiku-4-5",
1476
1476
  // Claude - provider/shortname patterns (common in agent frameworks)
1477
- "anthropic/sonnet": "anthropic/claude-sonnet-4.6",
1478
- "anthropic/opus": "anthropic/claude-opus-4.6",
1479
- "anthropic/haiku": "anthropic/claude-haiku-4.5",
1480
- "anthropic/claude": "anthropic/claude-sonnet-4.6",
1477
+ "anthropic/sonnet": "anthropic/claude-sonnet-4-6",
1478
+ "anthropic/opus": "anthropic/claude-opus-4-6",
1479
+ "anthropic/haiku": "anthropic/claude-haiku-4-5",
1480
+ "anthropic/claude": "anthropic/claude-sonnet-4-6",
1481
+ // Backward compatibility - old dot notation still works
1482
+ "anthropic/claude-sonnet-4.6": "anthropic/claude-sonnet-4-6",
1483
+ "anthropic/claude-opus-4.6": "anthropic/claude-opus-4-6",
1484
+ "anthropic/claude-opus-4.5": "anthropic/claude-opus-4-5",
1485
+ "anthropic/claude-haiku-4.5": "anthropic/claude-haiku-4-5",
1481
1486
  // OpenAI
1482
1487
  gpt: "openai/gpt-4o",
1483
1488
  gpt4: "openai/gpt-4o",
@@ -1666,7 +1671,7 @@ var BLOCKRUN_MODELS = [
1666
1671
  },
1667
1672
  // Anthropic - all Claude models excel at agentic workflows
1668
1673
  {
1669
- id: "anthropic/claude-haiku-4.5",
1674
+ id: "anthropic/claude-haiku-4-5",
1670
1675
  name: "Claude Haiku 4.5",
1671
1676
  inputPrice: 1,
1672
1677
  outputPrice: 5,
@@ -1675,7 +1680,7 @@ var BLOCKRUN_MODELS = [
1675
1680
  agentic: true
1676
1681
  },
1677
1682
  {
1678
- id: "anthropic/claude-sonnet-4.6",
1683
+ id: "anthropic/claude-sonnet-4-6",
1679
1684
  name: "Claude Sonnet 4.6",
1680
1685
  inputPrice: 3,
1681
1686
  outputPrice: 15,
@@ -1695,7 +1700,7 @@ var BLOCKRUN_MODELS = [
1695
1700
  agentic: true
1696
1701
  },
1697
1702
  {
1698
- id: "anthropic/claude-opus-4.5",
1703
+ id: "anthropic/claude-opus-4-5",
1699
1704
  name: "Claude Opus 4.5",
1700
1705
  inputPrice: 5,
1701
1706
  outputPrice: 25,
@@ -1705,7 +1710,7 @@ var BLOCKRUN_MODELS = [
1705
1710
  agentic: true
1706
1711
  },
1707
1712
  {
1708
- id: "anthropic/claude-opus-4.6",
1713
+ id: "anthropic/claude-opus-4-6",
1709
1714
  name: "Claude Opus 4.6",
1710
1715
  inputPrice: 5,
1711
1716
  outputPrice: 25,
@@ -3785,6 +3790,83 @@ var PROVIDER_ERROR_PATTERNS = [
3785
3790
  /request.*size.*exceeds/i,
3786
3791
  /payload too large/i
3787
3792
  ];
3793
+ var DEGRADED_RESPONSE_PATTERNS = [
3794
+ /the ai service is temporarily overloaded/i,
3795
+ /service is temporarily overloaded/i,
3796
+ /please try again in a moment/i
3797
+ ];
3798
+ var DEGRADED_LOOP_PATTERNS = [
3799
+ /the boxed is the response\./i,
3800
+ /the response is the text\./i,
3801
+ /the final answer is the boxed\./i
3802
+ ];
3803
+ function extractAssistantContent(payload) {
3804
+ if (!payload || typeof payload !== "object") return void 0;
3805
+ const record = payload;
3806
+ const choices = record.choices;
3807
+ if (!Array.isArray(choices) || choices.length === 0) return void 0;
3808
+ const firstChoice = choices[0];
3809
+ if (!firstChoice || typeof firstChoice !== "object") return void 0;
3810
+ const choice = firstChoice;
3811
+ const message = choice.message;
3812
+ if (!message || typeof message !== "object") return void 0;
3813
+ const content = message.content;
3814
+ return typeof content === "string" ? content : void 0;
3815
+ }
3816
+ function hasKnownLoopSignature(text) {
3817
+ const matchCount = DEGRADED_LOOP_PATTERNS.reduce(
3818
+ (count, pattern) => pattern.test(text) ? count + 1 : count,
3819
+ 0
3820
+ );
3821
+ if (matchCount >= 2) return true;
3822
+ const lines = text.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
3823
+ if (lines.length < 8) return false;
3824
+ const counts = /* @__PURE__ */ new Map();
3825
+ for (const line of lines) {
3826
+ counts.set(line, (counts.get(line) ?? 0) + 1);
3827
+ }
3828
+ const maxRepeat = Math.max(...counts.values());
3829
+ const uniqueRatio = counts.size / lines.length;
3830
+ return maxRepeat >= 3 && uniqueRatio <= 0.45;
3831
+ }
3832
+ function detectDegradedSuccessResponse(body) {
3833
+ const trimmed = body.trim();
3834
+ if (!trimmed) return void 0;
3835
+ if (DEGRADED_RESPONSE_PATTERNS.some((pattern) => pattern.test(trimmed))) {
3836
+ return "degraded response: overloaded placeholder";
3837
+ }
3838
+ if (hasKnownLoopSignature(trimmed)) {
3839
+ return "degraded response: repetitive loop output";
3840
+ }
3841
+ try {
3842
+ const parsed = JSON.parse(trimmed);
3843
+ const errorField = parsed.error;
3844
+ let errorText = "";
3845
+ if (typeof errorField === "string") {
3846
+ errorText = errorField;
3847
+ } else if (errorField && typeof errorField === "object") {
3848
+ const errObj = errorField;
3849
+ errorText = [
3850
+ typeof errObj.message === "string" ? errObj.message : "",
3851
+ typeof errObj.type === "string" ? errObj.type : "",
3852
+ typeof errObj.code === "string" ? errObj.code : ""
3853
+ ].filter(Boolean).join(" ");
3854
+ }
3855
+ if (errorText && PROVIDER_ERROR_PATTERNS.some((pattern) => pattern.test(errorText))) {
3856
+ return `degraded response: ${errorText.slice(0, 120)}`;
3857
+ }
3858
+ const assistantContent = extractAssistantContent(parsed);
3859
+ if (!assistantContent) return void 0;
3860
+ if (DEGRADED_RESPONSE_PATTERNS.some((pattern) => pattern.test(assistantContent))) {
3861
+ return "degraded response: overloaded assistant content";
3862
+ }
3863
+ if (hasKnownLoopSignature(assistantContent)) {
3864
+ return "degraded response: repetitive assistant loop";
3865
+ }
3866
+ } catch {
3867
+ }
3868
+ return void 0;
3869
+ }
3788
3870
  var FALLBACK_STATUS_CODES = [
3789
3871
  400,
3790
3872
  // Bad request - sometimes used for billing errors
@@ -4324,6 +4406,22 @@ async function tryModelRequest(upstreamUrl, method, headers, body, modelId, maxT
4324
4406
  isProviderError: isProviderErr
4325
4407
  };
4326
4408
  }
4409
+ const contentType = response.headers.get("content-type") || "";
4410
+ if (contentType.includes("json") || contentType.includes("text")) {
4411
+ try {
4412
+ const responseBody = await response.clone().text();
4413
+ const degradedReason = detectDegradedSuccessResponse(responseBody);
4414
+ if (degradedReason) {
4415
+ return {
4416
+ success: false,
4417
+ errorBody: degradedReason,
4418
+ errorStatus: 503,
4419
+ isProviderError: true
4420
+ };
4421
+ }
4422
+ } catch {
4423
+ }
4424
+ }
4327
4425
  return { success: true, response };
4328
4426
  } catch (err) {
4329
4427
  const errorMsg = err instanceof Error ? err.message : String(err);