@blockrun/llm 3.24.1 → 3.24.3
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/index.cjs +132 -43
- package/dist/index.js +132 -43
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -571,7 +571,69 @@ function withCost(body, response, bookedUsd, scheme) {
|
|
|
571
571
|
// src/client.ts
|
|
572
572
|
var import_accounts2 = require("viem/accounts");
|
|
573
573
|
|
|
574
|
-
// node_modules/.pnpm/@blockrun+router-core@https+++codeload.github.com+BlockRunAI+router-core+tar.gz+
|
|
574
|
+
// node_modules/.pnpm/@blockrun+router-core@https+++codeload.github.com+BlockRunAI+router-core+tar.gz+2cd5a1026f755_easf3bov3hzdfoup33nwewqudy/node_modules/@blockrun/router-core/dist/index.js
|
|
575
|
+
var UNSEGMENTED_SCRIPT = /[-ۿ -ヿ㐀-䶿一-鿿가-豈--]/;
|
|
576
|
+
var WORD_CHAR = /[\p{L}\p{N}]/u;
|
|
577
|
+
var ASCII_PHRASE = /^[a-z0-9' -]+$/;
|
|
578
|
+
var SEGMENTED_WORD_CHAR = "\\p{Script=Latin}\\p{Script=Cyrillic}\\p{Script=Greek}\\p{N}";
|
|
579
|
+
var BOUNDARY_BEFORE = `(?<![${SEGMENTED_WORD_CHAR}])`;
|
|
580
|
+
var BOUNDARY_AFTER = `(?![${SEGMENTED_WORD_CHAR}])`;
|
|
581
|
+
var BOUNDED_LAST_WORD_LENGTH = 6;
|
|
582
|
+
var SHORT_SUFFIXES = "(?:s|ed|ing)?";
|
|
583
|
+
var SIBILANT_PLURAL = "es";
|
|
584
|
+
var MID_SUFFIXES = "(?:s|es|ed|d|ing|er|ers|ly|ment|ments|ation|ations|e|en|n|a|as|o|os|em|et|ung|ungen)?";
|
|
585
|
+
var DROPPED_E_SUFFIXES = "(?:ing|ed|es|er|ers|ation|ations)";
|
|
586
|
+
var DOUBLED_CONSONANT_SUFFIXES = "(?:ing|ed|er|ers)";
|
|
587
|
+
var matcherCache = /* @__PURE__ */ new Map();
|
|
588
|
+
function escapeRegExp(value) {
|
|
589
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
590
|
+
}
|
|
591
|
+
function keywordMatcher(keyword) {
|
|
592
|
+
const cached = matcherCache.get(keyword);
|
|
593
|
+
if (cached) return cached;
|
|
594
|
+
const kw = keyword.toLowerCase();
|
|
595
|
+
let matcher;
|
|
596
|
+
if (UNSEGMENTED_SCRIPT.test(kw) || kw.length === 0) {
|
|
597
|
+
matcher = { needle: kw, pattern: null };
|
|
598
|
+
} else {
|
|
599
|
+
const lead = WORD_CHAR.test(kw[0]) ? BOUNDARY_BEFORE : "";
|
|
600
|
+
const escaped = escapeRegExp(kw);
|
|
601
|
+
let body = escaped;
|
|
602
|
+
let trail = "";
|
|
603
|
+
let needle = kw;
|
|
604
|
+
const lastWord = kw.slice(kw.lastIndexOf(" ") + 1);
|
|
605
|
+
if (WORD_CHAR.test(kw[kw.length - 1]) && ASCII_PHRASE.test(kw) && lastWord.length <= BOUNDED_LAST_WORD_LENGTH) {
|
|
606
|
+
const forms = [];
|
|
607
|
+
if (/\d$/.test(kw)) {
|
|
608
|
+
forms.push(escaped);
|
|
609
|
+
} else if (lastWord.length <= 3) {
|
|
610
|
+
forms.push(`${escaped}${SHORT_SUFFIXES}`);
|
|
611
|
+
if (/(?:x|s|z|ch|sh)$/.test(kw)) forms.push(`${escaped}${SIBILANT_PLURAL}`);
|
|
612
|
+
} else {
|
|
613
|
+
forms.push(`${escaped}${MID_SUFFIXES}`);
|
|
614
|
+
if (kw.endsWith("e")) {
|
|
615
|
+
forms.push(`${escaped.slice(0, -1)}${DROPPED_E_SUFFIXES}`);
|
|
616
|
+
needle = kw.slice(0, -1);
|
|
617
|
+
} else if (kw.endsWith("y")) {
|
|
618
|
+
forms.push(`${escaped.slice(0, -1)}(?:ies|ied)`);
|
|
619
|
+
needle = kw.slice(0, -1);
|
|
620
|
+
} else if (/[aeiou][bdgmnprt]$/.test(kw)) {
|
|
621
|
+
forms.push(`${escaped}${kw[kw.length - 1]}${DOUBLED_CONSONANT_SUFFIXES}`);
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
body = `(?:${forms.join("|")})`;
|
|
625
|
+
trail = BOUNDARY_AFTER;
|
|
626
|
+
}
|
|
627
|
+
matcher = { needle, pattern: new RegExp(`${lead}${body}${trail}`, "u") };
|
|
628
|
+
}
|
|
629
|
+
matcherCache.set(keyword, matcher);
|
|
630
|
+
return matcher;
|
|
631
|
+
}
|
|
632
|
+
function matchesKeyword(text, keyword) {
|
|
633
|
+
const { needle, pattern } = keywordMatcher(keyword);
|
|
634
|
+
if (!text.includes(needle)) return false;
|
|
635
|
+
return pattern === null ? true : pattern.test(text);
|
|
636
|
+
}
|
|
575
637
|
function scoreTokenCount(estimatedTokens, thresholds) {
|
|
576
638
|
if (estimatedTokens < thresholds.simple) {
|
|
577
639
|
return { name: "tokenCount", score: -1, signal: `short (${estimatedTokens} tokens)` };
|
|
@@ -582,7 +644,7 @@ function scoreTokenCount(estimatedTokens, thresholds) {
|
|
|
582
644
|
return { name: "tokenCount", score: 0, signal: null };
|
|
583
645
|
}
|
|
584
646
|
function scoreKeywordMatch(text, keywords, name, signalLabel, thresholds, scores) {
|
|
585
|
-
const matches = keywords.filter((kw) => text
|
|
647
|
+
const matches = keywords.filter((kw) => matchesKeyword(text, kw));
|
|
586
648
|
if (matches.length >= thresholds.high) {
|
|
587
649
|
return {
|
|
588
650
|
name,
|
|
@@ -618,7 +680,7 @@ function scoreAgenticTask(text, keywords) {
|
|
|
618
680
|
let matchCount = 0;
|
|
619
681
|
const signals = [];
|
|
620
682
|
for (const keyword of keywords) {
|
|
621
|
-
if (text
|
|
683
|
+
if (matchesKeyword(text, keyword)) {
|
|
622
684
|
matchCount++;
|
|
623
685
|
if (signals.length < 3) {
|
|
624
686
|
signals.push(keyword);
|
|
@@ -765,9 +827,7 @@ function classifyByRules(prompt, systemPrompt, estimatedTokens, config) {
|
|
|
765
827
|
const w = weights[d.name] ?? 0;
|
|
766
828
|
weightedScore += d.score * w;
|
|
767
829
|
}
|
|
768
|
-
const reasoningMatches = config.reasoningKeywords.filter(
|
|
769
|
-
(kw) => userText.includes(kw.toLowerCase())
|
|
770
|
-
);
|
|
830
|
+
const reasoningMatches = config.reasoningKeywords.filter((kw) => matchesKeyword(userText, kw));
|
|
771
831
|
if (reasoningMatches.length >= 2) {
|
|
772
832
|
const confidence2 = calibrateConfidence(
|
|
773
833
|
Math.max(weightedScore, 0.3),
|
|
@@ -832,7 +892,7 @@ function selectModel(tier, confidence, method, reasoning, tierConfigs, modelPric
|
|
|
832
892
|
const baselineInput = estimatedInputTokens / 1e6 * opusInputPrice;
|
|
833
893
|
const baselineOutput = maxOutputTokens / 1e6 * opusOutputPrice;
|
|
834
894
|
const baselineCost = baselineInput + baselineOutput;
|
|
835
|
-
const savings = routingProfile === "premium" ? 0 : baselineCost > 0 ? Math.max(0, (baselineCost - costEstimate) / baselineCost) : 0;
|
|
895
|
+
const savings = routingProfile === "premium" || pricing === void 0 ? 0 : baselineCost > 0 ? Math.max(0, (baselineCost - costEstimate) / baselineCost) : 0;
|
|
836
896
|
return {
|
|
837
897
|
model,
|
|
838
898
|
tier,
|
|
@@ -883,6 +943,21 @@ function filterCandidatesByCapacity(models, estimatedInputTokens, requestedOutpu
|
|
|
883
943
|
});
|
|
884
944
|
return filtered;
|
|
885
945
|
}
|
|
946
|
+
var CJK_CHARS = /[ -ヿ㐀-䶿一-鿿가-豈--]/g;
|
|
947
|
+
function estimateTokens(text) {
|
|
948
|
+
if (text.length === 0) return 0;
|
|
949
|
+
const cjk = text.match(CJK_CHARS)?.length ?? 0;
|
|
950
|
+
return cjk + Math.ceil((text.length - cjk) / 4);
|
|
951
|
+
}
|
|
952
|
+
function scanLimit(promptTruncationChars) {
|
|
953
|
+
return Math.max(1, Math.min(8e3, promptTruncationChars));
|
|
954
|
+
}
|
|
955
|
+
function sampleForScan(value, limit) {
|
|
956
|
+
if (value.length <= limit) return value;
|
|
957
|
+
const prefixLength = Math.ceil(limit / 2);
|
|
958
|
+
return `${value.slice(0, prefixLength)}
|
|
959
|
+
${value.slice(-(limit - prefixLength))}`;
|
|
960
|
+
}
|
|
886
961
|
function applyPromotions(tierConfigs, promotions, profile, now = /* @__PURE__ */ new Date()) {
|
|
887
962
|
if (!promotions || promotions.length === 0) return tierConfigs;
|
|
888
963
|
let result = tierConfigs;
|
|
@@ -925,16 +1000,10 @@ var RulesStrategy = class {
|
|
|
925
1000
|
route(prompt, systemPrompt, maxOutputTokens, options) {
|
|
926
1001
|
const { config, modelPricing } = options;
|
|
927
1002
|
const fullText = `${systemPrompt ?? ""} ${prompt}`;
|
|
928
|
-
const estimatedTokens =
|
|
929
|
-
const
|
|
930
|
-
const
|
|
931
|
-
|
|
932
|
-
const prefixLength = Math.ceil(scanLimit / 2);
|
|
933
|
-
return `${value.slice(0, prefixLength)}
|
|
934
|
-
${value.slice(-(scanLimit - prefixLength))}`;
|
|
935
|
-
};
|
|
936
|
-
const scannedPrompt = sample(prompt);
|
|
937
|
-
const scannedSystemPrompt = systemPrompt ? sample(systemPrompt) : void 0;
|
|
1003
|
+
const estimatedTokens = estimateTokens(fullText);
|
|
1004
|
+
const limit = scanLimit(config.classifier.promptTruncationChars);
|
|
1005
|
+
const scannedPrompt = sampleForScan(prompt, limit);
|
|
1006
|
+
const scannedSystemPrompt = systemPrompt ? sampleForScan(systemPrompt, limit) : void 0;
|
|
938
1007
|
const ruleResult = classifyByRules(
|
|
939
1008
|
scannedPrompt,
|
|
940
1009
|
scannedSystemPrompt,
|
|
@@ -988,7 +1057,7 @@ ${value.slice(-(scanLimit - prefixLength))}`;
|
|
|
988
1057
|
);
|
|
989
1058
|
return { ...decision2, tierConfigs, profile };
|
|
990
1059
|
}
|
|
991
|
-
const hasStructuredOutput = options.requiresStructuredOutput === true
|
|
1060
|
+
const hasStructuredOutput = options.requiresStructuredOutput === true;
|
|
992
1061
|
let tier;
|
|
993
1062
|
let confidence;
|
|
994
1063
|
const method = "rules";
|
|
@@ -1143,6 +1212,13 @@ var DEFAULT_MODEL_CAPABILITIES = Object.freeze({
|
|
|
1143
1212
|
supportsTools: true,
|
|
1144
1213
|
supportsVision: false
|
|
1145
1214
|
},
|
|
1215
|
+
"deepseek/deepseek-v4.1-flash": {
|
|
1216
|
+
// supportsTools: not probed — fails closed
|
|
1217
|
+
contextWindow: 1048576,
|
|
1218
|
+
maxOutputTokens: 65536,
|
|
1219
|
+
supportsTools: false,
|
|
1220
|
+
supportsVision: false
|
|
1221
|
+
},
|
|
1146
1222
|
"google/gemini-2.5-flash": {
|
|
1147
1223
|
contextWindow: 1048576,
|
|
1148
1224
|
maxOutputTokens: 65536,
|
|
@@ -1215,6 +1291,13 @@ var DEFAULT_MODEL_CAPABILITIES = Object.freeze({
|
|
|
1215
1291
|
supportsTools: true,
|
|
1216
1292
|
supportsVision: false
|
|
1217
1293
|
},
|
|
1294
|
+
"mistral/mistral-large-4": {
|
|
1295
|
+
// supportsTools: not probed — fails closed
|
|
1296
|
+
contextWindow: 524288,
|
|
1297
|
+
maxOutputTokens: 262144,
|
|
1298
|
+
supportsTools: false,
|
|
1299
|
+
supportsVision: true
|
|
1300
|
+
},
|
|
1218
1301
|
"moonshot/kimi-k3": {
|
|
1219
1302
|
contextWindow: 1048576,
|
|
1220
1303
|
maxOutputTokens: 65536,
|
|
@@ -1416,6 +1499,13 @@ var DEFAULT_MODEL_CAPABILITIES = Object.freeze({
|
|
|
1416
1499
|
supportsTools: true,
|
|
1417
1500
|
supportsVision: true
|
|
1418
1501
|
},
|
|
1502
|
+
"openai/gpt-6.1-sol": {
|
|
1503
|
+
// supportsTools: not probed — fails closed
|
|
1504
|
+
contextWindow: 105e4,
|
|
1505
|
+
maxOutputTokens: 128e3,
|
|
1506
|
+
supportsTools: false,
|
|
1507
|
+
supportsVision: true
|
|
1508
|
+
},
|
|
1419
1509
|
"openai/o1": {
|
|
1420
1510
|
contextWindow: 2e5,
|
|
1421
1511
|
maxOutputTokens: 1e5,
|
|
@@ -2241,16 +2331,10 @@ function likelyNeedsParallelToolCalls(prompt, needsTools, toolCount, toolNames)
|
|
|
2241
2331
|
}
|
|
2242
2332
|
function classifyTask(prompt, systemPrompt, options) {
|
|
2243
2333
|
const fullText = `${systemPrompt ?? ""} ${prompt}`;
|
|
2244
|
-
const estimatedInputTokens =
|
|
2245
|
-
const
|
|
2246
|
-
const
|
|
2247
|
-
|
|
2248
|
-
const prefixLength = Math.ceil(scanLimit / 2);
|
|
2249
|
-
return `${value.slice(0, prefixLength)}
|
|
2250
|
-
${value.slice(-(scanLimit - prefixLength))}`;
|
|
2251
|
-
};
|
|
2252
|
-
const scannedPrompt = sample(prompt);
|
|
2253
|
-
const scannedSystemPrompt = sample(systemPrompt ?? "");
|
|
2334
|
+
const estimatedInputTokens = estimateTokens(fullText);
|
|
2335
|
+
const limit = scanLimit(options.config.classifier.promptTruncationChars);
|
|
2336
|
+
const scannedPrompt = sampleForScan(prompt, limit);
|
|
2337
|
+
const scannedSystemPrompt = sampleForScan(systemPrompt ?? "", limit);
|
|
2254
2338
|
const scannedFullText = `${scannedSystemPrompt} ${scannedPrompt}`;
|
|
2255
2339
|
const text = scannedPrompt.toLowerCase();
|
|
2256
2340
|
const explicitCodeSignal = /```|\b(?:typescript|javascript|python|rust|java|sql|stack trace|traceback|exception)\b|\.(?:ts|tsx|js|py|go|rs)\b/i.test(
|
|
@@ -2262,7 +2346,9 @@ ${value.slice(-(scanLimit - prefixLength))}`;
|
|
|
2262
2346
|
const nativeCodeSignal = /\b(?:programmed|written|implemented?|code)\s+(?:in|using)\s+(?:c\+\+|c|rust|go)\b/i.test(
|
|
2263
2347
|
scannedPrompt
|
|
2264
2348
|
);
|
|
2265
|
-
const
|
|
2349
|
+
const errorClassSignal = /\b[A-Z][A-Za-z]*(?:Error|Exception)\b/.test(scannedPrompt);
|
|
2350
|
+
const hasCode = explicitCodeSignal || codeConstructSignal || nativeCodeSignal || errorClassSignal;
|
|
2351
|
+
const codeArtifact = /```|\b(?:stack trace|traceback)\b|\.(?:ts|tsx|js|py|go|rs)\b/i.test(scannedPrompt) || codeConstructSignal || nativeCodeSignal || errorClassSignal;
|
|
2266
2352
|
const toolsAvailable = options.hasTools ?? false;
|
|
2267
2353
|
const needsTools = options.requiresTools ?? (toolsAvailable && inferToolRequirement(scannedPrompt, scannedSystemPrompt));
|
|
2268
2354
|
const likelyParallelToolCalls = likelyNeedsParallelToolCalls(
|
|
@@ -2334,10 +2420,10 @@ ${value.slice(-(scanLimit - prefixLength))}`;
|
|
|
2334
2420
|
const needsVision = options.hasVision ?? false;
|
|
2335
2421
|
const needsStructuredOutput = options.requiresStructuredOutput ?? false;
|
|
2336
2422
|
const latencySensitive = /\b(?:urgent|asap|fast|quick|low latency|real[- ]time)\b|尽快|马上|快速|低延迟/i.test(
|
|
2337
|
-
|
|
2423
|
+
scannedPrompt
|
|
2338
2424
|
);
|
|
2339
2425
|
const highStakes = /\b(?:production|security|payment|legal|medical|financial|audit)\b|生产|安全|支付|法律|医疗|财务|审计/i.test(
|
|
2340
|
-
|
|
2426
|
+
scannedPrompt
|
|
2341
2427
|
);
|
|
2342
2428
|
const terminalToolSignal = normalizedToolNames.some(
|
|
2343
2429
|
(name) => /^(?:terminalexec|terminalinspect|terminalsendkeys)$/.test(name)
|
|
@@ -2373,7 +2459,7 @@ ${value.slice(-(scanLimit - prefixLength))}`;
|
|
|
2373
2459
|
);
|
|
2374
2460
|
const terminalSafetySensitive = terminalToolSignal && (highStakes || terminalCredentialSignal);
|
|
2375
2461
|
const implicitTerminalCode = needsTools && terminalToolSignal && agentRisk === "standard" && !highStakes && !complexTerminalOperation && numberedSteps < 3 && prompt.length <= 1e3 && simpleTerminalArtifact;
|
|
2376
|
-
const language = /[\u3400-\u9fff]/.test(
|
|
2462
|
+
const language = /[\u3400-\u9fff]/.test(scannedPrompt) ? "zh" : "other";
|
|
2377
2463
|
const multipleChoiceSignals = (scannedPrompt.match(/(?:^|\n)\s*[A-D][.)]\s+/gim) ?? []).length;
|
|
2378
2464
|
const numericSignals = (scannedPrompt.match(/-?\d+(?:[.,]\d+)?/g) ?? []).length;
|
|
2379
2465
|
const compactMathProblem = !hasCode && prompt.length < 2500 && numericSignals >= 2 && (/[+×÷=%$€£¥]|\b(?:total|each|per|times|half|twice|percent|how many|how much|calculate)\b/i.test(
|
|
@@ -2388,7 +2474,7 @@ ${value.slice(-(scanLimit - prefixLength))}`;
|
|
|
2388
2474
|
else if (needsTools) taskType = "tool_agent";
|
|
2389
2475
|
else if (multipleChoiceSignals >= 3) taskType = "reasoning_mcq";
|
|
2390
2476
|
else if (compactMathProblem) taskType = "reasoning_math";
|
|
2391
|
-
else if (/\b(?:bug|debug|error|failure|failing|regression|crash|修复|报错|错误|调试)\b/i.test(text))
|
|
2477
|
+
else if (errorClassSignal || /\b(?:bug|debug|error|failure|failing|regression|crash|修复|报错|错误|调试)\b/i.test(text))
|
|
2392
2478
|
taskType = "debug";
|
|
2393
2479
|
else if (hasCode || /\b(?:refactor|implement|patch|edit|rewrite|重构|实现|修改)\b/i.test(text))
|
|
2394
2480
|
taskType = "code_edit";
|
|
@@ -2414,7 +2500,8 @@ ${value.slice(-(scanLimit - prefixLength))}`;
|
|
|
2414
2500
|
agentRisk,
|
|
2415
2501
|
terminalToolSignal,
|
|
2416
2502
|
terminalSafetySensitive,
|
|
2417
|
-
implicitTerminalCode
|
|
2503
|
+
implicitTerminalCode,
|
|
2504
|
+
codeArtifact
|
|
2418
2505
|
};
|
|
2419
2506
|
}
|
|
2420
2507
|
function affinity(modelId, task, language = "other", agentDomain = "other", deepWebResearch = false, agentRisk = "standard", terminalToolSignal = false, terminalSafetySensitive = false) {
|
|
@@ -2817,15 +2904,17 @@ function profileScore(modelId, options, now) {
|
|
|
2817
2904
|
}
|
|
2818
2905
|
var PortfolioStrategy = class {
|
|
2819
2906
|
name = "portfolio";
|
|
2907
|
+
// Rules set the capability tier; the strategy is stateless, so one instance serves every request.
|
|
2908
|
+
rules = new RulesStrategy();
|
|
2820
2909
|
route(prompt, systemPrompt, maxOutputTokens, options) {
|
|
2821
2910
|
const features = classifyTask(prompt, systemPrompt, options);
|
|
2822
|
-
const base =
|
|
2911
|
+
const base = this.rules.route(prompt, systemPrompt, maxOutputTokens, {
|
|
2823
2912
|
...options,
|
|
2824
2913
|
requiresTools: features.needsTools
|
|
2825
2914
|
});
|
|
2826
2915
|
const tierConfigs = base.tierConfigs;
|
|
2827
2916
|
if (!tierConfigs) return base;
|
|
2828
|
-
const targetTier = (features.taskType === "reasoning_mcq" || features.taskType === "reasoning_math") && (base.tier === "SIMPLE" || base.tier === "MEDIUM") ? "REASONING" : base.tier;
|
|
2917
|
+
const targetTier = (features.taskType === "reasoning_mcq" || features.taskType === "reasoning_math") && (base.tier === "SIMPLE" || base.tier === "MEDIUM") ? "REASONING" : (features.taskType === "debug" || features.taskType === "code_edit") && features.codeArtifact && base.tier === "SIMPLE" ? "MEDIUM" : base.tier;
|
|
2829
2918
|
const tierConfig = tierConfigs[targetTier];
|
|
2830
2919
|
const configuredCandidates = tierConfig ? getFallbackChain(targetTier, tierConfigs) : [];
|
|
2831
2920
|
const unavailable = new Set(options.unavailableModels ?? []);
|
|
@@ -2843,10 +2932,10 @@ var PortfolioStrategy = class {
|
|
|
2843
2932
|
].filter(
|
|
2844
2933
|
(model2) => typeof model2 === "string" && model2.length > 0 && !unavailable.has(model2)
|
|
2845
2934
|
);
|
|
2846
|
-
const eligible =
|
|
2847
|
-
(model2) => isEligible(model2, features, maxOutputTokens, options)
|
|
2935
|
+
const eligible = new Set(
|
|
2936
|
+
chain.filter((model2) => isEligible(model2, features, maxOutputTokens, options))
|
|
2848
2937
|
);
|
|
2849
|
-
const eligibleCandidates = eligible.
|
|
2938
|
+
const eligibleCandidates = eligible.size > 0 ? [...eligible] : chain;
|
|
2850
2939
|
if (eligibleCandidates.length === 0) return base;
|
|
2851
2940
|
const profileName = options.routingProfile === "eco" ? "eco" : options.routingProfile === "premium" ? "premium" : "auto";
|
|
2852
2941
|
const portfolio = options.config.portfolio ?? DEFAULT_PORTFOLIO_WEIGHTS;
|
|
@@ -2881,11 +2970,11 @@ var PortfolioStrategy = class {
|
|
|
2881
2970
|
const rankedEntries = candidates.map((model2, index) => {
|
|
2882
2971
|
const cost = estimatedCost(model2, options, features.estimatedInputTokens, maxOutputTokens);
|
|
2883
2972
|
const costScore = Number.isFinite(cost) && maxCost > minCost ? 1 - (cost - minCost) / (maxCost - minCost) : 0.5;
|
|
2884
|
-
const capabilityScore =
|
|
2973
|
+
const capabilityScore = eligible.has(model2) ? 1 : 0;
|
|
2885
2974
|
const profile = profileScore(model2, options, now);
|
|
2886
2975
|
const observedQuality = profile?.quality === void 0 ? getAffinity(model2) : getAffinity(model2) * (1 - profile.freshness) + profile.quality * profile.freshness;
|
|
2887
|
-
const observedSpeed = profile ? profile.speed * profile.freshness : 0.5;
|
|
2888
|
-
const observedTailSpeed = profile ? profile.tailSpeed * profile.freshness : 0.5;
|
|
2976
|
+
const observedSpeed = profile ? profile.speed * profile.freshness + 0.5 * (1 - profile.freshness) : 0.5;
|
|
2977
|
+
const observedTailSpeed = profile ? profile.tailSpeed * profile.freshness + 0.5 * (1 - profile.freshness) : 0.5;
|
|
2889
2978
|
const observedReliability = profile ? profile.reliability * profile.freshness + (1 - profile.freshness) : 1;
|
|
2890
2979
|
const legacyScore = 1 - index / Math.max(1, candidates.length - 1);
|
|
2891
2980
|
const qualityWeight = profileWeights.quality + (features.highStakes ? portfolio.highStakesBoost.quality : 0);
|
|
@@ -4977,7 +5066,7 @@ function getCostSummary() {
|
|
|
4977
5066
|
}
|
|
4978
5067
|
|
|
4979
5068
|
// src/version.ts
|
|
4980
|
-
var SDK_VERSION = "3.24.
|
|
5069
|
+
var SDK_VERSION = "3.24.3";
|
|
4981
5070
|
var USER_AGENT = `blockrun-ts/${SDK_VERSION}`;
|
|
4982
5071
|
|
|
4983
5072
|
// src/client.ts
|
package/dist/index.js
CHANGED
|
@@ -440,7 +440,69 @@ function withCost(body, response, bookedUsd, scheme) {
|
|
|
440
440
|
// src/client.ts
|
|
441
441
|
import { privateKeyToAccount } from "viem/accounts";
|
|
442
442
|
|
|
443
|
-
// node_modules/.pnpm/@blockrun+router-core@https+++codeload.github.com+BlockRunAI+router-core+tar.gz+
|
|
443
|
+
// node_modules/.pnpm/@blockrun+router-core@https+++codeload.github.com+BlockRunAI+router-core+tar.gz+2cd5a1026f755_easf3bov3hzdfoup33nwewqudy/node_modules/@blockrun/router-core/dist/index.js
|
|
444
|
+
var UNSEGMENTED_SCRIPT = /[-ۿ -ヿ㐀-䶿一-鿿가-豈--]/;
|
|
445
|
+
var WORD_CHAR = /[\p{L}\p{N}]/u;
|
|
446
|
+
var ASCII_PHRASE = /^[a-z0-9' -]+$/;
|
|
447
|
+
var SEGMENTED_WORD_CHAR = "\\p{Script=Latin}\\p{Script=Cyrillic}\\p{Script=Greek}\\p{N}";
|
|
448
|
+
var BOUNDARY_BEFORE = `(?<![${SEGMENTED_WORD_CHAR}])`;
|
|
449
|
+
var BOUNDARY_AFTER = `(?![${SEGMENTED_WORD_CHAR}])`;
|
|
450
|
+
var BOUNDED_LAST_WORD_LENGTH = 6;
|
|
451
|
+
var SHORT_SUFFIXES = "(?:s|ed|ing)?";
|
|
452
|
+
var SIBILANT_PLURAL = "es";
|
|
453
|
+
var MID_SUFFIXES = "(?:s|es|ed|d|ing|er|ers|ly|ment|ments|ation|ations|e|en|n|a|as|o|os|em|et|ung|ungen)?";
|
|
454
|
+
var DROPPED_E_SUFFIXES = "(?:ing|ed|es|er|ers|ation|ations)";
|
|
455
|
+
var DOUBLED_CONSONANT_SUFFIXES = "(?:ing|ed|er|ers)";
|
|
456
|
+
var matcherCache = /* @__PURE__ */ new Map();
|
|
457
|
+
function escapeRegExp(value) {
|
|
458
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
459
|
+
}
|
|
460
|
+
function keywordMatcher(keyword) {
|
|
461
|
+
const cached = matcherCache.get(keyword);
|
|
462
|
+
if (cached) return cached;
|
|
463
|
+
const kw = keyword.toLowerCase();
|
|
464
|
+
let matcher;
|
|
465
|
+
if (UNSEGMENTED_SCRIPT.test(kw) || kw.length === 0) {
|
|
466
|
+
matcher = { needle: kw, pattern: null };
|
|
467
|
+
} else {
|
|
468
|
+
const lead = WORD_CHAR.test(kw[0]) ? BOUNDARY_BEFORE : "";
|
|
469
|
+
const escaped = escapeRegExp(kw);
|
|
470
|
+
let body = escaped;
|
|
471
|
+
let trail = "";
|
|
472
|
+
let needle = kw;
|
|
473
|
+
const lastWord = kw.slice(kw.lastIndexOf(" ") + 1);
|
|
474
|
+
if (WORD_CHAR.test(kw[kw.length - 1]) && ASCII_PHRASE.test(kw) && lastWord.length <= BOUNDED_LAST_WORD_LENGTH) {
|
|
475
|
+
const forms = [];
|
|
476
|
+
if (/\d$/.test(kw)) {
|
|
477
|
+
forms.push(escaped);
|
|
478
|
+
} else if (lastWord.length <= 3) {
|
|
479
|
+
forms.push(`${escaped}${SHORT_SUFFIXES}`);
|
|
480
|
+
if (/(?:x|s|z|ch|sh)$/.test(kw)) forms.push(`${escaped}${SIBILANT_PLURAL}`);
|
|
481
|
+
} else {
|
|
482
|
+
forms.push(`${escaped}${MID_SUFFIXES}`);
|
|
483
|
+
if (kw.endsWith("e")) {
|
|
484
|
+
forms.push(`${escaped.slice(0, -1)}${DROPPED_E_SUFFIXES}`);
|
|
485
|
+
needle = kw.slice(0, -1);
|
|
486
|
+
} else if (kw.endsWith("y")) {
|
|
487
|
+
forms.push(`${escaped.slice(0, -1)}(?:ies|ied)`);
|
|
488
|
+
needle = kw.slice(0, -1);
|
|
489
|
+
} else if (/[aeiou][bdgmnprt]$/.test(kw)) {
|
|
490
|
+
forms.push(`${escaped}${kw[kw.length - 1]}${DOUBLED_CONSONANT_SUFFIXES}`);
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
body = `(?:${forms.join("|")})`;
|
|
494
|
+
trail = BOUNDARY_AFTER;
|
|
495
|
+
}
|
|
496
|
+
matcher = { needle, pattern: new RegExp(`${lead}${body}${trail}`, "u") };
|
|
497
|
+
}
|
|
498
|
+
matcherCache.set(keyword, matcher);
|
|
499
|
+
return matcher;
|
|
500
|
+
}
|
|
501
|
+
function matchesKeyword(text, keyword) {
|
|
502
|
+
const { needle, pattern } = keywordMatcher(keyword);
|
|
503
|
+
if (!text.includes(needle)) return false;
|
|
504
|
+
return pattern === null ? true : pattern.test(text);
|
|
505
|
+
}
|
|
444
506
|
function scoreTokenCount(estimatedTokens, thresholds) {
|
|
445
507
|
if (estimatedTokens < thresholds.simple) {
|
|
446
508
|
return { name: "tokenCount", score: -1, signal: `short (${estimatedTokens} tokens)` };
|
|
@@ -451,7 +513,7 @@ function scoreTokenCount(estimatedTokens, thresholds) {
|
|
|
451
513
|
return { name: "tokenCount", score: 0, signal: null };
|
|
452
514
|
}
|
|
453
515
|
function scoreKeywordMatch(text, keywords, name, signalLabel, thresholds, scores) {
|
|
454
|
-
const matches = keywords.filter((kw) => text
|
|
516
|
+
const matches = keywords.filter((kw) => matchesKeyword(text, kw));
|
|
455
517
|
if (matches.length >= thresholds.high) {
|
|
456
518
|
return {
|
|
457
519
|
name,
|
|
@@ -487,7 +549,7 @@ function scoreAgenticTask(text, keywords) {
|
|
|
487
549
|
let matchCount = 0;
|
|
488
550
|
const signals = [];
|
|
489
551
|
for (const keyword of keywords) {
|
|
490
|
-
if (text
|
|
552
|
+
if (matchesKeyword(text, keyword)) {
|
|
491
553
|
matchCount++;
|
|
492
554
|
if (signals.length < 3) {
|
|
493
555
|
signals.push(keyword);
|
|
@@ -634,9 +696,7 @@ function classifyByRules(prompt, systemPrompt, estimatedTokens, config) {
|
|
|
634
696
|
const w = weights[d.name] ?? 0;
|
|
635
697
|
weightedScore += d.score * w;
|
|
636
698
|
}
|
|
637
|
-
const reasoningMatches = config.reasoningKeywords.filter(
|
|
638
|
-
(kw) => userText.includes(kw.toLowerCase())
|
|
639
|
-
);
|
|
699
|
+
const reasoningMatches = config.reasoningKeywords.filter((kw) => matchesKeyword(userText, kw));
|
|
640
700
|
if (reasoningMatches.length >= 2) {
|
|
641
701
|
const confidence2 = calibrateConfidence(
|
|
642
702
|
Math.max(weightedScore, 0.3),
|
|
@@ -701,7 +761,7 @@ function selectModel(tier, confidence, method, reasoning, tierConfigs, modelPric
|
|
|
701
761
|
const baselineInput = estimatedInputTokens / 1e6 * opusInputPrice;
|
|
702
762
|
const baselineOutput = maxOutputTokens / 1e6 * opusOutputPrice;
|
|
703
763
|
const baselineCost = baselineInput + baselineOutput;
|
|
704
|
-
const savings = routingProfile === "premium" ? 0 : baselineCost > 0 ? Math.max(0, (baselineCost - costEstimate) / baselineCost) : 0;
|
|
764
|
+
const savings = routingProfile === "premium" || pricing === void 0 ? 0 : baselineCost > 0 ? Math.max(0, (baselineCost - costEstimate) / baselineCost) : 0;
|
|
705
765
|
return {
|
|
706
766
|
model,
|
|
707
767
|
tier,
|
|
@@ -752,6 +812,21 @@ function filterCandidatesByCapacity(models, estimatedInputTokens, requestedOutpu
|
|
|
752
812
|
});
|
|
753
813
|
return filtered;
|
|
754
814
|
}
|
|
815
|
+
var CJK_CHARS = /[ -ヿ㐀-䶿一-鿿가-豈--]/g;
|
|
816
|
+
function estimateTokens(text) {
|
|
817
|
+
if (text.length === 0) return 0;
|
|
818
|
+
const cjk = text.match(CJK_CHARS)?.length ?? 0;
|
|
819
|
+
return cjk + Math.ceil((text.length - cjk) / 4);
|
|
820
|
+
}
|
|
821
|
+
function scanLimit(promptTruncationChars) {
|
|
822
|
+
return Math.max(1, Math.min(8e3, promptTruncationChars));
|
|
823
|
+
}
|
|
824
|
+
function sampleForScan(value, limit) {
|
|
825
|
+
if (value.length <= limit) return value;
|
|
826
|
+
const prefixLength = Math.ceil(limit / 2);
|
|
827
|
+
return `${value.slice(0, prefixLength)}
|
|
828
|
+
${value.slice(-(limit - prefixLength))}`;
|
|
829
|
+
}
|
|
755
830
|
function applyPromotions(tierConfigs, promotions, profile, now = /* @__PURE__ */ new Date()) {
|
|
756
831
|
if (!promotions || promotions.length === 0) return tierConfigs;
|
|
757
832
|
let result = tierConfigs;
|
|
@@ -794,16 +869,10 @@ var RulesStrategy = class {
|
|
|
794
869
|
route(prompt, systemPrompt, maxOutputTokens, options) {
|
|
795
870
|
const { config, modelPricing } = options;
|
|
796
871
|
const fullText = `${systemPrompt ?? ""} ${prompt}`;
|
|
797
|
-
const estimatedTokens =
|
|
798
|
-
const
|
|
799
|
-
const
|
|
800
|
-
|
|
801
|
-
const prefixLength = Math.ceil(scanLimit / 2);
|
|
802
|
-
return `${value.slice(0, prefixLength)}
|
|
803
|
-
${value.slice(-(scanLimit - prefixLength))}`;
|
|
804
|
-
};
|
|
805
|
-
const scannedPrompt = sample(prompt);
|
|
806
|
-
const scannedSystemPrompt = systemPrompt ? sample(systemPrompt) : void 0;
|
|
872
|
+
const estimatedTokens = estimateTokens(fullText);
|
|
873
|
+
const limit = scanLimit(config.classifier.promptTruncationChars);
|
|
874
|
+
const scannedPrompt = sampleForScan(prompt, limit);
|
|
875
|
+
const scannedSystemPrompt = systemPrompt ? sampleForScan(systemPrompt, limit) : void 0;
|
|
807
876
|
const ruleResult = classifyByRules(
|
|
808
877
|
scannedPrompt,
|
|
809
878
|
scannedSystemPrompt,
|
|
@@ -857,7 +926,7 @@ ${value.slice(-(scanLimit - prefixLength))}`;
|
|
|
857
926
|
);
|
|
858
927
|
return { ...decision2, tierConfigs, profile };
|
|
859
928
|
}
|
|
860
|
-
const hasStructuredOutput = options.requiresStructuredOutput === true
|
|
929
|
+
const hasStructuredOutput = options.requiresStructuredOutput === true;
|
|
861
930
|
let tier;
|
|
862
931
|
let confidence;
|
|
863
932
|
const method = "rules";
|
|
@@ -1012,6 +1081,13 @@ var DEFAULT_MODEL_CAPABILITIES = Object.freeze({
|
|
|
1012
1081
|
supportsTools: true,
|
|
1013
1082
|
supportsVision: false
|
|
1014
1083
|
},
|
|
1084
|
+
"deepseek/deepseek-v4.1-flash": {
|
|
1085
|
+
// supportsTools: not probed — fails closed
|
|
1086
|
+
contextWindow: 1048576,
|
|
1087
|
+
maxOutputTokens: 65536,
|
|
1088
|
+
supportsTools: false,
|
|
1089
|
+
supportsVision: false
|
|
1090
|
+
},
|
|
1015
1091
|
"google/gemini-2.5-flash": {
|
|
1016
1092
|
contextWindow: 1048576,
|
|
1017
1093
|
maxOutputTokens: 65536,
|
|
@@ -1084,6 +1160,13 @@ var DEFAULT_MODEL_CAPABILITIES = Object.freeze({
|
|
|
1084
1160
|
supportsTools: true,
|
|
1085
1161
|
supportsVision: false
|
|
1086
1162
|
},
|
|
1163
|
+
"mistral/mistral-large-4": {
|
|
1164
|
+
// supportsTools: not probed — fails closed
|
|
1165
|
+
contextWindow: 524288,
|
|
1166
|
+
maxOutputTokens: 262144,
|
|
1167
|
+
supportsTools: false,
|
|
1168
|
+
supportsVision: true
|
|
1169
|
+
},
|
|
1087
1170
|
"moonshot/kimi-k3": {
|
|
1088
1171
|
contextWindow: 1048576,
|
|
1089
1172
|
maxOutputTokens: 65536,
|
|
@@ -1285,6 +1368,13 @@ var DEFAULT_MODEL_CAPABILITIES = Object.freeze({
|
|
|
1285
1368
|
supportsTools: true,
|
|
1286
1369
|
supportsVision: true
|
|
1287
1370
|
},
|
|
1371
|
+
"openai/gpt-6.1-sol": {
|
|
1372
|
+
// supportsTools: not probed — fails closed
|
|
1373
|
+
contextWindow: 105e4,
|
|
1374
|
+
maxOutputTokens: 128e3,
|
|
1375
|
+
supportsTools: false,
|
|
1376
|
+
supportsVision: true
|
|
1377
|
+
},
|
|
1288
1378
|
"openai/o1": {
|
|
1289
1379
|
contextWindow: 2e5,
|
|
1290
1380
|
maxOutputTokens: 1e5,
|
|
@@ -2110,16 +2200,10 @@ function likelyNeedsParallelToolCalls(prompt, needsTools, toolCount, toolNames)
|
|
|
2110
2200
|
}
|
|
2111
2201
|
function classifyTask(prompt, systemPrompt, options) {
|
|
2112
2202
|
const fullText = `${systemPrompt ?? ""} ${prompt}`;
|
|
2113
|
-
const estimatedInputTokens =
|
|
2114
|
-
const
|
|
2115
|
-
const
|
|
2116
|
-
|
|
2117
|
-
const prefixLength = Math.ceil(scanLimit / 2);
|
|
2118
|
-
return `${value.slice(0, prefixLength)}
|
|
2119
|
-
${value.slice(-(scanLimit - prefixLength))}`;
|
|
2120
|
-
};
|
|
2121
|
-
const scannedPrompt = sample(prompt);
|
|
2122
|
-
const scannedSystemPrompt = sample(systemPrompt ?? "");
|
|
2203
|
+
const estimatedInputTokens = estimateTokens(fullText);
|
|
2204
|
+
const limit = scanLimit(options.config.classifier.promptTruncationChars);
|
|
2205
|
+
const scannedPrompt = sampleForScan(prompt, limit);
|
|
2206
|
+
const scannedSystemPrompt = sampleForScan(systemPrompt ?? "", limit);
|
|
2123
2207
|
const scannedFullText = `${scannedSystemPrompt} ${scannedPrompt}`;
|
|
2124
2208
|
const text = scannedPrompt.toLowerCase();
|
|
2125
2209
|
const explicitCodeSignal = /```|\b(?:typescript|javascript|python|rust|java|sql|stack trace|traceback|exception)\b|\.(?:ts|tsx|js|py|go|rs)\b/i.test(
|
|
@@ -2131,7 +2215,9 @@ ${value.slice(-(scanLimit - prefixLength))}`;
|
|
|
2131
2215
|
const nativeCodeSignal = /\b(?:programmed|written|implemented?|code)\s+(?:in|using)\s+(?:c\+\+|c|rust|go)\b/i.test(
|
|
2132
2216
|
scannedPrompt
|
|
2133
2217
|
);
|
|
2134
|
-
const
|
|
2218
|
+
const errorClassSignal = /\b[A-Z][A-Za-z]*(?:Error|Exception)\b/.test(scannedPrompt);
|
|
2219
|
+
const hasCode = explicitCodeSignal || codeConstructSignal || nativeCodeSignal || errorClassSignal;
|
|
2220
|
+
const codeArtifact = /```|\b(?:stack trace|traceback)\b|\.(?:ts|tsx|js|py|go|rs)\b/i.test(scannedPrompt) || codeConstructSignal || nativeCodeSignal || errorClassSignal;
|
|
2135
2221
|
const toolsAvailable = options.hasTools ?? false;
|
|
2136
2222
|
const needsTools = options.requiresTools ?? (toolsAvailable && inferToolRequirement(scannedPrompt, scannedSystemPrompt));
|
|
2137
2223
|
const likelyParallelToolCalls = likelyNeedsParallelToolCalls(
|
|
@@ -2203,10 +2289,10 @@ ${value.slice(-(scanLimit - prefixLength))}`;
|
|
|
2203
2289
|
const needsVision = options.hasVision ?? false;
|
|
2204
2290
|
const needsStructuredOutput = options.requiresStructuredOutput ?? false;
|
|
2205
2291
|
const latencySensitive = /\b(?:urgent|asap|fast|quick|low latency|real[- ]time)\b|尽快|马上|快速|低延迟/i.test(
|
|
2206
|
-
|
|
2292
|
+
scannedPrompt
|
|
2207
2293
|
);
|
|
2208
2294
|
const highStakes = /\b(?:production|security|payment|legal|medical|financial|audit)\b|生产|安全|支付|法律|医疗|财务|审计/i.test(
|
|
2209
|
-
|
|
2295
|
+
scannedPrompt
|
|
2210
2296
|
);
|
|
2211
2297
|
const terminalToolSignal = normalizedToolNames.some(
|
|
2212
2298
|
(name) => /^(?:terminalexec|terminalinspect|terminalsendkeys)$/.test(name)
|
|
@@ -2242,7 +2328,7 @@ ${value.slice(-(scanLimit - prefixLength))}`;
|
|
|
2242
2328
|
);
|
|
2243
2329
|
const terminalSafetySensitive = terminalToolSignal && (highStakes || terminalCredentialSignal);
|
|
2244
2330
|
const implicitTerminalCode = needsTools && terminalToolSignal && agentRisk === "standard" && !highStakes && !complexTerminalOperation && numberedSteps < 3 && prompt.length <= 1e3 && simpleTerminalArtifact;
|
|
2245
|
-
const language = /[\u3400-\u9fff]/.test(
|
|
2331
|
+
const language = /[\u3400-\u9fff]/.test(scannedPrompt) ? "zh" : "other";
|
|
2246
2332
|
const multipleChoiceSignals = (scannedPrompt.match(/(?:^|\n)\s*[A-D][.)]\s+/gim) ?? []).length;
|
|
2247
2333
|
const numericSignals = (scannedPrompt.match(/-?\d+(?:[.,]\d+)?/g) ?? []).length;
|
|
2248
2334
|
const compactMathProblem = !hasCode && prompt.length < 2500 && numericSignals >= 2 && (/[+×÷=%$€£¥]|\b(?:total|each|per|times|half|twice|percent|how many|how much|calculate)\b/i.test(
|
|
@@ -2257,7 +2343,7 @@ ${value.slice(-(scanLimit - prefixLength))}`;
|
|
|
2257
2343
|
else if (needsTools) taskType = "tool_agent";
|
|
2258
2344
|
else if (multipleChoiceSignals >= 3) taskType = "reasoning_mcq";
|
|
2259
2345
|
else if (compactMathProblem) taskType = "reasoning_math";
|
|
2260
|
-
else if (/\b(?:bug|debug|error|failure|failing|regression|crash|修复|报错|错误|调试)\b/i.test(text))
|
|
2346
|
+
else if (errorClassSignal || /\b(?:bug|debug|error|failure|failing|regression|crash|修复|报错|错误|调试)\b/i.test(text))
|
|
2261
2347
|
taskType = "debug";
|
|
2262
2348
|
else if (hasCode || /\b(?:refactor|implement|patch|edit|rewrite|重构|实现|修改)\b/i.test(text))
|
|
2263
2349
|
taskType = "code_edit";
|
|
@@ -2283,7 +2369,8 @@ ${value.slice(-(scanLimit - prefixLength))}`;
|
|
|
2283
2369
|
agentRisk,
|
|
2284
2370
|
terminalToolSignal,
|
|
2285
2371
|
terminalSafetySensitive,
|
|
2286
|
-
implicitTerminalCode
|
|
2372
|
+
implicitTerminalCode,
|
|
2373
|
+
codeArtifact
|
|
2287
2374
|
};
|
|
2288
2375
|
}
|
|
2289
2376
|
function affinity(modelId, task, language = "other", agentDomain = "other", deepWebResearch = false, agentRisk = "standard", terminalToolSignal = false, terminalSafetySensitive = false) {
|
|
@@ -2686,15 +2773,17 @@ function profileScore(modelId, options, now) {
|
|
|
2686
2773
|
}
|
|
2687
2774
|
var PortfolioStrategy = class {
|
|
2688
2775
|
name = "portfolio";
|
|
2776
|
+
// Rules set the capability tier; the strategy is stateless, so one instance serves every request.
|
|
2777
|
+
rules = new RulesStrategy();
|
|
2689
2778
|
route(prompt, systemPrompt, maxOutputTokens, options) {
|
|
2690
2779
|
const features = classifyTask(prompt, systemPrompt, options);
|
|
2691
|
-
const base =
|
|
2780
|
+
const base = this.rules.route(prompt, systemPrompt, maxOutputTokens, {
|
|
2692
2781
|
...options,
|
|
2693
2782
|
requiresTools: features.needsTools
|
|
2694
2783
|
});
|
|
2695
2784
|
const tierConfigs = base.tierConfigs;
|
|
2696
2785
|
if (!tierConfigs) return base;
|
|
2697
|
-
const targetTier = (features.taskType === "reasoning_mcq" || features.taskType === "reasoning_math") && (base.tier === "SIMPLE" || base.tier === "MEDIUM") ? "REASONING" : base.tier;
|
|
2786
|
+
const targetTier = (features.taskType === "reasoning_mcq" || features.taskType === "reasoning_math") && (base.tier === "SIMPLE" || base.tier === "MEDIUM") ? "REASONING" : (features.taskType === "debug" || features.taskType === "code_edit") && features.codeArtifact && base.tier === "SIMPLE" ? "MEDIUM" : base.tier;
|
|
2698
2787
|
const tierConfig = tierConfigs[targetTier];
|
|
2699
2788
|
const configuredCandidates = tierConfig ? getFallbackChain(targetTier, tierConfigs) : [];
|
|
2700
2789
|
const unavailable = new Set(options.unavailableModels ?? []);
|
|
@@ -2712,10 +2801,10 @@ var PortfolioStrategy = class {
|
|
|
2712
2801
|
].filter(
|
|
2713
2802
|
(model2) => typeof model2 === "string" && model2.length > 0 && !unavailable.has(model2)
|
|
2714
2803
|
);
|
|
2715
|
-
const eligible =
|
|
2716
|
-
(model2) => isEligible(model2, features, maxOutputTokens, options)
|
|
2804
|
+
const eligible = new Set(
|
|
2805
|
+
chain.filter((model2) => isEligible(model2, features, maxOutputTokens, options))
|
|
2717
2806
|
);
|
|
2718
|
-
const eligibleCandidates = eligible.
|
|
2807
|
+
const eligibleCandidates = eligible.size > 0 ? [...eligible] : chain;
|
|
2719
2808
|
if (eligibleCandidates.length === 0) return base;
|
|
2720
2809
|
const profileName = options.routingProfile === "eco" ? "eco" : options.routingProfile === "premium" ? "premium" : "auto";
|
|
2721
2810
|
const portfolio = options.config.portfolio ?? DEFAULT_PORTFOLIO_WEIGHTS;
|
|
@@ -2750,11 +2839,11 @@ var PortfolioStrategy = class {
|
|
|
2750
2839
|
const rankedEntries = candidates.map((model2, index) => {
|
|
2751
2840
|
const cost = estimatedCost(model2, options, features.estimatedInputTokens, maxOutputTokens);
|
|
2752
2841
|
const costScore = Number.isFinite(cost) && maxCost > minCost ? 1 - (cost - minCost) / (maxCost - minCost) : 0.5;
|
|
2753
|
-
const capabilityScore =
|
|
2842
|
+
const capabilityScore = eligible.has(model2) ? 1 : 0;
|
|
2754
2843
|
const profile = profileScore(model2, options, now);
|
|
2755
2844
|
const observedQuality = profile?.quality === void 0 ? getAffinity(model2) : getAffinity(model2) * (1 - profile.freshness) + profile.quality * profile.freshness;
|
|
2756
|
-
const observedSpeed = profile ? profile.speed * profile.freshness : 0.5;
|
|
2757
|
-
const observedTailSpeed = profile ? profile.tailSpeed * profile.freshness : 0.5;
|
|
2845
|
+
const observedSpeed = profile ? profile.speed * profile.freshness + 0.5 * (1 - profile.freshness) : 0.5;
|
|
2846
|
+
const observedTailSpeed = profile ? profile.tailSpeed * profile.freshness + 0.5 * (1 - profile.freshness) : 0.5;
|
|
2758
2847
|
const observedReliability = profile ? profile.reliability * profile.freshness + (1 - profile.freshness) : 1;
|
|
2759
2848
|
const legacyScore = 1 - index / Math.max(1, candidates.length - 1);
|
|
2760
2849
|
const qualityWeight = profileWeights.quality + (features.highStakes ? portfolio.highStakesBoost.quality : 0);
|
|
@@ -4846,7 +4935,7 @@ function getCostSummary() {
|
|
|
4846
4935
|
}
|
|
4847
4936
|
|
|
4848
4937
|
// src/version.ts
|
|
4849
|
-
var SDK_VERSION = "3.24.
|
|
4938
|
+
var SDK_VERSION = "3.24.3";
|
|
4850
4939
|
var USER_AGENT = `blockrun-ts/${SDK_VERSION}`;
|
|
4851
4940
|
|
|
4852
4941
|
// src/client.ts
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@blockrun/llm",
|
|
3
|
-
"version": "3.24.
|
|
3
|
+
"version": "3.24.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "TypeScript SDK for BlockRun - every frontier model behind one OpenAI-compatible client. Pay with a BlockRun API key or per-call in USDC. Smart routing picks the cheapest capable model. No rate limits.",
|
|
6
6
|
"main": "dist/index.cjs",
|
|
@@ -58,7 +58,7 @@
|
|
|
58
58
|
},
|
|
59
59
|
"devDependencies": {
|
|
60
60
|
"@blockrun/core": "^0.1.0",
|
|
61
|
-
"@blockrun/router-core": "https://codeload.github.com/BlockRunAI/router-core/tar.gz/
|
|
61
|
+
"@blockrun/router-core": "https://codeload.github.com/BlockRunAI/router-core/tar.gz/2cd5a1026f755cd39a3f0d6e61cab23a5ad391a9",
|
|
62
62
|
"@eslint/js": "^10.0.1",
|
|
63
63
|
"@solana/kit": "^5.5.1",
|
|
64
64
|
"@types/node": "^26.4.1",
|