@blockrun/clawrouter 0.9.27 → 0.9.29
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 +100 -2
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +4 -4
- package/dist/index.js +100 -2
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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
|
@@ -17,6 +17,10 @@ var MODEL_ALIASES = {
|
|
|
17
17
|
"anthropic/claude-opus-4.6": "anthropic/claude-opus-4-6",
|
|
18
18
|
"anthropic/claude-opus-4.5": "anthropic/claude-opus-4-5",
|
|
19
19
|
"anthropic/claude-haiku-4.5": "anthropic/claude-haiku-4-5",
|
|
20
|
+
// Base model names without version -> route to latest
|
|
21
|
+
"anthropic/claude-sonnet-4": "anthropic/claude-sonnet-4-6",
|
|
22
|
+
"anthropic/claude-opus-4": "anthropic/claude-opus-4-6",
|
|
23
|
+
"anthropic/claude-haiku-4": "anthropic/claude-haiku-4-5",
|
|
20
24
|
// OpenAI
|
|
21
25
|
gpt: "openai/gpt-4o",
|
|
22
26
|
gpt4: "openai/gpt-4o",
|
|
@@ -1004,6 +1008,7 @@ function calibrateConfidence(distance, steepness) {
|
|
|
1004
1008
|
}
|
|
1005
1009
|
|
|
1006
1010
|
// src/router/selector.ts
|
|
1011
|
+
var BASELINE_MODEL_ID = "anthropic/claude-opus-4-5";
|
|
1007
1012
|
function selectModel(tier, confidence, method, reasoning, tierConfigs, modelPricing, estimatedInputTokens, maxOutputTokens, routingProfile) {
|
|
1008
1013
|
const tierConfig = tierConfigs[tier];
|
|
1009
1014
|
const model = tierConfig.primary;
|
|
@@ -1013,7 +1018,7 @@ function selectModel(tier, confidence, method, reasoning, tierConfigs, modelPric
|
|
|
1013
1018
|
const inputCost = estimatedInputTokens / 1e6 * inputPrice;
|
|
1014
1019
|
const outputCost = maxOutputTokens / 1e6 * outputPrice;
|
|
1015
1020
|
const costEstimate = inputCost + outputCost;
|
|
1016
|
-
const opusPricing = modelPricing.get(
|
|
1021
|
+
const opusPricing = modelPricing.get(BASELINE_MODEL_ID);
|
|
1017
1022
|
const opusInputPrice = opusPricing?.inputPrice ?? 0;
|
|
1018
1023
|
const opusOutputPrice = opusPricing?.outputPrice ?? 0;
|
|
1019
1024
|
const baselineInput = estimatedInputTokens / 1e6 * opusInputPrice;
|
|
@@ -1042,7 +1047,7 @@ function calculateModelCost(model, modelPricing, estimatedInputTokens, maxOutput
|
|
|
1042
1047
|
const inputCost = estimatedInputTokens / 1e6 * inputPrice;
|
|
1043
1048
|
const outputCost = maxOutputTokens / 1e6 * outputPrice;
|
|
1044
1049
|
const costEstimate = inputCost + outputCost;
|
|
1045
|
-
const opusPricing = modelPricing.get(
|
|
1050
|
+
const opusPricing = modelPricing.get(BASELINE_MODEL_ID);
|
|
1046
1051
|
const opusInputPrice = opusPricing?.inputPrice ?? 0;
|
|
1047
1052
|
const opusOutputPrice = opusPricing?.outputPrice ?? 0;
|
|
1048
1053
|
const baselineInput = estimatedInputTokens / 1e6 * opusInputPrice;
|
|
@@ -3929,6 +3934,83 @@ var PROVIDER_ERROR_PATTERNS = [
|
|
|
3929
3934
|
/request.*size.*exceeds/i,
|
|
3930
3935
|
/payload too large/i
|
|
3931
3936
|
];
|
|
3937
|
+
var DEGRADED_RESPONSE_PATTERNS = [
|
|
3938
|
+
/the ai service is temporarily overloaded/i,
|
|
3939
|
+
/service is temporarily overloaded/i,
|
|
3940
|
+
/please try again in a moment/i
|
|
3941
|
+
];
|
|
3942
|
+
var DEGRADED_LOOP_PATTERNS = [
|
|
3943
|
+
/the boxed is the response\./i,
|
|
3944
|
+
/the response is the text\./i,
|
|
3945
|
+
/the final answer is the boxed\./i
|
|
3946
|
+
];
|
|
3947
|
+
function extractAssistantContent(payload) {
|
|
3948
|
+
if (!payload || typeof payload !== "object") return void 0;
|
|
3949
|
+
const record = payload;
|
|
3950
|
+
const choices = record.choices;
|
|
3951
|
+
if (!Array.isArray(choices) || choices.length === 0) return void 0;
|
|
3952
|
+
const firstChoice = choices[0];
|
|
3953
|
+
if (!firstChoice || typeof firstChoice !== "object") return void 0;
|
|
3954
|
+
const choice = firstChoice;
|
|
3955
|
+
const message = choice.message;
|
|
3956
|
+
if (!message || typeof message !== "object") return void 0;
|
|
3957
|
+
const content = message.content;
|
|
3958
|
+
return typeof content === "string" ? content : void 0;
|
|
3959
|
+
}
|
|
3960
|
+
function hasKnownLoopSignature(text) {
|
|
3961
|
+
const matchCount = DEGRADED_LOOP_PATTERNS.reduce(
|
|
3962
|
+
(count, pattern) => pattern.test(text) ? count + 1 : count,
|
|
3963
|
+
0
|
|
3964
|
+
);
|
|
3965
|
+
if (matchCount >= 2) return true;
|
|
3966
|
+
const lines = text.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
|
|
3967
|
+
if (lines.length < 8) return false;
|
|
3968
|
+
const counts = /* @__PURE__ */ new Map();
|
|
3969
|
+
for (const line of lines) {
|
|
3970
|
+
counts.set(line, (counts.get(line) ?? 0) + 1);
|
|
3971
|
+
}
|
|
3972
|
+
const maxRepeat = Math.max(...counts.values());
|
|
3973
|
+
const uniqueRatio = counts.size / lines.length;
|
|
3974
|
+
return maxRepeat >= 3 && uniqueRatio <= 0.45;
|
|
3975
|
+
}
|
|
3976
|
+
function detectDegradedSuccessResponse(body) {
|
|
3977
|
+
const trimmed = body.trim();
|
|
3978
|
+
if (!trimmed) return void 0;
|
|
3979
|
+
if (DEGRADED_RESPONSE_PATTERNS.some((pattern) => pattern.test(trimmed))) {
|
|
3980
|
+
return "degraded response: overloaded placeholder";
|
|
3981
|
+
}
|
|
3982
|
+
if (hasKnownLoopSignature(trimmed)) {
|
|
3983
|
+
return "degraded response: repetitive loop output";
|
|
3984
|
+
}
|
|
3985
|
+
try {
|
|
3986
|
+
const parsed = JSON.parse(trimmed);
|
|
3987
|
+
const errorField = parsed.error;
|
|
3988
|
+
let errorText = "";
|
|
3989
|
+
if (typeof errorField === "string") {
|
|
3990
|
+
errorText = errorField;
|
|
3991
|
+
} else if (errorField && typeof errorField === "object") {
|
|
3992
|
+
const errObj = errorField;
|
|
3993
|
+
errorText = [
|
|
3994
|
+
typeof errObj.message === "string" ? errObj.message : "",
|
|
3995
|
+
typeof errObj.type === "string" ? errObj.type : "",
|
|
3996
|
+
typeof errObj.code === "string" ? errObj.code : ""
|
|
3997
|
+
].filter(Boolean).join(" ");
|
|
3998
|
+
}
|
|
3999
|
+
if (errorText && PROVIDER_ERROR_PATTERNS.some((pattern) => pattern.test(errorText))) {
|
|
4000
|
+
return `degraded response: ${errorText.slice(0, 120)}`;
|
|
4001
|
+
}
|
|
4002
|
+
const assistantContent = extractAssistantContent(parsed);
|
|
4003
|
+
if (!assistantContent) return void 0;
|
|
4004
|
+
if (DEGRADED_RESPONSE_PATTERNS.some((pattern) => pattern.test(assistantContent))) {
|
|
4005
|
+
return "degraded response: overloaded assistant content";
|
|
4006
|
+
}
|
|
4007
|
+
if (hasKnownLoopSignature(assistantContent)) {
|
|
4008
|
+
return "degraded response: repetitive assistant loop";
|
|
4009
|
+
}
|
|
4010
|
+
} catch {
|
|
4011
|
+
}
|
|
4012
|
+
return void 0;
|
|
4013
|
+
}
|
|
3932
4014
|
var FALLBACK_STATUS_CODES = [
|
|
3933
4015
|
400,
|
|
3934
4016
|
// Bad request - sometimes used for billing errors
|
|
@@ -4468,6 +4550,22 @@ async function tryModelRequest(upstreamUrl, method, headers, body, modelId, maxT
|
|
|
4468
4550
|
isProviderError: isProviderErr
|
|
4469
4551
|
};
|
|
4470
4552
|
}
|
|
4553
|
+
const contentType = response.headers.get("content-type") || "";
|
|
4554
|
+
if (contentType.includes("json") || contentType.includes("text")) {
|
|
4555
|
+
try {
|
|
4556
|
+
const responseBody = await response.clone().text();
|
|
4557
|
+
const degradedReason = detectDegradedSuccessResponse(responseBody);
|
|
4558
|
+
if (degradedReason) {
|
|
4559
|
+
return {
|
|
4560
|
+
success: false,
|
|
4561
|
+
errorBody: degradedReason,
|
|
4562
|
+
errorStatus: 503,
|
|
4563
|
+
isProviderError: true
|
|
4564
|
+
};
|
|
4565
|
+
}
|
|
4566
|
+
} catch {
|
|
4567
|
+
}
|
|
4568
|
+
}
|
|
4471
4569
|
return { success: true, response };
|
|
4472
4570
|
} catch (err) {
|
|
4473
4571
|
const errorMsg = err instanceof Error ? err.message : String(err);
|