@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 +132 -34
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +4 -4
- package/dist/index.js +132 -34
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/scripts/reinstall.sh +2 -2
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(
|
|
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(
|
|
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
|
|
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
|
|
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
|
|
1313
|
+
"anthropic/claude-sonnet-4-6"
|
|
1313
1314
|
]
|
|
1314
1315
|
},
|
|
1315
1316
|
COMPLEX: {
|
|
1316
|
-
primary: "anthropic/claude-opus-4
|
|
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
|
|
1321
|
-
"anthropic/claude-sonnet-4
|
|
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
|
|
1328
|
+
primary: "anthropic/claude-sonnet-4-6",
|
|
1328
1329
|
// $3/$15 - best for reasoning/instructions
|
|
1329
1330
|
fallback: [
|
|
1330
|
-
"anthropic/claude-opus-4
|
|
1331
|
-
"anthropic/claude-opus-4
|
|
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
|
|
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
|
|
1360
|
-
"anthropic/claude-sonnet-4
|
|
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
|
|
1365
|
+
primary: "anthropic/claude-sonnet-4-6",
|
|
1365
1366
|
fallback: [
|
|
1366
|
-
"anthropic/claude-opus-4
|
|
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
|
|
1377
|
+
primary: "anthropic/claude-sonnet-4-6",
|
|
1377
1378
|
// Strong tool use + reasoning for agentic tasks
|
|
1378
1379
|
fallback: [
|
|
1379
|
-
"anthropic/claude-opus-4
|
|
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
|
|
1470
|
-
sonnet: "anthropic/claude-sonnet-4
|
|
1471
|
-
opus: "anthropic/claude-opus-4
|
|
1472
|
-
|
|
1473
|
-
"opus-
|
|
1474
|
-
|
|
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
|
|
1478
|
-
"anthropic/opus": "anthropic/claude-opus-4
|
|
1479
|
-
"anthropic/haiku": "anthropic/claude-haiku-4
|
|
1480
|
-
"anthropic/claude": "anthropic/claude-sonnet-4
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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);
|