@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/README.md +129 -115
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +153 -109
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +1387 -0
- package/dist/index.js +151 -107
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -990,7 +990,7 @@ var MODEL_ALIASES = {
|
|
|
990
990
|
gpt5: "openai/gpt-5.4",
|
|
991
991
|
"gpt-5.4": "openai/gpt-5.4",
|
|
992
992
|
"gpt-5.4-pro": "openai/gpt-5.4-pro",
|
|
993
|
-
codex: "openai/gpt-5.
|
|
993
|
+
codex: "openai/gpt-5.3-codex",
|
|
994
994
|
mini: "openai/gpt-4o-mini",
|
|
995
995
|
o1: "openai/o1",
|
|
996
996
|
o3: "openai/o3",
|
|
@@ -1146,15 +1146,29 @@ var BLOCKRUN_MODELS = [
|
|
|
1146
1146
|
reasoning: true,
|
|
1147
1147
|
toolCalling: true
|
|
1148
1148
|
},
|
|
1149
|
-
// OpenAI
|
|
1149
|
+
// OpenAI GPT-5.3 Family
|
|
1150
1150
|
{
|
|
1151
|
-
id: "openai/gpt-5.
|
|
1152
|
-
name: "GPT-5.
|
|
1153
|
-
version: "5.
|
|
1151
|
+
id: "openai/gpt-5.3",
|
|
1152
|
+
name: "GPT-5.3",
|
|
1153
|
+
version: "5.3",
|
|
1154
1154
|
inputPrice: 1.75,
|
|
1155
1155
|
outputPrice: 14,
|
|
1156
1156
|
contextWindow: 128e3,
|
|
1157
|
-
maxOutput:
|
|
1157
|
+
maxOutput: 16e3,
|
|
1158
|
+
reasoning: true,
|
|
1159
|
+
vision: true,
|
|
1160
|
+
agentic: true,
|
|
1161
|
+
toolCalling: true
|
|
1162
|
+
},
|
|
1163
|
+
// OpenAI Codex Family
|
|
1164
|
+
{
|
|
1165
|
+
id: "openai/gpt-5.3-codex",
|
|
1166
|
+
name: "GPT-5.3 Codex",
|
|
1167
|
+
version: "5.3",
|
|
1168
|
+
inputPrice: 1.75,
|
|
1169
|
+
outputPrice: 14,
|
|
1170
|
+
contextWindow: 4e5,
|
|
1171
|
+
maxOutput: 128e3,
|
|
1158
1172
|
agentic: true,
|
|
1159
1173
|
toolCalling: true
|
|
1160
1174
|
},
|
|
@@ -2022,6 +2036,99 @@ function getFallbackChainFiltered(tier, tierConfigs, estimatedTotalTokens, getCo
|
|
|
2022
2036
|
return filtered;
|
|
2023
2037
|
}
|
|
2024
2038
|
|
|
2039
|
+
// src/router/strategy.ts
|
|
2040
|
+
var RulesStrategy = class {
|
|
2041
|
+
name = "rules";
|
|
2042
|
+
route(prompt, systemPrompt, maxOutputTokens, options) {
|
|
2043
|
+
const { config, modelPricing } = options;
|
|
2044
|
+
const fullText = `${systemPrompt ?? ""} ${prompt}`;
|
|
2045
|
+
const estimatedTokens = Math.ceil(fullText.length / 4);
|
|
2046
|
+
const ruleResult = classifyByRules(prompt, systemPrompt, estimatedTokens, config.scoring);
|
|
2047
|
+
const { routingProfile } = options;
|
|
2048
|
+
let tierConfigs;
|
|
2049
|
+
let profileSuffix;
|
|
2050
|
+
let profile;
|
|
2051
|
+
if (routingProfile === "eco" && config.ecoTiers) {
|
|
2052
|
+
tierConfigs = config.ecoTiers;
|
|
2053
|
+
profileSuffix = " | eco";
|
|
2054
|
+
profile = "eco";
|
|
2055
|
+
} else if (routingProfile === "premium" && config.premiumTiers) {
|
|
2056
|
+
tierConfigs = config.premiumTiers;
|
|
2057
|
+
profileSuffix = " | premium";
|
|
2058
|
+
profile = "premium";
|
|
2059
|
+
} else {
|
|
2060
|
+
const agenticScore = ruleResult.agenticScore ?? 0;
|
|
2061
|
+
const isAutoAgentic = agenticScore >= 0.5;
|
|
2062
|
+
const isExplicitAgentic = config.overrides.agenticMode ?? false;
|
|
2063
|
+
const hasToolsInRequest = options.hasTools ?? false;
|
|
2064
|
+
const useAgenticTiers = (hasToolsInRequest || isAutoAgentic || isExplicitAgentic) && config.agenticTiers != null;
|
|
2065
|
+
tierConfigs = useAgenticTiers ? config.agenticTiers : config.tiers;
|
|
2066
|
+
profileSuffix = useAgenticTiers ? ` | agentic${hasToolsInRequest ? " (tools)" : ""}` : "";
|
|
2067
|
+
profile = useAgenticTiers ? "agentic" : "auto";
|
|
2068
|
+
}
|
|
2069
|
+
const agenticScoreValue = ruleResult.agenticScore;
|
|
2070
|
+
if (estimatedTokens > config.overrides.maxTokensForceComplex) {
|
|
2071
|
+
const decision2 = selectModel(
|
|
2072
|
+
"COMPLEX",
|
|
2073
|
+
0.95,
|
|
2074
|
+
"rules",
|
|
2075
|
+
`Input exceeds ${config.overrides.maxTokensForceComplex} tokens${profileSuffix}`,
|
|
2076
|
+
tierConfigs,
|
|
2077
|
+
modelPricing,
|
|
2078
|
+
estimatedTokens,
|
|
2079
|
+
maxOutputTokens,
|
|
2080
|
+
routingProfile,
|
|
2081
|
+
agenticScoreValue
|
|
2082
|
+
);
|
|
2083
|
+
return { ...decision2, tierConfigs, profile };
|
|
2084
|
+
}
|
|
2085
|
+
const hasStructuredOutput = systemPrompt ? /json|structured|schema/i.test(systemPrompt) : false;
|
|
2086
|
+
let tier;
|
|
2087
|
+
let confidence;
|
|
2088
|
+
const method = "rules";
|
|
2089
|
+
let reasoning = `score=${ruleResult.score.toFixed(2)} | ${ruleResult.signals.join(", ")}`;
|
|
2090
|
+
if (ruleResult.tier !== null) {
|
|
2091
|
+
tier = ruleResult.tier;
|
|
2092
|
+
confidence = ruleResult.confidence;
|
|
2093
|
+
} else {
|
|
2094
|
+
tier = config.overrides.ambiguousDefaultTier;
|
|
2095
|
+
confidence = 0.5;
|
|
2096
|
+
reasoning += ` | ambiguous -> default: ${tier}`;
|
|
2097
|
+
}
|
|
2098
|
+
if (hasStructuredOutput) {
|
|
2099
|
+
const tierRank = { SIMPLE: 0, MEDIUM: 1, COMPLEX: 2, REASONING: 3 };
|
|
2100
|
+
const minTier = config.overrides.structuredOutputMinTier;
|
|
2101
|
+
if (tierRank[tier] < tierRank[minTier]) {
|
|
2102
|
+
reasoning += ` | upgraded to ${minTier} (structured output)`;
|
|
2103
|
+
tier = minTier;
|
|
2104
|
+
}
|
|
2105
|
+
}
|
|
2106
|
+
reasoning += profileSuffix;
|
|
2107
|
+
const decision = selectModel(
|
|
2108
|
+
tier,
|
|
2109
|
+
confidence,
|
|
2110
|
+
method,
|
|
2111
|
+
reasoning,
|
|
2112
|
+
tierConfigs,
|
|
2113
|
+
modelPricing,
|
|
2114
|
+
estimatedTokens,
|
|
2115
|
+
maxOutputTokens,
|
|
2116
|
+
routingProfile,
|
|
2117
|
+
agenticScoreValue
|
|
2118
|
+
);
|
|
2119
|
+
return { ...decision, tierConfigs, profile };
|
|
2120
|
+
}
|
|
2121
|
+
};
|
|
2122
|
+
var registry = /* @__PURE__ */ new Map();
|
|
2123
|
+
registry.set("rules", new RulesStrategy());
|
|
2124
|
+
function getStrategy(name) {
|
|
2125
|
+
const strategy = registry.get(name);
|
|
2126
|
+
if (!strategy) {
|
|
2127
|
+
throw new Error(`Unknown routing strategy: ${name}`);
|
|
2128
|
+
}
|
|
2129
|
+
return strategy;
|
|
2130
|
+
}
|
|
2131
|
+
|
|
2025
2132
|
// src/router/config.ts
|
|
2026
2133
|
var DEFAULT_ROUTING_CONFIG = {
|
|
2027
2134
|
version: "2.0",
|
|
@@ -3114,7 +3221,11 @@ var DEFAULT_ROUTING_CONFIG = {
|
|
|
3114
3221
|
SIMPLE: {
|
|
3115
3222
|
primary: "nvidia/gpt-oss-120b",
|
|
3116
3223
|
// FREE! $0.00/$0.00
|
|
3117
|
-
fallback: [
|
|
3224
|
+
fallback: [
|
|
3225
|
+
"google/gemini-2.5-flash-lite",
|
|
3226
|
+
"google/gemini-2.5-flash",
|
|
3227
|
+
"deepseek/deepseek-chat"
|
|
3228
|
+
]
|
|
3118
3229
|
},
|
|
3119
3230
|
MEDIUM: {
|
|
3120
3231
|
primary: "google/gemini-2.5-flash-lite",
|
|
@@ -3147,8 +3258,8 @@ var DEFAULT_ROUTING_CONFIG = {
|
|
|
3147
3258
|
]
|
|
3148
3259
|
},
|
|
3149
3260
|
MEDIUM: {
|
|
3150
|
-
primary: "openai/gpt-5.
|
|
3151
|
-
// $
|
|
3261
|
+
primary: "openai/gpt-5.3-codex",
|
|
3262
|
+
// $1.75/$14 - 400K context, 128K output, replaces 5.2
|
|
3152
3263
|
fallback: [
|
|
3153
3264
|
"moonshot/kimi-k2.5",
|
|
3154
3265
|
"google/gemini-2.5-flash",
|
|
@@ -3164,7 +3275,7 @@ var DEFAULT_ROUTING_CONFIG = {
|
|
|
3164
3275
|
fallback: [
|
|
3165
3276
|
"openai/gpt-5.4",
|
|
3166
3277
|
// Newest flagship
|
|
3167
|
-
"openai/gpt-5.
|
|
3278
|
+
"openai/gpt-5.3-codex",
|
|
3168
3279
|
"anthropic/claude-opus-4.6",
|
|
3169
3280
|
"anthropic/claude-sonnet-4.6",
|
|
3170
3281
|
"google/gemini-3.1-pro",
|
|
@@ -3239,77 +3350,8 @@ var DEFAULT_ROUTING_CONFIG = {
|
|
|
3239
3350
|
|
|
3240
3351
|
// src/router/index.ts
|
|
3241
3352
|
function route(prompt, systemPrompt, maxOutputTokens, options) {
|
|
3242
|
-
const
|
|
3243
|
-
|
|
3244
|
-
const estimatedTokens = Math.ceil(fullText.length / 4);
|
|
3245
|
-
const ruleResult = classifyByRules(prompt, systemPrompt, estimatedTokens, config.scoring);
|
|
3246
|
-
const { routingProfile } = options;
|
|
3247
|
-
let tierConfigs;
|
|
3248
|
-
let profileSuffix;
|
|
3249
|
-
if (routingProfile === "eco" && config.ecoTiers) {
|
|
3250
|
-
tierConfigs = config.ecoTiers;
|
|
3251
|
-
profileSuffix = " | eco";
|
|
3252
|
-
} else if (routingProfile === "premium" && config.premiumTiers) {
|
|
3253
|
-
tierConfigs = config.premiumTiers;
|
|
3254
|
-
profileSuffix = " | premium";
|
|
3255
|
-
} else {
|
|
3256
|
-
const agenticScore = ruleResult.agenticScore ?? 0;
|
|
3257
|
-
const isAutoAgentic = agenticScore >= 0.5;
|
|
3258
|
-
const isExplicitAgentic = config.overrides.agenticMode ?? false;
|
|
3259
|
-
const hasToolsInRequest = options.hasTools ?? false;
|
|
3260
|
-
const useAgenticTiers = (hasToolsInRequest || isAutoAgentic || isExplicitAgentic) && config.agenticTiers != null;
|
|
3261
|
-
tierConfigs = useAgenticTiers ? config.agenticTiers : config.tiers;
|
|
3262
|
-
profileSuffix = useAgenticTiers ? ` | agentic${hasToolsInRequest ? " (tools)" : ""}` : "";
|
|
3263
|
-
}
|
|
3264
|
-
const agenticScoreValue = ruleResult.agenticScore;
|
|
3265
|
-
if (estimatedTokens > config.overrides.maxTokensForceComplex) {
|
|
3266
|
-
return selectModel(
|
|
3267
|
-
"COMPLEX",
|
|
3268
|
-
0.95,
|
|
3269
|
-
"rules",
|
|
3270
|
-
`Input exceeds ${config.overrides.maxTokensForceComplex} tokens${profileSuffix}`,
|
|
3271
|
-
tierConfigs,
|
|
3272
|
-
modelPricing,
|
|
3273
|
-
estimatedTokens,
|
|
3274
|
-
maxOutputTokens,
|
|
3275
|
-
routingProfile,
|
|
3276
|
-
agenticScoreValue
|
|
3277
|
-
);
|
|
3278
|
-
}
|
|
3279
|
-
const hasStructuredOutput = systemPrompt ? /json|structured|schema/i.test(systemPrompt) : false;
|
|
3280
|
-
let tier;
|
|
3281
|
-
let confidence;
|
|
3282
|
-
const method = "rules";
|
|
3283
|
-
let reasoning = `score=${ruleResult.score.toFixed(2)} | ${ruleResult.signals.join(", ")}`;
|
|
3284
|
-
if (ruleResult.tier !== null) {
|
|
3285
|
-
tier = ruleResult.tier;
|
|
3286
|
-
confidence = ruleResult.confidence;
|
|
3287
|
-
} else {
|
|
3288
|
-
tier = config.overrides.ambiguousDefaultTier;
|
|
3289
|
-
confidence = 0.5;
|
|
3290
|
-
reasoning += ` | ambiguous -> default: ${tier}`;
|
|
3291
|
-
}
|
|
3292
|
-
if (hasStructuredOutput) {
|
|
3293
|
-
const tierRank = { SIMPLE: 0, MEDIUM: 1, COMPLEX: 2, REASONING: 3 };
|
|
3294
|
-
const minTier = config.overrides.structuredOutputMinTier;
|
|
3295
|
-
if (tierRank[tier] < tierRank[minTier]) {
|
|
3296
|
-
reasoning += ` | upgraded to ${minTier} (structured output)`;
|
|
3297
|
-
tier = minTier;
|
|
3298
|
-
}
|
|
3299
|
-
}
|
|
3300
|
-
reasoning += profileSuffix;
|
|
3301
|
-
return selectModel(
|
|
3302
|
-
tier,
|
|
3303
|
-
confidence,
|
|
3304
|
-
method,
|
|
3305
|
-
reasoning,
|
|
3306
|
-
tierConfigs,
|
|
3307
|
-
modelPricing,
|
|
3308
|
-
estimatedTokens,
|
|
3309
|
-
maxOutputTokens,
|
|
3310
|
-
routingProfile,
|
|
3311
|
-
agenticScoreValue
|
|
3312
|
-
);
|
|
3353
|
+
const strategy = getStrategy("rules");
|
|
3354
|
+
return strategy.route(prompt, systemPrompt, maxOutputTokens, options);
|
|
3313
3355
|
}
|
|
3314
3356
|
|
|
3315
3357
|
// src/logger.ts
|
|
@@ -5454,6 +5496,12 @@ var ROUTING_PROFILES = /* @__PURE__ */ new Set([
|
|
|
5454
5496
|
"premium"
|
|
5455
5497
|
]);
|
|
5456
5498
|
var FREE_MODEL = "nvidia/gpt-oss-120b";
|
|
5499
|
+
var FREE_TIER_CONFIGS = {
|
|
5500
|
+
SIMPLE: { primary: FREE_MODEL, fallback: [] },
|
|
5501
|
+
MEDIUM: { primary: FREE_MODEL, fallback: [] },
|
|
5502
|
+
COMPLEX: { primary: FREE_MODEL, fallback: [] },
|
|
5503
|
+
REASONING: { primary: FREE_MODEL, fallback: [] }
|
|
5504
|
+
};
|
|
5457
5505
|
var freeRequestCount = 0;
|
|
5458
5506
|
var MAX_MESSAGES = 200;
|
|
5459
5507
|
var CONTEXT_LIMIT_KB = 5120;
|
|
@@ -7328,7 +7376,17 @@ async function proxyRequest(req, res, apiBase, payFetch, options, routerOpts, de
|
|
|
7328
7376
|
|
|
7329
7377
|
`;
|
|
7330
7378
|
}
|
|
7331
|
-
routingDecision = {
|
|
7379
|
+
routingDecision = {
|
|
7380
|
+
model: freeModel,
|
|
7381
|
+
tier: "SIMPLE",
|
|
7382
|
+
confidence: 1,
|
|
7383
|
+
method: "rules",
|
|
7384
|
+
reasoning: "free profile",
|
|
7385
|
+
costEstimate: 0,
|
|
7386
|
+
baselineCost: 0,
|
|
7387
|
+
savings: 1,
|
|
7388
|
+
tierConfigs: FREE_TIER_CONFIGS
|
|
7389
|
+
};
|
|
7332
7390
|
} else {
|
|
7333
7391
|
effectiveSessionId = getSessionId(req.headers) ?? deriveSessionId(parsedMessages);
|
|
7334
7392
|
const existingSession = effectiveSessionId ? sessionStore.getSession(effectiveSessionId) : void 0;
|
|
@@ -7419,18 +7477,7 @@ async function proxyRequest(req, res, apiBase, payFetch, options, routerOpts, de
|
|
|
7419
7477
|
const contentHash = hashRequestContent(prompt, toolCallNames);
|
|
7420
7478
|
const shouldEscalate = sessionStore.recordRequestHash(effectiveSessionId, contentHash);
|
|
7421
7479
|
if (shouldEscalate) {
|
|
7422
|
-
const activeTierConfigs =
|
|
7423
|
-
if (routingDecision.reasoning?.includes("agentic") && routerOpts.config.agenticTiers) {
|
|
7424
|
-
return routerOpts.config.agenticTiers;
|
|
7425
|
-
}
|
|
7426
|
-
if (routingProfile === "eco" && routerOpts.config.ecoTiers) {
|
|
7427
|
-
return routerOpts.config.ecoTiers;
|
|
7428
|
-
}
|
|
7429
|
-
if (routingProfile === "premium" && routerOpts.config.premiumTiers) {
|
|
7430
|
-
return routerOpts.config.premiumTiers;
|
|
7431
|
-
}
|
|
7432
|
-
return routerOpts.config.tiers;
|
|
7433
|
-
})();
|
|
7480
|
+
const activeTierConfigs = routingDecision.tierConfigs ?? routerOpts.config.tiers;
|
|
7434
7481
|
const escalation = sessionStore.escalateSession(
|
|
7435
7482
|
effectiveSessionId,
|
|
7436
7483
|
activeTierConfigs
|
|
@@ -7646,18 +7693,7 @@ async function proxyRequest(req, res, apiBase, payFetch, options, routerOpts, de
|
|
|
7646
7693
|
if (routingDecision) {
|
|
7647
7694
|
const estimatedInputTokens = Math.ceil(body.length / 4);
|
|
7648
7695
|
const estimatedTotalTokens = estimatedInputTokens + maxTokens;
|
|
7649
|
-
const tierConfigs =
|
|
7650
|
-
if (routingDecision.reasoning?.includes("agentic") && routerOpts.config.agenticTiers) {
|
|
7651
|
-
return routerOpts.config.agenticTiers;
|
|
7652
|
-
}
|
|
7653
|
-
if (routingProfile === "eco" && routerOpts.config.ecoTiers) {
|
|
7654
|
-
return routerOpts.config.ecoTiers;
|
|
7655
|
-
}
|
|
7656
|
-
if (routingProfile === "premium" && routerOpts.config.premiumTiers) {
|
|
7657
|
-
return routerOpts.config.premiumTiers;
|
|
7658
|
-
}
|
|
7659
|
-
return routerOpts.config.tiers;
|
|
7660
|
-
})();
|
|
7696
|
+
const tierConfigs = routingDecision.tierConfigs ?? routerOpts.config.tiers;
|
|
7661
7697
|
const fullChain = getFallbackChain(routingDecision.tier, tierConfigs);
|
|
7662
7698
|
const contextFiltered = getFallbackChainFiltered(
|
|
7663
7699
|
routingDecision.tier,
|
|
@@ -7737,6 +7773,14 @@ async function proxyRequest(req, res, apiBase, payFetch, options, routerOpts, de
|
|
|
7737
7773
|
status: result.errorStatus || 500
|
|
7738
7774
|
};
|
|
7739
7775
|
if (result.isProviderError && !isLastAttempt) {
|
|
7776
|
+
const isExplicitModelError = !routingDecision;
|
|
7777
|
+
const isUnknownExplicitModel = isExplicitModelError && /unknown.*model|invalid.*model/i.test(result.errorBody || "");
|
|
7778
|
+
if (isUnknownExplicitModel) {
|
|
7779
|
+
console.log(
|
|
7780
|
+
`[ClawRouter] Explicit model error from ${tryModel}, not falling back: ${result.errorBody?.slice(0, 100)}`
|
|
7781
|
+
);
|
|
7782
|
+
break;
|
|
7783
|
+
}
|
|
7740
7784
|
if (result.errorStatus === 429) {
|
|
7741
7785
|
markRateLimited(tryModel);
|
|
7742
7786
|
try {
|
|
@@ -8666,7 +8710,7 @@ function injectModelsConfig(logger) {
|
|
|
8666
8710
|
"anthropic/claude-sonnet-4.6",
|
|
8667
8711
|
"anthropic/claude-opus-4.6",
|
|
8668
8712
|
"anthropic/claude-haiku-4.5",
|
|
8669
|
-
"openai/gpt-5.
|
|
8713
|
+
"openai/gpt-5.3",
|
|
8670
8714
|
"openai/gpt-4o",
|
|
8671
8715
|
"openai/o3",
|
|
8672
8716
|
"google/gemini-3.1-pro",
|