@blockrun/clawrouter 0.12.241 → 0.12.242

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 CHANGED
@@ -33163,7 +33163,7 @@ var init_esm5 = __esm({
33163
33163
  }
33164
33164
  });
33165
33165
 
33166
- // src/router/rules.ts
33166
+ // node_modules/@blockrun/router-core/dist/index.js
33167
33167
  function scoreTokenCount(estimatedTokens, thresholds) {
33168
33168
  if (estimatedTokens < thresholds.simple) {
33169
33169
  return { name: "tokenCount", score: -1, signal: `short (${estimatedTokens} tokens)` };
@@ -33403,13 +33403,6 @@ function classifyByRules(prompt, systemPrompt, estimatedTokens, config) {
33403
33403
  function calibrateConfidence(distance, steepness) {
33404
33404
  return 1 / (1 + Math.exp(-steepness * distance));
33405
33405
  }
33406
- var init_rules = __esm({
33407
- "src/router/rules.ts"() {
33408
- "use strict";
33409
- }
33410
- });
33411
-
33412
- // src/router/selector.ts
33413
33406
  function selectModel(tier, confidence, method, reasoning, tierConfigs, modelPricing, estimatedInputTokens, maxOutputTokens, routingProfile, agenticScore) {
33414
33407
  const tierConfig = tierConfigs[tier];
33415
33408
  const model = tierConfig.primary;
@@ -33498,19 +33491,14 @@ function getFallbackChainFiltered(tier, tierConfigs, estimatedTotalTokens, getCo
33498
33491
  }
33499
33492
  return filtered;
33500
33493
  }
33501
- var BASELINE_MODEL_ID, BASELINE_INPUT_PRICE, BASELINE_OUTPUT_PRICE, SERVER_MARGIN_PERCENT, MIN_PAYMENT_USD;
33502
- var init_selector = __esm({
33503
- "src/router/selector.ts"() {
33504
- "use strict";
33505
- BASELINE_MODEL_ID = "anthropic/claude-opus-4.7";
33506
- BASELINE_INPUT_PRICE = 5;
33507
- BASELINE_OUTPUT_PRICE = 25;
33508
- SERVER_MARGIN_PERCENT = 5;
33509
- MIN_PAYMENT_USD = 1e-3;
33510
- }
33511
- });
33512
-
33513
- // src/router/strategy.ts
33494
+ function filterCandidatesByCapacity(models, estimatedInputTokens, requestedOutputTokens, getCapabilities2) {
33495
+ const filtered = models.filter((modelId) => {
33496
+ const capabilities = getCapabilities2(modelId);
33497
+ if (!capabilities) return true;
33498
+ return capabilities.contextWindow >= (estimatedInputTokens + requestedOutputTokens) * 1.1 && capabilities.maxOutput >= requestedOutputTokens;
33499
+ });
33500
+ return filtered;
33501
+ }
33514
33502
  function applyPromotions(tierConfigs, promotions, profile, now2 = /* @__PURE__ */ new Date()) {
33515
33503
  if (!promotions || promotions.length === 0) return tierConfigs;
33516
33504
  let result = tierConfigs;
@@ -33540,19 +33528,666 @@ function getStrategy(name) {
33540
33528
  }
33541
33529
  return strategy;
33542
33530
  }
33543
- var RulesStrategy, registry;
33544
- var init_strategy = __esm({
33545
- "src/router/strategy.ts"() {
33531
+ function registerStrategy(strategy) {
33532
+ registry.set(strategy.name, strategy);
33533
+ }
33534
+ function inferToolRequirement(prompt, _systemPrompt, toolChoice) {
33535
+ if (toolChoice === "none") return false;
33536
+ if (toolChoice === "required") return true;
33537
+ if (typeof toolChoice === "object" && toolChoice !== null && toolChoice.type === "function") {
33538
+ return true;
33539
+ }
33540
+ const text = prompt;
33541
+ const explicitTool = /\b(?:use|call|invoke)\s+(?:the\s+)?[\w.-]+\s+(?:tool|function|api)\b|\btool[_ -]?call\b|使用.{0,20}(?:工具|函数|接口)|调用.{0,20}(?:工具|函数|接口)/i;
33542
+ const codeEnvironment = /\b(?:run|execute)\s+(?:the\s+)?(?:tests?|command|script|build|linter)|\b(?:edit|modify|patch|create|write|save|delete|rename|move|inspect|read)\b.{0,60}\b(?:file|repository|repo|codebase|directory|folder)\b|\b(?:terminal|shell|bash|zsh|pytest|npm test|pnpm test|git\s+(?:status|diff|commit)|docker)\b|(?:运行|执行).{0,20}(?:测试|命令|脚本|构建)|(?:修改|编辑|修复|创建|读取|检查|保存).{0,30}(?:文件|仓库|代码库|目录)/i;
33543
+ const webAction = /\b(?:browse|search|look up|fetch|open)\b.{0,80}\b(?:web|website|url|online|documentation|docs|news|weather|price)\b|(?:浏览|搜索|查询|打开).{0,30}(?:网页|网站|链接|文档|新闻|天气|价格)/i;
33544
+ const statefulAction = /\b(?:refund|cancel|book|reserve|purchase|buy|return|exchange|transfer|update|change)\b.{0,80}\b(?:order|booking|reservation|account|address|payment|subscription|ticket|flight|item)\b|(?:退款|取消|预订|购买|退货|换货|转账|更新|修改).{0,30}(?:订单|预订|账户|地址|付款|订阅|票|航班|商品)/i;
33545
+ return explicitTool.test(text) || codeEnvironment.test(text) || webAction.test(text) || statefulAction.test(text);
33546
+ }
33547
+ function likelyNeedsParallelToolCalls(prompt, needsTools, toolCount, toolNames) {
33548
+ if (!needsTools || toolCount === void 0 || toolCount < 1) return false;
33549
+ const text = prompt.trim();
33550
+ const explicitRepeat = /\b(?:in parallel|simultaneously|concurrently|for each|each of|every one|both|(?:two|three|multiple|several)\s+(?:cities|locations|items|tasks|orders|users|files))\b|并行|同时|分别|每个|各自|(?:两个|三个|多个)(?:城市|地点|项目|任务|订单|用户|文件)|cada uno|para cada|simult[aá]neamente/i.test(
33551
+ text
33552
+ );
33553
+ if (explicitRepeat) return true;
33554
+ const sentenceClauses = text.split(/[.!?。!?]+/).map((part) => part.trim()).filter((part) => part.length >= 8);
33555
+ if (/\b(?:also|additionally|furthermore)\b|另外|此外|그리고/i.test(text) && sentenceClauses.length >= 2 || /\band\s+(?:also|for the)\b/i.test(text))
33556
+ return true;
33557
+ const pairedQuantity = /\b\d+(?:\.\d+)?\s+(?:and|or)\s+\d+(?:\.\d+)?\s*(?:gb|mb|tb|kg|g|ml|oz|cups?|cores?|cpus?)\b/i.test(
33558
+ text
33559
+ );
33560
+ if (pairedQuantity) return true;
33561
+ const operationTokens = /* @__PURE__ */ new Set([
33562
+ "add",
33563
+ "delete",
33564
+ "remove",
33565
+ "cancel",
33566
+ "return",
33567
+ "exchange",
33568
+ "modify",
33569
+ "book",
33570
+ "transfer",
33571
+ "send",
33572
+ "upload",
33573
+ "download",
33574
+ "create",
33575
+ "close"
33576
+ ]);
33577
+ const lowered = text.toLowerCase();
33578
+ const matchedOperationTokens = new Set(
33579
+ (toolNames ?? []).flatMap((name) => name.toLowerCase().split(/[^a-z0-9\u3400-\u9fff]+/)).filter((token) => operationTokens.has(token) && lowered.includes(token))
33580
+ );
33581
+ if (matchedOperationTokens.size >= 2) return true;
33582
+ const nonEmptyLines = text.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
33583
+ const quantityMentions = text.match(
33584
+ /\b(?:\d+(?:\.\d+)?|one|two|three|four|five|six|seven|eight|nine|ten)\s*(?:oz|ounce|ounces|g|gram|grams|kg|ml|cups?|pieces?|tablespoons?)\b/gi
33585
+ ) ?? [];
33586
+ if (nonEmptyLines.length >= 2 && quantityMentions.length >= 2) return true;
33587
+ const repeatedLookup = /\b(?:weather|climate|clima|tiempo|temperature|snow|news|report)\b|天气|气象|温度|降雪|新闻|报告/i.test(
33588
+ text
33589
+ );
33590
+ const multiLocationConnector = /\b(?:and also|both|y|e)\b|还有|以及|和|、/i.test(text);
33591
+ const commaSeparatedLocations = (text.match(/[,,]/g) ?? []).length >= 2;
33592
+ if (repeatedLookup && (multiLocationConnector || commaSeparatedLocations)) return true;
33593
+ const distinctOrderParts = /\b(?:food|meal)\b[\s\S]*\bdrink\b|\bdrink\b[\s\S]*\b(?:food|meal)\b/i.test(text);
33594
+ const koreanParallelClauses = (text.match(/,/g) ?? []).length >= 3 && /하고|그리고/.test(text);
33595
+ return distinctOrderParts || koreanParallelClauses;
33596
+ }
33597
+ function classifyTask(prompt, systemPrompt, options) {
33598
+ const fullText = `${systemPrompt ?? ""} ${prompt}`;
33599
+ const estimatedInputTokens = Math.ceil(fullText.length / 4);
33600
+ const scanLimit = Math.max(1, Math.min(8e3, options.config.classifier.promptTruncationChars));
33601
+ const sample = (value) => {
33602
+ if (value.length <= scanLimit) return value;
33603
+ const prefixLength = Math.ceil(scanLimit / 2);
33604
+ return `${value.slice(0, prefixLength)}
33605
+ ${value.slice(-(scanLimit - prefixLength))}`;
33606
+ };
33607
+ const scannedPrompt = sample(prompt);
33608
+ const scannedSystemPrompt = sample(systemPrompt ?? "");
33609
+ const scannedFullText = `${scannedSystemPrompt} ${scannedPrompt}`;
33610
+ const text = scannedPrompt.toLowerCase();
33611
+ const explicitCodeSignal = /```|\b(?:typescript|javascript|python|rust|java|sql|stack trace|traceback|exception)\b|\.(?:ts|tsx|js|py|go|rs)\b/i.test(
33612
+ scannedPrompt
33613
+ );
33614
+ const codeConstructSignal = /\b(?:implement|refactor|debug|write|edit|modify|create|define|review|fix)\b[\s\S]{0,48}\b(?:api|function|class|method)\b|\b(?:api|function|class|method)\b[\s\S]{0,48}\b(?:code|implementation|typescript|javascript|python|rust|java)\b/i.test(
33615
+ scannedPrompt
33616
+ );
33617
+ const nativeCodeSignal = /\b(?:programmed|written|implemented?|code)\s+(?:in|using)\s+(?:c\+\+|c|rust|go)\b/i.test(
33618
+ scannedPrompt
33619
+ );
33620
+ const hasCode = explicitCodeSignal || codeConstructSignal || nativeCodeSignal;
33621
+ const toolsAvailable = options.hasTools ?? false;
33622
+ const needsTools = options.requiresTools ?? (toolsAvailable && inferToolRequirement(scannedPrompt, scannedSystemPrompt));
33623
+ const likelyParallelToolCalls = likelyNeedsParallelToolCalls(
33624
+ scannedPrompt,
33625
+ needsTools,
33626
+ options.toolCount,
33627
+ options.toolNames
33628
+ );
33629
+ const normalizedToolNames = (options.toolNames ?? []).map((name) => name.toLowerCase());
33630
+ const airlineToolSignal = normalizedToolNames.some(
33631
+ (name) => /(?:flight|reservation|airport|baggage|passenger)/.test(name)
33632
+ );
33633
+ const retailToolSignal = normalizedToolNames.some(
33634
+ (name) => /(?:order|product|item|return|exchange|address)/.test(name)
33635
+ );
33636
+ const webResearchToolSignal = normalizedToolNames.some(
33637
+ (name) => /^(?:web_?search|web_?fetch)$/.test(name)
33638
+ );
33639
+ const agentDomain = airlineToolSignal && !retailToolSignal ? "airline" : retailToolSignal && !airlineToolSignal ? "retail" : webResearchToolSignal ? "web_research" : "other";
33640
+ const clueConnectors = scannedFullText.match(
33641
+ /\b(?:after|before|while|where|whose|which|in \d{4}|as of|over \d+|another|also|furthermore)\b|(?:之后|之前|其中|截至|超过|另一个|此外)/gi
33642
+ ) ?? [];
33643
+ const entityResolutionSignal = /\b(?:identify|who (?:is|was)|what (?:is|was) the name|which (?:person|player|company|country|city)|find the (?:person|player|name|entity))\b|(?:找出|识别|是谁|哪位|名称是什么)/i.test(
33644
+ scannedFullText
33645
+ );
33646
+ const exactAnswerSignal = /\b(?:exact answer|single best-supported answer|following clues|multiple public sources)\b|(?:精确答案|根据.*线索|多个公开来源)/i.test(
33647
+ scannedFullText
33648
+ );
33649
+ const deepWebResearch = agentDomain === "web_research" && (exactAnswerSignal || entityResolutionSignal && (clueConnectors.length >= 3 || prompt.length >= 320));
33650
+ const globalOptimizationSignal = /\b(?:cheapest|lowest[- ]price|least expensive|most expensive|highest(?:[- ]priced)?|largest|smallest|maximum|minimum|best available|closest|not (?:cost|exceed))\b|最便宜|最低价|最贵|最高价|最大|最小/i.test(
33651
+ scannedPrompt
33652
+ );
33653
+ const globalScopeSignal = /\b(?:everything|all (?:(?:my|your|their|the) )?(?:future |upcoming )?(?:items|orders|passengers|flights|reservations|bookings)|every (?:item|order|passenger|flight|reservation|booking))\b|全部|所有|每个/i.test(
33654
+ scannedPrompt
33655
+ );
33656
+ const globalChoiceSignal = globalOptimizationSignal || globalScopeSignal;
33657
+ const crossRecordSignal = /\b(?:another|other|different|previous)\s+(?:order|reservation|booking|account|address)\b|另一(?:个)?(?:订单|预订|账户|地址)|其他(?:订单|预订|账户|地址)/i.test(
33658
+ scannedPrompt
33659
+ );
33660
+ const reservationIds = scannedPrompt.match(/\b[A-Z0-9]{6}\b/g) ?? [];
33661
+ const crossReservationBatchSignal = agentDomain === "airline" && (/\b(?:two|three|multiple|several)(?:\s+of\s+(?:my|our|the))?\s+(?:upcoming\s+)?(?:reservations?|bookings?)\b|\b(?:a\s+)?(?:second|third)\s+(?:reservation|booking)\b/i.test(
33662
+ scannedPrompt
33663
+ ) || new Set(reservationIds).size >= 2);
33664
+ const conditionalGlobalWorkflowSignal = agentDomain === "airline" && globalScopeSignal && /\b(?:if|that (?:contain|have)|longer than|shorter than|under|over|at (?:most|least)|wherever possible)\b|如果|超过|少于|不超过|尽可能/i.test(
33665
+ scannedPrompt
33666
+ ) && /\b(?:cancel|change|upgrade|move|book)\b[\s\S]*\b(?:cancel|change|upgrade|move|book)\b|取消[\s\S]*(?:升级|更改)|升级[\s\S]*(?:取消|更改)/i.test(
33667
+ scannedPrompt
33668
+ );
33669
+ const policyExceptionSignal = agentDomain === "retail" && /\b(?:return|refund|send back|get (?:my |the )?money back)\b|退货|退款|退回/i.test(
33670
+ scannedPrompt
33671
+ ) && /\b(?:amex|american express|visa|mastercard|credit card|debit card|different card|another card|other card)\b|信用卡|借记卡|其他卡|另一张卡/i.test(
33672
+ scannedPrompt
33673
+ );
33674
+ const singleSelectedPolicyException = policyExceptionSignal && /\b(?:return|refund|send back)\b[^.!?。!?]{0,96}\b(?:the )?(?:pricier|cheaper|more expensive|less expensive|costlier|one)\b/i.test(
33675
+ scannedPrompt
33676
+ );
33677
+ const negotiatedWorkflowSignal = agentDomain === "retail" && /\b(?:return|exchange)\b|退货|退回|换货|交换/i.test(scannedPrompt);
33678
+ const numberedSteps = (scannedPrompt.match(/(?:^|\s)\d+(?:\.\d+)*[.)]\s+/g) ?? []).length;
33679
+ const complexMultiToolPlan = likelyParallelToolCalls && ((options.toolCount ?? 0) >= 6 || numberedSteps >= 3 || prompt.length > 1200);
33680
+ let agentRisk = needsTools && singleSelectedPolicyException ? "policy_exception_simple" : needsTools && policyExceptionSignal ? "policy_exception" : (
33681
+ // Airline prompts that require a global optimum (for example the
33682
+ // cheapest itinerary across several candidates) are materially harder
33683
+ // than applying one change to every passenger in a known reservation.
33684
+ // Full-session evidence supports Sonnet for the former, while upgrading
33685
+ // the latter merely because it says "all passengers" caused a large cost
33686
+ // increase without a quality gain.
33687
+ needsTools && agentDomain === "airline" && (globalOptimizationSignal || conditionalGlobalWorkflowSignal) ? "complex_high" : needsTools && (likelyParallelToolCalls || globalChoiceSignal || crossRecordSignal || crossReservationBatchSignal || negotiatedWorkflowSignal) ? "high" : "standard"
33688
+ );
33689
+ const needsVision = options.hasVision ?? false;
33690
+ const needsStructuredOutput = options.requiresStructuredOutput ?? false;
33691
+ const latencySensitive = /\b(?:urgent|asap|fast|quick|low latency|real[- ]time)\b|尽快|马上|快速|低延迟/i.test(
33692
+ scannedFullText
33693
+ );
33694
+ const highStakes = /\b(?:production|security|payment|legal|medical|financial|audit)\b|生产|安全|支付|法律|医疗|财务|审计/i.test(
33695
+ scannedFullText
33696
+ );
33697
+ const terminalToolSignal = normalizedToolNames.some(
33698
+ (name) => /^(?:terminalexec|terminalinspect|terminalsendkeys)$/.test(name)
33699
+ );
33700
+ const simpleTerminalArtifact = /\b(?:create|write|convert|generate|build|implement|run|fix|repair|debug|make)\b[\s\S]{0,120}\b(?:file|script|csv|parquet|json|txt|server|endpoint)\b/i.test(
33701
+ scannedPrompt
33702
+ );
33703
+ const terminalComplexRepair = terminalToolSignal && /\b(?:multiple|several)\s+(?:scripts?|files?|components?)\b|\b(?:pipeline|dependencies)\b[\s\S]{0,100}\b(?:fail|issue|fix|repair|run|execute)\b|\b(?:identify|find|fix|repair)\s+(?:and\s+)?(?:fix\s+)?all\s+(?:the\s+)?issues\b/i.test(
33704
+ scannedPrompt
33705
+ );
33706
+ const mentionedTerminalRuntimes = new Set(
33707
+ (scannedPrompt.match(/\b(?:gcc|clang|rustc|javac|go\s+build|node|python)\b/gi) ?? []).map(
33708
+ (name) => name.toLowerCase().replace(/\s+/g, " ")
33709
+ )
33710
+ );
33711
+ const terminalCrossRuntimeArtifact = terminalToolSignal && (/\bpolyglot\b/i.test(scannedPrompt) || /\b(?:both|each)\b[\s\S]{0,120}\b(?:compilers?|runtimes?|toolchains?)\b/i.test(
33712
+ scannedPrompt
33713
+ ) || mentionedTerminalRuntimes.size >= 2 && /\b(?:compile|build|run|execute)\b/i.test(scannedPrompt));
33714
+ const terminalFrameworkToNativeArtifact = terminalToolSignal && /\b(?:pytorch|tensorflow|jax|onnx|state[_ -]?dict|checkpoint|safetensors?)\b|\.(?:pth|pt|onnx)\b/i.test(
33715
+ scannedPrompt
33716
+ ) && /\b(?:pure|native|programmed|written|implemented?)\s+(?:in|using)\s+(?:c\+\+|c|rust|go)\b|\b(?:c\+\+|c|rust|go)\s+(?:program|binary|executable|cli|tool|implementation)\b/i.test(
33717
+ scannedPrompt
33718
+ ) && /\b(?:inference|model|weights?|tensor|export|convert|load)\b/i.test(scannedPrompt);
33719
+ if (needsTools && (terminalComplexRepair || terminalCrossRuntimeArtifact || terminalFrameworkToNativeArtifact) && (agentRisk === "standard" || agentRisk === "high"))
33720
+ agentRisk = "complex_high";
33721
+ const complexTerminalOperation = /\b(?:git|ssh|nginx|https|certificate|authentication|credential|deploy|production|encrypt|gpg|shred|securely delete|decommission|benchmark|evaluate|embedding|chess|image|search the web|schema|statistical|statistics|aggregate|join|multiple inputs?)\b/i.test(
33722
+ scannedPrompt
33723
+ );
33724
+ const terminalCredentialSignal = /\b(?:ssh|nginx|certificate|authentication|credentials?|passwords?|api keys?|deploy|production|encrypt|gpg|shred|securely delete|decommission)\b/i.test(
33725
+ scannedPrompt
33726
+ ) || /\b(?:access|auth|authentication|bearer|secret|api)\s+tokens?\b|\btokens?\s+(?:secret|credential|authentication)\b/i.test(
33727
+ scannedPrompt
33728
+ );
33729
+ const terminalSafetySensitive = terminalToolSignal && (highStakes || terminalCredentialSignal);
33730
+ const implicitTerminalCode = needsTools && terminalToolSignal && agentRisk === "standard" && !highStakes && !complexTerminalOperation && numberedSteps < 3 && prompt.length <= 1e3 && simpleTerminalArtifact;
33731
+ const language = /[\u3400-\u9fff]/.test(scannedFullText) ? "zh" : "other";
33732
+ const multipleChoiceSignals = (scannedPrompt.match(/(?:^|\n)\s*[A-D][.)]\s+/gim) ?? []).length;
33733
+ const numericSignals = (scannedPrompt.match(/-?\d+(?:[.,]\d+)?/g) ?? []).length;
33734
+ const compactMathProblem = !hasCode && prompt.length < 2500 && numericSignals >= 2 && (/[+×÷=%$€£¥]|\b(?:total|each|per|times|half|twice|percent|how many|how much|calculate)\b/i.test(
33735
+ scannedPrompt
33736
+ ) || /[??]\s*$/.test(scannedPrompt.trim()) || numericSignals >= 3);
33737
+ let taskType = "chat";
33738
+ if (needsVision) taskType = "vision";
33739
+ else if (estimatedInputTokens > 8e4) taskType = "long_context";
33740
+ else if (needsTools && (hasCode || implicitTerminalCode)) taskType = "code_agent";
33741
+ else if (needsTools && likelyParallelToolCalls && !complexMultiToolPlan)
33742
+ taskType = "tool_agent_parallel";
33743
+ else if (needsTools) taskType = "tool_agent";
33744
+ else if (multipleChoiceSignals >= 3) taskType = "reasoning_mcq";
33745
+ else if (compactMathProblem) taskType = "reasoning_math";
33746
+ else if (/\b(?:bug|debug|error|failure|failing|regression|crash|修复|报错|错误|调试)\b/i.test(text))
33747
+ taskType = "debug";
33748
+ else if (hasCode || /\b(?:refactor|implement|patch|edit|rewrite|重构|实现|修改)\b/i.test(text))
33749
+ taskType = "code_edit";
33750
+ else if (needsStructuredOutput || /\b(?:extract|json|schema|csv|字段|提取)\b/i.test(text))
33751
+ taskType = "extraction";
33752
+ else if (/\b(?:prove|derive|theorem|formal|mathematical|reasoning|证明|推导|定理|数学)\b/i.test(text))
33753
+ taskType = "reasoning";
33754
+ return {
33755
+ taskType,
33756
+ estimatedInputTokens,
33757
+ hasCode,
33758
+ needsTools,
33759
+ toolsAvailable,
33760
+ needsVision,
33761
+ needsStructuredOutput,
33762
+ latencySensitive,
33763
+ highStakes,
33764
+ language,
33765
+ likelyParallelToolCalls,
33766
+ complexMultiToolPlan,
33767
+ agentDomain,
33768
+ deepWebResearch,
33769
+ agentRisk,
33770
+ terminalToolSignal,
33771
+ terminalSafetySensitive,
33772
+ implicitTerminalCode
33773
+ };
33774
+ }
33775
+ function affinity(modelId, task, language = "other", agentDomain = "other", deepWebResearch = false, agentRisk = "standard", terminalToolSignal = false, terminalSafetySensitive = false) {
33776
+ const id2 = modelId.toLowerCase();
33777
+ const modelName = id2.slice(id2.indexOf("/") + 1);
33778
+ const match = (values, score) => values.some((value) => modelName === value) ? score : 0;
33779
+ const base3 = 0.68;
33780
+ switch (task) {
33781
+ case "code_agent":
33782
+ if (terminalToolSignal && agentRisk === "complex_high") {
33783
+ return Math.max(
33784
+ base3,
33785
+ match(["claude-sonnet-5"], 1),
33786
+ match(["gpt-5.3-codex"], 0.87),
33787
+ match(["gpt-5-mini"], 0.78),
33788
+ match(["gemini-3.5-flash"], 0.76)
33789
+ );
33790
+ }
33791
+ return Math.max(
33792
+ base3,
33793
+ match(["gpt-5.3-codex"], 1),
33794
+ match(["claude-sonnet-5"], 0.98),
33795
+ match(["gpt-5-mini"], 0.96),
33796
+ match(["gemini-3.5-flash"], 0.92),
33797
+ match(["kimi-k3"], 0.9),
33798
+ match(["deepseek-v4-pro", "glm-5.2"], 0.88)
33799
+ );
33800
+ case "tool_agent":
33801
+ if (terminalToolSignal && agentRisk === "complex_high") {
33802
+ return Math.max(
33803
+ base3,
33804
+ match(["claude-sonnet-5"], 1),
33805
+ match(["gpt-5.3-codex"], 0.87),
33806
+ match(["gpt-5-mini"], 0.78),
33807
+ match(["gemini-3.5-flash"], 0.76)
33808
+ );
33809
+ }
33810
+ if (terminalToolSignal && !terminalSafetySensitive) {
33811
+ return Math.max(
33812
+ base3,
33813
+ match(["gpt-5-mini"], 1),
33814
+ match(["gpt-5.3-codex"], 0.98),
33815
+ match(["claude-sonnet-5"], 0.9),
33816
+ match(["gemini-3.5-flash"], 0.89)
33817
+ );
33818
+ }
33819
+ if (terminalToolSignal && terminalSafetySensitive) {
33820
+ return Math.max(
33821
+ base3,
33822
+ match(["claude-sonnet-5"], 1),
33823
+ match(["claude-opus-4.8"], 0.9),
33824
+ match(["gpt-5.3-codex"], 0.84)
33825
+ );
33826
+ }
33827
+ if (agentDomain === "web_research") {
33828
+ return deepWebResearch ? Math.max(
33829
+ base3,
33830
+ match(["claude-sonnet-5"], 1),
33831
+ match(["gpt-5-mini"], 0.88),
33832
+ match(["gemini-3.5-flash"], 0.84),
33833
+ match(["claude-opus-5"], 0.8),
33834
+ match(["claude-opus-4.8"], 0.78)
33835
+ ) : Math.max(
33836
+ base3,
33837
+ match(["claude-sonnet-5"], 1),
33838
+ match(["gpt-5-mini"], 0.88),
33839
+ match(["gemini-3.5-flash"], 0.86),
33840
+ match(["claude-opus-5"], 0.84),
33841
+ match(["claude-opus-4.8"], 0.82)
33842
+ );
33843
+ }
33844
+ if (agentDomain === "retail") {
33845
+ if (agentRisk === "standard") {
33846
+ return Math.max(
33847
+ base3,
33848
+ match(["gpt-5-mini"], 1),
33849
+ match(["claude-sonnet-5"], 0.88),
33850
+ match(["gemini-3.5-flash"], 0.82),
33851
+ match(["gpt-5.3-codex"], 0.81),
33852
+ match(["kimi-k3"], 0.78),
33853
+ match(["deepseek-v4-pro"], 0.76)
33854
+ );
33855
+ }
33856
+ if (agentRisk === "policy_exception") {
33857
+ return Math.max(
33858
+ base3,
33859
+ match(["gpt-4.1"], 1),
33860
+ match(["claude-sonnet-5"], 0.9),
33861
+ match(["deepseek-v4-pro"], 0.82),
33862
+ match(["gpt-5-mini"], 0.8),
33863
+ match(["gpt-4o-mini"], 0.76)
33864
+ );
33865
+ }
33866
+ if (agentRisk === "policy_exception_simple") {
33867
+ return Math.max(
33868
+ base3,
33869
+ match(["gpt-5-mini"], 1),
33870
+ match(["gpt-4.1"], 0.86),
33871
+ match(["deepseek-v4-pro"], 0.82),
33872
+ match(["gpt-4o-mini"], 0.8)
33873
+ );
33874
+ }
33875
+ return Math.max(
33876
+ base3,
33877
+ match(["deepseek-v4-pro"], 1),
33878
+ match(["claude-sonnet-5"], 0.88),
33879
+ match(["gemini-3.5-flash"], 0.82),
33880
+ match(["gpt-5.3-codex"], 0.81),
33881
+ match(["kimi-k3"], 0.78),
33882
+ match(["gpt-5-mini"], 0.76)
33883
+ );
33884
+ }
33885
+ if (agentDomain === "airline") {
33886
+ if (agentRisk === "complex_high") {
33887
+ return Math.max(
33888
+ base3,
33889
+ match(["claude-sonnet-5"], 1),
33890
+ match(["gpt-5-mini"], 0.78),
33891
+ match(["gemini-3.5-flash"], 0.76),
33892
+ match(["deepseek-v4-pro"], 0.74)
33893
+ );
33894
+ }
33895
+ return Math.max(
33896
+ base3,
33897
+ match(["gpt-5-mini"], 1),
33898
+ match(["claude-sonnet-5"], 0.9),
33899
+ match(["gemini-3.5-flash"], 0.8),
33900
+ match(["deepseek-v4-pro"], 0.76)
33901
+ );
33902
+ }
33903
+ return Math.max(
33904
+ base3,
33905
+ match(["claude-sonnet-5"], 1),
33906
+ match(["gemini-3.5-flash"], 0.88),
33907
+ match(["gpt-5.3-codex"], 0.87),
33908
+ match(["gpt-5-mini"], 0.84),
33909
+ match(["kimi-k3"], 0.85),
33910
+ match(["deepseek-v4-pro"], 0.82)
33911
+ );
33912
+ case "tool_agent_parallel":
33913
+ if (terminalToolSignal) {
33914
+ return terminalSafetySensitive ? Math.max(
33915
+ base3,
33916
+ match(["claude-sonnet-5"], 1),
33917
+ match(["claude-opus-4.8"], 0.9),
33918
+ match(["gpt-5.3-codex"], 0.86)
33919
+ ) : Math.max(
33920
+ base3,
33921
+ match(["gpt-5-mini"], 1),
33922
+ match(["gpt-5.3-codex"], 0.98),
33923
+ match(["claude-sonnet-5"], 0.92),
33924
+ match(["gemini-3.5-flash"], 0.88)
33925
+ );
33926
+ }
33927
+ if (agentDomain === "web_research") {
33928
+ return deepWebResearch ? Math.max(
33929
+ base3,
33930
+ match(["claude-sonnet-5"], 1),
33931
+ match(["gpt-5-mini"], 0.88),
33932
+ match(["gemini-3.5-flash"], 0.84),
33933
+ match(["claude-opus-5"], 0.8),
33934
+ match(["claude-opus-4.8"], 0.78)
33935
+ ) : Math.max(
33936
+ base3,
33937
+ match(["claude-sonnet-5"], 1),
33938
+ match(["gpt-5-mini"], 0.88),
33939
+ match(["gemini-3.5-flash"], 0.86),
33940
+ match(["claude-opus-5"], 0.84),
33941
+ match(["claude-opus-4.8"], 0.82)
33942
+ );
33943
+ }
33944
+ if (agentDomain === "retail") {
33945
+ if (agentRisk === "policy_exception") {
33946
+ return Math.max(
33947
+ base3,
33948
+ match(["gpt-4.1"], 1),
33949
+ match(["claude-sonnet-5"], 0.9),
33950
+ match(["deepseek-v4-pro"], 0.82),
33951
+ match(["gpt-5-mini"], 0.8),
33952
+ match(["gpt-4o-mini"], 0.76)
33953
+ );
33954
+ }
33955
+ if (agentRisk === "policy_exception_simple") {
33956
+ return Math.max(
33957
+ base3,
33958
+ match(["gpt-5-mini"], 1),
33959
+ match(["gpt-4.1"], 0.86),
33960
+ match(["deepseek-v4-pro"], 0.82),
33961
+ match(["gpt-4o-mini"], 0.8)
33962
+ );
33963
+ }
33964
+ return Math.max(
33965
+ base3,
33966
+ match(["deepseek-v4-pro"], 1),
33967
+ match(["claude-sonnet-5"], 0.88),
33968
+ match(["claude-opus-4.8"], 0.84),
33969
+ match(["gpt-5-mini"], 0.78),
33970
+ match(["gemini-3.5-flash"], 0.76)
33971
+ );
33972
+ }
33973
+ if (agentDomain === "airline") {
33974
+ return agentRisk === "complex_high" ? Math.max(
33975
+ base3,
33976
+ match(["claude-sonnet-5"], 1),
33977
+ match(["gpt-5-mini"], 0.78),
33978
+ match(["claude-opus-4.8"], 0.76),
33979
+ match(["gemini-3.5-flash"], 0.74)
33980
+ ) : Math.max(
33981
+ base3,
33982
+ match(["gpt-5-mini"], 1),
33983
+ match(["claude-sonnet-5"], 0.9),
33984
+ match(["gemini-3.5-flash"], 0.8)
33985
+ );
33986
+ }
33987
+ return Math.max(
33988
+ base3,
33989
+ match(["claude-opus-4.8"], 1),
33990
+ match(["claude-sonnet-5"], 0.84),
33991
+ match(["grok-4.5"], 0.82),
33992
+ match(["gemini-3.5-flash"], 0.8),
33993
+ match(["deepseek-v4-pro"], 0.78)
33994
+ );
33995
+ case "code_edit":
33996
+ case "debug":
33997
+ return Math.max(
33998
+ base3,
33999
+ match(["gpt-5.3-codex"], 1),
34000
+ match(["claude-sonnet-4.6"], 0.94),
34001
+ match(["glm-5.2"], 0.9),
34002
+ match(["kimi-k2.7", "deepseek-v4-pro"], 0.86)
34003
+ );
34004
+ case "reasoning":
34005
+ return Math.max(
34006
+ base3,
34007
+ match(["claude-sonnet-5", "claude-sonnet-4.6"], 0.98),
34008
+ match(["deepseek-v4-pro"], 0.95),
34009
+ match(["grok-4.5"], 0.94),
34010
+ match(["gemini-3.1-pro", "gemini-3.5-flash"], 0.92)
34011
+ );
34012
+ case "reasoning_mcq":
34013
+ return Math.max(
34014
+ base3,
34015
+ match(["gemini-3-flash-preview"], 1),
34016
+ match(["gemini-3.5-flash"], 0.91),
34017
+ match(["grok-4.5"], 0.9),
34018
+ match(["claude-sonnet-5"], 0.88),
34019
+ match(["deepseek-v4-pro"], 0.84)
34020
+ );
34021
+ case "reasoning_math":
34022
+ return Math.max(
34023
+ base3,
34024
+ match(["gemini-3.5-flash"], 1),
34025
+ match(["grok-4.5"], 0.93),
34026
+ match(["claude-sonnet-5", "deepseek-v4-pro", "kimi-k3"], 0.9),
34027
+ match(["kimi-k2.7"], 0.84)
34028
+ );
34029
+ case "vision":
34030
+ return Math.max(
34031
+ base3,
34032
+ match(["gemini-3.1-pro"], 0.96),
34033
+ match(["qwen3.7-max", "claude-sonnet-4.6", "kimi-k2.7", "grok-4.3"], 0.9)
34034
+ );
34035
+ case "long_context":
34036
+ return Math.max(
34037
+ base3,
34038
+ match(["gemini-3.1-pro"], 1),
34039
+ match(["qwen3.7-max", "glm-5.2"], 0.89),
34040
+ match(["gemini-3.5-flash"], 0.88),
34041
+ match(["deepseek-v4-pro"], 0.85)
34042
+ );
34043
+ case "extraction": {
34044
+ const kimiExtractionAffinity = language === "zh" ? 1 : 0.9;
34045
+ return Math.max(
34046
+ base3,
34047
+ match(["gemini-3.5-flash", "gemini-2.5-flash", "gpt-4o-mini"], 0.9),
34048
+ match(["claude-sonnet-5", "claude-sonnet-4.6"], 0.9),
34049
+ match(["kimi-k3", "kimi-k2.7"], kimiExtractionAffinity)
34050
+ );
34051
+ }
34052
+ default:
34053
+ return Math.max(
34054
+ base3,
34055
+ match(["gemini-3.5-flash", "gemini-2.5-flash", "kimi-k3", "kimi-k2.7"], 0.86)
34056
+ );
34057
+ }
34058
+ }
34059
+ function evidenceCandidates(task) {
34060
+ if (task === "code_agent") {
34061
+ return [
34062
+ "openai/gpt-5.3-codex",
34063
+ "anthropic/claude-sonnet-5",
34064
+ "openai/gpt-5-mini",
34065
+ "google/gemini-3.5-flash",
34066
+ "moonshot/kimi-k3",
34067
+ "deepseek/deepseek-v4-pro"
34068
+ ];
34069
+ }
34070
+ if (task === "tool_agent") {
34071
+ return [
34072
+ "anthropic/claude-sonnet-5",
34073
+ "anthropic/claude-opus-5",
34074
+ "openai/gpt-5-mini",
34075
+ "openai/gpt-4.1",
34076
+ "openai/gpt-4o-mini",
34077
+ "google/gemini-3.5-flash",
34078
+ "openai/gpt-5.3-codex",
34079
+ "moonshot/kimi-k3",
34080
+ "deepseek/deepseek-v4-pro"
34081
+ ];
34082
+ }
34083
+ if (task === "tool_agent_parallel") {
34084
+ return [
34085
+ "anthropic/claude-opus-5",
34086
+ "anthropic/claude-opus-4.8",
34087
+ "anthropic/claude-sonnet-5",
34088
+ "openai/gpt-5-mini",
34089
+ "openai/gpt-4.1",
34090
+ "openai/gpt-4o-mini",
34091
+ "xai/grok-4.5",
34092
+ "google/gemini-3.5-flash",
34093
+ "deepseek/deepseek-v4-pro"
34094
+ ];
34095
+ }
34096
+ if (task === "long_context") {
34097
+ return [
34098
+ "google/gemini-3.1-pro",
34099
+ "deepseek/deepseek-v4-pro",
34100
+ "qwen/qwen3.7-max",
34101
+ "zai/glm-5.2",
34102
+ "google/gemini-3.5-flash"
34103
+ ];
34104
+ }
34105
+ if (task === "reasoning_mcq") {
34106
+ return [
34107
+ "google/gemini-3-flash-preview",
34108
+ "google/gemini-3.5-flash",
34109
+ "xai/grok-4.5",
34110
+ "anthropic/claude-sonnet-5",
34111
+ "deepseek/deepseek-v4-pro"
34112
+ ];
34113
+ }
34114
+ if (task === "reasoning_math") {
34115
+ return [
34116
+ "google/gemini-3.5-flash",
34117
+ "xai/grok-4.5",
34118
+ "anthropic/claude-sonnet-5",
34119
+ "deepseek/deepseek-v4-pro",
34120
+ "moonshot/kimi-k3"
34121
+ ];
34122
+ }
34123
+ return [];
34124
+ }
34125
+ function isEligible(modelId, features, maxOutputTokens, options) {
34126
+ const model = options.modelCapabilities?.[modelId] ?? DEFAULT_MODEL_CAPABILITIES[modelId];
34127
+ if (!model) return true;
34128
+ if (features.needsTools && !model.supportsTools) return false;
34129
+ if (features.needsVision && !model.supportsVision) return false;
34130
+ if (features.needsStructuredOutput && !model.supportsTools) return false;
34131
+ if (model.maxOutputTokens < maxOutputTokens) return false;
34132
+ return model.contextWindow >= (features.estimatedInputTokens + maxOutputTokens) * 1.1;
34133
+ }
34134
+ function estimatedCost(modelId, options, inputTokens, outputTokens) {
34135
+ const price = options.modelPricing.get(modelId);
34136
+ if (!price) return Number.POSITIVE_INFINITY;
34137
+ if (price.flatPrice !== void 0) return price.flatPrice;
34138
+ return (inputTokens * price.inputPrice + outputTokens * price.outputPrice) / 1e6;
34139
+ }
34140
+ function profileScore(modelId, options, now2) {
34141
+ const profile = options.modelPerformance?.[modelId] ?? LIVE_MODEL_PROFILES[modelId] ?? HISTORICAL_MODEL_PROFILES[modelId];
34142
+ if (!profile) return void 0;
34143
+ const measuredAt = Date.parse(profile.measuredAt);
34144
+ if (!Number.isFinite(measuredAt)) return void 0;
34145
+ const ageDays = Math.max(0, (now2.getTime() - measuredAt) / 864e5);
34146
+ const sampleConfidence = profile.samples === void 0 ? 1 : Math.min(1, Math.max(0, profile.samples) / 10);
34147
+ const freshness = Math.pow(0.5, ageDays / 30) * sampleConfidence;
34148
+ const quality = profile.intelligenceIndex === void 0 ? void 0 : Math.min(1, profile.intelligenceIndex / 50);
34149
+ const speed = Math.min(
34150
+ 1,
34151
+ (2e3 / Math.max(500, profile.latencyMs) + profile.outputTokensPerSecond / 250) / 2
34152
+ );
34153
+ const tailSpeed = Math.min(1, 3e3 / Math.max(750, profile.p95LatencyMs ?? profile.latencyMs));
34154
+ const reliability = Math.max(0, 1 - (profile.errorRate ?? 0));
34155
+ return { quality, speed, tailSpeed, reliability, freshness };
34156
+ }
34157
+ function route(prompt, systemPrompt, maxOutputTokens, options) {
34158
+ const strategy = getStrategy(options.config.strategy ?? "portfolio");
34159
+ return strategy.route(prompt, systemPrompt, maxOutputTokens, options);
34160
+ }
34161
+ var BASELINE_MODEL_ID, BASELINE_INPUT_PRICE, BASELINE_OUTPUT_PRICE, SERVER_MARGIN_PERCENT, MIN_PAYMENT_USD, RulesStrategy, registry, DEFAULT_MODEL_CAPABILITIES, model_profiles_generated_default, LIVE_MODEL_PROFILES, HISTORICAL_MODEL_PROFILES, DEFAULT_PORTFOLIO_WEIGHTS, PortfolioStrategy, DEFAULT_ROUTING_CONFIG;
34162
+ var init_dist = __esm({
34163
+ "node_modules/@blockrun/router-core/dist/index.js"() {
33546
34164
  "use strict";
33547
- init_rules();
33548
- init_selector();
34165
+ BASELINE_MODEL_ID = "anthropic/claude-opus-4.7";
34166
+ BASELINE_INPUT_PRICE = 5;
34167
+ BASELINE_OUTPUT_PRICE = 25;
34168
+ SERVER_MARGIN_PERCENT = 5;
34169
+ MIN_PAYMENT_USD = 1e-3;
33549
34170
  RulesStrategy = class {
33550
34171
  name = "rules";
33551
34172
  route(prompt, systemPrompt, maxOutputTokens, options) {
33552
34173
  const { config, modelPricing } = options;
33553
34174
  const fullText = `${systemPrompt ?? ""} ${prompt}`;
33554
34175
  const estimatedTokens = Math.ceil(fullText.length / 4);
33555
- const ruleResult = classifyByRules(prompt, systemPrompt, estimatedTokens, config.scoring);
34176
+ const scanLimit = Math.max(1, Math.min(8e3, config.classifier.promptTruncationChars));
34177
+ const sample = (value) => {
34178
+ if (value.length <= scanLimit) return value;
34179
+ const prefixLength = Math.ceil(scanLimit / 2);
34180
+ return `${value.slice(0, prefixLength)}
34181
+ ${value.slice(-(scanLimit - prefixLength))}`;
34182
+ };
34183
+ const scannedPrompt = sample(prompt);
34184
+ const scannedSystemPrompt = systemPrompt ? sample(systemPrompt) : void 0;
34185
+ const ruleResult = classifyByRules(
34186
+ scannedPrompt,
34187
+ scannedSystemPrompt,
34188
+ estimatedTokens,
34189
+ config.scoring
34190
+ );
33556
34191
  const { routingProfile } = options;
33557
34192
  let tierConfigs;
33558
34193
  let profileSuffix;
@@ -33569,7 +34204,7 @@ var init_strategy = __esm({
33569
34204
  const agenticScore = ruleResult.agenticScore ?? 0;
33570
34205
  const isAutoAgentic = agenticScore >= 0.5;
33571
34206
  const agenticModeSetting = config.overrides.agenticMode;
33572
- const hasToolsInRequest = options.hasTools ?? false;
34207
+ const hasToolsInRequest = options.requiresTools ?? options.hasTools ?? false;
33573
34208
  let useAgenticTiers;
33574
34209
  if (agenticModeSetting === false) {
33575
34210
  useAgenticTiers = false;
@@ -33599,7 +34234,7 @@ var init_strategy = __esm({
33599
34234
  );
33600
34235
  return { ...decision2, tierConfigs, profile };
33601
34236
  }
33602
- const hasStructuredOutput = systemPrompt ? /json|structured|schema/i.test(systemPrompt) : false;
34237
+ const hasStructuredOutput = options.requiresStructuredOutput === true || (scannedSystemPrompt ? /json|structured|schema/i.test(scannedSystemPrompt) : false);
33603
34238
  let tier;
33604
34239
  let confidence;
33605
34240
  const method = "rules";
@@ -33638,16 +34273,789 @@ var init_strategy = __esm({
33638
34273
  };
33639
34274
  registry = /* @__PURE__ */ new Map();
33640
34275
  registry.set("rules", new RulesStrategy());
33641
- }
33642
- });
33643
-
33644
- // src/router/config.ts
33645
- var DEFAULT_ROUTING_CONFIG;
33646
- var init_config = __esm({
33647
- "src/router/config.ts"() {
33648
- "use strict";
34276
+ DEFAULT_MODEL_CAPABILITIES = Object.freeze({
34277
+ "anthropic/claude-fable-5": {
34278
+ contextWindow: 1e6,
34279
+ maxOutputTokens: 128e3,
34280
+ supportsTools: true,
34281
+ supportsVision: true
34282
+ },
34283
+ "anthropic/claude-haiku-4.5": {
34284
+ contextWindow: 2e5,
34285
+ maxOutputTokens: 8192,
34286
+ supportsTools: true,
34287
+ supportsVision: true
34288
+ },
34289
+ "anthropic/claude-opus-4.6": {
34290
+ contextWindow: 1e6,
34291
+ maxOutputTokens: 128e3,
34292
+ supportsTools: true,
34293
+ supportsVision: true
34294
+ },
34295
+ "anthropic/claude-opus-4.7": {
34296
+ contextWindow: 1e6,
34297
+ maxOutputTokens: 128e3,
34298
+ supportsTools: true,
34299
+ supportsVision: true
34300
+ },
34301
+ "anthropic/claude-opus-4.8": {
34302
+ contextWindow: 1e6,
34303
+ maxOutputTokens: 128e3,
34304
+ supportsTools: true,
34305
+ supportsVision: true
34306
+ },
34307
+ "anthropic/claude-opus-5": {
34308
+ contextWindow: 1e6,
34309
+ maxOutputTokens: 128e3,
34310
+ supportsTools: true,
34311
+ supportsVision: true
34312
+ },
34313
+ "anthropic/claude-sonnet-4.6": {
34314
+ contextWindow: 2e5,
34315
+ maxOutputTokens: 64e3,
34316
+ supportsTools: true,
34317
+ supportsVision: true
34318
+ },
34319
+ "anthropic/claude-sonnet-5": {
34320
+ contextWindow: 1e6,
34321
+ maxOutputTokens: 128e3,
34322
+ supportsTools: true,
34323
+ supportsVision: true
34324
+ },
34325
+ "deepseek/deepseek-chat": {
34326
+ contextWindow: 1e6,
34327
+ maxOutputTokens: 8192,
34328
+ supportsTools: true,
34329
+ supportsVision: false
34330
+ },
34331
+ "deepseek/deepseek-reasoner": {
34332
+ contextWindow: 1e6,
34333
+ maxOutputTokens: 8192,
34334
+ supportsTools: true,
34335
+ supportsVision: false
34336
+ },
34337
+ "deepseek/deepseek-v4-pro": {
34338
+ contextWindow: 1048576,
34339
+ maxOutputTokens: 65536,
34340
+ supportsTools: true,
34341
+ supportsVision: false
34342
+ },
34343
+ "free/deepseek-v4-flash": {
34344
+ contextWindow: 1e6,
34345
+ maxOutputTokens: 16384,
34346
+ supportsTools: false,
34347
+ supportsVision: false
34348
+ },
34349
+ "free/gpt-oss-120b": {
34350
+ contextWindow: 128e3,
34351
+ maxOutputTokens: 16384,
34352
+ supportsTools: false,
34353
+ supportsVision: false
34354
+ },
34355
+ "free/gpt-oss-20b": {
34356
+ contextWindow: 128e3,
34357
+ maxOutputTokens: 16384,
34358
+ supportsTools: false,
34359
+ supportsVision: false
34360
+ },
34361
+ "free/seed-oss-36b": {
34362
+ contextWindow: 131072,
34363
+ maxOutputTokens: 16384,
34364
+ supportsTools: false,
34365
+ supportsVision: false
34366
+ },
34367
+ "google/gemini-2.5-flash": {
34368
+ contextWindow: 1e6,
34369
+ maxOutputTokens: 65536,
34370
+ supportsTools: true,
34371
+ supportsVision: true
34372
+ },
34373
+ "google/gemini-2.5-flash-lite": {
34374
+ contextWindow: 1e6,
34375
+ maxOutputTokens: 65536,
34376
+ supportsTools: true,
34377
+ supportsVision: false
34378
+ },
34379
+ "google/gemini-2.5-pro": {
34380
+ contextWindow: 105e4,
34381
+ maxOutputTokens: 65536,
34382
+ supportsTools: true,
34383
+ supportsVision: true
34384
+ },
34385
+ "google/gemini-3-flash-preview": {
34386
+ contextWindow: 1e6,
34387
+ maxOutputTokens: 65536,
34388
+ supportsTools: false,
34389
+ supportsVision: true
34390
+ },
34391
+ "google/gemini-3.1-flash-lite": {
34392
+ contextWindow: 1e6,
34393
+ maxOutputTokens: 8192,
34394
+ supportsTools: true,
34395
+ supportsVision: false
34396
+ },
34397
+ "google/gemini-3.1-pro": {
34398
+ contextWindow: 105e4,
34399
+ maxOutputTokens: 65536,
34400
+ supportsTools: true,
34401
+ supportsVision: true
34402
+ },
34403
+ "google/gemini-3.5-flash": {
34404
+ contextWindow: 1048576,
34405
+ maxOutputTokens: 65536,
34406
+ supportsTools: true,
34407
+ supportsVision: true
34408
+ },
34409
+ "moonshot/kimi-k2.5": {
34410
+ contextWindow: 262144,
34411
+ maxOutputTokens: 16384,
34412
+ supportsTools: true,
34413
+ supportsVision: true
34414
+ },
34415
+ "moonshot/kimi-k2.6": {
34416
+ contextWindow: 262144,
34417
+ maxOutputTokens: 65536,
34418
+ supportsTools: true,
34419
+ supportsVision: true
34420
+ },
34421
+ "moonshot/kimi-k2.7": {
34422
+ contextWindow: 262144,
34423
+ maxOutputTokens: 65536,
34424
+ supportsTools: true,
34425
+ supportsVision: true
34426
+ },
34427
+ "moonshot/kimi-k3": {
34428
+ contextWindow: 1048576,
34429
+ maxOutputTokens: 65536,
34430
+ supportsTools: true,
34431
+ supportsVision: true
34432
+ },
34433
+ "openai/gpt-4.1": {
34434
+ contextWindow: 128e3,
34435
+ maxOutputTokens: 16384,
34436
+ supportsTools: true,
34437
+ supportsVision: true
34438
+ },
34439
+ "openai/gpt-4o-mini": {
34440
+ contextWindow: 128e3,
34441
+ maxOutputTokens: 16384,
34442
+ supportsTools: true,
34443
+ supportsVision: false
34444
+ },
34445
+ "openai/gpt-5-mini": {
34446
+ contextWindow: 2e5,
34447
+ maxOutputTokens: 65536,
34448
+ supportsTools: true,
34449
+ supportsVision: false
34450
+ },
34451
+ "openai/gpt-5.3-codex": {
34452
+ contextWindow: 4e5,
34453
+ maxOutputTokens: 128e3,
34454
+ supportsTools: true,
34455
+ supportsVision: false
34456
+ },
34457
+ "openai/gpt-5.4": {
34458
+ contextWindow: 4e5,
34459
+ maxOutputTokens: 128e3,
34460
+ supportsTools: true,
34461
+ supportsVision: true
34462
+ },
34463
+ "openai/gpt-5.4-nano": {
34464
+ contextWindow: 105e4,
34465
+ maxOutputTokens: 32768,
34466
+ supportsTools: true,
34467
+ supportsVision: false
34468
+ },
34469
+ "openai/gpt-5.5": {
34470
+ contextWindow: 105e4,
34471
+ maxOutputTokens: 128e3,
34472
+ supportsTools: true,
34473
+ supportsVision: true
34474
+ },
34475
+ "openai/gpt-5.6-terra": {
34476
+ contextWindow: 105e4,
34477
+ maxOutputTokens: 128e3,
34478
+ supportsTools: true,
34479
+ supportsVision: true
34480
+ },
34481
+ "openai/o3": {
34482
+ contextWindow: 2e5,
34483
+ maxOutputTokens: 1e5,
34484
+ supportsTools: true,
34485
+ supportsVision: false
34486
+ },
34487
+ "openai/o4-mini": {
34488
+ contextWindow: 128e3,
34489
+ maxOutputTokens: 65536,
34490
+ supportsTools: true,
34491
+ supportsVision: false
34492
+ },
34493
+ "qwen/qwen3.7-max": {
34494
+ contextWindow: 1e6,
34495
+ maxOutputTokens: 65536,
34496
+ supportsTools: true,
34497
+ supportsVision: false
34498
+ },
34499
+ "xai/grok-3-mini": {
34500
+ contextWindow: 131072,
34501
+ maxOutputTokens: 16384,
34502
+ supportsTools: true,
34503
+ supportsVision: false
34504
+ },
34505
+ "xai/grok-4-0709": {
34506
+ contextWindow: 131072,
34507
+ maxOutputTokens: 16384,
34508
+ supportsTools: true,
34509
+ supportsVision: false
34510
+ },
34511
+ "xai/grok-4-1-fast-non-reasoning": {
34512
+ contextWindow: 131072,
34513
+ maxOutputTokens: 16384,
34514
+ supportsTools: true,
34515
+ supportsVision: false
34516
+ },
34517
+ "xai/grok-4-1-fast-reasoning": {
34518
+ contextWindow: 131072,
34519
+ maxOutputTokens: 16384,
34520
+ supportsTools: true,
34521
+ supportsVision: false
34522
+ },
34523
+ "xai/grok-4-fast-non-reasoning": {
34524
+ contextWindow: 131072,
34525
+ maxOutputTokens: 16384,
34526
+ supportsTools: true,
34527
+ supportsVision: false
34528
+ },
34529
+ "xai/grok-4-fast-reasoning": {
34530
+ contextWindow: 131072,
34531
+ maxOutputTokens: 16384,
34532
+ supportsTools: true,
34533
+ supportsVision: false
34534
+ },
34535
+ "xai/grok-4.5": {
34536
+ contextWindow: 5e5,
34537
+ maxOutputTokens: 16384,
34538
+ supportsTools: true,
34539
+ supportsVision: true
34540
+ },
34541
+ "zai/glm-5.1": {
34542
+ contextWindow: 2e5,
34543
+ maxOutputTokens: 128e3,
34544
+ supportsTools: true,
34545
+ supportsVision: false
34546
+ },
34547
+ "zai/glm-5.2": {
34548
+ contextWindow: 1e6,
34549
+ maxOutputTokens: 262144,
34550
+ supportsTools: true,
34551
+ supportsVision: false
34552
+ }
34553
+ });
34554
+ model_profiles_generated_default = {
34555
+ "openai/gpt-5.5": {
34556
+ measuredAt: "2026-07-21T10:21:31Z",
34557
+ latencyMs: 6243.1,
34558
+ p95LatencyMs: 9865,
34559
+ outputTokensPerSecond: 12.53,
34560
+ errorRate: 0,
34561
+ samples: 3
34562
+ },
34563
+ "openai/gpt-5.4-pro": {
34564
+ measuredAt: "2026-07-21T10:21:31Z",
34565
+ latencyMs: 13015.5,
34566
+ p95LatencyMs: 23976.4,
34567
+ outputTokensPerSecond: 6.42,
34568
+ errorRate: 0,
34569
+ samples: 3
34570
+ },
34571
+ "openai/gpt-5.4-mini": {
34572
+ measuredAt: "2026-07-21T10:21:31Z",
34573
+ latencyMs: 5550,
34574
+ p95LatencyMs: 6595.7,
34575
+ outputTokensPerSecond: 11.96,
34576
+ errorRate: 0.3333,
34577
+ samples: 3
34578
+ },
34579
+ "openai/gpt-5.3-codex": {
34580
+ measuredAt: "2026-07-21T10:21:31Z",
34581
+ latencyMs: 4617.1,
34582
+ p95LatencyMs: 5800.7,
34583
+ outputTokensPerSecond: 12.48,
34584
+ errorRate: 0,
34585
+ samples: 3
34586
+ },
34587
+ "anthropic/claude-opus-4.8": {
34588
+ measuredAt: "2026-07-21T10:21:31Z",
34589
+ latencyMs: 3915.1,
34590
+ p95LatencyMs: 6130.8,
34591
+ outputTokensPerSecond: 16.33,
34592
+ errorRate: 0,
34593
+ samples: 3
34594
+ },
34595
+ "anthropic/claude-opus-4.6": {
34596
+ measuredAt: "2026-07-21T10:21:31Z",
34597
+ latencyMs: 3765.5,
34598
+ p95LatencyMs: 4257.2,
34599
+ outputTokensPerSecond: 14.18,
34600
+ errorRate: 0,
34601
+ samples: 3
34602
+ },
34603
+ "anthropic/claude-sonnet-4.6": {
34604
+ measuredAt: "2026-07-21T10:21:31Z",
34605
+ latencyMs: 3860.6,
34606
+ p95LatencyMs: 5093.5,
34607
+ outputTokensPerSecond: 13.85,
34608
+ errorRate: 0,
34609
+ samples: 3
34610
+ },
34611
+ "anthropic/claude-haiku-4.5": {
34612
+ measuredAt: "2026-07-21T10:21:31Z",
34613
+ latencyMs: 2734.9,
34614
+ p95LatencyMs: 3181.6,
34615
+ outputTokensPerSecond: 19.58,
34616
+ errorRate: 0,
34617
+ samples: 3
34618
+ },
34619
+ "google/gemini-3.1-pro": {
34620
+ measuredAt: "2026-07-21T10:21:31Z",
34621
+ latencyMs: 13935.7,
34622
+ p95LatencyMs: 26675.3,
34623
+ outputTokensPerSecond: 77.47,
34624
+ errorRate: 0,
34625
+ samples: 3
34626
+ },
34627
+ "google/gemini-3.5-flash": {
34628
+ measuredAt: "2026-07-21T10:21:31Z",
34629
+ latencyMs: 4608.7,
34630
+ p95LatencyMs: 8420.9,
34631
+ outputTokensPerSecond: 57.88,
34632
+ errorRate: 0,
34633
+ samples: 3
34634
+ },
34635
+ "google/gemini-3.1-flash-lite": {
34636
+ measuredAt: "2026-07-21T10:21:31Z",
34637
+ latencyMs: 4619.7,
34638
+ p95LatencyMs: 9927.1,
34639
+ outputTokensPerSecond: 42.01,
34640
+ errorRate: 0,
34641
+ samples: 3
34642
+ },
34643
+ "google/gemini-2.5-flash": {
34644
+ measuredAt: "2026-07-21T10:21:31Z",
34645
+ latencyMs: 5506.9,
34646
+ p95LatencyMs: 11462.5,
34647
+ outputTokensPerSecond: 65.19,
34648
+ errorRate: 0,
34649
+ samples: 3
34650
+ },
34651
+ "deepseek/deepseek-v4-pro": {
34652
+ measuredAt: "2026-07-21T10:21:31Z",
34653
+ latencyMs: 6044.8,
34654
+ p95LatencyMs: 10782.3,
34655
+ outputTokensPerSecond: 22.47,
34656
+ errorRate: 0,
34657
+ samples: 3
34658
+ },
34659
+ "deepseek/deepseek-reasoner": {
34660
+ measuredAt: "2026-07-21T10:21:31Z",
34661
+ latencyMs: 4111.9,
34662
+ p95LatencyMs: 5305.7,
34663
+ outputTokensPerSecond: 16.46,
34664
+ errorRate: 0,
34665
+ samples: 3
34666
+ },
34667
+ "deepseek/deepseek-chat": {
34668
+ measuredAt: "2026-07-21T10:21:31Z",
34669
+ latencyMs: 2648.6,
34670
+ p95LatencyMs: 3524.1,
34671
+ outputTokensPerSecond: 16.73,
34672
+ errorRate: 0,
34673
+ samples: 3
34674
+ },
34675
+ "moonshot/kimi-k2.7": {
34676
+ measuredAt: "2026-07-21T10:21:31Z",
34677
+ latencyMs: 4295.4,
34678
+ p95LatencyMs: 6153.8,
34679
+ outputTokensPerSecond: 18.54,
34680
+ errorRate: 0,
34681
+ samples: 3
34682
+ },
34683
+ "qwen/qwen3.7-max": {
34684
+ measuredAt: "2026-07-21T10:21:31Z",
34685
+ latencyMs: 30729.4,
34686
+ p95LatencyMs: 39622,
34687
+ outputTokensPerSecond: 36.89,
34688
+ errorRate: 0.3333,
34689
+ samples: 3
34690
+ },
34691
+ "xai/grok-4.3": {
34692
+ measuredAt: "2026-07-21T10:21:31Z",
34693
+ latencyMs: 6946.1,
34694
+ p95LatencyMs: 9495.4,
34695
+ outputTokensPerSecond: 65.3,
34696
+ errorRate: 0,
34697
+ samples: 3
34698
+ },
34699
+ "xai/grok-4.20-reasoning": {
34700
+ measuredAt: "2026-07-21T10:21:31Z",
34701
+ latencyMs: 3472.4,
34702
+ p95LatencyMs: 5332.4,
34703
+ outputTokensPerSecond: 13.27,
34704
+ errorRate: 0,
34705
+ samples: 3
34706
+ },
34707
+ "xai/grok-4.20-non-reasoning": {
34708
+ measuredAt: "2026-07-21T10:21:31Z",
34709
+ latencyMs: 5174.4,
34710
+ p95LatencyMs: 6081.7,
34711
+ outputTokensPerSecond: 10.21,
34712
+ errorRate: 0.3333,
34713
+ samples: 3
34714
+ },
34715
+ "xai/grok-4-1-fast-reasoning": {
34716
+ measuredAt: "2026-07-21T10:21:31Z",
34717
+ latencyMs: 13148.2,
34718
+ p95LatencyMs: 19104.2,
34719
+ outputTokensPerSecond: 4.28,
34720
+ errorRate: 0,
34721
+ samples: 3
34722
+ },
34723
+ "minimax/minimax-m3": {
34724
+ measuredAt: "2026-07-21T10:21:31Z",
34725
+ latencyMs: 3385,
34726
+ p95LatencyMs: 4247.2,
34727
+ outputTokensPerSecond: 15.16,
34728
+ errorRate: 0,
34729
+ samples: 3
34730
+ },
34731
+ "minimax/minimax-m2.7": {
34732
+ measuredAt: "2026-07-21T10:21:31Z",
34733
+ latencyMs: 4596.7,
34734
+ p95LatencyMs: 6884.6,
34735
+ outputTokensPerSecond: 17.03,
34736
+ errorRate: 0,
34737
+ samples: 3
34738
+ },
34739
+ "zai/glm-5.2": {
34740
+ measuredAt: "2026-07-21T10:21:31Z",
34741
+ latencyMs: 4406.3,
34742
+ p95LatencyMs: 6139.7,
34743
+ outputTokensPerSecond: 10.41,
34744
+ errorRate: 0,
34745
+ samples: 3
34746
+ },
34747
+ "zai/glm-5.1": {
34748
+ measuredAt: "2026-07-21T10:21:31Z",
34749
+ latencyMs: 7775.4,
34750
+ p95LatencyMs: 9182.1,
34751
+ outputTokensPerSecond: 6.08,
34752
+ errorRate: 0,
34753
+ samples: 3
34754
+ },
34755
+ "zai/glm-5": {
34756
+ measuredAt: "2026-07-21T10:21:31Z",
34757
+ latencyMs: 4159.4,
34758
+ p95LatencyMs: 4992.7,
34759
+ outputTokensPerSecond: 10.28,
34760
+ errorRate: 0,
34761
+ samples: 3
34762
+ },
34763
+ "free/qwen3-coder-480b": {
34764
+ measuredAt: "2026-07-21T10:21:31Z",
34765
+ latencyMs: 2063.9,
34766
+ p95LatencyMs: 3646.3,
34767
+ outputTokensPerSecond: 39.8,
34768
+ errorRate: 0,
34769
+ samples: 3
34770
+ },
34771
+ "free/mistral-large-3-675b": {
34772
+ measuredAt: "2026-07-21T10:21:31Z",
34773
+ latencyMs: 3147.5,
34774
+ p95LatencyMs: 5555.3,
34775
+ outputTokensPerSecond: 27.76,
34776
+ errorRate: 0,
34777
+ samples: 3
34778
+ },
34779
+ "free/nemotron-3-nano-omni-30b-a3b-reasoning": {
34780
+ measuredAt: "2026-07-21T10:21:31Z",
34781
+ latencyMs: 6508.4,
34782
+ p95LatencyMs: 14252.7,
34783
+ outputTokensPerSecond: 68.26,
34784
+ errorRate: 0,
34785
+ samples: 3
34786
+ },
34787
+ "free/glm-4.7": {
34788
+ measuredAt: "2026-07-21T10:21:31Z",
34789
+ latencyMs: 2014.8,
34790
+ p95LatencyMs: 3039.9,
34791
+ outputTokensPerSecond: 39.92,
34792
+ errorRate: 0,
34793
+ samples: 3
34794
+ }
34795
+ };
34796
+ LIVE_MODEL_PROFILES = Object.freeze(
34797
+ model_profiles_generated_default
34798
+ );
34799
+ HISTORICAL_MODEL_PROFILES = Object.freeze({
34800
+ "anthropic/claude-haiku-4.5": {
34801
+ measuredAt: "2026-03-16T13:50:48Z",
34802
+ latencyMs: 2305,
34803
+ outputTokensPerSecond: 140.6
34804
+ },
34805
+ "anthropic/claude-opus-4.6": {
34806
+ measuredAt: "2026-03-16T13:50:48Z",
34807
+ latencyMs: 2139,
34808
+ outputTokensPerSecond: 119.7
34809
+ },
34810
+ "anthropic/claude-sonnet-4.6": {
34811
+ measuredAt: "2026-03-16T13:50:48Z",
34812
+ latencyMs: 2110,
34813
+ outputTokensPerSecond: 121.3
34814
+ },
34815
+ "deepseek/deepseek-chat": {
34816
+ measuredAt: "2026-03-16T13:50:48Z",
34817
+ latencyMs: 1431,
34818
+ outputTokensPerSecond: 179.2,
34819
+ intelligenceIndex: 32
34820
+ },
34821
+ "google/gemini-2.5-flash": {
34822
+ measuredAt: "2026-03-16T13:50:48Z",
34823
+ latencyMs: 1238,
34824
+ outputTokensPerSecond: 207.6,
34825
+ intelligenceIndex: 20
34826
+ },
34827
+ "google/gemini-2.5-flash-lite": {
34828
+ measuredAt: "2026-03-16T13:50:48Z",
34829
+ latencyMs: 1353,
34830
+ outputTokensPerSecond: 192.5,
34831
+ intelligenceIndex: 20
34832
+ },
34833
+ "google/gemini-2.5-pro": {
34834
+ measuredAt: "2026-03-16T13:50:48Z",
34835
+ latencyMs: 1294,
34836
+ outputTokensPerSecond: 197.8
34837
+ },
34838
+ "google/gemini-3.1-pro": {
34839
+ measuredAt: "2026-03-16T13:50:48Z",
34840
+ latencyMs: 1609,
34841
+ outputTokensPerSecond: 167.2
34842
+ },
34843
+ "moonshot/kimi-k2.5": {
34844
+ measuredAt: "2026-03-16T13:50:48Z",
34845
+ latencyMs: 1646,
34846
+ outputTokensPerSecond: 155.7
34847
+ },
34848
+ "openai/gpt-4o-mini": {
34849
+ measuredAt: "2026-03-16T13:50:48Z",
34850
+ latencyMs: 2764,
34851
+ outputTokensPerSecond: 92.8
34852
+ },
34853
+ "openai/gpt-5.3-codex": {
34854
+ measuredAt: "2026-03-16T13:50:48Z",
34855
+ latencyMs: 7935,
34856
+ outputTokensPerSecond: 32.3
34857
+ },
34858
+ "xai/grok-4-1-fast-non-reasoning": {
34859
+ measuredAt: "2026-03-16T13:50:48Z",
34860
+ latencyMs: 1244,
34861
+ outputTokensPerSecond: 205.8,
34862
+ intelligenceIndex: 41
34863
+ },
34864
+ "xai/grok-4-1-fast-reasoning": {
34865
+ measuredAt: "2026-03-16T13:50:48Z",
34866
+ latencyMs: 1454,
34867
+ outputTokensPerSecond: 176.2,
34868
+ intelligenceIndex: 41
34869
+ }
34870
+ });
34871
+ DEFAULT_PORTFOLIO_WEIGHTS = {
34872
+ auto: {
34873
+ quality: 0.47,
34874
+ capability: 0.2,
34875
+ cost: 0.18,
34876
+ speed: 0.07,
34877
+ reliability: 0.03,
34878
+ legacy: 0.05
34879
+ },
34880
+ eco: { quality: 0.36, capability: 0.2, cost: 0.28, speed: 0.1, reliability: 0.04, legacy: 0.02 },
34881
+ premium: {
34882
+ quality: 0.58,
34883
+ capability: 0.2,
34884
+ cost: 0.08,
34885
+ speed: 0.06,
34886
+ reliability: 0.06,
34887
+ legacy: 0.02
34888
+ },
34889
+ highStakesBoost: { quality: 0.08, reliability: 0.05 },
34890
+ latencySensitiveSpeedBoost: 0.08,
34891
+ affinityFloorGap: { auto: 0.1, eco: 0.22, premium: 0.05 }
34892
+ };
34893
+ PortfolioStrategy = class {
34894
+ name = "portfolio";
34895
+ route(prompt, systemPrompt, maxOutputTokens, options) {
34896
+ const features = classifyTask(prompt, systemPrompt, options);
34897
+ const base3 = new RulesStrategy().route(prompt, systemPrompt, maxOutputTokens, {
34898
+ ...options,
34899
+ requiresTools: features.needsTools
34900
+ });
34901
+ const tierConfigs = base3.tierConfigs;
34902
+ if (!tierConfigs) return base3;
34903
+ const targetTier = (features.taskType === "reasoning_mcq" || features.taskType === "reasoning_math") && (base3.tier === "SIMPLE" || base3.tier === "MEDIUM") ? "REASONING" : base3.tier;
34904
+ const tierConfig = tierConfigs[targetTier];
34905
+ const configuredCandidates = tierConfig ? getFallbackChain(targetTier, tierConfigs) : [];
34906
+ const chain3 = [
34907
+ .../* @__PURE__ */ new Set([...configuredCandidates, ...evidenceCandidates(features.taskType)])
34908
+ ].filter((model2) => typeof model2 === "string" && model2.length > 0);
34909
+ const eligible = chain3.filter(
34910
+ (model2) => isEligible(model2, features, maxOutputTokens, options)
34911
+ );
34912
+ const eligibleCandidates = eligible.length > 0 ? eligible : chain3;
34913
+ if (eligibleCandidates.length === 0) return base3;
34914
+ const profileName = options.routingProfile === "eco" ? "eco" : options.routingProfile === "premium" ? "premium" : "auto";
34915
+ const portfolio = options.config.portfolio ?? DEFAULT_PORTFOLIO_WEIGHTS;
34916
+ const getAffinity = (model2) => affinity(
34917
+ model2,
34918
+ features.taskType,
34919
+ features.language,
34920
+ features.agentDomain,
34921
+ features.deepWebResearch,
34922
+ features.agentRisk,
34923
+ features.terminalToolSignal,
34924
+ features.terminalSafetySensitive
34925
+ );
34926
+ const bestAffinity = Math.max(...eligibleCandidates.map(getAffinity));
34927
+ const specificAffinity = eligibleCandidates.filter((model2) => getAffinity(model2) > 0.68);
34928
+ const affinityPool = specificAffinity.length > 0 ? specificAffinity : [eligibleCandidates[0]];
34929
+ const affinityFloorGap = features.terminalToolSignal ? Math.max(
34930
+ portfolio.affinityFloorGap[profileName],
34931
+ features.terminalSafetySensitive ? 0.15 : 0.12
34932
+ ) : portfolio.affinityFloorGap[profileName];
34933
+ const candidates = affinityPool.filter(
34934
+ (model2) => getAffinity(model2) >= bestAffinity - affinityFloorGap
34935
+ );
34936
+ const costs = candidates.map(
34937
+ (model2) => estimatedCost(model2, options, features.estimatedInputTokens, maxOutputTokens)
34938
+ );
34939
+ const finiteCosts = costs.filter(Number.isFinite);
34940
+ const minCost = finiteCosts.length > 0 ? Math.min(...finiteCosts) : 0;
34941
+ const maxCost = finiteCosts.length > 0 ? Math.max(...finiteCosts) : 1;
34942
+ const now2 = options.now ?? /* @__PURE__ */ new Date();
34943
+ const profileWeights = portfolio[profileName];
34944
+ const rankedEntries = candidates.map((model2, index2) => {
34945
+ const cost = estimatedCost(model2, options, features.estimatedInputTokens, maxOutputTokens);
34946
+ const costScore = Number.isFinite(cost) && maxCost > minCost ? 1 - (cost - minCost) / (maxCost - minCost) : 0.5;
34947
+ const capabilityScore = isEligible(model2, features, maxOutputTokens, options) ? 1 : 0;
34948
+ const profile = profileScore(model2, options, now2);
34949
+ const observedQuality = profile?.quality === void 0 ? getAffinity(model2) : getAffinity(model2) * (1 - profile.freshness) + profile.quality * profile.freshness;
34950
+ const observedSpeed = profile ? profile.speed * profile.freshness : 0.5;
34951
+ const observedTailSpeed = profile ? profile.tailSpeed * profile.freshness : 0.5;
34952
+ const observedReliability = profile ? profile.reliability * profile.freshness + (1 - profile.freshness) : 1;
34953
+ const legacyScore = 1 - index2 / Math.max(1, candidates.length - 1);
34954
+ const qualityWeight = profileWeights.quality + (features.highStakes ? portfolio.highStakesBoost.quality : 0);
34955
+ const speedScore = features.latencySensitive ? observedTailSpeed : observedSpeed;
34956
+ const speedWeight = profileWeights.speed + (features.latencySensitive ? portfolio.latencySensitiveSpeedBoost : 0);
34957
+ const reliabilityWeight = profileWeights.reliability + (features.highStakes ? portfolio.highStakesBoost.reliability : 0);
34958
+ const score = observedQuality * qualityWeight + capabilityScore * profileWeights.capability + costScore * profileWeights.cost + speedScore * speedWeight + observedReliability * reliabilityWeight + legacyScore * profileWeights.legacy;
34959
+ return {
34960
+ model: model2,
34961
+ score,
34962
+ quality: observedQuality,
34963
+ cost: costScore,
34964
+ speed: speedScore,
34965
+ reliability: observedReliability
34966
+ };
34967
+ }).sort((a, b) => b.score - a.score);
34968
+ const scoredModels = rankedEntries.map((item) => item.model);
34969
+ const webResearchFallbackOrder = [
34970
+ "anthropic/claude-sonnet-5",
34971
+ "openai/gpt-5-mini",
34972
+ "google/gemini-3.5-flash",
34973
+ "anthropic/claude-opus-5",
34974
+ "anthropic/claude-opus-4.8",
34975
+ "openai/gpt-5.3-codex"
34976
+ ];
34977
+ const ranked = features.agentDomain === "web_research" ? [
34978
+ ...scoredModels,
34979
+ ...webResearchFallbackOrder.filter(
34980
+ (model2) => eligibleCandidates.includes(model2) && !scoredModels.includes(model2)
34981
+ ),
34982
+ ...eligibleCandidates.filter(
34983
+ (model2) => !scoredModels.includes(model2) && !webResearchFallbackOrder.includes(model2)
34984
+ )
34985
+ ] : features.taskType === "tool_agent" || features.taskType === "tool_agent_parallel" && features.agentDomain !== "other" ? [
34986
+ ...scoredModels,
34987
+ ...eligibleCandidates.filter((model2) => !scoredModels.includes(model2))
34988
+ ] : [
34989
+ ...scoredModels,
34990
+ ...eligibleCandidates.filter((model2) => !scoredModels.includes(model2))
34991
+ ];
34992
+ const model = ranked[0] ?? base3.model;
34993
+ const selectedTierConfigs = {
34994
+ ...tierConfigs,
34995
+ [targetTier]: { primary: model, fallback: ranked.slice(1) }
34996
+ };
34997
+ const decision = selectModel(
34998
+ targetTier,
34999
+ base3.confidence,
35000
+ "portfolio",
35001
+ `${base3.reasoning} | v3 task=${features.taskType} agentRisk=${features.agentRisk} deepWebResearch=${features.deepWebResearch} terminalCode=${features.implicitTerminalCode} terminalSafety=${features.terminalSafetySensitive} candidates=${ranked.length}`,
35002
+ selectedTierConfigs,
35003
+ options.modelPricing,
35004
+ features.estimatedInputTokens,
35005
+ maxOutputTokens,
35006
+ options.routingProfile,
35007
+ base3.agenticScore
35008
+ );
35009
+ return {
35010
+ ...decision,
35011
+ tierConfigs: selectedTierConfigs,
35012
+ profile: base3.profile,
35013
+ candidates: ranked,
35014
+ candidateScores: rankedEntries.map(({ model: model2, score, quality, cost, speed, reliability }) => ({
35015
+ model: model2,
35016
+ score,
35017
+ quality,
35018
+ cost,
35019
+ speed,
35020
+ reliability
35021
+ })),
35022
+ taskType: features.taskType,
35023
+ routerVersion: "v3-portfolio"
35024
+ };
35025
+ }
35026
+ };
33649
35027
  DEFAULT_ROUTING_CONFIG = {
33650
- version: "2.0",
35028
+ version: "3.4",
35029
+ strategy: "portfolio",
35030
+ portfolio: {
35031
+ auto: {
35032
+ quality: 0.47,
35033
+ capability: 0.2,
35034
+ cost: 0.18,
35035
+ speed: 0.07,
35036
+ reliability: 0.03,
35037
+ legacy: 0.05
35038
+ },
35039
+ eco: {
35040
+ quality: 0.36,
35041
+ capability: 0.2,
35042
+ cost: 0.28,
35043
+ speed: 0.1,
35044
+ reliability: 0.04,
35045
+ legacy: 0.02
35046
+ },
35047
+ premium: {
35048
+ quality: 0.58,
35049
+ capability: 0.2,
35050
+ cost: 0.08,
35051
+ speed: 0.06,
35052
+ reliability: 0.06,
35053
+ legacy: 0.02
35054
+ },
35055
+ highStakesBoost: { quality: 0.08, reliability: 0.05 },
35056
+ latencySensitiveSpeedBoost: 0.08,
35057
+ affinityFloorGap: { auto: 0.1, eco: 0.22, premium: 0.05 }
35058
+ },
33651
35059
  classifier: {
33652
35060
  llmModel: "google/gemini-2.5-flash",
33653
35061
  llmMaxTokens: 10,
@@ -35027,21 +36435,15 @@ var init_config = __esm({
35027
36435
  // Set to `true` to force agentic tiers; `false` to disable them entirely.
35028
36436
  }
35029
36437
  };
36438
+ registerStrategy(new PortfolioStrategy());
35030
36439
  }
35031
36440
  });
35032
36441
 
35033
36442
  // src/router/index.ts
35034
- function route(prompt, systemPrompt, maxOutputTokens, options) {
35035
- const strategy = getStrategy("rules");
35036
- return strategy.route(prompt, systemPrompt, maxOutputTokens, options);
35037
- }
35038
36443
  var init_router = __esm({
35039
36444
  "src/router/index.ts"() {
35040
36445
  "use strict";
35041
- init_strategy();
35042
- init_strategy();
35043
- init_selector();
35044
- init_config();
36446
+ init_dist();
35045
36447
  }
35046
36448
  });
35047
36449
 
@@ -56796,7 +58198,7 @@ var init_exclude_models = __esm({
56796
58198
 
56797
58199
  // src/config.ts
56798
58200
  var DEFAULT_PORT, PROXY_PORT;
56799
- var init_config2 = __esm({
58201
+ var init_config = __esm({
56800
58202
  "src/config.ts"() {
56801
58203
  "use strict";
56802
58204
  DEFAULT_PORT = 8402;
@@ -73194,27 +74596,27 @@ var require_dns = __commonJS({
73194
74596
  }
73195
74597
  );
73196
74598
  }
73197
- #defaultPick(origin2, hostnameRecords, affinity) {
74599
+ #defaultPick(origin2, hostnameRecords, affinity2) {
73198
74600
  let ip = null;
73199
74601
  const { records, offset } = hostnameRecords;
73200
74602
  let family;
73201
74603
  if (this.dualStack) {
73202
- if (affinity == null) {
74604
+ if (affinity2 == null) {
73203
74605
  if (offset == null || offset === maxInt) {
73204
74606
  hostnameRecords.offset = 0;
73205
- affinity = 4;
74607
+ affinity2 = 4;
73206
74608
  } else {
73207
74609
  hostnameRecords.offset++;
73208
- affinity = (hostnameRecords.offset & 1) === 1 ? 6 : 4;
74610
+ affinity2 = (hostnameRecords.offset & 1) === 1 ? 6 : 4;
73209
74611
  }
73210
74612
  }
73211
- if (records[affinity] != null && records[affinity].ips.length > 0) {
73212
- family = records[affinity];
74613
+ if (records[affinity2] != null && records[affinity2].ips.length > 0) {
74614
+ family = records[affinity2];
73213
74615
  } else {
73214
- family = records[affinity === 4 ? 6 : 4];
74616
+ family = records[affinity2 === 4 ? 6 : 4];
73215
74617
  }
73216
74618
  } else {
73217
- family = records[affinity];
74619
+ family = records[affinity2];
73218
74620
  }
73219
74621
  if (family == null || family.ips.length === 0) {
73220
74622
  return ip;
@@ -73231,7 +74633,7 @@ var require_dns = __commonJS({
73231
74633
  }
73232
74634
  if (Date.now() - ip.timestamp > ip.ttl) {
73233
74635
  family.ips.splice(position, 1);
73234
- return this.pick(origin2, hostnameRecords, affinity);
74636
+ return this.pick(origin2, hostnameRecords, affinity2);
73235
74637
  }
73236
74638
  return ip;
73237
74639
  }
@@ -73370,11 +74772,11 @@ var require_dns = __commonJS({
73370
74772
  throw new InvalidArgumentError("Invalid storage. Must be a object with methods: { get, set, full, delete }");
73371
74773
  }
73372
74774
  const dualStack = interceptorOpts?.dualStack ?? true;
73373
- let affinity;
74775
+ let affinity2;
73374
74776
  if (dualStack) {
73375
- affinity = interceptorOpts?.affinity ?? null;
74777
+ affinity2 = interceptorOpts?.affinity ?? null;
73376
74778
  } else {
73377
- affinity = interceptorOpts?.affinity ?? 4;
74779
+ affinity2 = interceptorOpts?.affinity ?? 4;
73378
74780
  }
73379
74781
  const opts = {
73380
74782
  maxTTL: interceptorOpts?.maxTTL ?? 1e4,
@@ -73382,7 +74784,7 @@ var require_dns = __commonJS({
73382
74784
  lookup: interceptorOpts?.lookup ?? null,
73383
74785
  pick: interceptorOpts?.pick ?? null,
73384
74786
  dualStack,
73385
- affinity,
74787
+ affinity: affinity2,
73386
74788
  maxItems: interceptorOpts?.maxItems ?? Infinity,
73387
74789
  storage: interceptorOpts?.storage
73388
74790
  };
@@ -86677,6 +88079,19 @@ function buildModelPricing() {
86677
88079
  }
86678
88080
  return map;
86679
88081
  }
88082
+ function buildModelCapabilities() {
88083
+ return Object.fromEntries(
88084
+ BLOCKRUN_MODELS.map((model) => [
88085
+ model.id,
88086
+ {
88087
+ contextWindow: model.contextWindow,
88088
+ maxOutputTokens: model.maxOutput,
88089
+ supportsTools: model.toolCalling === true,
88090
+ supportsVision: model.vision === true
88091
+ }
88092
+ ])
88093
+ );
88094
+ }
86680
88095
  function buildProxyModelList(createdAt = Math.floor(Date.now() / 1e3)) {
86681
88096
  const seen = /* @__PURE__ */ new Set();
86682
88097
  return OPENCLAW_MODELS.filter((model) => {
@@ -87022,7 +88437,8 @@ async function startProxy(options) {
87022
88437
  const modelPricing = buildModelPricing();
87023
88438
  const routerOpts = {
87024
88439
  config: routingConfig,
87025
- modelPricing
88440
+ modelPricing,
88441
+ modelCapabilities: buildModelCapabilities()
87026
88442
  };
87027
88443
  const deduplicator = new RequestDeduplicator();
87028
88444
  const responseCache2 = new ResponseCache(options.cacheConfig);
@@ -88168,6 +89584,7 @@ async function proxyRequest(req, res, apiBase, payFetch, options, routerOpts, de
88168
89584
  let maxTokens = DEFAULT_MAX_TOKENS;
88169
89585
  let routingProfile = null;
88170
89586
  let stickyExplicitModel;
89587
+ let pendingShadowComparison;
88171
89588
  let balanceFallbackNotice;
88172
89589
  let budgetDowngradeNotice;
88173
89590
  let budgetDowngradeHeaderMode;
@@ -88763,8 +90180,16 @@ async function proxyRequest(req, res, apiBase, payFetch, options, routerOpts, de
88763
90180
  const systemPrompt = typeof systemMsg?.content === "string" ? systemMsg.content : void 0;
88764
90181
  const tools = parsed.tools;
88765
90182
  hasTools = Array.isArray(tools) && tools.length > 0;
90183
+ const requiresTools = hasTools && inferToolRequirement(prompt, systemPrompt, parsed.tool_choice);
90184
+ const toolNames = (tools ?? []).map((tool) => {
90185
+ if (typeof tool !== "object" || tool === null) return void 0;
90186
+ const fn = tool.function;
90187
+ if (typeof fn !== "object" || fn === null) return void 0;
90188
+ const name = fn.name;
90189
+ return typeof name === "string" ? name : void 0;
90190
+ }).filter((name) => name !== void 0);
88766
90191
  if (hasTools && tools) {
88767
- console.log(`[ClawRouter] Tools detected (${tools.length}), forcing agentic tiers`);
90192
+ console.log(`[ClawRouter] Tools detected (${tools.length}), required=${requiresTools}`);
88768
90193
  }
88769
90194
  hasVision = parsedMessages.some((m) => {
88770
90195
  if (Array.isArray(m.content)) {
@@ -88778,8 +90203,36 @@ async function proxyRequest(req, res, apiBase, payFetch, options, routerOpts, de
88778
90203
  routingDecision = route(prompt, systemPrompt, maxTokens, {
88779
90204
  ...routerOpts,
88780
90205
  routingProfile: routingProfile ?? void 0,
88781
- hasTools
90206
+ hasTools,
90207
+ toolCount: tools?.length ?? 0,
90208
+ toolNames,
90209
+ requiresTools,
90210
+ hasVision,
90211
+ requiresStructuredOutput: typeof parsed.response_format === "object" && parsed.response_format !== null
88782
90212
  });
90213
+ const shadow = routerOpts.config.shadow;
90214
+ const activeStrategy = routerOpts.config.strategy ?? "portfolio";
90215
+ const shadowRate = Math.max(0, Math.min(1, shadow?.sampleRate ?? 1));
90216
+ if (shadow && shadow.strategy !== activeStrategy && Math.random() < shadowRate) {
90217
+ const requiresStructuredOutput = typeof parsed.response_format === "object" && parsed.response_format !== null;
90218
+ const shadowDecision = route(prompt, systemPrompt, maxTokens, {
90219
+ ...routerOpts,
90220
+ config: { ...routerOpts.config, strategy: shadow.strategy },
90221
+ routingProfile: routingProfile ?? void 0,
90222
+ hasTools,
90223
+ toolCount: tools?.length ?? 0,
90224
+ toolNames,
90225
+ requiresTools,
90226
+ hasVision,
90227
+ requiresStructuredOutput
90228
+ });
90229
+ pendingShadowComparison = {
90230
+ shadow: shadowDecision,
90231
+ hasTools,
90232
+ hasVision,
90233
+ requiresStructuredOutput
90234
+ };
90235
+ }
88783
90236
  if (hasTools && routingDecision.tier === "SIMPLE") {
88784
90237
  console.log(
88785
90238
  `[ClawRouter] SIMPLE+tools: keeping agentic model ${routingDecision.model} (tools need reliable function-call support)`
@@ -88888,6 +90341,21 @@ async function proxyRequest(req, res, apiBase, payFetch, options, routerOpts, de
88888
90341
  );
88889
90342
  }
88890
90343
  }
90344
+ if (pendingShadowComparison) {
90345
+ try {
90346
+ options.onShadowRouted?.({
90347
+ executed: routingDecision,
90348
+ shadow: pendingShadowComparison.shadow,
90349
+ sameModel: routingDecision.model === pendingShadowComparison.shadow.model,
90350
+ hasTools: pendingShadowComparison.hasTools,
90351
+ hasVision: pendingShadowComparison.hasVision,
90352
+ requiresStructuredOutput: pendingShadowComparison.requiresStructuredOutput
90353
+ });
90354
+ } catch (err) {
90355
+ const message = err instanceof Error ? err.message : String(err);
90356
+ console.warn(`[ClawRouter] Shadow routing callback failed: ${message}`);
90357
+ }
90358
+ }
88891
90359
  options.onRouted?.(routingDecision);
88892
90360
  }
88893
90361
  }
@@ -89235,35 +90703,64 @@ async function proxyRequest(req, res, apiBase, payFetch, options, routerOpts, de
89235
90703
  const estimatedInputTokens = Math.ceil(body.length / 4);
89236
90704
  const estimatedTotalTokens = estimatedInputTokens + maxTokens;
89237
90705
  const tierConfigs = routingDecision.tierConfigs ?? routerOpts.config.tiers;
89238
- const fullChain = prependStickyExplicitModel(
89239
- getFallbackChain(routingDecision.tier, tierConfigs)
89240
- );
89241
- const contextFiltered = prependStickyExplicitModel(
89242
- getFallbackChainFiltered(
89243
- routingDecision.tier,
89244
- tierConfigs,
89245
- estimatedTotalTokens,
89246
- getModelContextWindow
89247
- )
90706
+ const rankedCandidates = routingDecision.candidates ?? getFallbackChain(routingDecision.tier, tierConfigs);
90707
+ const selectedModel = routingDecision.model;
90708
+ const fullChain = prependStickyExplicitModel([
90709
+ selectedModel,
90710
+ ...rankedCandidates.filter((model) => model !== selectedModel)
90711
+ ]);
90712
+ const contextFiltered = filterCandidatesByCapacity(
90713
+ fullChain,
90714
+ estimatedInputTokens,
90715
+ maxTokens,
90716
+ (modelId2) => {
90717
+ const model = BLOCKRUN_MODEL_BY_ID.get(modelId2);
90718
+ return model ? { contextWindow: model.contextWindow, maxOutput: model.maxOutput } : void 0;
90719
+ }
89248
90720
  );
90721
+ if (contextFiltered.length === 0) {
90722
+ const errPayload = JSON.stringify({
90723
+ error: {
90724
+ message: `No routed model can satisfy the requested context and output capacity (~${estimatedTotalTokens} tokens). Reduce the input or max_tokens and retry.`,
90725
+ type: "invalid_request_error",
90726
+ code: "context_capacity_exceeded"
90727
+ }
90728
+ });
90729
+ if (heartbeatInterval) {
90730
+ clearInterval(heartbeatInterval);
90731
+ heartbeatInterval = void 0;
90732
+ }
90733
+ if (headersSentEarly) {
90734
+ safeWrite(res, `data: ${errPayload}
90735
+
90736
+ data: [DONE]
90737
+
90738
+ `);
90739
+ res.end();
90740
+ } else {
90741
+ res.writeHead(400, { "Content-Type": "application/json" });
90742
+ res.end(errPayload);
90743
+ }
90744
+ completed = true;
90745
+ deduplicator.removeInflight(dedupKey);
90746
+ clearTimeout(timeoutId);
90747
+ req.removeListener("close", onClientClose);
90748
+ return;
90749
+ }
89249
90750
  const contextExcluded = fullChain.filter((m) => !contextFiltered.includes(m));
89250
90751
  if (contextExcluded.length > 0) {
89251
90752
  console.log(
89252
90753
  `[ClawRouter] Context filter (~${estimatedTotalTokens} tokens): excluded ${contextExcluded.join(", ")}`
89253
90754
  );
89254
90755
  }
89255
- const excludeFiltered = prependStickyExplicitModel(
89256
- filterByExcludeList(contextFiltered, excludeList)
89257
- );
90756
+ const excludeFiltered = filterByExcludeList(contextFiltered, excludeList);
89258
90757
  const excludeExcluded = contextFiltered.filter((m) => !excludeFiltered.includes(m));
89259
90758
  if (excludeExcluded.length > 0) {
89260
90759
  console.log(
89261
90760
  `[ClawRouter] Exclude filter: excluded ${excludeExcluded.join(", ")} (user preference)`
89262
90761
  );
89263
90762
  }
89264
- let toolFiltered = prependStickyExplicitModel(
89265
- filterByToolCalling(excludeFiltered, hasTools, supportsToolCalling)
89266
- );
90763
+ let toolFiltered = filterByToolCalling(excludeFiltered, hasTools, supportsToolCalling);
89267
90764
  const toolExcluded = excludeFiltered.filter((m) => !toolFiltered.includes(m));
89268
90765
  if (toolExcluded.length > 0) {
89269
90766
  console.log(
@@ -89282,19 +90779,17 @@ async function proxyRequest(req, res, apiBase, payFetch, options, routerOpts, de
89282
90779
  console.log(
89283
90780
  `[ClawRouter] Tool-compliance filter: excluded ${dropped.join(", ")} (unreliable tool schema handling)`
89284
90781
  );
89285
- toolFiltered = prependStickyExplicitModel(compliant);
90782
+ toolFiltered = compliant;
89286
90783
  }
89287
90784
  }
89288
- const visionFiltered = prependStickyExplicitModel(
89289
- filterByVision(toolFiltered, hasVision, supportsVision)
89290
- );
90785
+ const visionFiltered = filterByVision(toolFiltered, hasVision, supportsVision);
89291
90786
  const visionExcluded = toolFiltered.filter((m) => !visionFiltered.includes(m));
89292
90787
  if (visionExcluded.length > 0) {
89293
90788
  console.log(
89294
90789
  `[ClawRouter] Vision filter: excluded ${visionExcluded.join(", ")} (no vision support)`
89295
90790
  );
89296
90791
  }
89297
- modelsToTry = prependStickyExplicitModel(visionFiltered).slice(0, MAX_FALLBACK_ATTEMPTS);
90792
+ modelsToTry = visionFiltered.slice(0, MAX_FALLBACK_ATTEMPTS);
89298
90793
  modelsToTry = prioritizeNonRateLimited(modelsToTry);
89299
90794
  } else {
89300
90795
  modelsToTry = modelId ? [modelId] : [];
@@ -90184,7 +91679,7 @@ var init_proxy = __esm({
90184
91679
  init_client2();
90185
91680
  init_esm5();
90186
91681
  init_router();
90187
- init_rules();
91682
+ init_router();
90188
91683
  init_models();
90189
91684
  init_max_tokens();
90190
91685
  init_logger();
@@ -90198,7 +91693,7 @@ var init_proxy = __esm({
90198
91693
  init_session();
90199
91694
  init_updater();
90200
91695
  init_exclude_models();
90201
- init_config2();
91696
+ init_config();
90202
91697
  init_journal();
90203
91698
  init_upstream_proxy();
90204
91699
  init_textual_tool_calls();
@@ -91830,7 +93325,7 @@ var init_headers = __esm({
91830
93325
 
91831
93326
  // node_modules/@polymarket/clob-client-v2/dist/config.js
91832
93327
  var AMOY_CONTRACTS, MATIC_CONTRACTS, COLLATERAL_TOKEN_DECIMALS, getContractConfig;
91833
- var init_config3 = __esm({
93328
+ var init_config2 = __esm({
91834
93329
  "node_modules/@polymarket/clob-client-v2/dist/config.js"() {
91835
93330
  "use strict";
91836
93331
  AMOY_CONTRACTS = {
@@ -92130,7 +93625,7 @@ var init_buildMarketOrderCreationArgs = __esm({
92130
93625
  "node_modules/@polymarket/clob-client-v2/dist/order-builder/helpers/buildMarketOrderCreationArgs.js"() {
92131
93626
  "use strict";
92132
93627
  init_constants2();
92133
- init_config3();
93628
+ init_config2();
92134
93629
  init_getMarketOrderRawAmounts();
92135
93630
  init_esm();
92136
93631
  }
@@ -92691,7 +94186,7 @@ var init_createMarketOrder = __esm({
92691
94186
  "node_modules/@polymarket/clob-client-v2/dist/order-builder/helpers/createMarketOrder.js"() {
92692
94187
  "use strict";
92693
94188
  init_signer();
92694
- init_config3();
94189
+ init_config2();
92695
94190
  init_buildMarketOrderCreationArgs();
92696
94191
  init_signatureTypeV2();
92697
94192
  init_buildOrder();
@@ -92799,7 +94294,7 @@ var init_buildOrderCreationArgs = __esm({
92799
94294
  "node_modules/@polymarket/clob-client-v2/dist/order-builder/helpers/buildOrderCreationArgs.js"() {
92800
94295
  "use strict";
92801
94296
  init_constants2();
92802
- init_config3();
94297
+ init_config2();
92803
94298
  init_getOrderRawAmounts();
92804
94299
  init_esm();
92805
94300
  }
@@ -92811,7 +94306,7 @@ var init_createOrder = __esm({
92811
94306
  "node_modules/@polymarket/clob-client-v2/dist/order-builder/helpers/createOrder.js"() {
92812
94307
  "use strict";
92813
94308
  init_signer();
92814
- init_config3();
94309
+ init_config2();
92815
94310
  init_signatureTypeV2();
92816
94311
  init_buildOrder();
92817
94312
  init_buildOrderCreationArgs();
@@ -92849,7 +94344,7 @@ var init_createExchangeV3OrderFromAmounts = __esm({
92849
94344
  "use strict";
92850
94345
  init_constants2();
92851
94346
  init_signer();
92852
- init_config3();
94347
+ init_config2();
92853
94348
  init_signatureTypeV2();
92854
94349
  init_buildOrder();
92855
94350
  createExchangeV3OrderFromAmounts = async (eoaSigner, chainId, signatureType, funderAddress, userOrder) => {
@@ -110651,7 +112146,7 @@ var init_axios2 = __esm({
110651
112146
 
110652
112147
  // node_modules/browser-or-node/dist/index.mjs
110653
112148
  var isBrowser, isNode, isWebWorker, isJsDom, isDeno, isBun;
110654
- var init_dist = __esm({
112149
+ var init_dist2 = __esm({
110655
112150
  "node_modules/browser-or-node/dist/index.mjs"() {
110656
112151
  "use strict";
110657
112152
  isBrowser = typeof window !== "undefined" && typeof window.document !== "undefined";
@@ -110675,7 +112170,7 @@ var init_http_helpers = __esm({
110675
112170
  "node_modules/@polymarket/clob-client-v2/dist/http-helpers/index.js"() {
110676
112171
  "use strict";
110677
112172
  init_axios2();
110678
- init_dist();
112173
+ init_dist2();
110679
112174
  GET = "GET";
110680
112175
  POST = "POST";
110681
112176
  DELETE = "DELETE";
@@ -111707,10 +113202,10 @@ var init_client4 = __esm({
111707
113202
  });
111708
113203
 
111709
113204
  // node_modules/@polymarket/clob-client-v2/dist/index.js
111710
- var init_dist2 = __esm({
113205
+ var init_dist3 = __esm({
111711
113206
  "node_modules/@polymarket/clob-client-v2/dist/index.js"() {
111712
113207
  "use strict";
111713
- init_config3();
113208
+ init_config2();
111714
113209
  init_signatureTypeV2();
111715
113210
  init_side();
111716
113211
  init_clob();
@@ -111730,7 +113225,7 @@ import * as net from "net";
111730
113225
  import * as http4 from "http";
111731
113226
  import { Agent as HttpsAgent } from "https";
111732
113227
  var INTERNAL, Agent2;
111733
- var init_dist3 = __esm({
113228
+ var init_dist4 = __esm({
111734
113229
  "node_modules/agent-base/dist/index.js"() {
111735
113230
  "use strict";
111736
113231
  init_helpers();
@@ -111969,7 +113464,7 @@ function createNegotiateAuth() {
111969
113464
  };
111970
113465
  };
111971
113466
  }
111972
- var init_dist4 = __esm({
113467
+ var init_dist5 = __esm({
111973
113468
  "node_modules/proxy-agent-negotiate/dist/index.js"() {
111974
113469
  "use strict";
111975
113470
  }
@@ -111996,13 +113491,13 @@ function omit(obj, ...keys) {
111996
113491
  return ret;
111997
113492
  }
111998
113493
  var import_debug2, debug2, setServernameFromNonIpHost, HttpsProxyAgent2;
111999
- var init_dist5 = __esm({
113494
+ var init_dist6 = __esm({
112000
113495
  "node_modules/https-proxy-agent/dist/index.js"() {
112001
113496
  "use strict";
112002
113497
  import_debug2 = __toESM(require_src(), 1);
112003
- init_dist3();
112004
- init_parse_proxy_response();
112005
113498
  init_dist4();
113499
+ init_parse_proxy_response();
113500
+ init_dist5();
112006
113501
  debug2 = (0, import_debug2.default)("https-proxy-agent");
112007
113502
  setServernameFromNonIpHost = (options) => {
112008
113503
  if (options.servername === void 0 && options.host && !net2.isIP(options.host)) {
@@ -112215,7 +113710,7 @@ var POLYGON_CHAIN_ID, CTF_EXCHANGE_V2, NEG_RISK_CTF_EXCHANGE_V2, NEG_RISK_ADAPTE
112215
113710
  var init_constants3 = __esm({
112216
113711
  "src/polymarket/constants.ts"() {
112217
113712
  "use strict";
112218
- init_dist2();
113713
+ init_dist3();
112219
113714
  POLYGON_CHAIN_ID = 137;
112220
113715
  CTF_EXCHANGE_V2 = "0xE111180000d2663C0091e4f400237545B87B996B";
112221
113716
  NEG_RISK_CTF_EXCHANGE_V2 = "0xe2222d279d744050d28e00520010520000310F59";
@@ -112752,11 +114247,11 @@ var init_client5 = __esm({
112752
114247
  "src/polymarket/client.ts"() {
112753
114248
  "use strict";
112754
114249
  init_axios2();
112755
- init_dist5();
114250
+ init_dist6();
112756
114251
  init_esm();
112757
114252
  init_accounts();
112758
114253
  init_chains();
112759
- init_dist2();
114254
+ init_dist3();
112760
114255
  init_wallet_adapter();
112761
114256
  init_constants3();
112762
114257
  init_creds();
@@ -113126,7 +114621,7 @@ var ledger;
113126
114621
  var init_orders = __esm({
113127
114622
  "src/polymarket/orders.ts"() {
113128
114623
  "use strict";
113129
- init_dist2();
114624
+ init_dist3();
113130
114625
  init_client5();
113131
114626
  init_constants3();
113132
114627
  init_creds();
@@ -220308,7 +221803,7 @@ var init_relayer = __esm({
220308
221803
  "use strict";
220309
221804
  import_builder_relayer_client = __toESM(require_dist3(), 1);
220310
221805
  import_builder_signing_sdk = __toESM(require_dist4(), 1);
220311
- init_dist2();
221806
+ init_dist3();
220312
221807
  init_esm();
220313
221808
  init_chains();
220314
221809
  init_client5();
@@ -220648,7 +222143,7 @@ var init_setup = __esm({
220648
222143
  "use strict";
220649
222144
  init_esm();
220650
222145
  init_chains();
220651
- init_dist2();
222146
+ init_dist3();
220652
222147
  init_client5();
220653
222148
  init_constants3();
220654
222149
  init_creds();
@@ -221102,7 +222597,7 @@ function sleep2(ms) {
221102
222597
  return new Promise((r2) => setTimeout(r2, ms));
221103
222598
  }
221104
222599
  var BlockrunError, PaymentError, APIError, BASE_CHAIN_ID2, USDC_BASE2, USDC_DOMAIN, TRANSFER_TYPES, BLOCKRUN_SERVICE_CODE2, LOCALHOST_DOMAINS, BLOCKRUN_DIR2, COST_LOG_FILE, SDK_VERSION, USER_AGENT2, DEFAULT_TIMEOUT, PHONE_PRICES, DEFAULT_API_URL13, DEFAULT_TIMEOUT13, DEFAULT_POLL_INTERVAL_MS, DEFAULT_POLL_BUDGET_MS, MAX_SIGNED_AUTH_SECONDS, BlockrunClient, WALLET_DIR2, WALLET_FILE3, WALLET_DIR22, SOLANA_WALLET_FILE, CACHE_DIR, DATA_DIR, COST_LOG_FILE2, DEFAULT_TTL;
221105
- var init_dist6 = __esm({
222600
+ var init_dist7 = __esm({
221106
222601
  "node_modules/@blockrun/llm/dist/index.js"() {
221107
222602
  "use strict";
221108
222603
  init_accounts();
@@ -221670,7 +223165,7 @@ var init_fund = __esm({
221670
223165
  "src/polymarket/fund.ts"() {
221671
223166
  "use strict";
221672
223167
  init_axios2();
221673
- init_dist6();
223168
+ init_dist7();
221674
223169
  init_wallet_adapter();
221675
223170
  init_client5();
221676
223171
  init_constants3();
@@ -222149,29 +223644,29 @@ var init_spend_control = __esm({
222149
223644
  getLimits() {
222150
223645
  return { ...this.limits };
222151
223646
  }
222152
- check(estimatedCost) {
223647
+ check(estimatedCost2) {
222153
223648
  const now2 = this.now();
222154
223649
  if (this.limits.perRequest !== void 0) {
222155
- if (estimatedCost > this.limits.perRequest) {
223650
+ if (estimatedCost2 > this.limits.perRequest) {
222156
223651
  return {
222157
223652
  allowed: false,
222158
223653
  blockedBy: "perRequest",
222159
223654
  remaining: this.limits.perRequest,
222160
- reason: `Per-request limit exceeded: $${estimatedCost.toFixed(4)} > $${this.limits.perRequest.toFixed(2)} max`
223655
+ reason: `Per-request limit exceeded: $${estimatedCost2.toFixed(4)} > $${this.limits.perRequest.toFixed(2)} max`
222161
223656
  };
222162
223657
  }
222163
223658
  }
222164
223659
  if (this.limits.hourly !== void 0) {
222165
223660
  const hourlySpent = this.getSpendingInWindow(now2 - HOUR_MS, now2);
222166
223661
  const remaining = this.limits.hourly - hourlySpent;
222167
- if (estimatedCost > remaining) {
223662
+ if (estimatedCost2 > remaining) {
222168
223663
  const oldestInWindow = this.history.find((r2) => r2.timestamp >= now2 - HOUR_MS);
222169
223664
  const resetIn = oldestInWindow ? Math.ceil((oldestInWindow.timestamp + HOUR_MS - now2) / 1e3) : 0;
222170
223665
  return {
222171
223666
  allowed: false,
222172
223667
  blockedBy: "hourly",
222173
223668
  remaining,
222174
- reason: `Hourly limit exceeded: $${(hourlySpent + estimatedCost).toFixed(2)} > $${this.limits.hourly.toFixed(2)} max`,
223669
+ reason: `Hourly limit exceeded: $${(hourlySpent + estimatedCost2).toFixed(2)} > $${this.limits.hourly.toFixed(2)} max`,
222175
223670
  resetIn
222176
223671
  };
222177
223672
  }
@@ -222179,26 +223674,26 @@ var init_spend_control = __esm({
222179
223674
  if (this.limits.daily !== void 0) {
222180
223675
  const dailySpent = this.getSpendingInWindow(now2 - DAY_MS, now2);
222181
223676
  const remaining = this.limits.daily - dailySpent;
222182
- if (estimatedCost > remaining) {
223677
+ if (estimatedCost2 > remaining) {
222183
223678
  const oldestInWindow = this.history.find((r2) => r2.timestamp >= now2 - DAY_MS);
222184
223679
  const resetIn = oldestInWindow ? Math.ceil((oldestInWindow.timestamp + DAY_MS - now2) / 1e3) : 0;
222185
223680
  return {
222186
223681
  allowed: false,
222187
223682
  blockedBy: "daily",
222188
223683
  remaining,
222189
- reason: `Daily limit exceeded: $${(dailySpent + estimatedCost).toFixed(2)} > $${this.limits.daily.toFixed(2)} max`,
223684
+ reason: `Daily limit exceeded: $${(dailySpent + estimatedCost2).toFixed(2)} > $${this.limits.daily.toFixed(2)} max`,
222190
223685
  resetIn
222191
223686
  };
222192
223687
  }
222193
223688
  }
222194
223689
  if (this.limits.session !== void 0) {
222195
223690
  const remaining = this.limits.session - this.sessionSpent;
222196
- if (estimatedCost > remaining) {
223691
+ if (estimatedCost2 > remaining) {
222197
223692
  return {
222198
223693
  allowed: false,
222199
223694
  blockedBy: "session",
222200
223695
  remaining,
222201
- reason: `Session limit exceeded: $${(this.sessionSpent + estimatedCost).toFixed(2)} > $${this.limits.session.toFixed(2)} max`
223696
+ reason: `Session limit exceeded: $${(this.sessionSpent + estimatedCost2).toFixed(2)} > $${this.limits.session.toFixed(2)} max`
222202
223697
  };
222203
223698
  }
222204
223699
  }
@@ -222383,6 +223878,7 @@ __export(index_exports, {
222383
223878
  deriveEvmKey: () => deriveEvmKey,
222384
223879
  deriveSolanaKeyBytes: () => deriveSolanaKeyBytes,
222385
223880
  fetchWithRetry: () => fetchWithRetry,
223881
+ filterCandidatesByCapacity: () => filterCandidatesByCapacity,
222386
223882
  formatDuration: () => formatDuration,
222387
223883
  formatStatsAscii: () => formatStatsAscii,
222388
223884
  generateWalletMnemonic: () => generateWalletMnemonic,
@@ -222395,6 +223891,7 @@ __export(index_exports, {
222395
223891
  getSessionId: () => getSessionId,
222396
223892
  getStats: () => getStats,
222397
223893
  hashRequestContent: () => hashRequestContent,
223894
+ inferToolRequirement: () => inferToolRequirement,
222398
223895
  injectAuthProfile: () => injectAuthProfile,
222399
223896
  injectModelsConfig: () => injectModelsConfig,
222400
223897
  isAgenticModel: () => isAgenticModel,
@@ -222939,6 +224436,11 @@ async function startProxyInBackground(api, startupGeneration) {
222939
224436
  `[${decision.tier}] ${decision.model} $${cost} (saved ${saved}%) | ${decision.reasoning}`
222940
224437
  );
222941
224438
  },
224439
+ onShadowRouted: (comparison) => {
224440
+ api.logger.info(
224441
+ `[router-shadow] executed=${comparison.executed.model} (${comparison.executed.method}) candidate=${comparison.shadow.model} (${comparison.shadow.method}) same=${comparison.sameModel} tools=${comparison.hasTools} vision=${comparison.hasVision} structured=${comparison.requiresStructuredOutput}`
224442
+ );
224443
+ },
222942
224444
  onLowBalance: (info) => {
222943
224445
  api.logger.warn(`[!] Low balance: ${info.balanceUSD}. Fund wallet: ${info.walletAddress}`);
222944
224446
  },