@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.
@@ -0,0 +1,3292 @@
1
+ import { createRequire as __blockrun_createRequire } from 'node:module'; const require = __blockrun_createRequire(import.meta.url);
2
+
3
+ // node_modules/@blockrun/router-core/dist/index.js
4
+ function scoreTokenCount(estimatedTokens, thresholds) {
5
+ if (estimatedTokens < thresholds.simple) {
6
+ return { name: "tokenCount", score: -1, signal: `short (${estimatedTokens} tokens)` };
7
+ }
8
+ if (estimatedTokens > thresholds.complex) {
9
+ return { name: "tokenCount", score: 1, signal: `long (${estimatedTokens} tokens)` };
10
+ }
11
+ return { name: "tokenCount", score: 0, signal: null };
12
+ }
13
+ function scoreKeywordMatch(text, keywords, name, signalLabel, thresholds, scores) {
14
+ const matches = keywords.filter((kw) => text.includes(kw.toLowerCase()));
15
+ if (matches.length >= thresholds.high) {
16
+ return {
17
+ name,
18
+ score: scores.high,
19
+ signal: `${signalLabel} (${matches.slice(0, 3).join(", ")})`
20
+ };
21
+ }
22
+ if (matches.length >= thresholds.low) {
23
+ return {
24
+ name,
25
+ score: scores.low,
26
+ signal: `${signalLabel} (${matches.slice(0, 3).join(", ")})`
27
+ };
28
+ }
29
+ return { name, score: scores.none, signal: null };
30
+ }
31
+ function scoreMultiStep(text) {
32
+ const patterns = [/first.*then/i, /step \d/i, /\d\.\s/];
33
+ const hits = patterns.filter((p) => p.test(text));
34
+ if (hits.length > 0) {
35
+ return { name: "multiStepPatterns", score: 0.5, signal: "multi-step" };
36
+ }
37
+ return { name: "multiStepPatterns", score: 0, signal: null };
38
+ }
39
+ function scoreQuestionComplexity(prompt) {
40
+ const count = (prompt.match(/\?/g) || []).length;
41
+ if (count > 3) {
42
+ return { name: "questionComplexity", score: 0.5, signal: `${count} questions` };
43
+ }
44
+ return { name: "questionComplexity", score: 0, signal: null };
45
+ }
46
+ function scoreAgenticTask(text, keywords) {
47
+ let matchCount = 0;
48
+ const signals = [];
49
+ for (const keyword of keywords) {
50
+ if (text.includes(keyword.toLowerCase())) {
51
+ matchCount++;
52
+ if (signals.length < 3) {
53
+ signals.push(keyword);
54
+ }
55
+ }
56
+ }
57
+ if (matchCount >= 4) {
58
+ return {
59
+ dimensionScore: {
60
+ name: "agenticTask",
61
+ score: 1,
62
+ signal: `agentic (${signals.join(", ")})`
63
+ },
64
+ agenticScore: 1
65
+ };
66
+ } else if (matchCount >= 3) {
67
+ return {
68
+ dimensionScore: {
69
+ name: "agenticTask",
70
+ score: 0.6,
71
+ signal: `agentic (${signals.join(", ")})`
72
+ },
73
+ agenticScore: 0.6
74
+ };
75
+ } else if (matchCount >= 1) {
76
+ return {
77
+ dimensionScore: {
78
+ name: "agenticTask",
79
+ score: 0.2,
80
+ signal: `agentic-light (${signals.join(", ")})`
81
+ },
82
+ agenticScore: 0.2
83
+ };
84
+ }
85
+ return {
86
+ dimensionScore: { name: "agenticTask", score: 0, signal: null },
87
+ agenticScore: 0
88
+ };
89
+ }
90
+ function classifyByRules(prompt, systemPrompt, estimatedTokens, config) {
91
+ const userText = prompt.toLowerCase();
92
+ const dimensions = [
93
+ // Token count uses total estimated tokens (system + user) — context size matters for model selection
94
+ scoreTokenCount(estimatedTokens, config.tokenCountThresholds),
95
+ scoreKeywordMatch(
96
+ userText,
97
+ config.codeKeywords,
98
+ "codePresence",
99
+ "code",
100
+ { low: 1, high: 2 },
101
+ { none: 0, low: 0.5, high: 1 }
102
+ ),
103
+ scoreKeywordMatch(
104
+ userText,
105
+ config.reasoningKeywords,
106
+ "reasoningMarkers",
107
+ "reasoning",
108
+ { low: 1, high: 2 },
109
+ { none: 0, low: 0.7, high: 1 }
110
+ ),
111
+ scoreKeywordMatch(
112
+ userText,
113
+ config.technicalKeywords,
114
+ "technicalTerms",
115
+ "technical",
116
+ { low: 2, high: 4 },
117
+ { none: 0, low: 0.5, high: 1 }
118
+ ),
119
+ scoreKeywordMatch(
120
+ userText,
121
+ config.creativeKeywords,
122
+ "creativeMarkers",
123
+ "creative",
124
+ { low: 1, high: 2 },
125
+ { none: 0, low: 0.5, high: 0.7 }
126
+ ),
127
+ scoreKeywordMatch(
128
+ userText,
129
+ config.simpleKeywords,
130
+ "simpleIndicators",
131
+ "simple",
132
+ { low: 1, high: 2 },
133
+ { none: 0, low: -1, high: -1 }
134
+ ),
135
+ scoreMultiStep(userText),
136
+ scoreQuestionComplexity(prompt),
137
+ // 6 new dimensions
138
+ scoreKeywordMatch(
139
+ userText,
140
+ config.imperativeVerbs,
141
+ "imperativeVerbs",
142
+ "imperative",
143
+ { low: 1, high: 2 },
144
+ { none: 0, low: 0.3, high: 0.5 }
145
+ ),
146
+ scoreKeywordMatch(
147
+ userText,
148
+ config.constraintIndicators,
149
+ "constraintCount",
150
+ "constraints",
151
+ { low: 1, high: 3 },
152
+ { none: 0, low: 0.3, high: 0.7 }
153
+ ),
154
+ scoreKeywordMatch(
155
+ userText,
156
+ config.outputFormatKeywords,
157
+ "outputFormat",
158
+ "format",
159
+ { low: 1, high: 2 },
160
+ { none: 0, low: 0.4, high: 0.7 }
161
+ ),
162
+ scoreKeywordMatch(
163
+ userText,
164
+ config.referenceKeywords,
165
+ "referenceComplexity",
166
+ "references",
167
+ { low: 1, high: 2 },
168
+ { none: 0, low: 0.3, high: 0.5 }
169
+ ),
170
+ scoreKeywordMatch(
171
+ userText,
172
+ config.negationKeywords,
173
+ "negationComplexity",
174
+ "negation",
175
+ { low: 2, high: 3 },
176
+ { none: 0, low: 0.3, high: 0.5 }
177
+ ),
178
+ scoreKeywordMatch(
179
+ userText,
180
+ config.domainSpecificKeywords,
181
+ "domainSpecificity",
182
+ "domain-specific",
183
+ { low: 1, high: 2 },
184
+ { none: 0, low: 0.5, high: 0.8 }
185
+ )
186
+ ];
187
+ const agenticResult = scoreAgenticTask(userText, config.agenticTaskKeywords);
188
+ dimensions.push(agenticResult.dimensionScore);
189
+ const agenticScore = agenticResult.agenticScore;
190
+ const signals = dimensions.filter((d) => d.signal !== null).map((d) => d.signal);
191
+ const weights = config.dimensionWeights;
192
+ let weightedScore = 0;
193
+ for (const d of dimensions) {
194
+ const w = weights[d.name] ?? 0;
195
+ weightedScore += d.score * w;
196
+ }
197
+ const reasoningMatches = config.reasoningKeywords.filter(
198
+ (kw) => userText.includes(kw.toLowerCase())
199
+ );
200
+ if (reasoningMatches.length >= 2) {
201
+ const confidence2 = calibrateConfidence(
202
+ Math.max(weightedScore, 0.3),
203
+ // ensure positive for confidence calc
204
+ config.confidenceSteepness
205
+ );
206
+ return {
207
+ score: weightedScore,
208
+ tier: "REASONING",
209
+ confidence: Math.max(confidence2, 0.85),
210
+ signals,
211
+ agenticScore,
212
+ dimensions
213
+ };
214
+ }
215
+ const { simpleMedium, mediumComplex, complexReasoning } = config.tierBoundaries;
216
+ let tier;
217
+ let distanceFromBoundary;
218
+ if (weightedScore < simpleMedium) {
219
+ tier = "SIMPLE";
220
+ distanceFromBoundary = simpleMedium - weightedScore;
221
+ } else if (weightedScore < mediumComplex) {
222
+ tier = "MEDIUM";
223
+ distanceFromBoundary = Math.min(weightedScore - simpleMedium, mediumComplex - weightedScore);
224
+ } else if (weightedScore < complexReasoning) {
225
+ tier = "COMPLEX";
226
+ distanceFromBoundary = Math.min(
227
+ weightedScore - mediumComplex,
228
+ complexReasoning - weightedScore
229
+ );
230
+ } else {
231
+ tier = "REASONING";
232
+ distanceFromBoundary = weightedScore - complexReasoning;
233
+ }
234
+ const confidence = calibrateConfidence(distanceFromBoundary, config.confidenceSteepness);
235
+ if (confidence < config.confidenceThreshold) {
236
+ return { score: weightedScore, tier: null, confidence, signals, agenticScore, dimensions };
237
+ }
238
+ return { score: weightedScore, tier, confidence, signals, agenticScore, dimensions };
239
+ }
240
+ function calibrateConfidence(distance, steepness) {
241
+ return 1 / (1 + Math.exp(-steepness * distance));
242
+ }
243
+ var BASELINE_MODEL_ID = "anthropic/claude-opus-4.7";
244
+ var BASELINE_INPUT_PRICE = 5;
245
+ var BASELINE_OUTPUT_PRICE = 25;
246
+ function selectModel(tier, confidence, method, reasoning, tierConfigs, modelPricing, estimatedInputTokens, maxOutputTokens, routingProfile, agenticScore) {
247
+ const tierConfig = tierConfigs[tier];
248
+ const model = tierConfig.primary;
249
+ const pricing = modelPricing.get(model);
250
+ let costEstimate;
251
+ if (pricing?.flatPrice !== void 0) {
252
+ costEstimate = pricing.flatPrice;
253
+ } else {
254
+ const inputPrice = pricing?.inputPrice ?? 0;
255
+ const outputPrice = pricing?.outputPrice ?? 0;
256
+ costEstimate = estimatedInputTokens / 1e6 * inputPrice + maxOutputTokens / 1e6 * outputPrice;
257
+ }
258
+ const opusPricing = modelPricing.get(BASELINE_MODEL_ID);
259
+ const opusInputPrice = opusPricing?.inputPrice ?? BASELINE_INPUT_PRICE;
260
+ const opusOutputPrice = opusPricing?.outputPrice ?? BASELINE_OUTPUT_PRICE;
261
+ const baselineInput = estimatedInputTokens / 1e6 * opusInputPrice;
262
+ const baselineOutput = maxOutputTokens / 1e6 * opusOutputPrice;
263
+ const baselineCost = baselineInput + baselineOutput;
264
+ const savings = routingProfile === "premium" ? 0 : baselineCost > 0 ? Math.max(0, (baselineCost - costEstimate) / baselineCost) : 0;
265
+ return {
266
+ model,
267
+ tier,
268
+ confidence,
269
+ method,
270
+ reasoning,
271
+ costEstimate,
272
+ baselineCost,
273
+ savings,
274
+ ...agenticScore !== void 0 && { agenticScore }
275
+ };
276
+ }
277
+ function getFallbackChain(tier, tierConfigs) {
278
+ const config = tierConfigs[tier];
279
+ return [config.primary, ...config.fallback];
280
+ }
281
+ var SERVER_MARGIN_PERCENT = 5;
282
+ var MIN_PAYMENT_USD = 1e-3;
283
+ function calculateModelCost(model, modelPricing, estimatedInputTokens, maxOutputTokens, routingProfile) {
284
+ const pricing = modelPricing.get(model);
285
+ let costEstimate;
286
+ if (pricing?.flatPrice !== void 0) {
287
+ costEstimate = Math.max(pricing.flatPrice * (1 + SERVER_MARGIN_PERCENT / 100), MIN_PAYMENT_USD);
288
+ } else {
289
+ const inputPrice = pricing?.inputPrice ?? 0;
290
+ const outputPrice = pricing?.outputPrice ?? 0;
291
+ const inputCost = estimatedInputTokens / 1e6 * inputPrice;
292
+ const outputCost = maxOutputTokens / 1e6 * outputPrice;
293
+ costEstimate = Math.max(
294
+ (inputCost + outputCost) * (1 + SERVER_MARGIN_PERCENT / 100),
295
+ MIN_PAYMENT_USD
296
+ );
297
+ }
298
+ const opusPricing = modelPricing.get(BASELINE_MODEL_ID);
299
+ const opusInputPrice = opusPricing?.inputPrice ?? BASELINE_INPUT_PRICE;
300
+ const opusOutputPrice = opusPricing?.outputPrice ?? BASELINE_OUTPUT_PRICE;
301
+ const baselineInput = estimatedInputTokens / 1e6 * opusInputPrice;
302
+ const baselineOutput = maxOutputTokens / 1e6 * opusOutputPrice;
303
+ const baselineCost = baselineInput + baselineOutput;
304
+ const savings = routingProfile === "premium" ? 0 : baselineCost > 0 ? Math.max(0, (baselineCost - costEstimate) / baselineCost) : 0;
305
+ return { costEstimate, baselineCost, savings };
306
+ }
307
+ function filterByToolCalling(models, hasTools, supportsToolCalling) {
308
+ if (!hasTools) return models;
309
+ const filtered = models.filter(supportsToolCalling);
310
+ return filtered.length > 0 ? filtered : models;
311
+ }
312
+ function filterByVision(models, hasVision, supportsVision) {
313
+ if (!hasVision) return models;
314
+ const filtered = models.filter(supportsVision);
315
+ return filtered.length > 0 ? filtered : models;
316
+ }
317
+ function filterByExcludeList(models, excludeList) {
318
+ if (excludeList.size === 0) return models;
319
+ const filtered = models.filter((m) => !excludeList.has(m));
320
+ return filtered.length > 0 ? filtered : models;
321
+ }
322
+ function getFallbackChainFiltered(tier, tierConfigs, estimatedTotalTokens, getContextWindow) {
323
+ const fullChain = getFallbackChain(tier, tierConfigs);
324
+ const filtered = fullChain.filter((modelId) => {
325
+ const contextWindow = getContextWindow(modelId);
326
+ if (contextWindow === void 0) {
327
+ return true;
328
+ }
329
+ return contextWindow >= estimatedTotalTokens * 1.1;
330
+ });
331
+ if (filtered.length === 0) {
332
+ return fullChain;
333
+ }
334
+ return filtered;
335
+ }
336
+ function filterCandidatesByCapacity(models, estimatedInputTokens, requestedOutputTokens, getCapabilities) {
337
+ const filtered = models.filter((modelId) => {
338
+ const capabilities = getCapabilities(modelId);
339
+ if (!capabilities) return true;
340
+ return capabilities.contextWindow >= (estimatedInputTokens + requestedOutputTokens) * 1.1 && capabilities.maxOutput >= requestedOutputTokens;
341
+ });
342
+ return filtered;
343
+ }
344
+ function applyPromotions(tierConfigs, promotions, profile, now = /* @__PURE__ */ new Date()) {
345
+ if (!promotions || promotions.length === 0) return tierConfigs;
346
+ let result = tierConfigs;
347
+ for (const promo of promotions) {
348
+ const start = new Date(promo.startDate);
349
+ const end = new Date(promo.endDate);
350
+ if (now < start || now >= end) continue;
351
+ if (promo.profiles && !promo.profiles.includes(profile)) continue;
352
+ if (result === tierConfigs) {
353
+ result = { ...tierConfigs };
354
+ for (const t of Object.keys(result)) {
355
+ result[t] = { ...result[t] };
356
+ }
357
+ }
358
+ for (const [tier, override] of Object.entries(promo.tierOverrides)) {
359
+ if (!result[tier]) continue;
360
+ if (override.primary) result[tier].primary = override.primary;
361
+ if (override.fallback) result[tier].fallback = override.fallback;
362
+ }
363
+ }
364
+ return result;
365
+ }
366
+ var RulesStrategy = class {
367
+ name = "rules";
368
+ route(prompt, systemPrompt, maxOutputTokens, options) {
369
+ const { config, modelPricing } = options;
370
+ const fullText = `${systemPrompt ?? ""} ${prompt}`;
371
+ const estimatedTokens = Math.ceil(fullText.length / 4);
372
+ const scanLimit = Math.max(1, Math.min(8e3, config.classifier.promptTruncationChars));
373
+ const sample = (value) => {
374
+ if (value.length <= scanLimit) return value;
375
+ const prefixLength = Math.ceil(scanLimit / 2);
376
+ return `${value.slice(0, prefixLength)}
377
+ ${value.slice(-(scanLimit - prefixLength))}`;
378
+ };
379
+ const scannedPrompt = sample(prompt);
380
+ const scannedSystemPrompt = systemPrompt ? sample(systemPrompt) : void 0;
381
+ const ruleResult = classifyByRules(
382
+ scannedPrompt,
383
+ scannedSystemPrompt,
384
+ estimatedTokens,
385
+ config.scoring
386
+ );
387
+ const { routingProfile } = options;
388
+ let tierConfigs;
389
+ let profileSuffix;
390
+ let profile;
391
+ if (routingProfile === "eco") {
392
+ tierConfigs = config.ecoTiers ?? config.tiers;
393
+ profileSuffix = config.ecoTiers ? " | eco" : " | eco (default tiers)";
394
+ profile = "eco";
395
+ } else if (routingProfile === "premium") {
396
+ tierConfigs = config.premiumTiers ?? config.tiers;
397
+ profileSuffix = config.premiumTiers ? " | premium" : " | premium (default tiers)";
398
+ profile = "premium";
399
+ } else {
400
+ const agenticScore = ruleResult.agenticScore ?? 0;
401
+ const isAutoAgentic = agenticScore >= 0.5;
402
+ const agenticModeSetting = config.overrides.agenticMode;
403
+ const hasToolsInRequest = options.requiresTools ?? options.hasTools ?? false;
404
+ let useAgenticTiers;
405
+ if (agenticModeSetting === false) {
406
+ useAgenticTiers = false;
407
+ } else if (agenticModeSetting === true) {
408
+ useAgenticTiers = config.agenticTiers != null;
409
+ } else {
410
+ useAgenticTiers = (hasToolsInRequest || isAutoAgentic) && config.agenticTiers != null;
411
+ }
412
+ tierConfigs = useAgenticTiers ? config.agenticTiers : config.tiers;
413
+ profileSuffix = useAgenticTiers ? ` | agentic${hasToolsInRequest ? " (tools)" : ""}` : "";
414
+ profile = useAgenticTiers ? "agentic" : "auto";
415
+ }
416
+ tierConfigs = applyPromotions(tierConfigs, config.promotions, profile, options.now);
417
+ const agenticScoreValue = ruleResult.agenticScore;
418
+ if (estimatedTokens > config.overrides.maxTokensForceComplex) {
419
+ const decision2 = selectModel(
420
+ "COMPLEX",
421
+ 0.95,
422
+ "rules",
423
+ `Input exceeds ${config.overrides.maxTokensForceComplex} tokens${profileSuffix}`,
424
+ tierConfigs,
425
+ modelPricing,
426
+ estimatedTokens,
427
+ maxOutputTokens,
428
+ routingProfile,
429
+ agenticScoreValue
430
+ );
431
+ return { ...decision2, tierConfigs, profile };
432
+ }
433
+ const hasStructuredOutput = options.requiresStructuredOutput === true || (scannedSystemPrompt ? /json|structured|schema/i.test(scannedSystemPrompt) : false);
434
+ let tier;
435
+ let confidence;
436
+ const method = "rules";
437
+ let reasoning = `score=${ruleResult.score.toFixed(2)} | ${ruleResult.signals.join(", ")}`;
438
+ if (ruleResult.tier !== null) {
439
+ tier = ruleResult.tier;
440
+ confidence = ruleResult.confidence;
441
+ } else {
442
+ tier = config.overrides.ambiguousDefaultTier;
443
+ confidence = 0.5;
444
+ reasoning += ` | ambiguous -> default: ${tier}`;
445
+ }
446
+ if (hasStructuredOutput) {
447
+ const tierRank = { SIMPLE: 0, MEDIUM: 1, COMPLEX: 2, REASONING: 3 };
448
+ const minTier = config.overrides.structuredOutputMinTier;
449
+ if (tierRank[tier] < tierRank[minTier]) {
450
+ reasoning += ` | upgraded to ${minTier} (structured output)`;
451
+ tier = minTier;
452
+ }
453
+ }
454
+ reasoning += profileSuffix;
455
+ const decision = selectModel(
456
+ tier,
457
+ confidence,
458
+ method,
459
+ reasoning,
460
+ tierConfigs,
461
+ modelPricing,
462
+ estimatedTokens,
463
+ maxOutputTokens,
464
+ routingProfile,
465
+ agenticScoreValue
466
+ );
467
+ return { ...decision, tierConfigs, profile };
468
+ }
469
+ };
470
+ var registry = /* @__PURE__ */ new Map();
471
+ registry.set("rules", new RulesStrategy());
472
+ function getStrategy(name) {
473
+ const strategy = registry.get(name);
474
+ if (!strategy) {
475
+ throw new Error(`Unknown routing strategy: ${name}`);
476
+ }
477
+ return strategy;
478
+ }
479
+ function registerStrategy(strategy) {
480
+ registry.set(strategy.name, strategy);
481
+ }
482
+ var DEFAULT_MODEL_CAPABILITIES = Object.freeze({
483
+ "anthropic/claude-fable-5": {
484
+ contextWindow: 1e6,
485
+ maxOutputTokens: 128e3,
486
+ supportsTools: true,
487
+ supportsVision: true
488
+ },
489
+ "anthropic/claude-haiku-4.5": {
490
+ contextWindow: 2e5,
491
+ maxOutputTokens: 8192,
492
+ supportsTools: true,
493
+ supportsVision: true
494
+ },
495
+ "anthropic/claude-opus-4.6": {
496
+ contextWindow: 1e6,
497
+ maxOutputTokens: 128e3,
498
+ supportsTools: true,
499
+ supportsVision: true
500
+ },
501
+ "anthropic/claude-opus-4.7": {
502
+ contextWindow: 1e6,
503
+ maxOutputTokens: 128e3,
504
+ supportsTools: true,
505
+ supportsVision: true
506
+ },
507
+ "anthropic/claude-opus-4.8": {
508
+ contextWindow: 1e6,
509
+ maxOutputTokens: 128e3,
510
+ supportsTools: true,
511
+ supportsVision: true
512
+ },
513
+ "anthropic/claude-opus-5": {
514
+ contextWindow: 1e6,
515
+ maxOutputTokens: 128e3,
516
+ supportsTools: true,
517
+ supportsVision: true
518
+ },
519
+ "anthropic/claude-sonnet-4.6": {
520
+ contextWindow: 2e5,
521
+ maxOutputTokens: 64e3,
522
+ supportsTools: true,
523
+ supportsVision: true
524
+ },
525
+ "anthropic/claude-sonnet-5": {
526
+ contextWindow: 1e6,
527
+ maxOutputTokens: 128e3,
528
+ supportsTools: true,
529
+ supportsVision: true
530
+ },
531
+ "deepseek/deepseek-chat": {
532
+ contextWindow: 1e6,
533
+ maxOutputTokens: 8192,
534
+ supportsTools: true,
535
+ supportsVision: false
536
+ },
537
+ "deepseek/deepseek-reasoner": {
538
+ contextWindow: 1e6,
539
+ maxOutputTokens: 8192,
540
+ supportsTools: true,
541
+ supportsVision: false
542
+ },
543
+ "deepseek/deepseek-v4-pro": {
544
+ contextWindow: 1048576,
545
+ maxOutputTokens: 65536,
546
+ supportsTools: true,
547
+ supportsVision: false
548
+ },
549
+ "free/deepseek-v4-flash": {
550
+ contextWindow: 1e6,
551
+ maxOutputTokens: 16384,
552
+ supportsTools: false,
553
+ supportsVision: false
554
+ },
555
+ "free/gpt-oss-120b": {
556
+ contextWindow: 128e3,
557
+ maxOutputTokens: 16384,
558
+ supportsTools: false,
559
+ supportsVision: false
560
+ },
561
+ "free/gpt-oss-20b": {
562
+ contextWindow: 128e3,
563
+ maxOutputTokens: 16384,
564
+ supportsTools: false,
565
+ supportsVision: false
566
+ },
567
+ "free/seed-oss-36b": {
568
+ contextWindow: 131072,
569
+ maxOutputTokens: 16384,
570
+ supportsTools: false,
571
+ supportsVision: false
572
+ },
573
+ "google/gemini-2.5-flash": {
574
+ contextWindow: 1e6,
575
+ maxOutputTokens: 65536,
576
+ supportsTools: true,
577
+ supportsVision: true
578
+ },
579
+ "google/gemini-2.5-flash-lite": {
580
+ contextWindow: 1e6,
581
+ maxOutputTokens: 65536,
582
+ supportsTools: true,
583
+ supportsVision: false
584
+ },
585
+ "google/gemini-2.5-pro": {
586
+ contextWindow: 105e4,
587
+ maxOutputTokens: 65536,
588
+ supportsTools: true,
589
+ supportsVision: true
590
+ },
591
+ "google/gemini-3-flash-preview": {
592
+ contextWindow: 1e6,
593
+ maxOutputTokens: 65536,
594
+ supportsTools: false,
595
+ supportsVision: true
596
+ },
597
+ "google/gemini-3.1-flash-lite": {
598
+ contextWindow: 1e6,
599
+ maxOutputTokens: 8192,
600
+ supportsTools: true,
601
+ supportsVision: false
602
+ },
603
+ "google/gemini-3.1-pro": {
604
+ contextWindow: 105e4,
605
+ maxOutputTokens: 65536,
606
+ supportsTools: true,
607
+ supportsVision: true
608
+ },
609
+ "google/gemini-3.5-flash": {
610
+ contextWindow: 1048576,
611
+ maxOutputTokens: 65536,
612
+ supportsTools: true,
613
+ supportsVision: true
614
+ },
615
+ "moonshot/kimi-k2.5": {
616
+ contextWindow: 262144,
617
+ maxOutputTokens: 16384,
618
+ supportsTools: true,
619
+ supportsVision: true
620
+ },
621
+ "moonshot/kimi-k2.6": {
622
+ contextWindow: 262144,
623
+ maxOutputTokens: 65536,
624
+ supportsTools: true,
625
+ supportsVision: true
626
+ },
627
+ "moonshot/kimi-k2.7": {
628
+ contextWindow: 262144,
629
+ maxOutputTokens: 65536,
630
+ supportsTools: true,
631
+ supportsVision: true
632
+ },
633
+ "moonshot/kimi-k3": {
634
+ contextWindow: 1048576,
635
+ maxOutputTokens: 65536,
636
+ supportsTools: true,
637
+ supportsVision: true
638
+ },
639
+ "openai/gpt-4.1": {
640
+ contextWindow: 128e3,
641
+ maxOutputTokens: 16384,
642
+ supportsTools: true,
643
+ supportsVision: true
644
+ },
645
+ "openai/gpt-4o-mini": {
646
+ contextWindow: 128e3,
647
+ maxOutputTokens: 16384,
648
+ supportsTools: true,
649
+ supportsVision: false
650
+ },
651
+ "openai/gpt-5-mini": {
652
+ contextWindow: 2e5,
653
+ maxOutputTokens: 65536,
654
+ supportsTools: true,
655
+ supportsVision: false
656
+ },
657
+ "openai/gpt-5.3-codex": {
658
+ contextWindow: 4e5,
659
+ maxOutputTokens: 128e3,
660
+ supportsTools: true,
661
+ supportsVision: false
662
+ },
663
+ "openai/gpt-5.4": {
664
+ contextWindow: 4e5,
665
+ maxOutputTokens: 128e3,
666
+ supportsTools: true,
667
+ supportsVision: true
668
+ },
669
+ "openai/gpt-5.4-nano": {
670
+ contextWindow: 105e4,
671
+ maxOutputTokens: 32768,
672
+ supportsTools: true,
673
+ supportsVision: false
674
+ },
675
+ "openai/gpt-5.5": {
676
+ contextWindow: 105e4,
677
+ maxOutputTokens: 128e3,
678
+ supportsTools: true,
679
+ supportsVision: true
680
+ },
681
+ "openai/gpt-5.6-terra": {
682
+ contextWindow: 105e4,
683
+ maxOutputTokens: 128e3,
684
+ supportsTools: true,
685
+ supportsVision: true
686
+ },
687
+ "openai/o3": {
688
+ contextWindow: 2e5,
689
+ maxOutputTokens: 1e5,
690
+ supportsTools: true,
691
+ supportsVision: false
692
+ },
693
+ "openai/o4-mini": {
694
+ contextWindow: 128e3,
695
+ maxOutputTokens: 65536,
696
+ supportsTools: true,
697
+ supportsVision: false
698
+ },
699
+ "qwen/qwen3.7-max": {
700
+ contextWindow: 1e6,
701
+ maxOutputTokens: 65536,
702
+ supportsTools: true,
703
+ supportsVision: false
704
+ },
705
+ "xai/grok-3-mini": {
706
+ contextWindow: 131072,
707
+ maxOutputTokens: 16384,
708
+ supportsTools: true,
709
+ supportsVision: false
710
+ },
711
+ "xai/grok-4-0709": {
712
+ contextWindow: 131072,
713
+ maxOutputTokens: 16384,
714
+ supportsTools: true,
715
+ supportsVision: false
716
+ },
717
+ "xai/grok-4-1-fast-non-reasoning": {
718
+ contextWindow: 131072,
719
+ maxOutputTokens: 16384,
720
+ supportsTools: true,
721
+ supportsVision: false
722
+ },
723
+ "xai/grok-4-1-fast-reasoning": {
724
+ contextWindow: 131072,
725
+ maxOutputTokens: 16384,
726
+ supportsTools: true,
727
+ supportsVision: false
728
+ },
729
+ "xai/grok-4-fast-non-reasoning": {
730
+ contextWindow: 131072,
731
+ maxOutputTokens: 16384,
732
+ supportsTools: true,
733
+ supportsVision: false
734
+ },
735
+ "xai/grok-4-fast-reasoning": {
736
+ contextWindow: 131072,
737
+ maxOutputTokens: 16384,
738
+ supportsTools: true,
739
+ supportsVision: false
740
+ },
741
+ "xai/grok-4.5": {
742
+ contextWindow: 5e5,
743
+ maxOutputTokens: 16384,
744
+ supportsTools: true,
745
+ supportsVision: true
746
+ },
747
+ "zai/glm-5.1": {
748
+ contextWindow: 2e5,
749
+ maxOutputTokens: 128e3,
750
+ supportsTools: true,
751
+ supportsVision: false
752
+ },
753
+ "zai/glm-5.2": {
754
+ contextWindow: 1e6,
755
+ maxOutputTokens: 262144,
756
+ supportsTools: true,
757
+ supportsVision: false
758
+ }
759
+ });
760
+ var model_profiles_generated_default = {
761
+ "openai/gpt-5.5": {
762
+ measuredAt: "2026-07-21T10:21:31Z",
763
+ latencyMs: 6243.1,
764
+ p95LatencyMs: 9865,
765
+ outputTokensPerSecond: 12.53,
766
+ errorRate: 0,
767
+ samples: 3
768
+ },
769
+ "openai/gpt-5.4-pro": {
770
+ measuredAt: "2026-07-21T10:21:31Z",
771
+ latencyMs: 13015.5,
772
+ p95LatencyMs: 23976.4,
773
+ outputTokensPerSecond: 6.42,
774
+ errorRate: 0,
775
+ samples: 3
776
+ },
777
+ "openai/gpt-5.4-mini": {
778
+ measuredAt: "2026-07-21T10:21:31Z",
779
+ latencyMs: 5550,
780
+ p95LatencyMs: 6595.7,
781
+ outputTokensPerSecond: 11.96,
782
+ errorRate: 0.3333,
783
+ samples: 3
784
+ },
785
+ "openai/gpt-5.3-codex": {
786
+ measuredAt: "2026-07-21T10:21:31Z",
787
+ latencyMs: 4617.1,
788
+ p95LatencyMs: 5800.7,
789
+ outputTokensPerSecond: 12.48,
790
+ errorRate: 0,
791
+ samples: 3
792
+ },
793
+ "anthropic/claude-opus-4.8": {
794
+ measuredAt: "2026-07-21T10:21:31Z",
795
+ latencyMs: 3915.1,
796
+ p95LatencyMs: 6130.8,
797
+ outputTokensPerSecond: 16.33,
798
+ errorRate: 0,
799
+ samples: 3
800
+ },
801
+ "anthropic/claude-opus-4.6": {
802
+ measuredAt: "2026-07-21T10:21:31Z",
803
+ latencyMs: 3765.5,
804
+ p95LatencyMs: 4257.2,
805
+ outputTokensPerSecond: 14.18,
806
+ errorRate: 0,
807
+ samples: 3
808
+ },
809
+ "anthropic/claude-sonnet-4.6": {
810
+ measuredAt: "2026-07-21T10:21:31Z",
811
+ latencyMs: 3860.6,
812
+ p95LatencyMs: 5093.5,
813
+ outputTokensPerSecond: 13.85,
814
+ errorRate: 0,
815
+ samples: 3
816
+ },
817
+ "anthropic/claude-haiku-4.5": {
818
+ measuredAt: "2026-07-21T10:21:31Z",
819
+ latencyMs: 2734.9,
820
+ p95LatencyMs: 3181.6,
821
+ outputTokensPerSecond: 19.58,
822
+ errorRate: 0,
823
+ samples: 3
824
+ },
825
+ "google/gemini-3.1-pro": {
826
+ measuredAt: "2026-07-21T10:21:31Z",
827
+ latencyMs: 13935.7,
828
+ p95LatencyMs: 26675.3,
829
+ outputTokensPerSecond: 77.47,
830
+ errorRate: 0,
831
+ samples: 3
832
+ },
833
+ "google/gemini-3.5-flash": {
834
+ measuredAt: "2026-07-21T10:21:31Z",
835
+ latencyMs: 4608.7,
836
+ p95LatencyMs: 8420.9,
837
+ outputTokensPerSecond: 57.88,
838
+ errorRate: 0,
839
+ samples: 3
840
+ },
841
+ "google/gemini-3.1-flash-lite": {
842
+ measuredAt: "2026-07-21T10:21:31Z",
843
+ latencyMs: 4619.7,
844
+ p95LatencyMs: 9927.1,
845
+ outputTokensPerSecond: 42.01,
846
+ errorRate: 0,
847
+ samples: 3
848
+ },
849
+ "google/gemini-2.5-flash": {
850
+ measuredAt: "2026-07-21T10:21:31Z",
851
+ latencyMs: 5506.9,
852
+ p95LatencyMs: 11462.5,
853
+ outputTokensPerSecond: 65.19,
854
+ errorRate: 0,
855
+ samples: 3
856
+ },
857
+ "deepseek/deepseek-v4-pro": {
858
+ measuredAt: "2026-07-21T10:21:31Z",
859
+ latencyMs: 6044.8,
860
+ p95LatencyMs: 10782.3,
861
+ outputTokensPerSecond: 22.47,
862
+ errorRate: 0,
863
+ samples: 3
864
+ },
865
+ "deepseek/deepseek-reasoner": {
866
+ measuredAt: "2026-07-21T10:21:31Z",
867
+ latencyMs: 4111.9,
868
+ p95LatencyMs: 5305.7,
869
+ outputTokensPerSecond: 16.46,
870
+ errorRate: 0,
871
+ samples: 3
872
+ },
873
+ "deepseek/deepseek-chat": {
874
+ measuredAt: "2026-07-21T10:21:31Z",
875
+ latencyMs: 2648.6,
876
+ p95LatencyMs: 3524.1,
877
+ outputTokensPerSecond: 16.73,
878
+ errorRate: 0,
879
+ samples: 3
880
+ },
881
+ "moonshot/kimi-k2.7": {
882
+ measuredAt: "2026-07-21T10:21:31Z",
883
+ latencyMs: 4295.4,
884
+ p95LatencyMs: 6153.8,
885
+ outputTokensPerSecond: 18.54,
886
+ errorRate: 0,
887
+ samples: 3
888
+ },
889
+ "qwen/qwen3.7-max": {
890
+ measuredAt: "2026-07-21T10:21:31Z",
891
+ latencyMs: 30729.4,
892
+ p95LatencyMs: 39622,
893
+ outputTokensPerSecond: 36.89,
894
+ errorRate: 0.3333,
895
+ samples: 3
896
+ },
897
+ "xai/grok-4.3": {
898
+ measuredAt: "2026-07-21T10:21:31Z",
899
+ latencyMs: 6946.1,
900
+ p95LatencyMs: 9495.4,
901
+ outputTokensPerSecond: 65.3,
902
+ errorRate: 0,
903
+ samples: 3
904
+ },
905
+ "xai/grok-4.20-reasoning": {
906
+ measuredAt: "2026-07-21T10:21:31Z",
907
+ latencyMs: 3472.4,
908
+ p95LatencyMs: 5332.4,
909
+ outputTokensPerSecond: 13.27,
910
+ errorRate: 0,
911
+ samples: 3
912
+ },
913
+ "xai/grok-4.20-non-reasoning": {
914
+ measuredAt: "2026-07-21T10:21:31Z",
915
+ latencyMs: 5174.4,
916
+ p95LatencyMs: 6081.7,
917
+ outputTokensPerSecond: 10.21,
918
+ errorRate: 0.3333,
919
+ samples: 3
920
+ },
921
+ "xai/grok-4-1-fast-reasoning": {
922
+ measuredAt: "2026-07-21T10:21:31Z",
923
+ latencyMs: 13148.2,
924
+ p95LatencyMs: 19104.2,
925
+ outputTokensPerSecond: 4.28,
926
+ errorRate: 0,
927
+ samples: 3
928
+ },
929
+ "minimax/minimax-m3": {
930
+ measuredAt: "2026-07-21T10:21:31Z",
931
+ latencyMs: 3385,
932
+ p95LatencyMs: 4247.2,
933
+ outputTokensPerSecond: 15.16,
934
+ errorRate: 0,
935
+ samples: 3
936
+ },
937
+ "minimax/minimax-m2.7": {
938
+ measuredAt: "2026-07-21T10:21:31Z",
939
+ latencyMs: 4596.7,
940
+ p95LatencyMs: 6884.6,
941
+ outputTokensPerSecond: 17.03,
942
+ errorRate: 0,
943
+ samples: 3
944
+ },
945
+ "zai/glm-5.2": {
946
+ measuredAt: "2026-07-21T10:21:31Z",
947
+ latencyMs: 4406.3,
948
+ p95LatencyMs: 6139.7,
949
+ outputTokensPerSecond: 10.41,
950
+ errorRate: 0,
951
+ samples: 3
952
+ },
953
+ "zai/glm-5.1": {
954
+ measuredAt: "2026-07-21T10:21:31Z",
955
+ latencyMs: 7775.4,
956
+ p95LatencyMs: 9182.1,
957
+ outputTokensPerSecond: 6.08,
958
+ errorRate: 0,
959
+ samples: 3
960
+ },
961
+ "zai/glm-5": {
962
+ measuredAt: "2026-07-21T10:21:31Z",
963
+ latencyMs: 4159.4,
964
+ p95LatencyMs: 4992.7,
965
+ outputTokensPerSecond: 10.28,
966
+ errorRate: 0,
967
+ samples: 3
968
+ },
969
+ "free/qwen3-coder-480b": {
970
+ measuredAt: "2026-07-21T10:21:31Z",
971
+ latencyMs: 2063.9,
972
+ p95LatencyMs: 3646.3,
973
+ outputTokensPerSecond: 39.8,
974
+ errorRate: 0,
975
+ samples: 3
976
+ },
977
+ "free/mistral-large-3-675b": {
978
+ measuredAt: "2026-07-21T10:21:31Z",
979
+ latencyMs: 3147.5,
980
+ p95LatencyMs: 5555.3,
981
+ outputTokensPerSecond: 27.76,
982
+ errorRate: 0,
983
+ samples: 3
984
+ },
985
+ "free/nemotron-3-nano-omni-30b-a3b-reasoning": {
986
+ measuredAt: "2026-07-21T10:21:31Z",
987
+ latencyMs: 6508.4,
988
+ p95LatencyMs: 14252.7,
989
+ outputTokensPerSecond: 68.26,
990
+ errorRate: 0,
991
+ samples: 3
992
+ },
993
+ "free/glm-4.7": {
994
+ measuredAt: "2026-07-21T10:21:31Z",
995
+ latencyMs: 2014.8,
996
+ p95LatencyMs: 3039.9,
997
+ outputTokensPerSecond: 39.92,
998
+ errorRate: 0,
999
+ samples: 3
1000
+ }
1001
+ };
1002
+ var LIVE_MODEL_PROFILES = Object.freeze(
1003
+ model_profiles_generated_default
1004
+ );
1005
+ var HISTORICAL_MODEL_PROFILES = Object.freeze({
1006
+ "anthropic/claude-haiku-4.5": {
1007
+ measuredAt: "2026-03-16T13:50:48Z",
1008
+ latencyMs: 2305,
1009
+ outputTokensPerSecond: 140.6
1010
+ },
1011
+ "anthropic/claude-opus-4.6": {
1012
+ measuredAt: "2026-03-16T13:50:48Z",
1013
+ latencyMs: 2139,
1014
+ outputTokensPerSecond: 119.7
1015
+ },
1016
+ "anthropic/claude-sonnet-4.6": {
1017
+ measuredAt: "2026-03-16T13:50:48Z",
1018
+ latencyMs: 2110,
1019
+ outputTokensPerSecond: 121.3
1020
+ },
1021
+ "deepseek/deepseek-chat": {
1022
+ measuredAt: "2026-03-16T13:50:48Z",
1023
+ latencyMs: 1431,
1024
+ outputTokensPerSecond: 179.2,
1025
+ intelligenceIndex: 32
1026
+ },
1027
+ "google/gemini-2.5-flash": {
1028
+ measuredAt: "2026-03-16T13:50:48Z",
1029
+ latencyMs: 1238,
1030
+ outputTokensPerSecond: 207.6,
1031
+ intelligenceIndex: 20
1032
+ },
1033
+ "google/gemini-2.5-flash-lite": {
1034
+ measuredAt: "2026-03-16T13:50:48Z",
1035
+ latencyMs: 1353,
1036
+ outputTokensPerSecond: 192.5,
1037
+ intelligenceIndex: 20
1038
+ },
1039
+ "google/gemini-2.5-pro": {
1040
+ measuredAt: "2026-03-16T13:50:48Z",
1041
+ latencyMs: 1294,
1042
+ outputTokensPerSecond: 197.8
1043
+ },
1044
+ "google/gemini-3.1-pro": {
1045
+ measuredAt: "2026-03-16T13:50:48Z",
1046
+ latencyMs: 1609,
1047
+ outputTokensPerSecond: 167.2
1048
+ },
1049
+ "moonshot/kimi-k2.5": {
1050
+ measuredAt: "2026-03-16T13:50:48Z",
1051
+ latencyMs: 1646,
1052
+ outputTokensPerSecond: 155.7
1053
+ },
1054
+ "openai/gpt-4o-mini": {
1055
+ measuredAt: "2026-03-16T13:50:48Z",
1056
+ latencyMs: 2764,
1057
+ outputTokensPerSecond: 92.8
1058
+ },
1059
+ "openai/gpt-5.3-codex": {
1060
+ measuredAt: "2026-03-16T13:50:48Z",
1061
+ latencyMs: 7935,
1062
+ outputTokensPerSecond: 32.3
1063
+ },
1064
+ "xai/grok-4-1-fast-non-reasoning": {
1065
+ measuredAt: "2026-03-16T13:50:48Z",
1066
+ latencyMs: 1244,
1067
+ outputTokensPerSecond: 205.8,
1068
+ intelligenceIndex: 41
1069
+ },
1070
+ "xai/grok-4-1-fast-reasoning": {
1071
+ measuredAt: "2026-03-16T13:50:48Z",
1072
+ latencyMs: 1454,
1073
+ outputTokensPerSecond: 176.2,
1074
+ intelligenceIndex: 41
1075
+ }
1076
+ });
1077
+ function inferToolRequirement(prompt, _systemPrompt, toolChoice) {
1078
+ if (toolChoice === "none") return false;
1079
+ if (toolChoice === "required") return true;
1080
+ if (typeof toolChoice === "object" && toolChoice !== null && toolChoice.type === "function") {
1081
+ return true;
1082
+ }
1083
+ const text = prompt;
1084
+ const explicitTool = /\b(?:use|call|invoke)\s+(?:the\s+)?[\w.-]+\s+(?:tool|function|api)\b|\btool[_ -]?call\b|使用.{0,20}(?:工具|函数|接口)|调用.{0,20}(?:工具|函数|接口)/i;
1085
+ 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;
1086
+ 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;
1087
+ 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;
1088
+ return explicitTool.test(text) || codeEnvironment.test(text) || webAction.test(text) || statefulAction.test(text);
1089
+ }
1090
+ var DEFAULT_PORTFOLIO_WEIGHTS = {
1091
+ auto: {
1092
+ quality: 0.47,
1093
+ capability: 0.2,
1094
+ cost: 0.18,
1095
+ speed: 0.07,
1096
+ reliability: 0.03,
1097
+ legacy: 0.05
1098
+ },
1099
+ eco: { quality: 0.36, capability: 0.2, cost: 0.28, speed: 0.1, reliability: 0.04, legacy: 0.02 },
1100
+ premium: {
1101
+ quality: 0.58,
1102
+ capability: 0.2,
1103
+ cost: 0.08,
1104
+ speed: 0.06,
1105
+ reliability: 0.06,
1106
+ legacy: 0.02
1107
+ },
1108
+ highStakesBoost: { quality: 0.08, reliability: 0.05 },
1109
+ latencySensitiveSpeedBoost: 0.08,
1110
+ affinityFloorGap: { auto: 0.1, eco: 0.22, premium: 0.05 }
1111
+ };
1112
+ function likelyNeedsParallelToolCalls(prompt, needsTools, toolCount, toolNames) {
1113
+ if (!needsTools || toolCount === void 0 || toolCount < 1) return false;
1114
+ const text = prompt.trim();
1115
+ 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(
1116
+ text
1117
+ );
1118
+ if (explicitRepeat) return true;
1119
+ const sentenceClauses = text.split(/[.!?。!?]+/).map((part) => part.trim()).filter((part) => part.length >= 8);
1120
+ if (/\b(?:also|additionally|furthermore)\b|另外|此外|그리고/i.test(text) && sentenceClauses.length >= 2 || /\band\s+(?:also|for the)\b/i.test(text))
1121
+ return true;
1122
+ 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(
1123
+ text
1124
+ );
1125
+ if (pairedQuantity) return true;
1126
+ const operationTokens = /* @__PURE__ */ new Set([
1127
+ "add",
1128
+ "delete",
1129
+ "remove",
1130
+ "cancel",
1131
+ "return",
1132
+ "exchange",
1133
+ "modify",
1134
+ "book",
1135
+ "transfer",
1136
+ "send",
1137
+ "upload",
1138
+ "download",
1139
+ "create",
1140
+ "close"
1141
+ ]);
1142
+ const lowered = text.toLowerCase();
1143
+ const matchedOperationTokens = new Set(
1144
+ (toolNames ?? []).flatMap((name) => name.toLowerCase().split(/[^a-z0-9\u3400-\u9fff]+/)).filter((token) => operationTokens.has(token) && lowered.includes(token))
1145
+ );
1146
+ if (matchedOperationTokens.size >= 2) return true;
1147
+ const nonEmptyLines = text.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
1148
+ const quantityMentions = text.match(
1149
+ /\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
1150
+ ) ?? [];
1151
+ if (nonEmptyLines.length >= 2 && quantityMentions.length >= 2) return true;
1152
+ const repeatedLookup = /\b(?:weather|climate|clima|tiempo|temperature|snow|news|report)\b|天气|气象|温度|降雪|新闻|报告/i.test(
1153
+ text
1154
+ );
1155
+ const multiLocationConnector = /\b(?:and also|both|y|e)\b|还有|以及|和|、/i.test(text);
1156
+ const commaSeparatedLocations = (text.match(/[,,]/g) ?? []).length >= 2;
1157
+ if (repeatedLookup && (multiLocationConnector || commaSeparatedLocations)) return true;
1158
+ const distinctOrderParts = /\b(?:food|meal)\b[\s\S]*\bdrink\b|\bdrink\b[\s\S]*\b(?:food|meal)\b/i.test(text);
1159
+ const koreanParallelClauses = (text.match(/,/g) ?? []).length >= 3 && /하고|그리고/.test(text);
1160
+ return distinctOrderParts || koreanParallelClauses;
1161
+ }
1162
+ function classifyTask(prompt, systemPrompt, options) {
1163
+ const fullText = `${systemPrompt ?? ""} ${prompt}`;
1164
+ const estimatedInputTokens = Math.ceil(fullText.length / 4);
1165
+ const scanLimit = Math.max(1, Math.min(8e3, options.config.classifier.promptTruncationChars));
1166
+ const sample = (value) => {
1167
+ if (value.length <= scanLimit) return value;
1168
+ const prefixLength = Math.ceil(scanLimit / 2);
1169
+ return `${value.slice(0, prefixLength)}
1170
+ ${value.slice(-(scanLimit - prefixLength))}`;
1171
+ };
1172
+ const scannedPrompt = sample(prompt);
1173
+ const scannedSystemPrompt = sample(systemPrompt ?? "");
1174
+ const scannedFullText = `${scannedSystemPrompt} ${scannedPrompt}`;
1175
+ const text = scannedPrompt.toLowerCase();
1176
+ const explicitCodeSignal = /```|\b(?:typescript|javascript|python|rust|java|sql|stack trace|traceback|exception)\b|\.(?:ts|tsx|js|py|go|rs)\b/i.test(
1177
+ scannedPrompt
1178
+ );
1179
+ 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(
1180
+ scannedPrompt
1181
+ );
1182
+ const nativeCodeSignal = /\b(?:programmed|written|implemented?|code)\s+(?:in|using)\s+(?:c\+\+|c|rust|go)\b/i.test(
1183
+ scannedPrompt
1184
+ );
1185
+ const hasCode = explicitCodeSignal || codeConstructSignal || nativeCodeSignal;
1186
+ const toolsAvailable = options.hasTools ?? false;
1187
+ const needsTools = options.requiresTools ?? (toolsAvailable && inferToolRequirement(scannedPrompt, scannedSystemPrompt));
1188
+ const likelyParallelToolCalls = likelyNeedsParallelToolCalls(
1189
+ scannedPrompt,
1190
+ needsTools,
1191
+ options.toolCount,
1192
+ options.toolNames
1193
+ );
1194
+ const normalizedToolNames = (options.toolNames ?? []).map((name) => name.toLowerCase());
1195
+ const airlineToolSignal = normalizedToolNames.some(
1196
+ (name) => /(?:flight|reservation|airport|baggage|passenger)/.test(name)
1197
+ );
1198
+ const retailToolSignal = normalizedToolNames.some(
1199
+ (name) => /(?:order|product|item|return|exchange|address)/.test(name)
1200
+ );
1201
+ const webResearchToolSignal = normalizedToolNames.some(
1202
+ (name) => /^(?:web_?search|web_?fetch)$/.test(name)
1203
+ );
1204
+ const agentDomain = airlineToolSignal && !retailToolSignal ? "airline" : retailToolSignal && !airlineToolSignal ? "retail" : webResearchToolSignal ? "web_research" : "other";
1205
+ const clueConnectors = scannedFullText.match(
1206
+ /\b(?:after|before|while|where|whose|which|in \d{4}|as of|over \d+|another|also|furthermore)\b|(?:之后|之前|其中|截至|超过|另一个|此外)/gi
1207
+ ) ?? [];
1208
+ 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(
1209
+ scannedFullText
1210
+ );
1211
+ const exactAnswerSignal = /\b(?:exact answer|single best-supported answer|following clues|multiple public sources)\b|(?:精确答案|根据.*线索|多个公开来源)/i.test(
1212
+ scannedFullText
1213
+ );
1214
+ const deepWebResearch = agentDomain === "web_research" && (exactAnswerSignal || entityResolutionSignal && (clueConnectors.length >= 3 || prompt.length >= 320));
1215
+ 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(
1216
+ scannedPrompt
1217
+ );
1218
+ 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(
1219
+ scannedPrompt
1220
+ );
1221
+ const globalChoiceSignal = globalOptimizationSignal || globalScopeSignal;
1222
+ const crossRecordSignal = /\b(?:another|other|different|previous)\s+(?:order|reservation|booking|account|address)\b|另一(?:个)?(?:订单|预订|账户|地址)|其他(?:订单|预订|账户|地址)/i.test(
1223
+ scannedPrompt
1224
+ );
1225
+ const reservationIds = scannedPrompt.match(/\b[A-Z0-9]{6}\b/g) ?? [];
1226
+ 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(
1227
+ scannedPrompt
1228
+ ) || new Set(reservationIds).size >= 2);
1229
+ const conditionalGlobalWorkflowSignal = agentDomain === "airline" && globalScopeSignal && /\b(?:if|that (?:contain|have)|longer than|shorter than|under|over|at (?:most|least)|wherever possible)\b|如果|超过|少于|不超过|尽可能/i.test(
1230
+ scannedPrompt
1231
+ ) && /\b(?:cancel|change|upgrade|move|book)\b[\s\S]*\b(?:cancel|change|upgrade|move|book)\b|取消[\s\S]*(?:升级|更改)|升级[\s\S]*(?:取消|更改)/i.test(
1232
+ scannedPrompt
1233
+ );
1234
+ const policyExceptionSignal = agentDomain === "retail" && /\b(?:return|refund|send back|get (?:my |the )?money back)\b|退货|退款|退回/i.test(
1235
+ scannedPrompt
1236
+ ) && /\b(?:amex|american express|visa|mastercard|credit card|debit card|different card|another card|other card)\b|信用卡|借记卡|其他卡|另一张卡/i.test(
1237
+ scannedPrompt
1238
+ );
1239
+ const singleSelectedPolicyException = policyExceptionSignal && /\b(?:return|refund|send back)\b[^.!?。!?]{0,96}\b(?:the )?(?:pricier|cheaper|more expensive|less expensive|costlier|one)\b/i.test(
1240
+ scannedPrompt
1241
+ );
1242
+ const negotiatedWorkflowSignal = agentDomain === "retail" && /\b(?:return|exchange)\b|退货|退回|换货|交换/i.test(scannedPrompt);
1243
+ const numberedSteps = (scannedPrompt.match(/(?:^|\s)\d+(?:\.\d+)*[.)]\s+/g) ?? []).length;
1244
+ const complexMultiToolPlan = likelyParallelToolCalls && ((options.toolCount ?? 0) >= 6 || numberedSteps >= 3 || prompt.length > 1200);
1245
+ let agentRisk = needsTools && singleSelectedPolicyException ? "policy_exception_simple" : needsTools && policyExceptionSignal ? "policy_exception" : (
1246
+ // Airline prompts that require a global optimum (for example the
1247
+ // cheapest itinerary across several candidates) are materially harder
1248
+ // than applying one change to every passenger in a known reservation.
1249
+ // Full-session evidence supports Sonnet for the former, while upgrading
1250
+ // the latter merely because it says "all passengers" caused a large cost
1251
+ // increase without a quality gain.
1252
+ needsTools && agentDomain === "airline" && (globalOptimizationSignal || conditionalGlobalWorkflowSignal) ? "complex_high" : needsTools && (likelyParallelToolCalls || globalChoiceSignal || crossRecordSignal || crossReservationBatchSignal || negotiatedWorkflowSignal) ? "high" : "standard"
1253
+ );
1254
+ const needsVision = options.hasVision ?? false;
1255
+ const needsStructuredOutput = options.requiresStructuredOutput ?? false;
1256
+ const latencySensitive = /\b(?:urgent|asap|fast|quick|low latency|real[- ]time)\b|尽快|马上|快速|低延迟/i.test(
1257
+ scannedFullText
1258
+ );
1259
+ const highStakes = /\b(?:production|security|payment|legal|medical|financial|audit)\b|生产|安全|支付|法律|医疗|财务|审计/i.test(
1260
+ scannedFullText
1261
+ );
1262
+ const terminalToolSignal = normalizedToolNames.some(
1263
+ (name) => /^(?:terminalexec|terminalinspect|terminalsendkeys)$/.test(name)
1264
+ );
1265
+ 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(
1266
+ scannedPrompt
1267
+ );
1268
+ 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(
1269
+ scannedPrompt
1270
+ );
1271
+ const mentionedTerminalRuntimes = new Set(
1272
+ (scannedPrompt.match(/\b(?:gcc|clang|rustc|javac|go\s+build|node|python)\b/gi) ?? []).map(
1273
+ (name) => name.toLowerCase().replace(/\s+/g, " ")
1274
+ )
1275
+ );
1276
+ const terminalCrossRuntimeArtifact = terminalToolSignal && (/\bpolyglot\b/i.test(scannedPrompt) || /\b(?:both|each)\b[\s\S]{0,120}\b(?:compilers?|runtimes?|toolchains?)\b/i.test(
1277
+ scannedPrompt
1278
+ ) || mentionedTerminalRuntimes.size >= 2 && /\b(?:compile|build|run|execute)\b/i.test(scannedPrompt));
1279
+ const terminalFrameworkToNativeArtifact = terminalToolSignal && /\b(?:pytorch|tensorflow|jax|onnx|state[_ -]?dict|checkpoint|safetensors?)\b|\.(?:pth|pt|onnx)\b/i.test(
1280
+ scannedPrompt
1281
+ ) && /\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(
1282
+ scannedPrompt
1283
+ ) && /\b(?:inference|model|weights?|tensor|export|convert|load)\b/i.test(scannedPrompt);
1284
+ if (needsTools && (terminalComplexRepair || terminalCrossRuntimeArtifact || terminalFrameworkToNativeArtifact) && (agentRisk === "standard" || agentRisk === "high"))
1285
+ agentRisk = "complex_high";
1286
+ 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(
1287
+ scannedPrompt
1288
+ );
1289
+ const terminalCredentialSignal = /\b(?:ssh|nginx|certificate|authentication|credentials?|passwords?|api keys?|deploy|production|encrypt|gpg|shred|securely delete|decommission)\b/i.test(
1290
+ scannedPrompt
1291
+ ) || /\b(?:access|auth|authentication|bearer|secret|api)\s+tokens?\b|\btokens?\s+(?:secret|credential|authentication)\b/i.test(
1292
+ scannedPrompt
1293
+ );
1294
+ const terminalSafetySensitive = terminalToolSignal && (highStakes || terminalCredentialSignal);
1295
+ const implicitTerminalCode = needsTools && terminalToolSignal && agentRisk === "standard" && !highStakes && !complexTerminalOperation && numberedSteps < 3 && prompt.length <= 1e3 && simpleTerminalArtifact;
1296
+ const language = /[\u3400-\u9fff]/.test(scannedFullText) ? "zh" : "other";
1297
+ const multipleChoiceSignals = (scannedPrompt.match(/(?:^|\n)\s*[A-D][.)]\s+/gim) ?? []).length;
1298
+ const numericSignals = (scannedPrompt.match(/-?\d+(?:[.,]\d+)?/g) ?? []).length;
1299
+ const compactMathProblem = !hasCode && prompt.length < 2500 && numericSignals >= 2 && (/[+×÷=%$€£¥]|\b(?:total|each|per|times|half|twice|percent|how many|how much|calculate)\b/i.test(
1300
+ scannedPrompt
1301
+ ) || /[??]\s*$/.test(scannedPrompt.trim()) || numericSignals >= 3);
1302
+ let taskType = "chat";
1303
+ if (needsVision) taskType = "vision";
1304
+ else if (estimatedInputTokens > 8e4) taskType = "long_context";
1305
+ else if (needsTools && (hasCode || implicitTerminalCode)) taskType = "code_agent";
1306
+ else if (needsTools && likelyParallelToolCalls && !complexMultiToolPlan)
1307
+ taskType = "tool_agent_parallel";
1308
+ else if (needsTools) taskType = "tool_agent";
1309
+ else if (multipleChoiceSignals >= 3) taskType = "reasoning_mcq";
1310
+ else if (compactMathProblem) taskType = "reasoning_math";
1311
+ else if (/\b(?:bug|debug|error|failure|failing|regression|crash|修复|报错|错误|调试)\b/i.test(text))
1312
+ taskType = "debug";
1313
+ else if (hasCode || /\b(?:refactor|implement|patch|edit|rewrite|重构|实现|修改)\b/i.test(text))
1314
+ taskType = "code_edit";
1315
+ else if (needsStructuredOutput || /\b(?:extract|json|schema|csv|字段|提取)\b/i.test(text))
1316
+ taskType = "extraction";
1317
+ else if (/\b(?:prove|derive|theorem|formal|mathematical|reasoning|证明|推导|定理|数学)\b/i.test(text))
1318
+ taskType = "reasoning";
1319
+ return {
1320
+ taskType,
1321
+ estimatedInputTokens,
1322
+ hasCode,
1323
+ needsTools,
1324
+ toolsAvailable,
1325
+ needsVision,
1326
+ needsStructuredOutput,
1327
+ latencySensitive,
1328
+ highStakes,
1329
+ language,
1330
+ likelyParallelToolCalls,
1331
+ complexMultiToolPlan,
1332
+ agentDomain,
1333
+ deepWebResearch,
1334
+ agentRisk,
1335
+ terminalToolSignal,
1336
+ terminalSafetySensitive,
1337
+ implicitTerminalCode
1338
+ };
1339
+ }
1340
+ function affinity(modelId, task, language = "other", agentDomain = "other", deepWebResearch = false, agentRisk = "standard", terminalToolSignal = false, terminalSafetySensitive = false) {
1341
+ const id = modelId.toLowerCase();
1342
+ const modelName = id.slice(id.indexOf("/") + 1);
1343
+ const match = (values, score) => values.some((value) => modelName === value) ? score : 0;
1344
+ const base = 0.68;
1345
+ switch (task) {
1346
+ case "code_agent":
1347
+ if (terminalToolSignal && agentRisk === "complex_high") {
1348
+ return Math.max(
1349
+ base,
1350
+ match(["claude-sonnet-5"], 1),
1351
+ match(["gpt-5.3-codex"], 0.87),
1352
+ match(["gpt-5-mini"], 0.78),
1353
+ match(["gemini-3.5-flash"], 0.76)
1354
+ );
1355
+ }
1356
+ return Math.max(
1357
+ base,
1358
+ match(["gpt-5.3-codex"], 1),
1359
+ match(["claude-sonnet-5"], 0.98),
1360
+ match(["gpt-5-mini"], 0.96),
1361
+ match(["gemini-3.5-flash"], 0.92),
1362
+ match(["kimi-k3"], 0.9),
1363
+ match(["deepseek-v4-pro", "glm-5.2"], 0.88)
1364
+ );
1365
+ case "tool_agent":
1366
+ if (terminalToolSignal && agentRisk === "complex_high") {
1367
+ return Math.max(
1368
+ base,
1369
+ match(["claude-sonnet-5"], 1),
1370
+ match(["gpt-5.3-codex"], 0.87),
1371
+ match(["gpt-5-mini"], 0.78),
1372
+ match(["gemini-3.5-flash"], 0.76)
1373
+ );
1374
+ }
1375
+ if (terminalToolSignal && !terminalSafetySensitive) {
1376
+ return Math.max(
1377
+ base,
1378
+ match(["gpt-5-mini"], 1),
1379
+ match(["gpt-5.3-codex"], 0.98),
1380
+ match(["claude-sonnet-5"], 0.9),
1381
+ match(["gemini-3.5-flash"], 0.89)
1382
+ );
1383
+ }
1384
+ if (terminalToolSignal && terminalSafetySensitive) {
1385
+ return Math.max(
1386
+ base,
1387
+ match(["claude-sonnet-5"], 1),
1388
+ match(["claude-opus-4.8"], 0.9),
1389
+ match(["gpt-5.3-codex"], 0.84)
1390
+ );
1391
+ }
1392
+ if (agentDomain === "web_research") {
1393
+ return deepWebResearch ? Math.max(
1394
+ base,
1395
+ match(["claude-sonnet-5"], 1),
1396
+ match(["gpt-5-mini"], 0.88),
1397
+ match(["gemini-3.5-flash"], 0.84),
1398
+ match(["claude-opus-5"], 0.8),
1399
+ match(["claude-opus-4.8"], 0.78)
1400
+ ) : Math.max(
1401
+ base,
1402
+ match(["claude-sonnet-5"], 1),
1403
+ match(["gpt-5-mini"], 0.88),
1404
+ match(["gemini-3.5-flash"], 0.86),
1405
+ match(["claude-opus-5"], 0.84),
1406
+ match(["claude-opus-4.8"], 0.82)
1407
+ );
1408
+ }
1409
+ if (agentDomain === "retail") {
1410
+ if (agentRisk === "standard") {
1411
+ return Math.max(
1412
+ base,
1413
+ match(["gpt-5-mini"], 1),
1414
+ match(["claude-sonnet-5"], 0.88),
1415
+ match(["gemini-3.5-flash"], 0.82),
1416
+ match(["gpt-5.3-codex"], 0.81),
1417
+ match(["kimi-k3"], 0.78),
1418
+ match(["deepseek-v4-pro"], 0.76)
1419
+ );
1420
+ }
1421
+ if (agentRisk === "policy_exception") {
1422
+ return Math.max(
1423
+ base,
1424
+ match(["gpt-4.1"], 1),
1425
+ match(["claude-sonnet-5"], 0.9),
1426
+ match(["deepseek-v4-pro"], 0.82),
1427
+ match(["gpt-5-mini"], 0.8),
1428
+ match(["gpt-4o-mini"], 0.76)
1429
+ );
1430
+ }
1431
+ if (agentRisk === "policy_exception_simple") {
1432
+ return Math.max(
1433
+ base,
1434
+ match(["gpt-5-mini"], 1),
1435
+ match(["gpt-4.1"], 0.86),
1436
+ match(["deepseek-v4-pro"], 0.82),
1437
+ match(["gpt-4o-mini"], 0.8)
1438
+ );
1439
+ }
1440
+ return Math.max(
1441
+ base,
1442
+ match(["deepseek-v4-pro"], 1),
1443
+ match(["claude-sonnet-5"], 0.88),
1444
+ match(["gemini-3.5-flash"], 0.82),
1445
+ match(["gpt-5.3-codex"], 0.81),
1446
+ match(["kimi-k3"], 0.78),
1447
+ match(["gpt-5-mini"], 0.76)
1448
+ );
1449
+ }
1450
+ if (agentDomain === "airline") {
1451
+ if (agentRisk === "complex_high") {
1452
+ return Math.max(
1453
+ base,
1454
+ match(["claude-sonnet-5"], 1),
1455
+ match(["gpt-5-mini"], 0.78),
1456
+ match(["gemini-3.5-flash"], 0.76),
1457
+ match(["deepseek-v4-pro"], 0.74)
1458
+ );
1459
+ }
1460
+ return Math.max(
1461
+ base,
1462
+ match(["gpt-5-mini"], 1),
1463
+ match(["claude-sonnet-5"], 0.9),
1464
+ match(["gemini-3.5-flash"], 0.8),
1465
+ match(["deepseek-v4-pro"], 0.76)
1466
+ );
1467
+ }
1468
+ return Math.max(
1469
+ base,
1470
+ match(["claude-sonnet-5"], 1),
1471
+ match(["gemini-3.5-flash"], 0.88),
1472
+ match(["gpt-5.3-codex"], 0.87),
1473
+ match(["gpt-5-mini"], 0.84),
1474
+ match(["kimi-k3"], 0.85),
1475
+ match(["deepseek-v4-pro"], 0.82)
1476
+ );
1477
+ case "tool_agent_parallel":
1478
+ if (terminalToolSignal) {
1479
+ return terminalSafetySensitive ? Math.max(
1480
+ base,
1481
+ match(["claude-sonnet-5"], 1),
1482
+ match(["claude-opus-4.8"], 0.9),
1483
+ match(["gpt-5.3-codex"], 0.86)
1484
+ ) : Math.max(
1485
+ base,
1486
+ match(["gpt-5-mini"], 1),
1487
+ match(["gpt-5.3-codex"], 0.98),
1488
+ match(["claude-sonnet-5"], 0.92),
1489
+ match(["gemini-3.5-flash"], 0.88)
1490
+ );
1491
+ }
1492
+ if (agentDomain === "web_research") {
1493
+ return deepWebResearch ? Math.max(
1494
+ base,
1495
+ match(["claude-sonnet-5"], 1),
1496
+ match(["gpt-5-mini"], 0.88),
1497
+ match(["gemini-3.5-flash"], 0.84),
1498
+ match(["claude-opus-5"], 0.8),
1499
+ match(["claude-opus-4.8"], 0.78)
1500
+ ) : Math.max(
1501
+ base,
1502
+ match(["claude-sonnet-5"], 1),
1503
+ match(["gpt-5-mini"], 0.88),
1504
+ match(["gemini-3.5-flash"], 0.86),
1505
+ match(["claude-opus-5"], 0.84),
1506
+ match(["claude-opus-4.8"], 0.82)
1507
+ );
1508
+ }
1509
+ if (agentDomain === "retail") {
1510
+ if (agentRisk === "policy_exception") {
1511
+ return Math.max(
1512
+ base,
1513
+ match(["gpt-4.1"], 1),
1514
+ match(["claude-sonnet-5"], 0.9),
1515
+ match(["deepseek-v4-pro"], 0.82),
1516
+ match(["gpt-5-mini"], 0.8),
1517
+ match(["gpt-4o-mini"], 0.76)
1518
+ );
1519
+ }
1520
+ if (agentRisk === "policy_exception_simple") {
1521
+ return Math.max(
1522
+ base,
1523
+ match(["gpt-5-mini"], 1),
1524
+ match(["gpt-4.1"], 0.86),
1525
+ match(["deepseek-v4-pro"], 0.82),
1526
+ match(["gpt-4o-mini"], 0.8)
1527
+ );
1528
+ }
1529
+ return Math.max(
1530
+ base,
1531
+ match(["deepseek-v4-pro"], 1),
1532
+ match(["claude-sonnet-5"], 0.88),
1533
+ match(["claude-opus-4.8"], 0.84),
1534
+ match(["gpt-5-mini"], 0.78),
1535
+ match(["gemini-3.5-flash"], 0.76)
1536
+ );
1537
+ }
1538
+ if (agentDomain === "airline") {
1539
+ return agentRisk === "complex_high" ? Math.max(
1540
+ base,
1541
+ match(["claude-sonnet-5"], 1),
1542
+ match(["gpt-5-mini"], 0.78),
1543
+ match(["claude-opus-4.8"], 0.76),
1544
+ match(["gemini-3.5-flash"], 0.74)
1545
+ ) : Math.max(
1546
+ base,
1547
+ match(["gpt-5-mini"], 1),
1548
+ match(["claude-sonnet-5"], 0.9),
1549
+ match(["gemini-3.5-flash"], 0.8)
1550
+ );
1551
+ }
1552
+ return Math.max(
1553
+ base,
1554
+ match(["claude-opus-4.8"], 1),
1555
+ match(["claude-sonnet-5"], 0.84),
1556
+ match(["grok-4.5"], 0.82),
1557
+ match(["gemini-3.5-flash"], 0.8),
1558
+ match(["deepseek-v4-pro"], 0.78)
1559
+ );
1560
+ case "code_edit":
1561
+ case "debug":
1562
+ return Math.max(
1563
+ base,
1564
+ match(["gpt-5.3-codex"], 1),
1565
+ match(["claude-sonnet-4.6"], 0.94),
1566
+ match(["glm-5.2"], 0.9),
1567
+ match(["kimi-k2.7", "deepseek-v4-pro"], 0.86)
1568
+ );
1569
+ case "reasoning":
1570
+ return Math.max(
1571
+ base,
1572
+ match(["claude-sonnet-5", "claude-sonnet-4.6"], 0.98),
1573
+ match(["deepseek-v4-pro"], 0.95),
1574
+ match(["grok-4.5"], 0.94),
1575
+ match(["gemini-3.1-pro", "gemini-3.5-flash"], 0.92)
1576
+ );
1577
+ case "reasoning_mcq":
1578
+ return Math.max(
1579
+ base,
1580
+ match(["gemini-3-flash-preview"], 1),
1581
+ match(["gemini-3.5-flash"], 0.91),
1582
+ match(["grok-4.5"], 0.9),
1583
+ match(["claude-sonnet-5"], 0.88),
1584
+ match(["deepseek-v4-pro"], 0.84)
1585
+ );
1586
+ case "reasoning_math":
1587
+ return Math.max(
1588
+ base,
1589
+ match(["gemini-3.5-flash"], 1),
1590
+ match(["grok-4.5"], 0.93),
1591
+ match(["claude-sonnet-5", "deepseek-v4-pro", "kimi-k3"], 0.9),
1592
+ match(["kimi-k2.7"], 0.84)
1593
+ );
1594
+ case "vision":
1595
+ return Math.max(
1596
+ base,
1597
+ match(["gemini-3.1-pro"], 0.96),
1598
+ match(["qwen3.7-max", "claude-sonnet-4.6", "kimi-k2.7", "grok-4.3"], 0.9)
1599
+ );
1600
+ case "long_context":
1601
+ return Math.max(
1602
+ base,
1603
+ match(["gemini-3.1-pro"], 1),
1604
+ match(["qwen3.7-max", "glm-5.2"], 0.89),
1605
+ match(["gemini-3.5-flash"], 0.88),
1606
+ match(["deepseek-v4-pro"], 0.85)
1607
+ );
1608
+ case "extraction": {
1609
+ const kimiExtractionAffinity = language === "zh" ? 1 : 0.9;
1610
+ return Math.max(
1611
+ base,
1612
+ match(["gemini-3.5-flash", "gemini-2.5-flash", "gpt-4o-mini"], 0.9),
1613
+ match(["claude-sonnet-5", "claude-sonnet-4.6"], 0.9),
1614
+ match(["kimi-k3", "kimi-k2.7"], kimiExtractionAffinity)
1615
+ );
1616
+ }
1617
+ default:
1618
+ return Math.max(
1619
+ base,
1620
+ match(["gemini-3.5-flash", "gemini-2.5-flash", "kimi-k3", "kimi-k2.7"], 0.86)
1621
+ );
1622
+ }
1623
+ }
1624
+ function evidenceCandidates(task) {
1625
+ if (task === "code_agent") {
1626
+ return [
1627
+ "openai/gpt-5.3-codex",
1628
+ "anthropic/claude-sonnet-5",
1629
+ "openai/gpt-5-mini",
1630
+ "google/gemini-3.5-flash",
1631
+ "moonshot/kimi-k3",
1632
+ "deepseek/deepseek-v4-pro"
1633
+ ];
1634
+ }
1635
+ if (task === "tool_agent") {
1636
+ return [
1637
+ "anthropic/claude-sonnet-5",
1638
+ "anthropic/claude-opus-5",
1639
+ "openai/gpt-5-mini",
1640
+ "openai/gpt-4.1",
1641
+ "openai/gpt-4o-mini",
1642
+ "google/gemini-3.5-flash",
1643
+ "openai/gpt-5.3-codex",
1644
+ "moonshot/kimi-k3",
1645
+ "deepseek/deepseek-v4-pro"
1646
+ ];
1647
+ }
1648
+ if (task === "tool_agent_parallel") {
1649
+ return [
1650
+ "anthropic/claude-opus-5",
1651
+ "anthropic/claude-opus-4.8",
1652
+ "anthropic/claude-sonnet-5",
1653
+ "openai/gpt-5-mini",
1654
+ "openai/gpt-4.1",
1655
+ "openai/gpt-4o-mini",
1656
+ "xai/grok-4.5",
1657
+ "google/gemini-3.5-flash",
1658
+ "deepseek/deepseek-v4-pro"
1659
+ ];
1660
+ }
1661
+ if (task === "long_context") {
1662
+ return [
1663
+ "google/gemini-3.1-pro",
1664
+ "deepseek/deepseek-v4-pro",
1665
+ "qwen/qwen3.7-max",
1666
+ "zai/glm-5.2",
1667
+ "google/gemini-3.5-flash"
1668
+ ];
1669
+ }
1670
+ if (task === "reasoning_mcq") {
1671
+ return [
1672
+ "google/gemini-3-flash-preview",
1673
+ "google/gemini-3.5-flash",
1674
+ "xai/grok-4.5",
1675
+ "anthropic/claude-sonnet-5",
1676
+ "deepseek/deepseek-v4-pro"
1677
+ ];
1678
+ }
1679
+ if (task === "reasoning_math") {
1680
+ return [
1681
+ "google/gemini-3.5-flash",
1682
+ "xai/grok-4.5",
1683
+ "anthropic/claude-sonnet-5",
1684
+ "deepseek/deepseek-v4-pro",
1685
+ "moonshot/kimi-k3"
1686
+ ];
1687
+ }
1688
+ return [];
1689
+ }
1690
+ function isEligible(modelId, features, maxOutputTokens, options) {
1691
+ const model = options.modelCapabilities?.[modelId] ?? DEFAULT_MODEL_CAPABILITIES[modelId];
1692
+ if (!model) return true;
1693
+ if (features.needsTools && !model.supportsTools) return false;
1694
+ if (features.needsVision && !model.supportsVision) return false;
1695
+ if (features.needsStructuredOutput && !model.supportsTools) return false;
1696
+ if (model.maxOutputTokens < maxOutputTokens) return false;
1697
+ return model.contextWindow >= (features.estimatedInputTokens + maxOutputTokens) * 1.1;
1698
+ }
1699
+ function estimatedCost(modelId, options, inputTokens, outputTokens) {
1700
+ const price = options.modelPricing.get(modelId);
1701
+ if (!price) return Number.POSITIVE_INFINITY;
1702
+ if (price.flatPrice !== void 0) return price.flatPrice;
1703
+ return (inputTokens * price.inputPrice + outputTokens * price.outputPrice) / 1e6;
1704
+ }
1705
+ function profileScore(modelId, options, now) {
1706
+ const profile = options.modelPerformance?.[modelId] ?? LIVE_MODEL_PROFILES[modelId] ?? HISTORICAL_MODEL_PROFILES[modelId];
1707
+ if (!profile) return void 0;
1708
+ const measuredAt = Date.parse(profile.measuredAt);
1709
+ if (!Number.isFinite(measuredAt)) return void 0;
1710
+ const ageDays = Math.max(0, (now.getTime() - measuredAt) / 864e5);
1711
+ const sampleConfidence = profile.samples === void 0 ? 1 : Math.min(1, Math.max(0, profile.samples) / 10);
1712
+ const freshness = Math.pow(0.5, ageDays / 30) * sampleConfidence;
1713
+ const quality = profile.intelligenceIndex === void 0 ? void 0 : Math.min(1, profile.intelligenceIndex / 50);
1714
+ const speed = Math.min(
1715
+ 1,
1716
+ (2e3 / Math.max(500, profile.latencyMs) + profile.outputTokensPerSecond / 250) / 2
1717
+ );
1718
+ const tailSpeed = Math.min(1, 3e3 / Math.max(750, profile.p95LatencyMs ?? profile.latencyMs));
1719
+ const reliability = Math.max(0, 1 - (profile.errorRate ?? 0));
1720
+ return { quality, speed, tailSpeed, reliability, freshness };
1721
+ }
1722
+ var PortfolioStrategy = class {
1723
+ name = "portfolio";
1724
+ route(prompt, systemPrompt, maxOutputTokens, options) {
1725
+ const features = classifyTask(prompt, systemPrompt, options);
1726
+ const base = new RulesStrategy().route(prompt, systemPrompt, maxOutputTokens, {
1727
+ ...options,
1728
+ requiresTools: features.needsTools
1729
+ });
1730
+ const tierConfigs = base.tierConfigs;
1731
+ if (!tierConfigs) return base;
1732
+ const targetTier = (features.taskType === "reasoning_mcq" || features.taskType === "reasoning_math") && (base.tier === "SIMPLE" || base.tier === "MEDIUM") ? "REASONING" : base.tier;
1733
+ const tierConfig = tierConfigs[targetTier];
1734
+ const configuredCandidates = tierConfig ? getFallbackChain(targetTier, tierConfigs) : [];
1735
+ const chain = [
1736
+ .../* @__PURE__ */ new Set([...configuredCandidates, ...evidenceCandidates(features.taskType)])
1737
+ ].filter((model2) => typeof model2 === "string" && model2.length > 0);
1738
+ const eligible = chain.filter(
1739
+ (model2) => isEligible(model2, features, maxOutputTokens, options)
1740
+ );
1741
+ const eligibleCandidates = eligible.length > 0 ? eligible : chain;
1742
+ if (eligibleCandidates.length === 0) return base;
1743
+ const profileName = options.routingProfile === "eco" ? "eco" : options.routingProfile === "premium" ? "premium" : "auto";
1744
+ const portfolio = options.config.portfolio ?? DEFAULT_PORTFOLIO_WEIGHTS;
1745
+ const getAffinity = (model2) => affinity(
1746
+ model2,
1747
+ features.taskType,
1748
+ features.language,
1749
+ features.agentDomain,
1750
+ features.deepWebResearch,
1751
+ features.agentRisk,
1752
+ features.terminalToolSignal,
1753
+ features.terminalSafetySensitive
1754
+ );
1755
+ const bestAffinity = Math.max(...eligibleCandidates.map(getAffinity));
1756
+ const specificAffinity = eligibleCandidates.filter((model2) => getAffinity(model2) > 0.68);
1757
+ const affinityPool = specificAffinity.length > 0 ? specificAffinity : [eligibleCandidates[0]];
1758
+ const affinityFloorGap = features.terminalToolSignal ? Math.max(
1759
+ portfolio.affinityFloorGap[profileName],
1760
+ features.terminalSafetySensitive ? 0.15 : 0.12
1761
+ ) : portfolio.affinityFloorGap[profileName];
1762
+ const candidates = affinityPool.filter(
1763
+ (model2) => getAffinity(model2) >= bestAffinity - affinityFloorGap
1764
+ );
1765
+ const costs = candidates.map(
1766
+ (model2) => estimatedCost(model2, options, features.estimatedInputTokens, maxOutputTokens)
1767
+ );
1768
+ const finiteCosts = costs.filter(Number.isFinite);
1769
+ const minCost = finiteCosts.length > 0 ? Math.min(...finiteCosts) : 0;
1770
+ const maxCost = finiteCosts.length > 0 ? Math.max(...finiteCosts) : 1;
1771
+ const now = options.now ?? /* @__PURE__ */ new Date();
1772
+ const profileWeights = portfolio[profileName];
1773
+ const rankedEntries = candidates.map((model2, index) => {
1774
+ const cost = estimatedCost(model2, options, features.estimatedInputTokens, maxOutputTokens);
1775
+ const costScore = Number.isFinite(cost) && maxCost > minCost ? 1 - (cost - minCost) / (maxCost - minCost) : 0.5;
1776
+ const capabilityScore = isEligible(model2, features, maxOutputTokens, options) ? 1 : 0;
1777
+ const profile = profileScore(model2, options, now);
1778
+ const observedQuality = profile?.quality === void 0 ? getAffinity(model2) : getAffinity(model2) * (1 - profile.freshness) + profile.quality * profile.freshness;
1779
+ const observedSpeed = profile ? profile.speed * profile.freshness : 0.5;
1780
+ const observedTailSpeed = profile ? profile.tailSpeed * profile.freshness : 0.5;
1781
+ const observedReliability = profile ? profile.reliability * profile.freshness + (1 - profile.freshness) : 1;
1782
+ const legacyScore = 1 - index / Math.max(1, candidates.length - 1);
1783
+ const qualityWeight = profileWeights.quality + (features.highStakes ? portfolio.highStakesBoost.quality : 0);
1784
+ const speedScore = features.latencySensitive ? observedTailSpeed : observedSpeed;
1785
+ const speedWeight = profileWeights.speed + (features.latencySensitive ? portfolio.latencySensitiveSpeedBoost : 0);
1786
+ const reliabilityWeight = profileWeights.reliability + (features.highStakes ? portfolio.highStakesBoost.reliability : 0);
1787
+ const score = observedQuality * qualityWeight + capabilityScore * profileWeights.capability + costScore * profileWeights.cost + speedScore * speedWeight + observedReliability * reliabilityWeight + legacyScore * profileWeights.legacy;
1788
+ return {
1789
+ model: model2,
1790
+ score,
1791
+ quality: observedQuality,
1792
+ cost: costScore,
1793
+ speed: speedScore,
1794
+ reliability: observedReliability
1795
+ };
1796
+ }).sort((a, b) => b.score - a.score);
1797
+ const scoredModels = rankedEntries.map((item) => item.model);
1798
+ const webResearchFallbackOrder = [
1799
+ "anthropic/claude-sonnet-5",
1800
+ "openai/gpt-5-mini",
1801
+ "google/gemini-3.5-flash",
1802
+ "anthropic/claude-opus-5",
1803
+ "anthropic/claude-opus-4.8",
1804
+ "openai/gpt-5.3-codex"
1805
+ ];
1806
+ const ranked = features.agentDomain === "web_research" ? [
1807
+ ...scoredModels,
1808
+ ...webResearchFallbackOrder.filter(
1809
+ (model2) => eligibleCandidates.includes(model2) && !scoredModels.includes(model2)
1810
+ ),
1811
+ ...eligibleCandidates.filter(
1812
+ (model2) => !scoredModels.includes(model2) && !webResearchFallbackOrder.includes(model2)
1813
+ )
1814
+ ] : features.taskType === "tool_agent" || features.taskType === "tool_agent_parallel" && features.agentDomain !== "other" ? [
1815
+ ...scoredModels,
1816
+ ...eligibleCandidates.filter((model2) => !scoredModels.includes(model2))
1817
+ ] : [
1818
+ ...scoredModels,
1819
+ ...eligibleCandidates.filter((model2) => !scoredModels.includes(model2))
1820
+ ];
1821
+ const model = ranked[0] ?? base.model;
1822
+ const selectedTierConfigs = {
1823
+ ...tierConfigs,
1824
+ [targetTier]: { primary: model, fallback: ranked.slice(1) }
1825
+ };
1826
+ const decision = selectModel(
1827
+ targetTier,
1828
+ base.confidence,
1829
+ "portfolio",
1830
+ `${base.reasoning} | v3 task=${features.taskType} agentRisk=${features.agentRisk} deepWebResearch=${features.deepWebResearch} terminalCode=${features.implicitTerminalCode} terminalSafety=${features.terminalSafetySensitive} candidates=${ranked.length}`,
1831
+ selectedTierConfigs,
1832
+ options.modelPricing,
1833
+ features.estimatedInputTokens,
1834
+ maxOutputTokens,
1835
+ options.routingProfile,
1836
+ base.agenticScore
1837
+ );
1838
+ return {
1839
+ ...decision,
1840
+ tierConfigs: selectedTierConfigs,
1841
+ profile: base.profile,
1842
+ candidates: ranked,
1843
+ candidateScores: rankedEntries.map(({ model: model2, score, quality, cost, speed, reliability }) => ({
1844
+ model: model2,
1845
+ score,
1846
+ quality,
1847
+ cost,
1848
+ speed,
1849
+ reliability
1850
+ })),
1851
+ taskType: features.taskType,
1852
+ routerVersion: "v3-portfolio"
1853
+ };
1854
+ }
1855
+ };
1856
+ var DEFAULT_ROUTING_CONFIG = {
1857
+ version: "3.4",
1858
+ strategy: "portfolio",
1859
+ portfolio: {
1860
+ auto: {
1861
+ quality: 0.47,
1862
+ capability: 0.2,
1863
+ cost: 0.18,
1864
+ speed: 0.07,
1865
+ reliability: 0.03,
1866
+ legacy: 0.05
1867
+ },
1868
+ eco: {
1869
+ quality: 0.36,
1870
+ capability: 0.2,
1871
+ cost: 0.28,
1872
+ speed: 0.1,
1873
+ reliability: 0.04,
1874
+ legacy: 0.02
1875
+ },
1876
+ premium: {
1877
+ quality: 0.58,
1878
+ capability: 0.2,
1879
+ cost: 0.08,
1880
+ speed: 0.06,
1881
+ reliability: 0.06,
1882
+ legacy: 0.02
1883
+ },
1884
+ highStakesBoost: { quality: 0.08, reliability: 0.05 },
1885
+ latencySensitiveSpeedBoost: 0.08,
1886
+ affinityFloorGap: { auto: 0.1, eco: 0.22, premium: 0.05 }
1887
+ },
1888
+ classifier: {
1889
+ llmModel: "google/gemini-2.5-flash",
1890
+ llmMaxTokens: 10,
1891
+ llmTemperature: 0,
1892
+ promptTruncationChars: 500,
1893
+ cacheTtlMs: 36e5
1894
+ // 1 hour
1895
+ },
1896
+ scoring: {
1897
+ tokenCountThresholds: { simple: 50, complex: 500 },
1898
+ // Multilingual keywords: EN + ZH + JA + RU + DE + ES + PT + KO + AR
1899
+ codeKeywords: [
1900
+ // English
1901
+ "function",
1902
+ "class",
1903
+ "import",
1904
+ "def",
1905
+ "SELECT",
1906
+ "async",
1907
+ "await",
1908
+ "const",
1909
+ "let",
1910
+ "var",
1911
+ "return",
1912
+ "```",
1913
+ // Chinese
1914
+ "\u51FD\u6570",
1915
+ "\u7C7B",
1916
+ "\u5BFC\u5165",
1917
+ "\u5B9A\u4E49",
1918
+ "\u67E5\u8BE2",
1919
+ "\u5F02\u6B65",
1920
+ "\u7B49\u5F85",
1921
+ "\u5E38\u91CF",
1922
+ "\u53D8\u91CF",
1923
+ "\u8FD4\u56DE",
1924
+ // Japanese
1925
+ "\u95A2\u6570",
1926
+ "\u30AF\u30E9\u30B9",
1927
+ "\u30A4\u30F3\u30DD\u30FC\u30C8",
1928
+ "\u975E\u540C\u671F",
1929
+ "\u5B9A\u6570",
1930
+ "\u5909\u6570",
1931
+ // Russian
1932
+ "\u0444\u0443\u043D\u043A\u0446\u0438\u044F",
1933
+ "\u043A\u043B\u0430\u0441\u0441",
1934
+ "\u0438\u043C\u043F\u043E\u0440\u0442",
1935
+ "\u043E\u043F\u0440\u0435\u0434\u0435\u043B",
1936
+ "\u0437\u0430\u043F\u0440\u043E\u0441",
1937
+ "\u0430\u0441\u0438\u043D\u0445\u0440\u043E\u043D\u043D\u044B\u0439",
1938
+ "\u043E\u0436\u0438\u0434\u0430\u0442\u044C",
1939
+ "\u043A\u043E\u043D\u0441\u0442\u0430\u043D\u0442\u0430",
1940
+ "\u043F\u0435\u0440\u0435\u043C\u0435\u043D\u043D\u0430\u044F",
1941
+ "\u0432\u0435\u0440\u043D\u0443\u0442\u044C",
1942
+ // German
1943
+ "funktion",
1944
+ "klasse",
1945
+ "importieren",
1946
+ "definieren",
1947
+ "abfrage",
1948
+ "asynchron",
1949
+ "erwarten",
1950
+ "konstante",
1951
+ "variable",
1952
+ "zur\xFCckgeben",
1953
+ // Spanish
1954
+ "funci\xF3n",
1955
+ "clase",
1956
+ "importar",
1957
+ "definir",
1958
+ "consulta",
1959
+ "as\xEDncrono",
1960
+ "esperar",
1961
+ "constante",
1962
+ "variable",
1963
+ "retornar",
1964
+ // Portuguese
1965
+ "fun\xE7\xE3o",
1966
+ "classe",
1967
+ "importar",
1968
+ "definir",
1969
+ "consulta",
1970
+ "ass\xEDncrono",
1971
+ "aguardar",
1972
+ "constante",
1973
+ "vari\xE1vel",
1974
+ "retornar",
1975
+ // Korean
1976
+ "\uD568\uC218",
1977
+ "\uD074\uB798\uC2A4",
1978
+ "\uAC00\uC838\uC624\uAE30",
1979
+ "\uC815\uC758",
1980
+ "\uCFFC\uB9AC",
1981
+ "\uBE44\uB3D9\uAE30",
1982
+ "\uB300\uAE30",
1983
+ "\uC0C1\uC218",
1984
+ "\uBCC0\uC218",
1985
+ "\uBC18\uD658",
1986
+ // Arabic
1987
+ "\u062F\u0627\u0644\u0629",
1988
+ "\u0641\u0626\u0629",
1989
+ "\u0627\u0633\u062A\u064A\u0631\u0627\u062F",
1990
+ "\u062A\u0639\u0631\u064A\u0641",
1991
+ "\u0627\u0633\u062A\u0639\u0644\u0627\u0645",
1992
+ "\u063A\u064A\u0631 \u0645\u062A\u0632\u0627\u0645\u0646",
1993
+ "\u0627\u0646\u062A\u0638\u0627\u0631",
1994
+ "\u062B\u0627\u0628\u062A",
1995
+ "\u0645\u062A\u063A\u064A\u0631",
1996
+ "\u0625\u0631\u062C\u0627\u0639"
1997
+ ],
1998
+ reasoningKeywords: [
1999
+ // English
2000
+ "prove",
2001
+ "theorem",
2002
+ "derive",
2003
+ "step by step",
2004
+ "chain of thought",
2005
+ "formally",
2006
+ "mathematical",
2007
+ "proof",
2008
+ "logically",
2009
+ // Chinese
2010
+ "\u8BC1\u660E",
2011
+ "\u5B9A\u7406",
2012
+ "\u63A8\u5BFC",
2013
+ "\u9010\u6B65",
2014
+ "\u601D\u7EF4\u94FE",
2015
+ "\u5F62\u5F0F\u5316",
2016
+ "\u6570\u5B66",
2017
+ "\u903B\u8F91",
2018
+ // Japanese
2019
+ "\u8A3C\u660E",
2020
+ "\u5B9A\u7406",
2021
+ "\u5C0E\u51FA",
2022
+ "\u30B9\u30C6\u30C3\u30D7\u30D0\u30A4\u30B9\u30C6\u30C3\u30D7",
2023
+ "\u8AD6\u7406\u7684",
2024
+ // Russian
2025
+ "\u0434\u043E\u043A\u0430\u0437\u0430\u0442\u044C",
2026
+ "\u0434\u043E\u043A\u0430\u0436\u0438",
2027
+ "\u0434\u043E\u043A\u0430\u0437\u0430\u0442\u0435\u043B\u044C\u0441\u0442\u0432",
2028
+ "\u0442\u0435\u043E\u0440\u0435\u043C\u0430",
2029
+ "\u0432\u044B\u0432\u0435\u0441\u0442\u0438",
2030
+ "\u0448\u0430\u0433 \u0437\u0430 \u0448\u0430\u0433\u043E\u043C",
2031
+ "\u043F\u043E\u0448\u0430\u0433\u043E\u0432\u043E",
2032
+ "\u043F\u043E\u044D\u0442\u0430\u043F\u043D\u043E",
2033
+ "\u0446\u0435\u043F\u043E\u0447\u043A\u0430 \u0440\u0430\u0441\u0441\u0443\u0436\u0434\u0435\u043D\u0438\u0439",
2034
+ "\u0440\u0430\u0441\u0441\u0443\u0436\u0434\u0435\u043D\u0438",
2035
+ "\u0444\u043E\u0440\u043C\u0430\u043B\u044C\u043D\u043E",
2036
+ "\u043C\u0430\u0442\u0435\u043C\u0430\u0442\u0438\u0447\u0435\u0441\u043A\u0438",
2037
+ "\u043B\u043E\u0433\u0438\u0447\u0435\u0441\u043A\u0438",
2038
+ // German
2039
+ "beweisen",
2040
+ "beweis",
2041
+ "theorem",
2042
+ "ableiten",
2043
+ "schritt f\xFCr schritt",
2044
+ "gedankenkette",
2045
+ "formal",
2046
+ "mathematisch",
2047
+ "logisch",
2048
+ // Spanish
2049
+ "demostrar",
2050
+ "teorema",
2051
+ "derivar",
2052
+ "paso a paso",
2053
+ "cadena de pensamiento",
2054
+ "formalmente",
2055
+ "matem\xE1tico",
2056
+ "prueba",
2057
+ "l\xF3gicamente",
2058
+ // Portuguese
2059
+ "provar",
2060
+ "teorema",
2061
+ "derivar",
2062
+ "passo a passo",
2063
+ "cadeia de pensamento",
2064
+ "formalmente",
2065
+ "matem\xE1tico",
2066
+ "prova",
2067
+ "logicamente",
2068
+ // Korean
2069
+ "\uC99D\uBA85",
2070
+ "\uC815\uB9AC",
2071
+ "\uB3C4\uCD9C",
2072
+ "\uB2E8\uACC4\uBCC4",
2073
+ "\uC0AC\uACE0\uC758 \uC5F0\uC1C4",
2074
+ "\uD615\uC2DD\uC801",
2075
+ "\uC218\uD559\uC801",
2076
+ "\uB17C\uB9AC\uC801",
2077
+ // Arabic
2078
+ "\u0625\u062B\u0628\u0627\u062A",
2079
+ "\u0646\u0638\u0631\u064A\u0629",
2080
+ "\u0627\u0634\u062A\u0642\u0627\u0642",
2081
+ "\u062E\u0637\u0648\u0629 \u0628\u062E\u0637\u0648\u0629",
2082
+ "\u0633\u0644\u0633\u0644\u0629 \u0627\u0644\u062A\u0641\u0643\u064A\u0631",
2083
+ "\u0631\u0633\u0645\u064A\u0627\u064B",
2084
+ "\u0631\u064A\u0627\u0636\u064A",
2085
+ "\u0628\u0631\u0647\u0627\u0646",
2086
+ "\u0645\u0646\u0637\u0642\u064A\u0627\u064B"
2087
+ ],
2088
+ simpleKeywords: [
2089
+ // English
2090
+ "what is",
2091
+ "define",
2092
+ "translate",
2093
+ "hello",
2094
+ "yes or no",
2095
+ "capital of",
2096
+ "how old",
2097
+ "who is",
2098
+ "when was",
2099
+ // Chinese
2100
+ "\u4EC0\u4E48\u662F",
2101
+ "\u5B9A\u4E49",
2102
+ "\u7FFB\u8BD1",
2103
+ "\u4F60\u597D",
2104
+ "\u662F\u5426",
2105
+ "\u9996\u90FD",
2106
+ "\u591A\u5927",
2107
+ "\u8C01\u662F",
2108
+ "\u4F55\u65F6",
2109
+ // Japanese
2110
+ "\u3068\u306F",
2111
+ "\u5B9A\u7FA9",
2112
+ "\u7FFB\u8A33",
2113
+ "\u3053\u3093\u306B\u3061\u306F",
2114
+ "\u306F\u3044\u304B\u3044\u3044\u3048",
2115
+ "\u9996\u90FD",
2116
+ "\u8AB0",
2117
+ // Russian
2118
+ "\u0447\u0442\u043E \u0442\u0430\u043A\u043E\u0435",
2119
+ "\u043E\u043F\u0440\u0435\u0434\u0435\u043B\u0435\u043D\u0438\u0435",
2120
+ "\u043F\u0435\u0440\u0435\u0432\u0435\u0441\u0442\u0438",
2121
+ "\u043F\u0435\u0440\u0435\u0432\u0435\u0434\u0438",
2122
+ "\u043F\u0440\u0438\u0432\u0435\u0442",
2123
+ "\u0434\u0430 \u0438\u043B\u0438 \u043D\u0435\u0442",
2124
+ "\u0441\u0442\u043E\u043B\u0438\u0446\u0430",
2125
+ "\u0441\u043A\u043E\u043B\u044C\u043A\u043E \u043B\u0435\u0442",
2126
+ "\u043A\u0442\u043E \u0442\u0430\u043A\u043E\u0439",
2127
+ "\u043A\u043E\u0433\u0434\u0430",
2128
+ "\u043E\u0431\u044A\u044F\u0441\u043D\u0438",
2129
+ // German
2130
+ "was ist",
2131
+ "definiere",
2132
+ "\xFCbersetze",
2133
+ "hallo",
2134
+ "ja oder nein",
2135
+ "hauptstadt",
2136
+ "wie alt",
2137
+ "wer ist",
2138
+ "wann",
2139
+ "erkl\xE4re",
2140
+ // Spanish
2141
+ "qu\xE9 es",
2142
+ "definir",
2143
+ "traducir",
2144
+ "hola",
2145
+ "s\xED o no",
2146
+ "capital de",
2147
+ "cu\xE1ntos a\xF1os",
2148
+ "qui\xE9n es",
2149
+ "cu\xE1ndo",
2150
+ // Portuguese
2151
+ "o que \xE9",
2152
+ "definir",
2153
+ "traduzir",
2154
+ "ol\xE1",
2155
+ "sim ou n\xE3o",
2156
+ "capital de",
2157
+ "quantos anos",
2158
+ "quem \xE9",
2159
+ "quando",
2160
+ // Korean
2161
+ "\uBB34\uC5C7",
2162
+ "\uC815\uC758",
2163
+ "\uBC88\uC5ED",
2164
+ "\uC548\uB155\uD558\uC138\uC694",
2165
+ "\uC608 \uB610\uB294 \uC544\uB2C8\uC624",
2166
+ "\uC218\uB3C4",
2167
+ "\uB204\uAD6C",
2168
+ "\uC5B8\uC81C",
2169
+ // Arabic
2170
+ "\u0645\u0627 \u0647\u0648",
2171
+ "\u062A\u0639\u0631\u064A\u0641",
2172
+ "\u062A\u0631\u062C\u0645",
2173
+ "\u0645\u0631\u062D\u0628\u0627",
2174
+ "\u0646\u0639\u0645 \u0623\u0648 \u0644\u0627",
2175
+ "\u0639\u0627\u0635\u0645\u0629",
2176
+ "\u0645\u0646 \u0647\u0648",
2177
+ "\u0645\u062A\u0649"
2178
+ ],
2179
+ technicalKeywords: [
2180
+ // English
2181
+ "algorithm",
2182
+ "optimize",
2183
+ "architecture",
2184
+ "distributed",
2185
+ "kubernetes",
2186
+ "microservice",
2187
+ "database",
2188
+ "infrastructure",
2189
+ // Chinese
2190
+ "\u7B97\u6CD5",
2191
+ "\u4F18\u5316",
2192
+ "\u67B6\u6784",
2193
+ "\u5206\u5E03\u5F0F",
2194
+ "\u5FAE\u670D\u52A1",
2195
+ "\u6570\u636E\u5E93",
2196
+ "\u57FA\u7840\u8BBE\u65BD",
2197
+ // Japanese
2198
+ "\u30A2\u30EB\u30B4\u30EA\u30BA\u30E0",
2199
+ "\u6700\u9069\u5316",
2200
+ "\u30A2\u30FC\u30AD\u30C6\u30AF\u30C1\u30E3",
2201
+ "\u5206\u6563",
2202
+ "\u30DE\u30A4\u30AF\u30ED\u30B5\u30FC\u30D3\u30B9",
2203
+ "\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9",
2204
+ // Russian
2205
+ "\u0430\u043B\u0433\u043E\u0440\u0438\u0442\u043C",
2206
+ "\u043E\u043F\u0442\u0438\u043C\u0438\u0437\u0438\u0440\u043E\u0432\u0430\u0442\u044C",
2207
+ "\u043E\u043F\u0442\u0438\u043C\u0438\u0437\u0430\u0446\u0438",
2208
+ "\u043E\u043F\u0442\u0438\u043C\u0438\u0437\u0438\u0440\u0443\u0439",
2209
+ "\u0430\u0440\u0445\u0438\u0442\u0435\u043A\u0442\u0443\u0440\u0430",
2210
+ "\u0440\u0430\u0441\u043F\u0440\u0435\u0434\u0435\u043B\u0451\u043D\u043D\u044B\u0439",
2211
+ "\u043C\u0438\u043A\u0440\u043E\u0441\u0435\u0440\u0432\u0438\u0441",
2212
+ "\u0431\u0430\u0437\u0430 \u0434\u0430\u043D\u043D\u044B\u0445",
2213
+ "\u0438\u043D\u0444\u0440\u0430\u0441\u0442\u0440\u0443\u043A\u0442\u0443\u0440\u0430",
2214
+ // German
2215
+ "algorithmus",
2216
+ "optimieren",
2217
+ "architektur",
2218
+ "verteilt",
2219
+ "kubernetes",
2220
+ "mikroservice",
2221
+ "datenbank",
2222
+ "infrastruktur",
2223
+ // Spanish
2224
+ "algoritmo",
2225
+ "optimizar",
2226
+ "arquitectura",
2227
+ "distribuido",
2228
+ "microservicio",
2229
+ "base de datos",
2230
+ "infraestructura",
2231
+ // Portuguese
2232
+ "algoritmo",
2233
+ "otimizar",
2234
+ "arquitetura",
2235
+ "distribu\xEDdo",
2236
+ "microsservi\xE7o",
2237
+ "banco de dados",
2238
+ "infraestrutura",
2239
+ // Korean
2240
+ "\uC54C\uACE0\uB9AC\uC998",
2241
+ "\uCD5C\uC801\uD654",
2242
+ "\uC544\uD0A4\uD14D\uCC98",
2243
+ "\uBD84\uC0B0",
2244
+ "\uB9C8\uC774\uD06C\uB85C\uC11C\uBE44\uC2A4",
2245
+ "\uB370\uC774\uD130\uBCA0\uC774\uC2A4",
2246
+ "\uC778\uD504\uB77C",
2247
+ // Arabic
2248
+ "\u062E\u0648\u0627\u0631\u0632\u0645\u064A\u0629",
2249
+ "\u062A\u062D\u0633\u064A\u0646",
2250
+ "\u0628\u0646\u064A\u0629",
2251
+ "\u0645\u0648\u0632\u0639",
2252
+ "\u062E\u062F\u0645\u0629 \u0645\u0635\u063A\u0631\u0629",
2253
+ "\u0642\u0627\u0639\u062F\u0629 \u0628\u064A\u0627\u0646\u0627\u062A",
2254
+ "\u0628\u0646\u064A\u0629 \u062A\u062D\u062A\u064A\u0629"
2255
+ ],
2256
+ creativeKeywords: [
2257
+ // English
2258
+ "story",
2259
+ "poem",
2260
+ "compose",
2261
+ "brainstorm",
2262
+ "creative",
2263
+ "imagine",
2264
+ "write a",
2265
+ // Chinese
2266
+ "\u6545\u4E8B",
2267
+ "\u8BD7",
2268
+ "\u521B\u4F5C",
2269
+ "\u5934\u8111\u98CE\u66B4",
2270
+ "\u521B\u610F",
2271
+ "\u60F3\u8C61",
2272
+ "\u5199\u4E00\u4E2A",
2273
+ // Japanese
2274
+ "\u7269\u8A9E",
2275
+ "\u8A69",
2276
+ "\u4F5C\u66F2",
2277
+ "\u30D6\u30EC\u30A4\u30F3\u30B9\u30C8\u30FC\u30E0",
2278
+ "\u5275\u9020\u7684",
2279
+ "\u60F3\u50CF",
2280
+ // Russian
2281
+ "\u0438\u0441\u0442\u043E\u0440\u0438\u044F",
2282
+ "\u0440\u0430\u0441\u0441\u043A\u0430\u0437",
2283
+ "\u0441\u0442\u0438\u0445\u043E\u0442\u0432\u043E\u0440\u0435\u043D\u0438\u0435",
2284
+ "\u0441\u043E\u0447\u0438\u043D\u0438\u0442\u044C",
2285
+ "\u0441\u043E\u0447\u0438\u043D\u0438",
2286
+ "\u043C\u043E\u0437\u0433\u043E\u0432\u043E\u0439 \u0448\u0442\u0443\u0440\u043C",
2287
+ "\u0442\u0432\u043E\u0440\u0447\u0435\u0441\u043A\u0438\u0439",
2288
+ "\u043F\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u0438\u0442\u044C",
2289
+ "\u043F\u0440\u0438\u0434\u0443\u043C\u0430\u0439",
2290
+ "\u043D\u0430\u043F\u0438\u0448\u0438",
2291
+ // German
2292
+ "geschichte",
2293
+ "gedicht",
2294
+ "komponieren",
2295
+ "brainstorming",
2296
+ "kreativ",
2297
+ "vorstellen",
2298
+ "schreibe",
2299
+ "erz\xE4hlung",
2300
+ // Spanish
2301
+ "historia",
2302
+ "poema",
2303
+ "componer",
2304
+ "lluvia de ideas",
2305
+ "creativo",
2306
+ "imaginar",
2307
+ "escribe",
2308
+ // Portuguese
2309
+ "hist\xF3ria",
2310
+ "poema",
2311
+ "compor",
2312
+ "criativo",
2313
+ "imaginar",
2314
+ "escreva",
2315
+ // Korean
2316
+ "\uC774\uC57C\uAE30",
2317
+ "\uC2DC",
2318
+ "\uC791\uACE1",
2319
+ "\uBE0C\uB808\uC778\uC2A4\uD1A0\uBC0D",
2320
+ "\uCC3D\uC758\uC801",
2321
+ "\uC0C1\uC0C1",
2322
+ "\uC791\uC131",
2323
+ // Arabic
2324
+ "\u0642\u0635\u0629",
2325
+ "\u0642\u0635\u064A\u062F\u0629",
2326
+ "\u062A\u0623\u0644\u064A\u0641",
2327
+ "\u0639\u0635\u0641 \u0630\u0647\u0646\u064A",
2328
+ "\u0625\u0628\u062F\u0627\u0639\u064A",
2329
+ "\u062A\u062E\u064A\u0644",
2330
+ "\u0627\u0643\u062A\u0628"
2331
+ ],
2332
+ // New dimension keyword lists (multilingual)
2333
+ imperativeVerbs: [
2334
+ // English
2335
+ "build",
2336
+ "create",
2337
+ "implement",
2338
+ "design",
2339
+ "develop",
2340
+ "construct",
2341
+ "generate",
2342
+ "deploy",
2343
+ "configure",
2344
+ "set up",
2345
+ // Chinese
2346
+ "\u6784\u5EFA",
2347
+ "\u521B\u5EFA",
2348
+ "\u5B9E\u73B0",
2349
+ "\u8BBE\u8BA1",
2350
+ "\u5F00\u53D1",
2351
+ "\u751F\u6210",
2352
+ "\u90E8\u7F72",
2353
+ "\u914D\u7F6E",
2354
+ "\u8BBE\u7F6E",
2355
+ // Japanese
2356
+ "\u69CB\u7BC9",
2357
+ "\u4F5C\u6210",
2358
+ "\u5B9F\u88C5",
2359
+ "\u8A2D\u8A08",
2360
+ "\u958B\u767A",
2361
+ "\u751F\u6210",
2362
+ "\u30C7\u30D7\u30ED\u30A4",
2363
+ "\u8A2D\u5B9A",
2364
+ // Russian
2365
+ "\u043F\u043E\u0441\u0442\u0440\u043E\u0438\u0442\u044C",
2366
+ "\u043F\u043E\u0441\u0442\u0440\u043E\u0439",
2367
+ "\u0441\u043E\u0437\u0434\u0430\u0442\u044C",
2368
+ "\u0441\u043E\u0437\u0434\u0430\u0439",
2369
+ "\u0440\u0435\u0430\u043B\u0438\u0437\u043E\u0432\u0430\u0442\u044C",
2370
+ "\u0440\u0435\u0430\u043B\u0438\u0437\u0443\u0439",
2371
+ "\u0441\u043F\u0440\u043E\u0435\u043A\u0442\u0438\u0440\u043E\u0432\u0430\u0442\u044C",
2372
+ "\u0440\u0430\u0437\u0440\u0430\u0431\u043E\u0442\u0430\u0442\u044C",
2373
+ "\u0440\u0430\u0437\u0440\u0430\u0431\u043E\u0442\u0430\u0439",
2374
+ "\u0441\u043A\u043E\u043D\u0441\u0442\u0440\u0443\u0438\u0440\u043E\u0432\u0430\u0442\u044C",
2375
+ "\u0441\u0433\u0435\u043D\u0435\u0440\u0438\u0440\u043E\u0432\u0430\u0442\u044C",
2376
+ "\u0441\u0433\u0435\u043D\u0435\u0440\u0438\u0440\u0443\u0439",
2377
+ "\u0440\u0430\u0437\u0432\u0435\u0440\u043D\u0443\u0442\u044C",
2378
+ "\u0440\u0430\u0437\u0432\u0435\u0440\u043D\u0438",
2379
+ "\u043D\u0430\u0441\u0442\u0440\u043E\u0438\u0442\u044C",
2380
+ "\u043D\u0430\u0441\u0442\u0440\u043E\u0439",
2381
+ // German
2382
+ "erstellen",
2383
+ "bauen",
2384
+ "implementieren",
2385
+ "entwerfen",
2386
+ "entwickeln",
2387
+ "konstruieren",
2388
+ "generieren",
2389
+ "bereitstellen",
2390
+ "konfigurieren",
2391
+ "einrichten",
2392
+ // Spanish
2393
+ "construir",
2394
+ "crear",
2395
+ "implementar",
2396
+ "dise\xF1ar",
2397
+ "desarrollar",
2398
+ "generar",
2399
+ "desplegar",
2400
+ "configurar",
2401
+ // Portuguese
2402
+ "construir",
2403
+ "criar",
2404
+ "implementar",
2405
+ "projetar",
2406
+ "desenvolver",
2407
+ "gerar",
2408
+ "implantar",
2409
+ "configurar",
2410
+ // Korean
2411
+ "\uAD6C\uCD95",
2412
+ "\uC0DD\uC131",
2413
+ "\uAD6C\uD604",
2414
+ "\uC124\uACC4",
2415
+ "\uAC1C\uBC1C",
2416
+ "\uBC30\uD3EC",
2417
+ "\uC124\uC815",
2418
+ // Arabic
2419
+ "\u0628\u0646\u0627\u0621",
2420
+ "\u0625\u0646\u0634\u0627\u0621",
2421
+ "\u062A\u0646\u0641\u064A\u0630",
2422
+ "\u062A\u0635\u0645\u064A\u0645",
2423
+ "\u062A\u0637\u0648\u064A\u0631",
2424
+ "\u062A\u0648\u0644\u064A\u062F",
2425
+ "\u0646\u0634\u0631",
2426
+ "\u0625\u0639\u062F\u0627\u062F"
2427
+ ],
2428
+ constraintIndicators: [
2429
+ // English
2430
+ "under",
2431
+ "at most",
2432
+ "at least",
2433
+ "within",
2434
+ "no more than",
2435
+ "o(",
2436
+ "maximum",
2437
+ "minimum",
2438
+ "limit",
2439
+ "budget",
2440
+ // Chinese
2441
+ "\u4E0D\u8D85\u8FC7",
2442
+ "\u81F3\u5C11",
2443
+ "\u6700\u591A",
2444
+ "\u5728\u5185",
2445
+ "\u6700\u5927",
2446
+ "\u6700\u5C0F",
2447
+ "\u9650\u5236",
2448
+ "\u9884\u7B97",
2449
+ // Japanese
2450
+ "\u4EE5\u4E0B",
2451
+ "\u6700\u5927",
2452
+ "\u6700\u5C0F",
2453
+ "\u5236\u9650",
2454
+ "\u4E88\u7B97",
2455
+ // Russian
2456
+ "\u043D\u0435 \u0431\u043E\u043B\u0435\u0435",
2457
+ "\u043D\u0435 \u043C\u0435\u043D\u0435\u0435",
2458
+ "\u043A\u0430\u043A \u043C\u0438\u043D\u0438\u043C\u0443\u043C",
2459
+ "\u0432 \u043F\u0440\u0435\u0434\u0435\u043B\u0430\u0445",
2460
+ "\u043C\u0430\u043A\u0441\u0438\u043C\u0443\u043C",
2461
+ "\u043C\u0438\u043D\u0438\u043C\u0443\u043C",
2462
+ "\u043E\u0433\u0440\u0430\u043D\u0438\u0447\u0435\u043D\u0438\u0435",
2463
+ "\u0431\u044E\u0434\u0436\u0435\u0442",
2464
+ // German
2465
+ "h\xF6chstens",
2466
+ "mindestens",
2467
+ "innerhalb",
2468
+ "nicht mehr als",
2469
+ "maximal",
2470
+ "minimal",
2471
+ "grenze",
2472
+ "budget",
2473
+ // Spanish
2474
+ "como m\xE1ximo",
2475
+ "al menos",
2476
+ "dentro de",
2477
+ "no m\xE1s de",
2478
+ "m\xE1ximo",
2479
+ "m\xEDnimo",
2480
+ "l\xEDmite",
2481
+ "presupuesto",
2482
+ // Portuguese
2483
+ "no m\xE1ximo",
2484
+ "pelo menos",
2485
+ "dentro de",
2486
+ "n\xE3o mais que",
2487
+ "m\xE1ximo",
2488
+ "m\xEDnimo",
2489
+ "limite",
2490
+ "or\xE7amento",
2491
+ // Korean
2492
+ "\uC774\uD558",
2493
+ "\uC774\uC0C1",
2494
+ "\uCD5C\uB300",
2495
+ "\uCD5C\uC18C",
2496
+ "\uC81C\uD55C",
2497
+ "\uC608\uC0B0",
2498
+ // Arabic
2499
+ "\u0639\u0644\u0649 \u0627\u0644\u0623\u0643\u062B\u0631",
2500
+ "\u0639\u0644\u0649 \u0627\u0644\u0623\u0642\u0644",
2501
+ "\u0636\u0645\u0646",
2502
+ "\u0644\u0627 \u064A\u0632\u064A\u062F \u0639\u0646",
2503
+ "\u0623\u0642\u0635\u0649",
2504
+ "\u0623\u062F\u0646\u0649",
2505
+ "\u062D\u062F",
2506
+ "\u0645\u064A\u0632\u0627\u0646\u064A\u0629"
2507
+ ],
2508
+ outputFormatKeywords: [
2509
+ // English
2510
+ "json",
2511
+ "yaml",
2512
+ "xml",
2513
+ "table",
2514
+ "csv",
2515
+ "markdown",
2516
+ "schema",
2517
+ "format as",
2518
+ "structured",
2519
+ // Chinese
2520
+ "\u8868\u683C",
2521
+ "\u683C\u5F0F\u5316\u4E3A",
2522
+ "\u7ED3\u6784\u5316",
2523
+ // Japanese
2524
+ "\u30C6\u30FC\u30D6\u30EB",
2525
+ "\u30D5\u30A9\u30FC\u30DE\u30C3\u30C8",
2526
+ "\u69CB\u9020\u5316",
2527
+ // Russian
2528
+ "\u0442\u0430\u0431\u043B\u0438\u0446\u0430",
2529
+ "\u0444\u043E\u0440\u043C\u0430\u0442\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u043A\u0430\u043A",
2530
+ "\u0441\u0442\u0440\u0443\u043A\u0442\u0443\u0440\u0438\u0440\u043E\u0432\u0430\u043D\u043D\u044B\u0439",
2531
+ // German
2532
+ "tabelle",
2533
+ "formatieren als",
2534
+ "strukturiert",
2535
+ // Spanish
2536
+ "tabla",
2537
+ "formatear como",
2538
+ "estructurado",
2539
+ // Portuguese
2540
+ "tabela",
2541
+ "formatar como",
2542
+ "estruturado",
2543
+ // Korean
2544
+ "\uD14C\uC774\uBE14",
2545
+ "\uD615\uC2DD",
2546
+ "\uAD6C\uC870\uD654",
2547
+ // Arabic
2548
+ "\u062C\u062F\u0648\u0644",
2549
+ "\u062A\u0646\u0633\u064A\u0642",
2550
+ "\u0645\u0646\u0638\u0645"
2551
+ ],
2552
+ referenceKeywords: [
2553
+ // English
2554
+ "above",
2555
+ "below",
2556
+ "previous",
2557
+ "following",
2558
+ "the docs",
2559
+ "the api",
2560
+ "the code",
2561
+ "earlier",
2562
+ "attached",
2563
+ // Chinese
2564
+ "\u4E0A\u9762",
2565
+ "\u4E0B\u9762",
2566
+ "\u4E4B\u524D",
2567
+ "\u63A5\u4E0B\u6765",
2568
+ "\u6587\u6863",
2569
+ "\u4EE3\u7801",
2570
+ "\u9644\u4EF6",
2571
+ // Japanese
2572
+ "\u4E0A\u8A18",
2573
+ "\u4E0B\u8A18",
2574
+ "\u524D\u306E",
2575
+ "\u6B21\u306E",
2576
+ "\u30C9\u30AD\u30E5\u30E1\u30F3\u30C8",
2577
+ "\u30B3\u30FC\u30C9",
2578
+ // Russian
2579
+ "\u0432\u044B\u0448\u0435",
2580
+ "\u043D\u0438\u0436\u0435",
2581
+ "\u043F\u0440\u0435\u0434\u044B\u0434\u0443\u0449\u0438\u0439",
2582
+ "\u0441\u043B\u0435\u0434\u0443\u044E\u0449\u0438\u0439",
2583
+ "\u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u0430\u0446\u0438\u044F",
2584
+ "\u043A\u043E\u0434",
2585
+ "\u0440\u0430\u043D\u0435\u0435",
2586
+ "\u0432\u043B\u043E\u0436\u0435\u043D\u0438\u0435",
2587
+ // German
2588
+ "oben",
2589
+ "unten",
2590
+ "vorherige",
2591
+ "folgende",
2592
+ "dokumentation",
2593
+ "der code",
2594
+ "fr\xFCher",
2595
+ "anhang",
2596
+ // Spanish
2597
+ "arriba",
2598
+ "abajo",
2599
+ "anterior",
2600
+ "siguiente",
2601
+ "documentaci\xF3n",
2602
+ "el c\xF3digo",
2603
+ "adjunto",
2604
+ // Portuguese
2605
+ "acima",
2606
+ "abaixo",
2607
+ "anterior",
2608
+ "seguinte",
2609
+ "documenta\xE7\xE3o",
2610
+ "o c\xF3digo",
2611
+ "anexo",
2612
+ // Korean
2613
+ "\uC704",
2614
+ "\uC544\uB798",
2615
+ "\uC774\uC804",
2616
+ "\uB2E4\uC74C",
2617
+ "\uBB38\uC11C",
2618
+ "\uCF54\uB4DC",
2619
+ "\uCCA8\uBD80",
2620
+ // Arabic
2621
+ "\u0623\u0639\u0644\u0627\u0647",
2622
+ "\u0623\u062F\u0646\u0627\u0647",
2623
+ "\u0627\u0644\u0633\u0627\u0628\u0642",
2624
+ "\u0627\u0644\u062A\u0627\u0644\u064A",
2625
+ "\u0627\u0644\u0648\u062B\u0627\u0626\u0642",
2626
+ "\u0627\u0644\u0643\u0648\u062F",
2627
+ "\u0645\u0631\u0641\u0642"
2628
+ ],
2629
+ negationKeywords: [
2630
+ // English
2631
+ "don't",
2632
+ "do not",
2633
+ "avoid",
2634
+ "never",
2635
+ "without",
2636
+ "except",
2637
+ "exclude",
2638
+ "no longer",
2639
+ // Chinese
2640
+ "\u4E0D\u8981",
2641
+ "\u907F\u514D",
2642
+ "\u4ECE\u4E0D",
2643
+ "\u6CA1\u6709",
2644
+ "\u9664\u4E86",
2645
+ "\u6392\u9664",
2646
+ // Japanese
2647
+ "\u3057\u306A\u3044\u3067",
2648
+ "\u907F\u3051\u308B",
2649
+ "\u6C7A\u3057\u3066",
2650
+ "\u306A\u3057\u3067",
2651
+ "\u9664\u304F",
2652
+ // Russian
2653
+ "\u043D\u0435 \u0434\u0435\u043B\u0430\u0439",
2654
+ "\u043D\u0435 \u043D\u0430\u0434\u043E",
2655
+ "\u043D\u0435\u043B\u044C\u0437\u044F",
2656
+ "\u0438\u0437\u0431\u0435\u0433\u0430\u0442\u044C",
2657
+ "\u043D\u0438\u043A\u043E\u0433\u0434\u0430",
2658
+ "\u0431\u0435\u0437",
2659
+ "\u043A\u0440\u043E\u043C\u0435",
2660
+ "\u0438\u0441\u043A\u043B\u044E\u0447\u0438\u0442\u044C",
2661
+ "\u0431\u043E\u043B\u044C\u0448\u0435 \u043D\u0435",
2662
+ // German
2663
+ "nicht",
2664
+ "vermeide",
2665
+ "niemals",
2666
+ "ohne",
2667
+ "au\xDFer",
2668
+ "ausschlie\xDFen",
2669
+ "nicht mehr",
2670
+ // Spanish
2671
+ "no hagas",
2672
+ "evitar",
2673
+ "nunca",
2674
+ "sin",
2675
+ "excepto",
2676
+ "excluir",
2677
+ // Portuguese
2678
+ "n\xE3o fa\xE7a",
2679
+ "evitar",
2680
+ "nunca",
2681
+ "sem",
2682
+ "exceto",
2683
+ "excluir",
2684
+ // Korean
2685
+ "\uD558\uC9C0 \uB9C8",
2686
+ "\uD53C\uD558\uB2E4",
2687
+ "\uC808\uB300",
2688
+ "\uC5C6\uC774",
2689
+ "\uC81C\uC678",
2690
+ // Arabic
2691
+ "\u0644\u0627 \u062A\u0641\u0639\u0644",
2692
+ "\u062A\u062C\u0646\u0628",
2693
+ "\u0623\u0628\u062F\u0627\u064B",
2694
+ "\u0628\u062F\u0648\u0646",
2695
+ "\u0628\u0627\u0633\u062A\u062B\u0646\u0627\u0621",
2696
+ "\u0627\u0633\u062A\u0628\u0639\u0627\u062F"
2697
+ ],
2698
+ domainSpecificKeywords: [
2699
+ // English
2700
+ "quantum",
2701
+ "fpga",
2702
+ "vlsi",
2703
+ "risc-v",
2704
+ "asic",
2705
+ "photonics",
2706
+ "genomics",
2707
+ "proteomics",
2708
+ "topological",
2709
+ "homomorphic",
2710
+ "zero-knowledge",
2711
+ "lattice-based",
2712
+ // Chinese
2713
+ "\u91CF\u5B50",
2714
+ "\u5149\u5B50\u5B66",
2715
+ "\u57FA\u56E0\u7EC4\u5B66",
2716
+ "\u86CB\u767D\u8D28\u7EC4\u5B66",
2717
+ "\u62D3\u6251",
2718
+ "\u540C\u6001",
2719
+ "\u96F6\u77E5\u8BC6",
2720
+ "\u683C\u5BC6\u7801",
2721
+ // Japanese
2722
+ "\u91CF\u5B50",
2723
+ "\u30D5\u30A9\u30C8\u30CB\u30AF\u30B9",
2724
+ "\u30B2\u30CE\u30DF\u30AF\u30B9",
2725
+ "\u30C8\u30DD\u30ED\u30B8\u30AB\u30EB",
2726
+ // Russian
2727
+ "\u043A\u0432\u0430\u043D\u0442\u043E\u0432\u044B\u0439",
2728
+ "\u0444\u043E\u0442\u043E\u043D\u0438\u043A\u0430",
2729
+ "\u0433\u0435\u043D\u043E\u043C\u0438\u043A\u0430",
2730
+ "\u043F\u0440\u043E\u0442\u0435\u043E\u043C\u0438\u043A\u0430",
2731
+ "\u0442\u043E\u043F\u043E\u043B\u043E\u0433\u0438\u0447\u0435\u0441\u043A\u0438\u0439",
2732
+ "\u0433\u043E\u043C\u043E\u043C\u043E\u0440\u0444\u043D\u044B\u0439",
2733
+ "\u0441 \u043D\u0443\u043B\u0435\u0432\u044B\u043C \u0440\u0430\u0437\u0433\u043B\u0430\u0448\u0435\u043D\u0438\u0435\u043C",
2734
+ "\u043D\u0430 \u043E\u0441\u043D\u043E\u0432\u0435 \u0440\u0435\u0448\u0451\u0442\u043E\u043A",
2735
+ // German
2736
+ "quanten",
2737
+ "photonik",
2738
+ "genomik",
2739
+ "proteomik",
2740
+ "topologisch",
2741
+ "homomorph",
2742
+ "zero-knowledge",
2743
+ "gitterbasiert",
2744
+ // Spanish
2745
+ "cu\xE1ntico",
2746
+ "fot\xF3nica",
2747
+ "gen\xF3mica",
2748
+ "prote\xF3mica",
2749
+ "topol\xF3gico",
2750
+ "homom\xF3rfico",
2751
+ // Portuguese
2752
+ "qu\xE2ntico",
2753
+ "fot\xF4nica",
2754
+ "gen\xF4mica",
2755
+ "prote\xF4mica",
2756
+ "topol\xF3gico",
2757
+ "homom\xF3rfico",
2758
+ // Korean
2759
+ "\uC591\uC790",
2760
+ "\uD3EC\uD1A0\uB2C9\uC2A4",
2761
+ "\uC720\uC804\uCCB4\uD559",
2762
+ "\uC704\uC0C1",
2763
+ "\uB3D9\uD615",
2764
+ // Arabic
2765
+ "\u0643\u0645\u064A",
2766
+ "\u0636\u0648\u0626\u064A\u0627\u062A",
2767
+ "\u062C\u064A\u0646\u0648\u0645\u064A\u0627\u062A",
2768
+ "\u0637\u0648\u0628\u0648\u0644\u0648\u062C\u064A",
2769
+ "\u062A\u0645\u0627\u062B\u0644\u064A"
2770
+ ],
2771
+ // Agentic task keywords - file ops, execution, multi-step, iterative work
2772
+ // Pruned: removed overly common words like "then", "first", "run", "test", "build"
2773
+ agenticTaskKeywords: [
2774
+ // English - File operations (clearly agentic)
2775
+ "read file",
2776
+ "read the file",
2777
+ "look at",
2778
+ "check the",
2779
+ "open the",
2780
+ "edit",
2781
+ "modify",
2782
+ "update the",
2783
+ "change the",
2784
+ "write to",
2785
+ "create file",
2786
+ // English - Execution (specific commands only)
2787
+ "execute",
2788
+ "deploy",
2789
+ "install",
2790
+ "npm",
2791
+ "pip",
2792
+ "compile",
2793
+ // English - Multi-step patterns (specific only)
2794
+ "after that",
2795
+ "and also",
2796
+ "once done",
2797
+ "step 1",
2798
+ "step 2",
2799
+ // English - Iterative work
2800
+ "fix",
2801
+ "debug",
2802
+ "until it works",
2803
+ "keep trying",
2804
+ "iterate",
2805
+ "make sure",
2806
+ "verify",
2807
+ "confirm",
2808
+ // Chinese (keep specific ones)
2809
+ "\u8BFB\u53D6\u6587\u4EF6",
2810
+ "\u67E5\u770B",
2811
+ "\u6253\u5F00",
2812
+ "\u7F16\u8F91",
2813
+ "\u4FEE\u6539",
2814
+ "\u66F4\u65B0",
2815
+ "\u521B\u5EFA",
2816
+ "\u6267\u884C",
2817
+ "\u90E8\u7F72",
2818
+ "\u5B89\u88C5",
2819
+ "\u7B2C\u4E00\u6B65",
2820
+ "\u7B2C\u4E8C\u6B65",
2821
+ "\u4FEE\u590D",
2822
+ "\u8C03\u8BD5",
2823
+ "\u76F4\u5230",
2824
+ "\u786E\u8BA4",
2825
+ "\u9A8C\u8BC1",
2826
+ // Spanish
2827
+ "leer archivo",
2828
+ "editar",
2829
+ "modificar",
2830
+ "actualizar",
2831
+ "ejecutar",
2832
+ "desplegar",
2833
+ "instalar",
2834
+ "paso 1",
2835
+ "paso 2",
2836
+ "arreglar",
2837
+ "depurar",
2838
+ "verificar",
2839
+ // Portuguese
2840
+ "ler arquivo",
2841
+ "editar",
2842
+ "modificar",
2843
+ "atualizar",
2844
+ "executar",
2845
+ "implantar",
2846
+ "instalar",
2847
+ "passo 1",
2848
+ "passo 2",
2849
+ "corrigir",
2850
+ "depurar",
2851
+ "verificar",
2852
+ // Korean
2853
+ "\uD30C\uC77C \uC77D\uAE30",
2854
+ "\uD3B8\uC9D1",
2855
+ "\uC218\uC815",
2856
+ "\uC5C5\uB370\uC774\uD2B8",
2857
+ "\uC2E4\uD589",
2858
+ "\uBC30\uD3EC",
2859
+ "\uC124\uCE58",
2860
+ "\uB2E8\uACC4 1",
2861
+ "\uB2E8\uACC4 2",
2862
+ "\uB514\uBC84\uADF8",
2863
+ "\uD655\uC778",
2864
+ // Arabic
2865
+ "\u0642\u0631\u0627\u0621\u0629 \u0645\u0644\u0641",
2866
+ "\u062A\u062D\u0631\u064A\u0631",
2867
+ "\u062A\u0639\u062F\u064A\u0644",
2868
+ "\u062A\u062D\u062F\u064A\u062B",
2869
+ "\u062A\u0646\u0641\u064A\u0630",
2870
+ "\u0646\u0634\u0631",
2871
+ "\u062A\u062B\u0628\u064A\u062A",
2872
+ "\u0627\u0644\u062E\u0637\u0648\u0629 1",
2873
+ "\u0627\u0644\u062E\u0637\u0648\u0629 2",
2874
+ "\u0625\u0635\u0644\u0627\u062D",
2875
+ "\u062A\u0635\u062D\u064A\u062D",
2876
+ "\u062A\u062D\u0642\u0642"
2877
+ ],
2878
+ // Dimension weights (sum to 1.0)
2879
+ dimensionWeights: {
2880
+ tokenCount: 0.08,
2881
+ codePresence: 0.15,
2882
+ reasoningMarkers: 0.18,
2883
+ technicalTerms: 0.1,
2884
+ creativeMarkers: 0.05,
2885
+ simpleIndicators: 0.02,
2886
+ // Reduced from 0.12 to make room for agenticTask
2887
+ multiStepPatterns: 0.12,
2888
+ questionComplexity: 0.05,
2889
+ imperativeVerbs: 0.03,
2890
+ constraintCount: 0.04,
2891
+ outputFormat: 0.03,
2892
+ referenceComplexity: 0.02,
2893
+ negationComplexity: 0.01,
2894
+ domainSpecificity: 0.02,
2895
+ agenticTask: 0.04
2896
+ // Reduced - agentic signals influence tier selection, not dominate it
2897
+ },
2898
+ // Tier boundaries on weighted score axis
2899
+ tierBoundaries: {
2900
+ simpleMedium: 0,
2901
+ mediumComplex: 0.3,
2902
+ // Raised from 0.18 - prevent simple tasks from reaching expensive COMPLEX tier
2903
+ complexReasoning: 0.5
2904
+ // Raised from 0.4 - reserve for true reasoning tasks
2905
+ },
2906
+ // Sigmoid steepness for confidence calibration
2907
+ confidenceSteepness: 12,
2908
+ // Below this confidence → ambiguous (null tier)
2909
+ confidenceThreshold: 0.7
2910
+ },
2911
+ // Auto (balanced) tier configs - current default smart routing
2912
+ // Benchmark-tuned 2026-03-16: balancing quality (retention) + latency
2913
+ tiers: {
2914
+ SIMPLE: {
2915
+ primary: "google/gemini-2.5-flash",
2916
+ // 1,238ms, IQ 20, 60% retention (best) — fast AND quality
2917
+ fallback: [
2918
+ "google/gemini-3-flash-preview",
2919
+ // 1,398ms, IQ 46 — smarter fallback
2920
+ "deepseek/deepseek-chat",
2921
+ // V4 Flash chat ($0.20/$0.40, 1M ctx) — repriced 2026-04-24
2922
+ "moonshot/kimi-k2.5",
2923
+ // 1,646ms, IQ 47, strong quality
2924
+ "google/gemini-3.1-flash-lite",
2925
+ // $0.25/$1.50, 1M context — newest flash-lite
2926
+ "google/gemini-2.5-flash-lite",
2927
+ // 1,353ms, $0.10/$0.40
2928
+ "openai/gpt-5.4-nano",
2929
+ // $0.20/$1.25, 1M context
2930
+ "xai/grok-4-fast-non-reasoning",
2931
+ // 1,143ms, $0.20/$0.50 — fast fallback
2932
+ "free/gpt-oss-120b"
2933
+ // 1,252ms, FREE fallback (hidden from /v1/models but direct calls work)
2934
+ ]
2935
+ },
2936
+ MEDIUM: {
2937
+ primary: "moonshot/kimi-k2.7",
2938
+ // $0.95/$4.00, 256K ctx, multi-modal + reasoning — Moonshot flagship; promoted from K2.6 (2026-06-14) after BlockRun added K2.7 + hid K2.6. Same price as K2.6.
2939
+ fallback: [
2940
+ "moonshot/kimi-k2.6",
2941
+ // identical-cost in-family hot swap (K2.6 still routable)
2942
+ "moonshot/kimi-k2.5",
2943
+ // $0.60/$3.00 — graceful-degradation backstop
2944
+ "google/gemini-3-flash-preview",
2945
+ // 1,398ms, IQ 46 — nearly same IQ, faster + cheaper
2946
+ "deepseek/deepseek-chat",
2947
+ // 1,431ms, IQ 32, 41% retention
2948
+ "google/gemini-2.5-flash",
2949
+ // 1,238ms, 60% retention
2950
+ "google/gemini-3.1-flash-lite",
2951
+ // $0.25/$1.50, 1M context
2952
+ "google/gemini-2.5-flash-lite",
2953
+ // 1,353ms, $0.10/$0.40
2954
+ "xai/grok-4-1-fast-non-reasoning",
2955
+ // 1,244ms, fast fallback
2956
+ "xai/grok-3-mini"
2957
+ // 1,202ms, $0.30/$0.50
2958
+ ]
2959
+ },
2960
+ COMPLEX: {
2961
+ primary: "google/gemini-3.1-pro",
2962
+ // 1,609ms, IQ 57 — fast flagship quality
2963
+ fallback: [
2964
+ "google/gemini-3-flash-preview",
2965
+ // 1,398ms, IQ 46 — fast + smart
2966
+ "xai/grok-4-0709",
2967
+ // 1,348ms, IQ 41
2968
+ "google/gemini-2.5-pro",
2969
+ // 1,294ms
2970
+ "anthropic/claude-sonnet-5",
2971
+ // near-Opus quality at Sonnet cost, 1M ctx
2972
+ "anthropic/claude-sonnet-4.6",
2973
+ // 2,110ms, IQ 52 — quality fallback
2974
+ "deepseek/deepseek-chat",
2975
+ // 1,431ms, IQ 32
2976
+ "google/gemini-2.5-flash",
2977
+ // 1,238ms, IQ 20 — cheap last resort
2978
+ "openai/gpt-5.6-terra",
2979
+ // GPT-5.6 balanced tier — newest generation, stable (Sol excluded: #202)
2980
+ "openai/gpt-5.5",
2981
+ // Prior OpenAI flagship — 1M+ ctx, native agent + computer use; benchmark TBD
2982
+ "openai/gpt-5.4"
2983
+ // 6,213ms, IQ 57 — previous flagship, benchmarked
2984
+ ]
2985
+ },
2986
+ REASONING: {
2987
+ primary: "xai/grok-4-1-fast-reasoning",
2988
+ // 1,454ms, $0.20/$0.50
2989
+ fallback: [
2990
+ "xai/grok-4-fast-reasoning",
2991
+ // 1,298ms, $0.20/$0.50
2992
+ "deepseek/deepseek-reasoner",
2993
+ // V4 Flash thinking ($0.20/$0.40, 1M ctx)
2994
+ "deepseek/deepseek-v4-pro",
2995
+ // V4 Pro flagship ($0.50/$1.00 promo through 2026-05-31, list $2/$4) — strongest open-weight reasoner
2996
+ "openai/o4-mini",
2997
+ // 2,328ms ($1.10/$4.40)
2998
+ "openai/o3"
2999
+ // 2,862ms
3000
+ ]
3001
+ }
3002
+ },
3003
+ // Eco tier configs - absolute cheapest (blockrun/eco)
3004
+ ecoTiers: {
3005
+ SIMPLE: {
3006
+ primary: "free/gpt-oss-120b",
3007
+ // FREE! $0.00/$0.00 — heavy user default
3008
+ fallback: [
3009
+ "free/gpt-oss-20b",
3010
+ // FREE — smaller, faster
3011
+ "free/deepseek-v4-flash",
3012
+ // FREE — 1M ctx; slow (~10 tok/s, 07-28 probe) but completes
3013
+ // seed-oss-36b sat here as the free coder until it EOL'd 2026-08-03 (HTTP 410).
3014
+ // gpt-oss-120b/20b already head this chain, so the rung is dropped, not retargeted.
3015
+ "google/gemini-3.1-flash-lite",
3016
+ // $0.25/$1.50 — newest flash-lite
3017
+ "openai/gpt-5.4-nano",
3018
+ // $0.20/$1.25 — fast nano
3019
+ "google/gemini-2.5-flash-lite",
3020
+ // $0.10/$0.40
3021
+ "xai/grok-4-fast-non-reasoning"
3022
+ // $0.20/$0.50
3023
+ ]
3024
+ },
3025
+ MEDIUM: {
3026
+ primary: "google/gemini-3.1-flash-lite",
3027
+ // $0.25/$1.50 — newest flash-lite
3028
+ fallback: [
3029
+ "openai/gpt-5.4-nano",
3030
+ // $0.20/$1.25
3031
+ "google/gemini-2.5-flash-lite",
3032
+ // $0.10/$0.40
3033
+ "xai/grok-4-fast-non-reasoning",
3034
+ "google/gemini-2.5-flash"
3035
+ ]
3036
+ },
3037
+ COMPLEX: {
3038
+ primary: "google/gemini-3.1-flash-lite",
3039
+ // $0.25/$1.50
3040
+ fallback: [
3041
+ "google/gemini-2.5-flash-lite",
3042
+ "xai/grok-4-0709",
3043
+ "google/gemini-2.5-flash",
3044
+ "deepseek/deepseek-chat"
3045
+ ]
3046
+ },
3047
+ REASONING: {
3048
+ primary: "xai/grok-4-1-fast-reasoning",
3049
+ // $0.20/$0.50
3050
+ fallback: [
3051
+ "xai/grok-4-fast-reasoning",
3052
+ "deepseek/deepseek-reasoner",
3053
+ // V4 Flash thinking — $0.20/$0.40
3054
+ "deepseek/deepseek-v4-pro"
3055
+ // V4 Pro flagship — $0.50/$1.00 promo, post-promo $2/$4
3056
+ ]
3057
+ }
3058
+ },
3059
+ // Premium tier configs - best quality (blockrun/premium)
3060
+ // codex=complex coding, kimi=simple coding, sonnet=reasoning/instructions, opus=architecture/PM/audits
3061
+ premiumTiers: {
3062
+ SIMPLE: {
3063
+ primary: "moonshot/kimi-k2.7",
3064
+ // $0.95/$4.00 - Moonshot flagship (256K ctx, multi-modal + reasoning); promoted from K2.6 (2026-06-14), same price
3065
+ fallback: [
3066
+ "moonshot/kimi-k2.6",
3067
+ // identical-cost in-family hot swap (K2.6 still routable)
3068
+ "moonshot/kimi-k2.5",
3069
+ // $0.60/$3.00 - proven reliable backstop when Moonshot direct API falters
3070
+ "google/gemini-2.5-flash",
3071
+ // 60% retention, fast growth
3072
+ "anthropic/claude-haiku-4.5",
3073
+ "google/gemini-2.5-flash-lite",
3074
+ "deepseek/deepseek-chat"
3075
+ ]
3076
+ },
3077
+ MEDIUM: {
3078
+ primary: "openai/gpt-5.3-codex",
3079
+ // $1.75/$14 - 400K context, 128K output, replaces 5.2
3080
+ fallback: [
3081
+ "moonshot/kimi-k2.7",
3082
+ // Moonshot flagship
3083
+ "moonshot/kimi-k2.6",
3084
+ "moonshot/kimi-k2.5",
3085
+ "google/gemini-2.5-flash",
3086
+ // 60% retention, good coding capability
3087
+ "google/gemini-2.5-pro",
3088
+ "xai/grok-4-0709",
3089
+ "anthropic/claude-sonnet-5",
3090
+ "anthropic/claude-sonnet-4.6"
3091
+ ]
3092
+ },
3093
+ COMPLEX: {
3094
+ // fable-5 was promoted here 2026-06-11, force-reverted 2026-06-13 when Anthropic
3095
+ // withdrew the offer, and restored 2026-07-14 now that BlockRun has relisted it.
3096
+ primary: "anthropic/claude-fable-5",
3097
+ // Best quality for complex tasks — Mythos-class flagship above Opus ($10/$50, 1M ctx, always-on thinking)
3098
+ // Fallback chain de-Gemini'd 2026-04-22: when Anthropic 503s, Gemini is
3099
+ // also prone to "high demand" 503s (correlated failure — everyone falls
3100
+ // back to Google at the same time). Prefer xAI Grok → Moonshot → OpenAI
3101
+ // flagship → DeepSeek → NVIDIA free instead.
3102
+ fallback: [
3103
+ "anthropic/claude-opus-5",
3104
+ // in-family hot swap first (half the price, 1M ctx + adaptive thinking)
3105
+ "anthropic/claude-opus-4.8",
3106
+ // in-family hot swap (identical cost to 5)
3107
+ "anthropic/claude-opus-4.7",
3108
+ // in-family hot swap (identical cost to 4.8)
3109
+ "anthropic/claude-opus-4.6",
3110
+ // in-family hot swap
3111
+ "anthropic/claude-sonnet-5",
3112
+ // Sonnet-tier drop-down, near-Opus quality
3113
+ "anthropic/claude-sonnet-4.6",
3114
+ "xai/grok-4.5",
3115
+ // xAI flagship — 503-resistant, direct-xAI SKU (added 2026-07-14)
3116
+ "xai/grok-4-0709",
3117
+ // 503-resistant flagship
3118
+ "moonshot/kimi-k2.7",
3119
+ // Moonshot flagship, independent infra
3120
+ "moonshot/kimi-k2.6",
3121
+ "moonshot/kimi-k2.5",
3122
+ "openai/gpt-5.6-terra",
3123
+ // GPT-5.6 balanced tier — newest generation, stable (Sol excluded: #202)
3124
+ "openai/gpt-5.5",
3125
+ // Prior OpenAI flagship — 1M+ ctx, native agent + computer use
3126
+ "openai/gpt-5.4",
3127
+ // Previous flagship (slow but stable, benchmarked at 6,213ms)
3128
+ "openai/gpt-5.3-codex",
3129
+ "deepseek/deepseek-chat",
3130
+ // Cheap, reliable
3131
+ "free/gpt-oss-120b"
3132
+ // NVIDIA free ultimate backstop (was seed-oss-36b; EOL'd 2026-08-03)
3133
+ ]
3134
+ },
3135
+ REASONING: {
3136
+ primary: "anthropic/claude-sonnet-4.6",
3137
+ // 2,110ms, $3/$15 - best for reasoning/instructions
3138
+ fallback: [
3139
+ "anthropic/claude-sonnet-5",
3140
+ // in-family hot swap — same cost, adaptive thinking, 1M ctx
3141
+ "anthropic/claude-opus-5",
3142
+ // Newest flagship Opus w/ adaptive thinking
3143
+ "anthropic/claude-opus-4.8",
3144
+ // Prior flagship Opus — identical cost to 5
3145
+ "anthropic/claude-opus-4.7",
3146
+ // Flagship Opus w/ adaptive thinking
3147
+ "anthropic/claude-opus-4.6",
3148
+ // 2,139ms
3149
+ "xai/grok-4-1-fast-reasoning",
3150
+ // 1,454ms, cheap fast reasoning
3151
+ "openai/o4-mini",
3152
+ // 2,328ms ($1.10/$4.40)
3153
+ "openai/o3"
3154
+ // 2,862ms
3155
+ ]
3156
+ }
3157
+ },
3158
+ // Agentic tier configs - models that excel at multi-step autonomous tasks
3159
+ agenticTiers: {
3160
+ SIMPLE: {
3161
+ primary: "openai/gpt-4o-mini",
3162
+ // $0.15/$0.60 - best tool compliance at lowest cost
3163
+ fallback: [
3164
+ "moonshot/kimi-k2.5",
3165
+ // 1,646ms, strong tool use quality
3166
+ "anthropic/claude-haiku-4.5",
3167
+ // 2,305ms
3168
+ "xai/grok-4-1-fast-non-reasoning"
3169
+ // 1,244ms, fast fallback
3170
+ ]
3171
+ },
3172
+ MEDIUM: {
3173
+ primary: "moonshot/kimi-k2.7",
3174
+ // $0.95/$4.00 — Moonshot flagship, strong tool use; promoted from K2.6 (2026-06-14) after BlockRun added K2.7 + hid K2.6. Same price.
3175
+ fallback: [
3176
+ "moonshot/kimi-k2.6",
3177
+ // identical-cost in-family hot swap (K2.6 still routable)
3178
+ "moonshot/kimi-k2.5",
3179
+ // $0.60/$3.00 — graceful-degradation backstop
3180
+ "xai/grok-4-1-fast-non-reasoning",
3181
+ // 1,244ms, fast fallback
3182
+ "openai/gpt-4o-mini",
3183
+ // 2,764ms, reliable tool calling
3184
+ "anthropic/claude-haiku-4.5",
3185
+ // 2,305ms
3186
+ "deepseek/deepseek-chat"
3187
+ // 1,431ms
3188
+ ]
3189
+ },
3190
+ COMPLEX: {
3191
+ primary: "anthropic/claude-sonnet-4.6",
3192
+ // 2,110ms — best agentic quality
3193
+ // Fallback chain de-Gemini'd 2026-04-22: Gemini's "high demand" 503s
3194
+ // correlate with Anthropic outages (everyone falls back together).
3195
+ // Prefer 503-resistant providers first.
3196
+ fallback: [
3197
+ "anthropic/claude-sonnet-5",
3198
+ // in-family hot swap — same cost, near-Opus agentic quality
3199
+ "anthropic/claude-opus-5",
3200
+ // Newest flagship Opus — in-family hot swap
3201
+ "anthropic/claude-opus-4.8",
3202
+ // Prior flagship Opus — identical cost to 5
3203
+ "anthropic/claude-opus-4.7",
3204
+ // Flagship Opus — in-family hot swap
3205
+ "anthropic/claude-opus-4.6",
3206
+ // 2,139ms
3207
+ "xai/grok-4-0709",
3208
+ // 1,348ms — strong tool use, independent infra
3209
+ "moonshot/kimi-k2.7",
3210
+ // Moonshot flagship — strong tool use, independent infra
3211
+ "moonshot/kimi-k2.5",
3212
+ // cost-stability backstop
3213
+ "openai/gpt-5.6-terra",
3214
+ // GPT-5.6 balanced tier — newest generation, stable (Sol excluded: #202)
3215
+ "openai/gpt-5.5",
3216
+ // Prior flagship — native agent + computer use (exactly the agentic-tier use case)
3217
+ "openai/gpt-5.4",
3218
+ // Previous flagship — 6,213ms, reliable
3219
+ "deepseek/deepseek-chat",
3220
+ // 1,431ms — cheap, reliable
3221
+ "free/gpt-oss-120b"
3222
+ // NVIDIA free ultimate backstop (was seed-oss-36b; EOL'd 2026-08-03)
3223
+ ]
3224
+ },
3225
+ REASONING: {
3226
+ primary: "anthropic/claude-sonnet-4.6",
3227
+ // 2,110ms — strong tool use + reasoning
3228
+ fallback: [
3229
+ "anthropic/claude-sonnet-5",
3230
+ // in-family hot swap — same cost, adaptive thinking
3231
+ "anthropic/claude-opus-5",
3232
+ // Newest flagship Opus w/ adaptive thinking
3233
+ "anthropic/claude-opus-4.8",
3234
+ // Prior flagship Opus — identical cost to 5
3235
+ "anthropic/claude-opus-4.7",
3236
+ // Flagship Opus w/ adaptive thinking
3237
+ "anthropic/claude-opus-4.6",
3238
+ // 2,139ms
3239
+ "xai/grok-4-1-fast-reasoning",
3240
+ // 1,454ms
3241
+ "deepseek/deepseek-reasoner"
3242
+ // 1,454ms
3243
+ ]
3244
+ }
3245
+ },
3246
+ // Time-windowed promotions — auto-applied when active, ignored when expired
3247
+ promotions: [
3248
+ {
3249
+ name: "GLM-5.1 Launch Promo ($0.001 flat)",
3250
+ startDate: "2026-04-01",
3251
+ endDate: "2026-05-01",
3252
+ tierOverrides: {
3253
+ SIMPLE: { primary: "zai/glm-5.1" }
3254
+ },
3255
+ profiles: ["auto"]
3256
+ // only auto profile — eco stays free, premium stays premium
3257
+ }
3258
+ ],
3259
+ overrides: {
3260
+ maxTokensForceComplex: 1e5,
3261
+ structuredOutputMinTier: "MEDIUM",
3262
+ ambiguousDefaultTier: "MEDIUM"
3263
+ // agenticMode left undefined → auto-detect via tools/agenticScore.
3264
+ // Set to `true` to force agentic tiers; `false` to disable them entirely.
3265
+ }
3266
+ };
3267
+ registerStrategy(new PortfolioStrategy());
3268
+ function route(prompt, systemPrompt, maxOutputTokens, options) {
3269
+ const strategy = getStrategy(options.config.strategy ?? "portfolio");
3270
+ return strategy.route(prompt, systemPrompt, maxOutputTokens, options);
3271
+ }
3272
+ export {
3273
+ DEFAULT_MODEL_CAPABILITIES,
3274
+ DEFAULT_ROUTING_CONFIG,
3275
+ HISTORICAL_MODEL_PROFILES,
3276
+ LIVE_MODEL_PROFILES,
3277
+ PortfolioStrategy,
3278
+ RulesStrategy,
3279
+ calculateModelCost,
3280
+ classifyByRules,
3281
+ filterByExcludeList,
3282
+ filterByToolCalling,
3283
+ filterByVision,
3284
+ filterCandidatesByCapacity,
3285
+ getFallbackChain,
3286
+ getFallbackChainFiltered,
3287
+ getStrategy,
3288
+ inferToolRequirement,
3289
+ registerStrategy,
3290
+ route
3291
+ };
3292
+ //# sourceMappingURL=index.js.map