@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/index.d.ts
CHANGED
|
@@ -667,16 +667,16 @@ declare const blockrunProvider: ProviderPlugin;
|
|
|
667
667
|
|
|
668
668
|
/**
|
|
669
669
|
* Model aliases for convenient shorthand access.
|
|
670
|
-
* Users can type `/model claude` instead of `/model blockrun/anthropic/claude-sonnet-4
|
|
670
|
+
* Users can type `/model claude` instead of `/model blockrun/anthropic/claude-sonnet-4-6`.
|
|
671
671
|
*/
|
|
672
672
|
declare const MODEL_ALIASES: Record<string, string>;
|
|
673
673
|
/**
|
|
674
674
|
* Resolve a model alias to its full model ID.
|
|
675
675
|
* Also strips "blockrun/" prefix for direct model paths.
|
|
676
676
|
* Examples:
|
|
677
|
-
* - "claude" -> "anthropic/claude-sonnet-4
|
|
678
|
-
* - "blockrun/claude" -> "anthropic/claude-sonnet-4
|
|
679
|
-
* - "blockrun/anthropic/claude-sonnet-4
|
|
677
|
+
* - "claude" -> "anthropic/claude-sonnet-4-6" (alias)
|
|
678
|
+
* - "blockrun/claude" -> "anthropic/claude-sonnet-4-6" (alias with prefix)
|
|
679
|
+
* - "blockrun/anthropic/claude-sonnet-4-6" -> "anthropic/claude-sonnet-4-6" (prefix stripped)
|
|
680
680
|
* - "openai/gpt-4o" -> "openai/gpt-4o" (unchanged)
|
|
681
681
|
*/
|
|
682
682
|
declare function resolveModelAlias(model: string): string;
|
package/dist/index.js
CHANGED
|
@@ -1,18 +1,22 @@
|
|
|
1
1
|
// src/models.ts
|
|
2
2
|
var MODEL_ALIASES = {
|
|
3
|
-
// Claude - short names
|
|
4
|
-
claude: "anthropic/claude-sonnet-4
|
|
5
|
-
sonnet: "anthropic/claude-sonnet-4
|
|
6
|
-
opus: "anthropic/claude-opus-4
|
|
7
|
-
|
|
8
|
-
"opus-
|
|
9
|
-
|
|
10
|
-
haiku: "anthropic/claude-haiku-4.5",
|
|
3
|
+
// Claude - short names (use dashes in version, not dots - Anthropic API format)
|
|
4
|
+
claude: "anthropic/claude-sonnet-4-6",
|
|
5
|
+
sonnet: "anthropic/claude-sonnet-4-6",
|
|
6
|
+
opus: "anthropic/claude-opus-4-6",
|
|
7
|
+
"opus-46": "anthropic/claude-opus-4-6",
|
|
8
|
+
"opus-45": "anthropic/claude-opus-4-5",
|
|
9
|
+
haiku: "anthropic/claude-haiku-4-5",
|
|
11
10
|
// Claude - provider/shortname patterns (common in agent frameworks)
|
|
12
|
-
"anthropic/sonnet": "anthropic/claude-sonnet-4
|
|
13
|
-
"anthropic/opus": "anthropic/claude-opus-4
|
|
14
|
-
"anthropic/haiku": "anthropic/claude-haiku-4
|
|
15
|
-
"anthropic/claude": "anthropic/claude-sonnet-4
|
|
11
|
+
"anthropic/sonnet": "anthropic/claude-sonnet-4-6",
|
|
12
|
+
"anthropic/opus": "anthropic/claude-opus-4-6",
|
|
13
|
+
"anthropic/haiku": "anthropic/claude-haiku-4-5",
|
|
14
|
+
"anthropic/claude": "anthropic/claude-sonnet-4-6",
|
|
15
|
+
// Backward compatibility - old dot notation still works
|
|
16
|
+
"anthropic/claude-sonnet-4.6": "anthropic/claude-sonnet-4-6",
|
|
17
|
+
"anthropic/claude-opus-4.6": "anthropic/claude-opus-4-6",
|
|
18
|
+
"anthropic/claude-opus-4.5": "anthropic/claude-opus-4-5",
|
|
19
|
+
"anthropic/claude-haiku-4.5": "anthropic/claude-haiku-4-5",
|
|
16
20
|
// OpenAI
|
|
17
21
|
gpt: "openai/gpt-4o",
|
|
18
22
|
gpt4: "openai/gpt-4o",
|
|
@@ -201,7 +205,7 @@ var BLOCKRUN_MODELS = [
|
|
|
201
205
|
},
|
|
202
206
|
// Anthropic - all Claude models excel at agentic workflows
|
|
203
207
|
{
|
|
204
|
-
id: "anthropic/claude-haiku-4
|
|
208
|
+
id: "anthropic/claude-haiku-4-5",
|
|
205
209
|
name: "Claude Haiku 4.5",
|
|
206
210
|
inputPrice: 1,
|
|
207
211
|
outputPrice: 5,
|
|
@@ -210,7 +214,7 @@ var BLOCKRUN_MODELS = [
|
|
|
210
214
|
agentic: true
|
|
211
215
|
},
|
|
212
216
|
{
|
|
213
|
-
id: "anthropic/claude-sonnet-4
|
|
217
|
+
id: "anthropic/claude-sonnet-4-6",
|
|
214
218
|
name: "Claude Sonnet 4.6",
|
|
215
219
|
inputPrice: 3,
|
|
216
220
|
outputPrice: 15,
|
|
@@ -230,7 +234,7 @@ var BLOCKRUN_MODELS = [
|
|
|
230
234
|
agentic: true
|
|
231
235
|
},
|
|
232
236
|
{
|
|
233
|
-
id: "anthropic/claude-opus-4
|
|
237
|
+
id: "anthropic/claude-opus-4-5",
|
|
234
238
|
name: "Claude Opus 4.5",
|
|
235
239
|
inputPrice: 5,
|
|
236
240
|
outputPrice: 25,
|
|
@@ -240,7 +244,7 @@ var BLOCKRUN_MODELS = [
|
|
|
240
244
|
agentic: true
|
|
241
245
|
},
|
|
242
246
|
{
|
|
243
|
-
id: "anthropic/claude-opus-4
|
|
247
|
+
id: "anthropic/claude-opus-4-6",
|
|
244
248
|
name: "Claude Opus 4.6",
|
|
245
249
|
inputPrice: 5,
|
|
246
250
|
outputPrice: 25,
|
|
@@ -1000,6 +1004,7 @@ function calibrateConfidence(distance, steepness) {
|
|
|
1000
1004
|
}
|
|
1001
1005
|
|
|
1002
1006
|
// src/router/selector.ts
|
|
1007
|
+
var BASELINE_MODEL_ID = "anthropic/claude-opus-4-5";
|
|
1003
1008
|
function selectModel(tier, confidence, method, reasoning, tierConfigs, modelPricing, estimatedInputTokens, maxOutputTokens, routingProfile) {
|
|
1004
1009
|
const tierConfig = tierConfigs[tier];
|
|
1005
1010
|
const model = tierConfig.primary;
|
|
@@ -1009,7 +1014,7 @@ function selectModel(tier, confidence, method, reasoning, tierConfigs, modelPric
|
|
|
1009
1014
|
const inputCost = estimatedInputTokens / 1e6 * inputPrice;
|
|
1010
1015
|
const outputCost = maxOutputTokens / 1e6 * outputPrice;
|
|
1011
1016
|
const costEstimate = inputCost + outputCost;
|
|
1012
|
-
const opusPricing = modelPricing.get(
|
|
1017
|
+
const opusPricing = modelPricing.get(BASELINE_MODEL_ID);
|
|
1013
1018
|
const opusInputPrice = opusPricing?.inputPrice ?? 0;
|
|
1014
1019
|
const opusOutputPrice = opusPricing?.outputPrice ?? 0;
|
|
1015
1020
|
const baselineInput = estimatedInputTokens / 1e6 * opusInputPrice;
|
|
@@ -1038,7 +1043,7 @@ function calculateModelCost(model, modelPricing, estimatedInputTokens, maxOutput
|
|
|
1038
1043
|
const inputCost = estimatedInputTokens / 1e6 * inputPrice;
|
|
1039
1044
|
const outputCost = maxOutputTokens / 1e6 * outputPrice;
|
|
1040
1045
|
const costEstimate = inputCost + outputCost;
|
|
1041
|
-
const opusPricing = modelPricing.get(
|
|
1046
|
+
const opusPricing = modelPricing.get(BASELINE_MODEL_ID);
|
|
1042
1047
|
const opusInputPrice = opusPricing?.inputPrice ?? 0;
|
|
1043
1048
|
const opusOutputPrice = opusPricing?.outputPrice ?? 0;
|
|
1044
1049
|
const baselineInput = estimatedInputTokens / 1e6 * opusInputPrice;
|
|
@@ -1726,7 +1731,7 @@ var DEFAULT_ROUTING_CONFIG = {
|
|
|
1726
1731
|
"openai/gpt-5.2",
|
|
1727
1732
|
// Newer and cheaper input than gpt-4o
|
|
1728
1733
|
"openai/gpt-4o",
|
|
1729
|
-
"anthropic/claude-sonnet-4
|
|
1734
|
+
"anthropic/claude-sonnet-4-6"
|
|
1730
1735
|
]
|
|
1731
1736
|
},
|
|
1732
1737
|
REASONING: {
|
|
@@ -1789,7 +1794,7 @@ var DEFAULT_ROUTING_CONFIG = {
|
|
|
1789
1794
|
SIMPLE: {
|
|
1790
1795
|
primary: "moonshot/kimi-k2.5",
|
|
1791
1796
|
// $0.50/$2.40 - good for simple coding
|
|
1792
|
-
fallback: ["anthropic/claude-haiku-4
|
|
1797
|
+
fallback: ["anthropic/claude-haiku-4-5", "google/gemini-2.5-flash", "xai/grok-code-fast-1"]
|
|
1793
1798
|
},
|
|
1794
1799
|
MEDIUM: {
|
|
1795
1800
|
primary: "openai/gpt-5.2-codex",
|
|
@@ -1798,26 +1803,26 @@ var DEFAULT_ROUTING_CONFIG = {
|
|
|
1798
1803
|
"moonshot/kimi-k2.5",
|
|
1799
1804
|
"google/gemini-2.5-pro",
|
|
1800
1805
|
"xai/grok-4-0709",
|
|
1801
|
-
"anthropic/claude-sonnet-4
|
|
1806
|
+
"anthropic/claude-sonnet-4-6"
|
|
1802
1807
|
]
|
|
1803
1808
|
},
|
|
1804
1809
|
COMPLEX: {
|
|
1805
|
-
primary: "anthropic/claude-opus-4
|
|
1810
|
+
primary: "anthropic/claude-opus-4-6",
|
|
1806
1811
|
// Best quality for complex tasks
|
|
1807
1812
|
fallback: [
|
|
1808
1813
|
"openai/gpt-5.2-codex",
|
|
1809
|
-
"anthropic/claude-opus-4
|
|
1810
|
-
"anthropic/claude-sonnet-4
|
|
1814
|
+
"anthropic/claude-opus-4-5",
|
|
1815
|
+
"anthropic/claude-sonnet-4-6",
|
|
1811
1816
|
"google/gemini-3-pro-preview",
|
|
1812
1817
|
"moonshot/kimi-k2.5"
|
|
1813
1818
|
]
|
|
1814
1819
|
},
|
|
1815
1820
|
REASONING: {
|
|
1816
|
-
primary: "anthropic/claude-sonnet-4
|
|
1821
|
+
primary: "anthropic/claude-sonnet-4-6",
|
|
1817
1822
|
// $3/$15 - best for reasoning/instructions
|
|
1818
1823
|
fallback: [
|
|
1819
|
-
"anthropic/claude-opus-4
|
|
1820
|
-
"anthropic/claude-opus-4
|
|
1824
|
+
"anthropic/claude-opus-4-6",
|
|
1825
|
+
"anthropic/claude-opus-4-5",
|
|
1821
1826
|
"openai/o4-mini",
|
|
1822
1827
|
// Newer and cheaper than o3 ($1.10 vs $2.00)
|
|
1823
1828
|
"openai/o3",
|
|
@@ -1833,7 +1838,7 @@ var DEFAULT_ROUTING_CONFIG = {
|
|
|
1833
1838
|
fallback: [
|
|
1834
1839
|
"minimax/minimax-m2.5",
|
|
1835
1840
|
// $0.30/$1.20 - agentic capable, cheaper than kimi
|
|
1836
|
-
"anthropic/claude-haiku-4
|
|
1841
|
+
"anthropic/claude-haiku-4-5",
|
|
1837
1842
|
"xai/grok-4-1-fast-non-reasoning",
|
|
1838
1843
|
"openai/gpt-4o-mini"
|
|
1839
1844
|
]
|
|
@@ -1845,14 +1850,14 @@ var DEFAULT_ROUTING_CONFIG = {
|
|
|
1845
1850
|
"minimax/minimax-m2.5",
|
|
1846
1851
|
// $0.30/$1.20 - agentic capable
|
|
1847
1852
|
"moonshot/kimi-k2.5",
|
|
1848
|
-
"anthropic/claude-haiku-4
|
|
1849
|
-
"anthropic/claude-sonnet-4
|
|
1853
|
+
"anthropic/claude-haiku-4-5",
|
|
1854
|
+
"anthropic/claude-sonnet-4-6"
|
|
1850
1855
|
]
|
|
1851
1856
|
},
|
|
1852
1857
|
COMPLEX: {
|
|
1853
|
-
primary: "anthropic/claude-sonnet-4
|
|
1858
|
+
primary: "anthropic/claude-sonnet-4-6",
|
|
1854
1859
|
fallback: [
|
|
1855
|
-
"anthropic/claude-opus-4
|
|
1860
|
+
"anthropic/claude-opus-4-6",
|
|
1856
1861
|
// Latest Opus - best agentic
|
|
1857
1862
|
"minimax/minimax-m2.5",
|
|
1858
1863
|
// $0.30/$1.20 - cheap agentic fallback
|
|
@@ -1862,10 +1867,10 @@ var DEFAULT_ROUTING_CONFIG = {
|
|
|
1862
1867
|
]
|
|
1863
1868
|
},
|
|
1864
1869
|
REASONING: {
|
|
1865
|
-
primary: "anthropic/claude-sonnet-4
|
|
1870
|
+
primary: "anthropic/claude-sonnet-4-6",
|
|
1866
1871
|
// Strong tool use + reasoning for agentic tasks
|
|
1867
1872
|
fallback: [
|
|
1868
|
-
"anthropic/claude-opus-4
|
|
1873
|
+
"anthropic/claude-opus-4-6",
|
|
1869
1874
|
"minimax/minimax-m2.5",
|
|
1870
1875
|
// $0.30/$1.20 - reasoning + agentic
|
|
1871
1876
|
"xai/grok-4-1-fast-reasoning",
|
|
@@ -3925,6 +3930,83 @@ var PROVIDER_ERROR_PATTERNS = [
|
|
|
3925
3930
|
/request.*size.*exceeds/i,
|
|
3926
3931
|
/payload too large/i
|
|
3927
3932
|
];
|
|
3933
|
+
var DEGRADED_RESPONSE_PATTERNS = [
|
|
3934
|
+
/the ai service is temporarily overloaded/i,
|
|
3935
|
+
/service is temporarily overloaded/i,
|
|
3936
|
+
/please try again in a moment/i
|
|
3937
|
+
];
|
|
3938
|
+
var DEGRADED_LOOP_PATTERNS = [
|
|
3939
|
+
/the boxed is the response\./i,
|
|
3940
|
+
/the response is the text\./i,
|
|
3941
|
+
/the final answer is the boxed\./i
|
|
3942
|
+
];
|
|
3943
|
+
function extractAssistantContent(payload) {
|
|
3944
|
+
if (!payload || typeof payload !== "object") return void 0;
|
|
3945
|
+
const record = payload;
|
|
3946
|
+
const choices = record.choices;
|
|
3947
|
+
if (!Array.isArray(choices) || choices.length === 0) return void 0;
|
|
3948
|
+
const firstChoice = choices[0];
|
|
3949
|
+
if (!firstChoice || typeof firstChoice !== "object") return void 0;
|
|
3950
|
+
const choice = firstChoice;
|
|
3951
|
+
const message = choice.message;
|
|
3952
|
+
if (!message || typeof message !== "object") return void 0;
|
|
3953
|
+
const content = message.content;
|
|
3954
|
+
return typeof content === "string" ? content : void 0;
|
|
3955
|
+
}
|
|
3956
|
+
function hasKnownLoopSignature(text) {
|
|
3957
|
+
const matchCount = DEGRADED_LOOP_PATTERNS.reduce(
|
|
3958
|
+
(count, pattern) => pattern.test(text) ? count + 1 : count,
|
|
3959
|
+
0
|
|
3960
|
+
);
|
|
3961
|
+
if (matchCount >= 2) return true;
|
|
3962
|
+
const lines = text.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
|
|
3963
|
+
if (lines.length < 8) return false;
|
|
3964
|
+
const counts = /* @__PURE__ */ new Map();
|
|
3965
|
+
for (const line of lines) {
|
|
3966
|
+
counts.set(line, (counts.get(line) ?? 0) + 1);
|
|
3967
|
+
}
|
|
3968
|
+
const maxRepeat = Math.max(...counts.values());
|
|
3969
|
+
const uniqueRatio = counts.size / lines.length;
|
|
3970
|
+
return maxRepeat >= 3 && uniqueRatio <= 0.45;
|
|
3971
|
+
}
|
|
3972
|
+
function detectDegradedSuccessResponse(body) {
|
|
3973
|
+
const trimmed = body.trim();
|
|
3974
|
+
if (!trimmed) return void 0;
|
|
3975
|
+
if (DEGRADED_RESPONSE_PATTERNS.some((pattern) => pattern.test(trimmed))) {
|
|
3976
|
+
return "degraded response: overloaded placeholder";
|
|
3977
|
+
}
|
|
3978
|
+
if (hasKnownLoopSignature(trimmed)) {
|
|
3979
|
+
return "degraded response: repetitive loop output";
|
|
3980
|
+
}
|
|
3981
|
+
try {
|
|
3982
|
+
const parsed = JSON.parse(trimmed);
|
|
3983
|
+
const errorField = parsed.error;
|
|
3984
|
+
let errorText = "";
|
|
3985
|
+
if (typeof errorField === "string") {
|
|
3986
|
+
errorText = errorField;
|
|
3987
|
+
} else if (errorField && typeof errorField === "object") {
|
|
3988
|
+
const errObj = errorField;
|
|
3989
|
+
errorText = [
|
|
3990
|
+
typeof errObj.message === "string" ? errObj.message : "",
|
|
3991
|
+
typeof errObj.type === "string" ? errObj.type : "",
|
|
3992
|
+
typeof errObj.code === "string" ? errObj.code : ""
|
|
3993
|
+
].filter(Boolean).join(" ");
|
|
3994
|
+
}
|
|
3995
|
+
if (errorText && PROVIDER_ERROR_PATTERNS.some((pattern) => pattern.test(errorText))) {
|
|
3996
|
+
return `degraded response: ${errorText.slice(0, 120)}`;
|
|
3997
|
+
}
|
|
3998
|
+
const assistantContent = extractAssistantContent(parsed);
|
|
3999
|
+
if (!assistantContent) return void 0;
|
|
4000
|
+
if (DEGRADED_RESPONSE_PATTERNS.some((pattern) => pattern.test(assistantContent))) {
|
|
4001
|
+
return "degraded response: overloaded assistant content";
|
|
4002
|
+
}
|
|
4003
|
+
if (hasKnownLoopSignature(assistantContent)) {
|
|
4004
|
+
return "degraded response: repetitive assistant loop";
|
|
4005
|
+
}
|
|
4006
|
+
} catch {
|
|
4007
|
+
}
|
|
4008
|
+
return void 0;
|
|
4009
|
+
}
|
|
3928
4010
|
var FALLBACK_STATUS_CODES = [
|
|
3929
4011
|
400,
|
|
3930
4012
|
// Bad request - sometimes used for billing errors
|
|
@@ -4464,6 +4546,22 @@ async function tryModelRequest(upstreamUrl, method, headers, body, modelId, maxT
|
|
|
4464
4546
|
isProviderError: isProviderErr
|
|
4465
4547
|
};
|
|
4466
4548
|
}
|
|
4549
|
+
const contentType = response.headers.get("content-type") || "";
|
|
4550
|
+
if (contentType.includes("json") || contentType.includes("text")) {
|
|
4551
|
+
try {
|
|
4552
|
+
const responseBody = await response.clone().text();
|
|
4553
|
+
const degradedReason = detectDegradedSuccessResponse(responseBody);
|
|
4554
|
+
if (degradedReason) {
|
|
4555
|
+
return {
|
|
4556
|
+
success: false,
|
|
4557
|
+
errorBody: degradedReason,
|
|
4558
|
+
errorStatus: 503,
|
|
4559
|
+
isProviderError: true
|
|
4560
|
+
};
|
|
4561
|
+
}
|
|
4562
|
+
} catch {
|
|
4563
|
+
}
|
|
4564
|
+
}
|
|
4467
4565
|
return { success: true, response };
|
|
4468
4566
|
} catch (err) {
|
|
4469
4567
|
const errorMsg = err instanceof Error ? err.message : String(err);
|