@blockrun/llm 3.11.0 → 3.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +315 -194
- package/dist/index.cjs +3826 -285
- package/dist/index.d.cts +70 -21
- package/dist/index.d.ts +70 -21
- package/dist/index.js +3826 -285
- package/package.json +3 -7
package/dist/index.js
CHANGED
|
@@ -31,6 +31,3362 @@ var APIError = class extends BlockrunError {
|
|
|
31
31
|
}
|
|
32
32
|
};
|
|
33
33
|
|
|
34
|
+
// node_modules/.pnpm/@blockrun+router-core@https+++codeload.github.com+BlockRunAI+router-core+tar.gz+d4308049348e1_gni7wlazdyzf7iqax5nhqdpoqi/node_modules/@blockrun/router-core/dist/index.js
|
|
35
|
+
function scoreTokenCount(estimatedTokens, thresholds) {
|
|
36
|
+
if (estimatedTokens < thresholds.simple) {
|
|
37
|
+
return { name: "tokenCount", score: -1, signal: `short (${estimatedTokens} tokens)` };
|
|
38
|
+
}
|
|
39
|
+
if (estimatedTokens > thresholds.complex) {
|
|
40
|
+
return { name: "tokenCount", score: 1, signal: `long (${estimatedTokens} tokens)` };
|
|
41
|
+
}
|
|
42
|
+
return { name: "tokenCount", score: 0, signal: null };
|
|
43
|
+
}
|
|
44
|
+
function scoreKeywordMatch(text, keywords, name, signalLabel, thresholds, scores) {
|
|
45
|
+
const matches = keywords.filter((kw) => text.includes(kw.toLowerCase()));
|
|
46
|
+
if (matches.length >= thresholds.high) {
|
|
47
|
+
return {
|
|
48
|
+
name,
|
|
49
|
+
score: scores.high,
|
|
50
|
+
signal: `${signalLabel} (${matches.slice(0, 3).join(", ")})`
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
if (matches.length >= thresholds.low) {
|
|
54
|
+
return {
|
|
55
|
+
name,
|
|
56
|
+
score: scores.low,
|
|
57
|
+
signal: `${signalLabel} (${matches.slice(0, 3).join(", ")})`
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
return { name, score: scores.none, signal: null };
|
|
61
|
+
}
|
|
62
|
+
function scoreMultiStep(text) {
|
|
63
|
+
const patterns = [/first.*then/i, /step \d/i, /\d\.\s/];
|
|
64
|
+
const hits = patterns.filter((p) => p.test(text));
|
|
65
|
+
if (hits.length > 0) {
|
|
66
|
+
return { name: "multiStepPatterns", score: 0.5, signal: "multi-step" };
|
|
67
|
+
}
|
|
68
|
+
return { name: "multiStepPatterns", score: 0, signal: null };
|
|
69
|
+
}
|
|
70
|
+
function scoreQuestionComplexity(prompt) {
|
|
71
|
+
const count = (prompt.match(/\?/g) || []).length;
|
|
72
|
+
if (count > 3) {
|
|
73
|
+
return { name: "questionComplexity", score: 0.5, signal: `${count} questions` };
|
|
74
|
+
}
|
|
75
|
+
return { name: "questionComplexity", score: 0, signal: null };
|
|
76
|
+
}
|
|
77
|
+
function scoreAgenticTask(text, keywords) {
|
|
78
|
+
let matchCount = 0;
|
|
79
|
+
const signals = [];
|
|
80
|
+
for (const keyword of keywords) {
|
|
81
|
+
if (text.includes(keyword.toLowerCase())) {
|
|
82
|
+
matchCount++;
|
|
83
|
+
if (signals.length < 3) {
|
|
84
|
+
signals.push(keyword);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
if (matchCount >= 4) {
|
|
89
|
+
return {
|
|
90
|
+
dimensionScore: {
|
|
91
|
+
name: "agenticTask",
|
|
92
|
+
score: 1,
|
|
93
|
+
signal: `agentic (${signals.join(", ")})`
|
|
94
|
+
},
|
|
95
|
+
agenticScore: 1
|
|
96
|
+
};
|
|
97
|
+
} else if (matchCount >= 3) {
|
|
98
|
+
return {
|
|
99
|
+
dimensionScore: {
|
|
100
|
+
name: "agenticTask",
|
|
101
|
+
score: 0.6,
|
|
102
|
+
signal: `agentic (${signals.join(", ")})`
|
|
103
|
+
},
|
|
104
|
+
agenticScore: 0.6
|
|
105
|
+
};
|
|
106
|
+
} else if (matchCount >= 1) {
|
|
107
|
+
return {
|
|
108
|
+
dimensionScore: {
|
|
109
|
+
name: "agenticTask",
|
|
110
|
+
score: 0.2,
|
|
111
|
+
signal: `agentic-light (${signals.join(", ")})`
|
|
112
|
+
},
|
|
113
|
+
agenticScore: 0.2
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
return {
|
|
117
|
+
dimensionScore: { name: "agenticTask", score: 0, signal: null },
|
|
118
|
+
agenticScore: 0
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
function classifyByRules(prompt, systemPrompt, estimatedTokens, config) {
|
|
122
|
+
const userText = prompt.toLowerCase();
|
|
123
|
+
const dimensions = [
|
|
124
|
+
// Token count uses total estimated tokens (system + user) — context size matters for model selection
|
|
125
|
+
scoreTokenCount(estimatedTokens, config.tokenCountThresholds),
|
|
126
|
+
scoreKeywordMatch(
|
|
127
|
+
userText,
|
|
128
|
+
config.codeKeywords,
|
|
129
|
+
"codePresence",
|
|
130
|
+
"code",
|
|
131
|
+
{ low: 1, high: 2 },
|
|
132
|
+
{ none: 0, low: 0.5, high: 1 }
|
|
133
|
+
),
|
|
134
|
+
scoreKeywordMatch(
|
|
135
|
+
userText,
|
|
136
|
+
config.reasoningKeywords,
|
|
137
|
+
"reasoningMarkers",
|
|
138
|
+
"reasoning",
|
|
139
|
+
{ low: 1, high: 2 },
|
|
140
|
+
{ none: 0, low: 0.7, high: 1 }
|
|
141
|
+
),
|
|
142
|
+
scoreKeywordMatch(
|
|
143
|
+
userText,
|
|
144
|
+
config.technicalKeywords,
|
|
145
|
+
"technicalTerms",
|
|
146
|
+
"technical",
|
|
147
|
+
{ low: 2, high: 4 },
|
|
148
|
+
{ none: 0, low: 0.5, high: 1 }
|
|
149
|
+
),
|
|
150
|
+
scoreKeywordMatch(
|
|
151
|
+
userText,
|
|
152
|
+
config.creativeKeywords,
|
|
153
|
+
"creativeMarkers",
|
|
154
|
+
"creative",
|
|
155
|
+
{ low: 1, high: 2 },
|
|
156
|
+
{ none: 0, low: 0.5, high: 0.7 }
|
|
157
|
+
),
|
|
158
|
+
scoreKeywordMatch(
|
|
159
|
+
userText,
|
|
160
|
+
config.simpleKeywords,
|
|
161
|
+
"simpleIndicators",
|
|
162
|
+
"simple",
|
|
163
|
+
{ low: 1, high: 2 },
|
|
164
|
+
{ none: 0, low: -1, high: -1 }
|
|
165
|
+
),
|
|
166
|
+
scoreMultiStep(userText),
|
|
167
|
+
scoreQuestionComplexity(prompt),
|
|
168
|
+
// 6 new dimensions
|
|
169
|
+
scoreKeywordMatch(
|
|
170
|
+
userText,
|
|
171
|
+
config.imperativeVerbs,
|
|
172
|
+
"imperativeVerbs",
|
|
173
|
+
"imperative",
|
|
174
|
+
{ low: 1, high: 2 },
|
|
175
|
+
{ none: 0, low: 0.3, high: 0.5 }
|
|
176
|
+
),
|
|
177
|
+
scoreKeywordMatch(
|
|
178
|
+
userText,
|
|
179
|
+
config.constraintIndicators,
|
|
180
|
+
"constraintCount",
|
|
181
|
+
"constraints",
|
|
182
|
+
{ low: 1, high: 3 },
|
|
183
|
+
{ none: 0, low: 0.3, high: 0.7 }
|
|
184
|
+
),
|
|
185
|
+
scoreKeywordMatch(
|
|
186
|
+
userText,
|
|
187
|
+
config.outputFormatKeywords,
|
|
188
|
+
"outputFormat",
|
|
189
|
+
"format",
|
|
190
|
+
{ low: 1, high: 2 },
|
|
191
|
+
{ none: 0, low: 0.4, high: 0.7 }
|
|
192
|
+
),
|
|
193
|
+
scoreKeywordMatch(
|
|
194
|
+
userText,
|
|
195
|
+
config.referenceKeywords,
|
|
196
|
+
"referenceComplexity",
|
|
197
|
+
"references",
|
|
198
|
+
{ low: 1, high: 2 },
|
|
199
|
+
{ none: 0, low: 0.3, high: 0.5 }
|
|
200
|
+
),
|
|
201
|
+
scoreKeywordMatch(
|
|
202
|
+
userText,
|
|
203
|
+
config.negationKeywords,
|
|
204
|
+
"negationComplexity",
|
|
205
|
+
"negation",
|
|
206
|
+
{ low: 2, high: 3 },
|
|
207
|
+
{ none: 0, low: 0.3, high: 0.5 }
|
|
208
|
+
),
|
|
209
|
+
scoreKeywordMatch(
|
|
210
|
+
userText,
|
|
211
|
+
config.domainSpecificKeywords,
|
|
212
|
+
"domainSpecificity",
|
|
213
|
+
"domain-specific",
|
|
214
|
+
{ low: 1, high: 2 },
|
|
215
|
+
{ none: 0, low: 0.5, high: 0.8 }
|
|
216
|
+
)
|
|
217
|
+
];
|
|
218
|
+
const agenticResult = scoreAgenticTask(userText, config.agenticTaskKeywords);
|
|
219
|
+
dimensions.push(agenticResult.dimensionScore);
|
|
220
|
+
const agenticScore = agenticResult.agenticScore;
|
|
221
|
+
const signals = dimensions.filter((d) => d.signal !== null).map((d) => d.signal);
|
|
222
|
+
const weights = config.dimensionWeights;
|
|
223
|
+
let weightedScore = 0;
|
|
224
|
+
for (const d of dimensions) {
|
|
225
|
+
const w = weights[d.name] ?? 0;
|
|
226
|
+
weightedScore += d.score * w;
|
|
227
|
+
}
|
|
228
|
+
const reasoningMatches = config.reasoningKeywords.filter(
|
|
229
|
+
(kw) => userText.includes(kw.toLowerCase())
|
|
230
|
+
);
|
|
231
|
+
if (reasoningMatches.length >= 2) {
|
|
232
|
+
const confidence2 = calibrateConfidence(
|
|
233
|
+
Math.max(weightedScore, 0.3),
|
|
234
|
+
// ensure positive for confidence calc
|
|
235
|
+
config.confidenceSteepness
|
|
236
|
+
);
|
|
237
|
+
return {
|
|
238
|
+
score: weightedScore,
|
|
239
|
+
tier: "REASONING",
|
|
240
|
+
confidence: Math.max(confidence2, 0.85),
|
|
241
|
+
signals,
|
|
242
|
+
agenticScore,
|
|
243
|
+
dimensions
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
const { simpleMedium, mediumComplex, complexReasoning } = config.tierBoundaries;
|
|
247
|
+
let tier;
|
|
248
|
+
let distanceFromBoundary;
|
|
249
|
+
if (weightedScore < simpleMedium) {
|
|
250
|
+
tier = "SIMPLE";
|
|
251
|
+
distanceFromBoundary = simpleMedium - weightedScore;
|
|
252
|
+
} else if (weightedScore < mediumComplex) {
|
|
253
|
+
tier = "MEDIUM";
|
|
254
|
+
distanceFromBoundary = Math.min(weightedScore - simpleMedium, mediumComplex - weightedScore);
|
|
255
|
+
} else if (weightedScore < complexReasoning) {
|
|
256
|
+
tier = "COMPLEX";
|
|
257
|
+
distanceFromBoundary = Math.min(
|
|
258
|
+
weightedScore - mediumComplex,
|
|
259
|
+
complexReasoning - weightedScore
|
|
260
|
+
);
|
|
261
|
+
} else {
|
|
262
|
+
tier = "REASONING";
|
|
263
|
+
distanceFromBoundary = weightedScore - complexReasoning;
|
|
264
|
+
}
|
|
265
|
+
const confidence = calibrateConfidence(distanceFromBoundary, config.confidenceSteepness);
|
|
266
|
+
if (confidence < config.confidenceThreshold) {
|
|
267
|
+
return { score: weightedScore, tier: null, confidence, signals, agenticScore, dimensions };
|
|
268
|
+
}
|
|
269
|
+
return { score: weightedScore, tier, confidence, signals, agenticScore, dimensions };
|
|
270
|
+
}
|
|
271
|
+
function calibrateConfidence(distance, steepness) {
|
|
272
|
+
return 1 / (1 + Math.exp(-steepness * distance));
|
|
273
|
+
}
|
|
274
|
+
var BASELINE_MODEL_ID = "anthropic/claude-opus-4.7";
|
|
275
|
+
var BASELINE_INPUT_PRICE = 5;
|
|
276
|
+
var BASELINE_OUTPUT_PRICE = 25;
|
|
277
|
+
function selectModel(tier, confidence, method, reasoning, tierConfigs, modelPricing, estimatedInputTokens, maxOutputTokens, routingProfile, agenticScore) {
|
|
278
|
+
const tierConfig = tierConfigs[tier];
|
|
279
|
+
const model = tierConfig.primary;
|
|
280
|
+
const pricing = modelPricing.get(model);
|
|
281
|
+
let costEstimate;
|
|
282
|
+
if (pricing?.flatPrice !== void 0) {
|
|
283
|
+
costEstimate = pricing.flatPrice;
|
|
284
|
+
} else {
|
|
285
|
+
const inputPrice = pricing?.inputPrice ?? 0;
|
|
286
|
+
const outputPrice = pricing?.outputPrice ?? 0;
|
|
287
|
+
costEstimate = estimatedInputTokens / 1e6 * inputPrice + maxOutputTokens / 1e6 * outputPrice;
|
|
288
|
+
}
|
|
289
|
+
const opusPricing = modelPricing.get(BASELINE_MODEL_ID);
|
|
290
|
+
const opusInputPrice = opusPricing?.inputPrice ?? BASELINE_INPUT_PRICE;
|
|
291
|
+
const opusOutputPrice = opusPricing?.outputPrice ?? BASELINE_OUTPUT_PRICE;
|
|
292
|
+
const baselineInput = estimatedInputTokens / 1e6 * opusInputPrice;
|
|
293
|
+
const baselineOutput = maxOutputTokens / 1e6 * opusOutputPrice;
|
|
294
|
+
const baselineCost = baselineInput + baselineOutput;
|
|
295
|
+
const savings = routingProfile === "premium" ? 0 : baselineCost > 0 ? Math.max(0, (baselineCost - costEstimate) / baselineCost) : 0;
|
|
296
|
+
return {
|
|
297
|
+
model,
|
|
298
|
+
tier,
|
|
299
|
+
confidence,
|
|
300
|
+
method,
|
|
301
|
+
reasoning,
|
|
302
|
+
costEstimate,
|
|
303
|
+
baselineCost,
|
|
304
|
+
savings,
|
|
305
|
+
...agenticScore !== void 0 && { agenticScore }
|
|
306
|
+
};
|
|
307
|
+
}
|
|
308
|
+
function getFallbackChain(tier, tierConfigs) {
|
|
309
|
+
const config = tierConfigs[tier];
|
|
310
|
+
return [config.primary, ...config.fallback];
|
|
311
|
+
}
|
|
312
|
+
var SERVER_MARGIN_PERCENT = 5;
|
|
313
|
+
var MIN_PAYMENT_USD = 1e-3;
|
|
314
|
+
function calculateModelCost(model, modelPricing, estimatedInputTokens, maxOutputTokens, routingProfile) {
|
|
315
|
+
const pricing = modelPricing.get(model);
|
|
316
|
+
let costEstimate;
|
|
317
|
+
if (pricing?.flatPrice !== void 0) {
|
|
318
|
+
costEstimate = Math.max(pricing.flatPrice * (1 + SERVER_MARGIN_PERCENT / 100), MIN_PAYMENT_USD);
|
|
319
|
+
} else {
|
|
320
|
+
const inputPrice = pricing?.inputPrice ?? 0;
|
|
321
|
+
const outputPrice = pricing?.outputPrice ?? 0;
|
|
322
|
+
const inputCost = estimatedInputTokens / 1e6 * inputPrice;
|
|
323
|
+
const outputCost = maxOutputTokens / 1e6 * outputPrice;
|
|
324
|
+
costEstimate = Math.max(
|
|
325
|
+
(inputCost + outputCost) * (1 + SERVER_MARGIN_PERCENT / 100),
|
|
326
|
+
MIN_PAYMENT_USD
|
|
327
|
+
);
|
|
328
|
+
}
|
|
329
|
+
const opusPricing = modelPricing.get(BASELINE_MODEL_ID);
|
|
330
|
+
const opusInputPrice = opusPricing?.inputPrice ?? BASELINE_INPUT_PRICE;
|
|
331
|
+
const opusOutputPrice = opusPricing?.outputPrice ?? BASELINE_OUTPUT_PRICE;
|
|
332
|
+
const baselineInput = estimatedInputTokens / 1e6 * opusInputPrice;
|
|
333
|
+
const baselineOutput = maxOutputTokens / 1e6 * opusOutputPrice;
|
|
334
|
+
const baselineCost = baselineInput + baselineOutput;
|
|
335
|
+
const savings = routingProfile === "premium" ? 0 : baselineCost > 0 ? Math.max(0, (baselineCost - costEstimate) / baselineCost) : 0;
|
|
336
|
+
return { costEstimate, baselineCost, savings };
|
|
337
|
+
}
|
|
338
|
+
function filterCandidatesByCapacity(models, estimatedInputTokens, requestedOutputTokens, getCapabilities) {
|
|
339
|
+
const filtered = models.filter((modelId) => {
|
|
340
|
+
const capabilities = getCapabilities(modelId);
|
|
341
|
+
if (!capabilities) return true;
|
|
342
|
+
return capabilities.contextWindow >= (estimatedInputTokens + requestedOutputTokens) * 1.1 && capabilities.maxOutput >= requestedOutputTokens;
|
|
343
|
+
});
|
|
344
|
+
return filtered;
|
|
345
|
+
}
|
|
346
|
+
function applyPromotions(tierConfigs, promotions, profile, now = /* @__PURE__ */ new Date()) {
|
|
347
|
+
if (!promotions || promotions.length === 0) return tierConfigs;
|
|
348
|
+
let result = tierConfigs;
|
|
349
|
+
for (const promo of promotions) {
|
|
350
|
+
const start = new Date(promo.startDate);
|
|
351
|
+
const end = new Date(promo.endDate);
|
|
352
|
+
if (now < start || now >= end) continue;
|
|
353
|
+
if (promo.profiles && !promo.profiles.includes(profile)) continue;
|
|
354
|
+
if (result === tierConfigs) {
|
|
355
|
+
result = { ...tierConfigs };
|
|
356
|
+
for (const t of Object.keys(result)) {
|
|
357
|
+
result[t] = { ...result[t] };
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
for (const [tier, override] of Object.entries(promo.tierOverrides)) {
|
|
361
|
+
if (!result[tier]) continue;
|
|
362
|
+
if (override.primary) result[tier].primary = override.primary;
|
|
363
|
+
if (override.fallback) result[tier].fallback = override.fallback;
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
return result;
|
|
367
|
+
}
|
|
368
|
+
var RulesStrategy = class {
|
|
369
|
+
name = "rules";
|
|
370
|
+
route(prompt, systemPrompt, maxOutputTokens, options) {
|
|
371
|
+
const { config, modelPricing } = options;
|
|
372
|
+
const fullText = `${systemPrompt ?? ""} ${prompt}`;
|
|
373
|
+
const estimatedTokens = Math.ceil(fullText.length / 4);
|
|
374
|
+
const scanLimit = Math.max(1, Math.min(8e3, config.classifier.promptTruncationChars));
|
|
375
|
+
const sample = (value) => {
|
|
376
|
+
if (value.length <= scanLimit) return value;
|
|
377
|
+
const prefixLength = Math.ceil(scanLimit / 2);
|
|
378
|
+
return `${value.slice(0, prefixLength)}
|
|
379
|
+
${value.slice(-(scanLimit - prefixLength))}`;
|
|
380
|
+
};
|
|
381
|
+
const scannedPrompt = sample(prompt);
|
|
382
|
+
const scannedSystemPrompt = systemPrompt ? sample(systemPrompt) : void 0;
|
|
383
|
+
const ruleResult = classifyByRules(
|
|
384
|
+
scannedPrompt,
|
|
385
|
+
scannedSystemPrompt,
|
|
386
|
+
estimatedTokens,
|
|
387
|
+
config.scoring
|
|
388
|
+
);
|
|
389
|
+
const { routingProfile } = options;
|
|
390
|
+
let tierConfigs;
|
|
391
|
+
let profileSuffix;
|
|
392
|
+
let profile;
|
|
393
|
+
if (routingProfile === "eco") {
|
|
394
|
+
tierConfigs = config.ecoTiers ?? config.tiers;
|
|
395
|
+
profileSuffix = config.ecoTiers ? " | eco" : " | eco (default tiers)";
|
|
396
|
+
profile = "eco";
|
|
397
|
+
} else if (routingProfile === "premium") {
|
|
398
|
+
tierConfigs = config.premiumTiers ?? config.tiers;
|
|
399
|
+
profileSuffix = config.premiumTiers ? " | premium" : " | premium (default tiers)";
|
|
400
|
+
profile = "premium";
|
|
401
|
+
} else {
|
|
402
|
+
const agenticScore = ruleResult.agenticScore ?? 0;
|
|
403
|
+
const isAutoAgentic = agenticScore >= 0.5;
|
|
404
|
+
const agenticModeSetting = config.overrides.agenticMode;
|
|
405
|
+
const hasToolsInRequest = options.requiresTools ?? options.hasTools ?? false;
|
|
406
|
+
let useAgenticTiers;
|
|
407
|
+
if (agenticModeSetting === false) {
|
|
408
|
+
useAgenticTiers = false;
|
|
409
|
+
} else if (agenticModeSetting === true) {
|
|
410
|
+
useAgenticTiers = config.agenticTiers != null;
|
|
411
|
+
} else {
|
|
412
|
+
useAgenticTiers = (hasToolsInRequest || isAutoAgentic) && config.agenticTiers != null;
|
|
413
|
+
}
|
|
414
|
+
tierConfigs = useAgenticTiers ? config.agenticTiers : config.tiers;
|
|
415
|
+
profileSuffix = useAgenticTiers ? ` | agentic${hasToolsInRequest ? " (tools)" : ""}` : "";
|
|
416
|
+
profile = useAgenticTiers ? "agentic" : "auto";
|
|
417
|
+
}
|
|
418
|
+
tierConfigs = applyPromotions(tierConfigs, config.promotions, profile, options.now);
|
|
419
|
+
const agenticScoreValue = ruleResult.agenticScore;
|
|
420
|
+
if (estimatedTokens > config.overrides.maxTokensForceComplex) {
|
|
421
|
+
const decision2 = selectModel(
|
|
422
|
+
"COMPLEX",
|
|
423
|
+
0.95,
|
|
424
|
+
"rules",
|
|
425
|
+
`Input exceeds ${config.overrides.maxTokensForceComplex} tokens${profileSuffix}`,
|
|
426
|
+
tierConfigs,
|
|
427
|
+
modelPricing,
|
|
428
|
+
estimatedTokens,
|
|
429
|
+
maxOutputTokens,
|
|
430
|
+
routingProfile,
|
|
431
|
+
agenticScoreValue
|
|
432
|
+
);
|
|
433
|
+
return { ...decision2, tierConfigs, profile };
|
|
434
|
+
}
|
|
435
|
+
const hasStructuredOutput = options.requiresStructuredOutput === true || (scannedSystemPrompt ? /json|structured|schema/i.test(scannedSystemPrompt) : false);
|
|
436
|
+
let tier;
|
|
437
|
+
let confidence;
|
|
438
|
+
const method = "rules";
|
|
439
|
+
let reasoning = `score=${ruleResult.score.toFixed(2)} | ${ruleResult.signals.join(", ")}`;
|
|
440
|
+
if (ruleResult.tier !== null) {
|
|
441
|
+
tier = ruleResult.tier;
|
|
442
|
+
confidence = ruleResult.confidence;
|
|
443
|
+
} else {
|
|
444
|
+
tier = config.overrides.ambiguousDefaultTier;
|
|
445
|
+
confidence = 0.5;
|
|
446
|
+
reasoning += ` | ambiguous -> default: ${tier}`;
|
|
447
|
+
}
|
|
448
|
+
if (hasStructuredOutput) {
|
|
449
|
+
const tierRank = { SIMPLE: 0, MEDIUM: 1, COMPLEX: 2, REASONING: 3 };
|
|
450
|
+
const minTier = config.overrides.structuredOutputMinTier;
|
|
451
|
+
if (tierRank[tier] < tierRank[minTier]) {
|
|
452
|
+
reasoning += ` | upgraded to ${minTier} (structured output)`;
|
|
453
|
+
tier = minTier;
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
reasoning += profileSuffix;
|
|
457
|
+
const decision = selectModel(
|
|
458
|
+
tier,
|
|
459
|
+
confidence,
|
|
460
|
+
method,
|
|
461
|
+
reasoning,
|
|
462
|
+
tierConfigs,
|
|
463
|
+
modelPricing,
|
|
464
|
+
estimatedTokens,
|
|
465
|
+
maxOutputTokens,
|
|
466
|
+
routingProfile,
|
|
467
|
+
agenticScoreValue
|
|
468
|
+
);
|
|
469
|
+
return { ...decision, tierConfigs, profile };
|
|
470
|
+
}
|
|
471
|
+
};
|
|
472
|
+
var registry = /* @__PURE__ */ new Map();
|
|
473
|
+
registry.set("rules", new RulesStrategy());
|
|
474
|
+
function getStrategy(name) {
|
|
475
|
+
const strategy = registry.get(name);
|
|
476
|
+
if (!strategy) {
|
|
477
|
+
throw new Error(`Unknown routing strategy: ${name}`);
|
|
478
|
+
}
|
|
479
|
+
return strategy;
|
|
480
|
+
}
|
|
481
|
+
function registerStrategy(strategy) {
|
|
482
|
+
registry.set(strategy.name, strategy);
|
|
483
|
+
}
|
|
484
|
+
var DEFAULT_MODEL_CAPABILITIES = Object.freeze({
|
|
485
|
+
"anthropic/claude-fable-5": {
|
|
486
|
+
contextWindow: 1e6,
|
|
487
|
+
maxOutputTokens: 128e3,
|
|
488
|
+
supportsTools: true,
|
|
489
|
+
supportsVision: true
|
|
490
|
+
},
|
|
491
|
+
"anthropic/claude-haiku-4.5": {
|
|
492
|
+
contextWindow: 2e5,
|
|
493
|
+
maxOutputTokens: 8192,
|
|
494
|
+
supportsTools: true,
|
|
495
|
+
supportsVision: true
|
|
496
|
+
},
|
|
497
|
+
"anthropic/claude-opus-4.6": {
|
|
498
|
+
contextWindow: 1e6,
|
|
499
|
+
maxOutputTokens: 128e3,
|
|
500
|
+
supportsTools: true,
|
|
501
|
+
supportsVision: true
|
|
502
|
+
},
|
|
503
|
+
"anthropic/claude-opus-4.7": {
|
|
504
|
+
contextWindow: 1e6,
|
|
505
|
+
maxOutputTokens: 128e3,
|
|
506
|
+
supportsTools: true,
|
|
507
|
+
supportsVision: true
|
|
508
|
+
},
|
|
509
|
+
"anthropic/claude-opus-4.8": {
|
|
510
|
+
contextWindow: 1e6,
|
|
511
|
+
maxOutputTokens: 128e3,
|
|
512
|
+
supportsTools: true,
|
|
513
|
+
supportsVision: true
|
|
514
|
+
},
|
|
515
|
+
"anthropic/claude-opus-5": {
|
|
516
|
+
contextWindow: 1e6,
|
|
517
|
+
maxOutputTokens: 128e3,
|
|
518
|
+
supportsTools: true,
|
|
519
|
+
supportsVision: true
|
|
520
|
+
},
|
|
521
|
+
"anthropic/claude-sonnet-4.6": {
|
|
522
|
+
contextWindow: 2e5,
|
|
523
|
+
maxOutputTokens: 64e3,
|
|
524
|
+
supportsTools: true,
|
|
525
|
+
supportsVision: true
|
|
526
|
+
},
|
|
527
|
+
"anthropic/claude-sonnet-5": {
|
|
528
|
+
contextWindow: 1e6,
|
|
529
|
+
maxOutputTokens: 128e3,
|
|
530
|
+
supportsTools: true,
|
|
531
|
+
supportsVision: true
|
|
532
|
+
},
|
|
533
|
+
"deepseek/deepseek-chat": {
|
|
534
|
+
contextWindow: 1e6,
|
|
535
|
+
maxOutputTokens: 8192,
|
|
536
|
+
supportsTools: true,
|
|
537
|
+
supportsVision: false
|
|
538
|
+
},
|
|
539
|
+
"deepseek/deepseek-reasoner": {
|
|
540
|
+
contextWindow: 1e6,
|
|
541
|
+
maxOutputTokens: 8192,
|
|
542
|
+
supportsTools: true,
|
|
543
|
+
supportsVision: false
|
|
544
|
+
},
|
|
545
|
+
"deepseek/deepseek-v4-pro": {
|
|
546
|
+
contextWindow: 1048576,
|
|
547
|
+
maxOutputTokens: 65536,
|
|
548
|
+
supportsTools: true,
|
|
549
|
+
supportsVision: false
|
|
550
|
+
},
|
|
551
|
+
"free/deepseek-v4-flash": {
|
|
552
|
+
contextWindow: 1e6,
|
|
553
|
+
maxOutputTokens: 16384,
|
|
554
|
+
supportsTools: false,
|
|
555
|
+
supportsVision: false
|
|
556
|
+
},
|
|
557
|
+
"free/gpt-oss-120b": {
|
|
558
|
+
contextWindow: 128e3,
|
|
559
|
+
maxOutputTokens: 16384,
|
|
560
|
+
supportsTools: false,
|
|
561
|
+
supportsVision: false
|
|
562
|
+
},
|
|
563
|
+
"free/gpt-oss-20b": {
|
|
564
|
+
contextWindow: 128e3,
|
|
565
|
+
maxOutputTokens: 16384,
|
|
566
|
+
supportsTools: false,
|
|
567
|
+
supportsVision: false
|
|
568
|
+
},
|
|
569
|
+
"free/seed-oss-36b": {
|
|
570
|
+
contextWindow: 131072,
|
|
571
|
+
maxOutputTokens: 16384,
|
|
572
|
+
supportsTools: false,
|
|
573
|
+
supportsVision: false
|
|
574
|
+
},
|
|
575
|
+
"google/gemini-2.5-flash": {
|
|
576
|
+
contextWindow: 1e6,
|
|
577
|
+
maxOutputTokens: 65536,
|
|
578
|
+
supportsTools: true,
|
|
579
|
+
supportsVision: true
|
|
580
|
+
},
|
|
581
|
+
"google/gemini-2.5-flash-lite": {
|
|
582
|
+
contextWindow: 1e6,
|
|
583
|
+
maxOutputTokens: 65536,
|
|
584
|
+
supportsTools: true,
|
|
585
|
+
supportsVision: false
|
|
586
|
+
},
|
|
587
|
+
"google/gemini-2.5-pro": {
|
|
588
|
+
contextWindow: 105e4,
|
|
589
|
+
maxOutputTokens: 65536,
|
|
590
|
+
supportsTools: true,
|
|
591
|
+
supportsVision: true
|
|
592
|
+
},
|
|
593
|
+
"google/gemini-3-flash-preview": {
|
|
594
|
+
contextWindow: 1e6,
|
|
595
|
+
maxOutputTokens: 65536,
|
|
596
|
+
supportsTools: false,
|
|
597
|
+
supportsVision: true
|
|
598
|
+
},
|
|
599
|
+
"google/gemini-3.1-flash-lite": {
|
|
600
|
+
contextWindow: 1e6,
|
|
601
|
+
maxOutputTokens: 8192,
|
|
602
|
+
supportsTools: true,
|
|
603
|
+
supportsVision: false
|
|
604
|
+
},
|
|
605
|
+
"google/gemini-3.1-pro": {
|
|
606
|
+
contextWindow: 105e4,
|
|
607
|
+
maxOutputTokens: 65536,
|
|
608
|
+
supportsTools: true,
|
|
609
|
+
supportsVision: true
|
|
610
|
+
},
|
|
611
|
+
"google/gemini-3.5-flash": {
|
|
612
|
+
contextWindow: 1048576,
|
|
613
|
+
maxOutputTokens: 65536,
|
|
614
|
+
supportsTools: true,
|
|
615
|
+
supportsVision: true
|
|
616
|
+
},
|
|
617
|
+
"moonshot/kimi-k2.5": {
|
|
618
|
+
contextWindow: 262144,
|
|
619
|
+
maxOutputTokens: 16384,
|
|
620
|
+
supportsTools: true,
|
|
621
|
+
supportsVision: true
|
|
622
|
+
},
|
|
623
|
+
"moonshot/kimi-k2.6": {
|
|
624
|
+
contextWindow: 262144,
|
|
625
|
+
maxOutputTokens: 65536,
|
|
626
|
+
supportsTools: true,
|
|
627
|
+
supportsVision: true
|
|
628
|
+
},
|
|
629
|
+
"moonshot/kimi-k2.7": {
|
|
630
|
+
contextWindow: 262144,
|
|
631
|
+
maxOutputTokens: 65536,
|
|
632
|
+
supportsTools: true,
|
|
633
|
+
supportsVision: true
|
|
634
|
+
},
|
|
635
|
+
"moonshot/kimi-k3": {
|
|
636
|
+
contextWindow: 1048576,
|
|
637
|
+
maxOutputTokens: 65536,
|
|
638
|
+
supportsTools: true,
|
|
639
|
+
supportsVision: true
|
|
640
|
+
},
|
|
641
|
+
"openai/gpt-4.1": {
|
|
642
|
+
contextWindow: 128e3,
|
|
643
|
+
maxOutputTokens: 16384,
|
|
644
|
+
supportsTools: true,
|
|
645
|
+
supportsVision: true
|
|
646
|
+
},
|
|
647
|
+
"openai/gpt-4o-mini": {
|
|
648
|
+
contextWindow: 128e3,
|
|
649
|
+
maxOutputTokens: 16384,
|
|
650
|
+
supportsTools: true,
|
|
651
|
+
supportsVision: false
|
|
652
|
+
},
|
|
653
|
+
"openai/gpt-5-mini": {
|
|
654
|
+
contextWindow: 2e5,
|
|
655
|
+
maxOutputTokens: 65536,
|
|
656
|
+
supportsTools: true,
|
|
657
|
+
supportsVision: false
|
|
658
|
+
},
|
|
659
|
+
"openai/gpt-5.3-codex": {
|
|
660
|
+
contextWindow: 4e5,
|
|
661
|
+
maxOutputTokens: 128e3,
|
|
662
|
+
supportsTools: true,
|
|
663
|
+
supportsVision: false
|
|
664
|
+
},
|
|
665
|
+
"openai/gpt-5.4": {
|
|
666
|
+
contextWindow: 4e5,
|
|
667
|
+
maxOutputTokens: 128e3,
|
|
668
|
+
supportsTools: true,
|
|
669
|
+
supportsVision: true
|
|
670
|
+
},
|
|
671
|
+
"openai/gpt-5.4-nano": {
|
|
672
|
+
contextWindow: 105e4,
|
|
673
|
+
maxOutputTokens: 32768,
|
|
674
|
+
supportsTools: true,
|
|
675
|
+
supportsVision: false
|
|
676
|
+
},
|
|
677
|
+
"openai/gpt-5.5": {
|
|
678
|
+
contextWindow: 105e4,
|
|
679
|
+
maxOutputTokens: 128e3,
|
|
680
|
+
supportsTools: true,
|
|
681
|
+
supportsVision: true
|
|
682
|
+
},
|
|
683
|
+
"openai/gpt-5.6-terra": {
|
|
684
|
+
contextWindow: 105e4,
|
|
685
|
+
maxOutputTokens: 128e3,
|
|
686
|
+
supportsTools: true,
|
|
687
|
+
supportsVision: true
|
|
688
|
+
},
|
|
689
|
+
"openai/o3": {
|
|
690
|
+
contextWindow: 2e5,
|
|
691
|
+
maxOutputTokens: 1e5,
|
|
692
|
+
supportsTools: true,
|
|
693
|
+
supportsVision: false
|
|
694
|
+
},
|
|
695
|
+
"openai/o4-mini": {
|
|
696
|
+
contextWindow: 128e3,
|
|
697
|
+
maxOutputTokens: 65536,
|
|
698
|
+
supportsTools: true,
|
|
699
|
+
supportsVision: false
|
|
700
|
+
},
|
|
701
|
+
"qwen/qwen3.7-max": {
|
|
702
|
+
contextWindow: 1e6,
|
|
703
|
+
maxOutputTokens: 65536,
|
|
704
|
+
supportsTools: true,
|
|
705
|
+
supportsVision: false
|
|
706
|
+
},
|
|
707
|
+
"xai/grok-3-mini": {
|
|
708
|
+
contextWindow: 131072,
|
|
709
|
+
maxOutputTokens: 16384,
|
|
710
|
+
supportsTools: true,
|
|
711
|
+
supportsVision: false
|
|
712
|
+
},
|
|
713
|
+
"xai/grok-4-0709": {
|
|
714
|
+
contextWindow: 131072,
|
|
715
|
+
maxOutputTokens: 16384,
|
|
716
|
+
supportsTools: true,
|
|
717
|
+
supportsVision: false
|
|
718
|
+
},
|
|
719
|
+
"xai/grok-4-1-fast-non-reasoning": {
|
|
720
|
+
contextWindow: 131072,
|
|
721
|
+
maxOutputTokens: 16384,
|
|
722
|
+
supportsTools: true,
|
|
723
|
+
supportsVision: false
|
|
724
|
+
},
|
|
725
|
+
"xai/grok-4-1-fast-reasoning": {
|
|
726
|
+
contextWindow: 131072,
|
|
727
|
+
maxOutputTokens: 16384,
|
|
728
|
+
supportsTools: true,
|
|
729
|
+
supportsVision: false
|
|
730
|
+
},
|
|
731
|
+
"xai/grok-4-fast-non-reasoning": {
|
|
732
|
+
contextWindow: 131072,
|
|
733
|
+
maxOutputTokens: 16384,
|
|
734
|
+
supportsTools: true,
|
|
735
|
+
supportsVision: false
|
|
736
|
+
},
|
|
737
|
+
"xai/grok-4-fast-reasoning": {
|
|
738
|
+
contextWindow: 131072,
|
|
739
|
+
maxOutputTokens: 16384,
|
|
740
|
+
supportsTools: true,
|
|
741
|
+
supportsVision: false
|
|
742
|
+
},
|
|
743
|
+
"xai/grok-4.5": {
|
|
744
|
+
contextWindow: 5e5,
|
|
745
|
+
maxOutputTokens: 16384,
|
|
746
|
+
supportsTools: true,
|
|
747
|
+
supportsVision: true
|
|
748
|
+
},
|
|
749
|
+
"zai/glm-5.1": {
|
|
750
|
+
contextWindow: 2e5,
|
|
751
|
+
maxOutputTokens: 128e3,
|
|
752
|
+
supportsTools: true,
|
|
753
|
+
supportsVision: false
|
|
754
|
+
},
|
|
755
|
+
"zai/glm-5.2": {
|
|
756
|
+
contextWindow: 1e6,
|
|
757
|
+
maxOutputTokens: 262144,
|
|
758
|
+
supportsTools: true,
|
|
759
|
+
supportsVision: false
|
|
760
|
+
}
|
|
761
|
+
});
|
|
762
|
+
var model_profiles_generated_default = {
|
|
763
|
+
"openai/gpt-5.5": {
|
|
764
|
+
measuredAt: "2026-07-21T10:21:31Z",
|
|
765
|
+
latencyMs: 6243.1,
|
|
766
|
+
p95LatencyMs: 9865,
|
|
767
|
+
outputTokensPerSecond: 12.53,
|
|
768
|
+
errorRate: 0,
|
|
769
|
+
samples: 3
|
|
770
|
+
},
|
|
771
|
+
"openai/gpt-5.4-pro": {
|
|
772
|
+
measuredAt: "2026-07-21T10:21:31Z",
|
|
773
|
+
latencyMs: 13015.5,
|
|
774
|
+
p95LatencyMs: 23976.4,
|
|
775
|
+
outputTokensPerSecond: 6.42,
|
|
776
|
+
errorRate: 0,
|
|
777
|
+
samples: 3
|
|
778
|
+
},
|
|
779
|
+
"openai/gpt-5.4-mini": {
|
|
780
|
+
measuredAt: "2026-07-21T10:21:31Z",
|
|
781
|
+
latencyMs: 5550,
|
|
782
|
+
p95LatencyMs: 6595.7,
|
|
783
|
+
outputTokensPerSecond: 11.96,
|
|
784
|
+
errorRate: 0.3333,
|
|
785
|
+
samples: 3
|
|
786
|
+
},
|
|
787
|
+
"openai/gpt-5.3-codex": {
|
|
788
|
+
measuredAt: "2026-07-21T10:21:31Z",
|
|
789
|
+
latencyMs: 4617.1,
|
|
790
|
+
p95LatencyMs: 5800.7,
|
|
791
|
+
outputTokensPerSecond: 12.48,
|
|
792
|
+
errorRate: 0,
|
|
793
|
+
samples: 3
|
|
794
|
+
},
|
|
795
|
+
"anthropic/claude-opus-4.8": {
|
|
796
|
+
measuredAt: "2026-07-21T10:21:31Z",
|
|
797
|
+
latencyMs: 3915.1,
|
|
798
|
+
p95LatencyMs: 6130.8,
|
|
799
|
+
outputTokensPerSecond: 16.33,
|
|
800
|
+
errorRate: 0,
|
|
801
|
+
samples: 3
|
|
802
|
+
},
|
|
803
|
+
"anthropic/claude-opus-4.6": {
|
|
804
|
+
measuredAt: "2026-07-21T10:21:31Z",
|
|
805
|
+
latencyMs: 3765.5,
|
|
806
|
+
p95LatencyMs: 4257.2,
|
|
807
|
+
outputTokensPerSecond: 14.18,
|
|
808
|
+
errorRate: 0,
|
|
809
|
+
samples: 3
|
|
810
|
+
},
|
|
811
|
+
"anthropic/claude-sonnet-4.6": {
|
|
812
|
+
measuredAt: "2026-07-21T10:21:31Z",
|
|
813
|
+
latencyMs: 3860.6,
|
|
814
|
+
p95LatencyMs: 5093.5,
|
|
815
|
+
outputTokensPerSecond: 13.85,
|
|
816
|
+
errorRate: 0,
|
|
817
|
+
samples: 3
|
|
818
|
+
},
|
|
819
|
+
"anthropic/claude-haiku-4.5": {
|
|
820
|
+
measuredAt: "2026-07-21T10:21:31Z",
|
|
821
|
+
latencyMs: 2734.9,
|
|
822
|
+
p95LatencyMs: 3181.6,
|
|
823
|
+
outputTokensPerSecond: 19.58,
|
|
824
|
+
errorRate: 0,
|
|
825
|
+
samples: 3
|
|
826
|
+
},
|
|
827
|
+
"google/gemini-3.1-pro": {
|
|
828
|
+
measuredAt: "2026-07-21T10:21:31Z",
|
|
829
|
+
latencyMs: 13935.7,
|
|
830
|
+
p95LatencyMs: 26675.3,
|
|
831
|
+
outputTokensPerSecond: 77.47,
|
|
832
|
+
errorRate: 0,
|
|
833
|
+
samples: 3
|
|
834
|
+
},
|
|
835
|
+
"google/gemini-3.5-flash": {
|
|
836
|
+
measuredAt: "2026-07-21T10:21:31Z",
|
|
837
|
+
latencyMs: 4608.7,
|
|
838
|
+
p95LatencyMs: 8420.9,
|
|
839
|
+
outputTokensPerSecond: 57.88,
|
|
840
|
+
errorRate: 0,
|
|
841
|
+
samples: 3
|
|
842
|
+
},
|
|
843
|
+
"google/gemini-3.1-flash-lite": {
|
|
844
|
+
measuredAt: "2026-07-21T10:21:31Z",
|
|
845
|
+
latencyMs: 4619.7,
|
|
846
|
+
p95LatencyMs: 9927.1,
|
|
847
|
+
outputTokensPerSecond: 42.01,
|
|
848
|
+
errorRate: 0,
|
|
849
|
+
samples: 3
|
|
850
|
+
},
|
|
851
|
+
"google/gemini-2.5-flash": {
|
|
852
|
+
measuredAt: "2026-07-21T10:21:31Z",
|
|
853
|
+
latencyMs: 5506.9,
|
|
854
|
+
p95LatencyMs: 11462.5,
|
|
855
|
+
outputTokensPerSecond: 65.19,
|
|
856
|
+
errorRate: 0,
|
|
857
|
+
samples: 3
|
|
858
|
+
},
|
|
859
|
+
"deepseek/deepseek-v4-pro": {
|
|
860
|
+
measuredAt: "2026-07-21T10:21:31Z",
|
|
861
|
+
latencyMs: 6044.8,
|
|
862
|
+
p95LatencyMs: 10782.3,
|
|
863
|
+
outputTokensPerSecond: 22.47,
|
|
864
|
+
errorRate: 0,
|
|
865
|
+
samples: 3
|
|
866
|
+
},
|
|
867
|
+
"deepseek/deepseek-reasoner": {
|
|
868
|
+
measuredAt: "2026-07-21T10:21:31Z",
|
|
869
|
+
latencyMs: 4111.9,
|
|
870
|
+
p95LatencyMs: 5305.7,
|
|
871
|
+
outputTokensPerSecond: 16.46,
|
|
872
|
+
errorRate: 0,
|
|
873
|
+
samples: 3
|
|
874
|
+
},
|
|
875
|
+
"deepseek/deepseek-chat": {
|
|
876
|
+
measuredAt: "2026-07-21T10:21:31Z",
|
|
877
|
+
latencyMs: 2648.6,
|
|
878
|
+
p95LatencyMs: 3524.1,
|
|
879
|
+
outputTokensPerSecond: 16.73,
|
|
880
|
+
errorRate: 0,
|
|
881
|
+
samples: 3
|
|
882
|
+
},
|
|
883
|
+
"moonshot/kimi-k2.7": {
|
|
884
|
+
measuredAt: "2026-07-21T10:21:31Z",
|
|
885
|
+
latencyMs: 4295.4,
|
|
886
|
+
p95LatencyMs: 6153.8,
|
|
887
|
+
outputTokensPerSecond: 18.54,
|
|
888
|
+
errorRate: 0,
|
|
889
|
+
samples: 3
|
|
890
|
+
},
|
|
891
|
+
"qwen/qwen3.7-max": {
|
|
892
|
+
measuredAt: "2026-07-21T10:21:31Z",
|
|
893
|
+
latencyMs: 30729.4,
|
|
894
|
+
p95LatencyMs: 39622,
|
|
895
|
+
outputTokensPerSecond: 36.89,
|
|
896
|
+
errorRate: 0.3333,
|
|
897
|
+
samples: 3
|
|
898
|
+
},
|
|
899
|
+
"xai/grok-4.3": {
|
|
900
|
+
measuredAt: "2026-07-21T10:21:31Z",
|
|
901
|
+
latencyMs: 6946.1,
|
|
902
|
+
p95LatencyMs: 9495.4,
|
|
903
|
+
outputTokensPerSecond: 65.3,
|
|
904
|
+
errorRate: 0,
|
|
905
|
+
samples: 3
|
|
906
|
+
},
|
|
907
|
+
"xai/grok-4.20-reasoning": {
|
|
908
|
+
measuredAt: "2026-07-21T10:21:31Z",
|
|
909
|
+
latencyMs: 3472.4,
|
|
910
|
+
p95LatencyMs: 5332.4,
|
|
911
|
+
outputTokensPerSecond: 13.27,
|
|
912
|
+
errorRate: 0,
|
|
913
|
+
samples: 3
|
|
914
|
+
},
|
|
915
|
+
"xai/grok-4.20-non-reasoning": {
|
|
916
|
+
measuredAt: "2026-07-21T10:21:31Z",
|
|
917
|
+
latencyMs: 5174.4,
|
|
918
|
+
p95LatencyMs: 6081.7,
|
|
919
|
+
outputTokensPerSecond: 10.21,
|
|
920
|
+
errorRate: 0.3333,
|
|
921
|
+
samples: 3
|
|
922
|
+
},
|
|
923
|
+
"xai/grok-4-1-fast-reasoning": {
|
|
924
|
+
measuredAt: "2026-07-21T10:21:31Z",
|
|
925
|
+
latencyMs: 13148.2,
|
|
926
|
+
p95LatencyMs: 19104.2,
|
|
927
|
+
outputTokensPerSecond: 4.28,
|
|
928
|
+
errorRate: 0,
|
|
929
|
+
samples: 3
|
|
930
|
+
},
|
|
931
|
+
"minimax/minimax-m3": {
|
|
932
|
+
measuredAt: "2026-07-21T10:21:31Z",
|
|
933
|
+
latencyMs: 3385,
|
|
934
|
+
p95LatencyMs: 4247.2,
|
|
935
|
+
outputTokensPerSecond: 15.16,
|
|
936
|
+
errorRate: 0,
|
|
937
|
+
samples: 3
|
|
938
|
+
},
|
|
939
|
+
"minimax/minimax-m2.7": {
|
|
940
|
+
measuredAt: "2026-07-21T10:21:31Z",
|
|
941
|
+
latencyMs: 4596.7,
|
|
942
|
+
p95LatencyMs: 6884.6,
|
|
943
|
+
outputTokensPerSecond: 17.03,
|
|
944
|
+
errorRate: 0,
|
|
945
|
+
samples: 3
|
|
946
|
+
},
|
|
947
|
+
"zai/glm-5.2": {
|
|
948
|
+
measuredAt: "2026-07-21T10:21:31Z",
|
|
949
|
+
latencyMs: 4406.3,
|
|
950
|
+
p95LatencyMs: 6139.7,
|
|
951
|
+
outputTokensPerSecond: 10.41,
|
|
952
|
+
errorRate: 0,
|
|
953
|
+
samples: 3
|
|
954
|
+
},
|
|
955
|
+
"zai/glm-5.1": {
|
|
956
|
+
measuredAt: "2026-07-21T10:21:31Z",
|
|
957
|
+
latencyMs: 7775.4,
|
|
958
|
+
p95LatencyMs: 9182.1,
|
|
959
|
+
outputTokensPerSecond: 6.08,
|
|
960
|
+
errorRate: 0,
|
|
961
|
+
samples: 3
|
|
962
|
+
},
|
|
963
|
+
"zai/glm-5": {
|
|
964
|
+
measuredAt: "2026-07-21T10:21:31Z",
|
|
965
|
+
latencyMs: 4159.4,
|
|
966
|
+
p95LatencyMs: 4992.7,
|
|
967
|
+
outputTokensPerSecond: 10.28,
|
|
968
|
+
errorRate: 0,
|
|
969
|
+
samples: 3
|
|
970
|
+
},
|
|
971
|
+
"free/qwen3-coder-480b": {
|
|
972
|
+
measuredAt: "2026-07-21T10:21:31Z",
|
|
973
|
+
latencyMs: 2063.9,
|
|
974
|
+
p95LatencyMs: 3646.3,
|
|
975
|
+
outputTokensPerSecond: 39.8,
|
|
976
|
+
errorRate: 0,
|
|
977
|
+
samples: 3
|
|
978
|
+
},
|
|
979
|
+
"free/mistral-large-3-675b": {
|
|
980
|
+
measuredAt: "2026-07-21T10:21:31Z",
|
|
981
|
+
latencyMs: 3147.5,
|
|
982
|
+
p95LatencyMs: 5555.3,
|
|
983
|
+
outputTokensPerSecond: 27.76,
|
|
984
|
+
errorRate: 0,
|
|
985
|
+
samples: 3
|
|
986
|
+
},
|
|
987
|
+
"free/nemotron-3-nano-omni-30b-a3b-reasoning": {
|
|
988
|
+
measuredAt: "2026-07-21T10:21:31Z",
|
|
989
|
+
latencyMs: 6508.4,
|
|
990
|
+
p95LatencyMs: 14252.7,
|
|
991
|
+
outputTokensPerSecond: 68.26,
|
|
992
|
+
errorRate: 0,
|
|
993
|
+
samples: 3
|
|
994
|
+
},
|
|
995
|
+
"free/glm-4.7": {
|
|
996
|
+
measuredAt: "2026-07-21T10:21:31Z",
|
|
997
|
+
latencyMs: 2014.8,
|
|
998
|
+
p95LatencyMs: 3039.9,
|
|
999
|
+
outputTokensPerSecond: 39.92,
|
|
1000
|
+
errorRate: 0,
|
|
1001
|
+
samples: 3
|
|
1002
|
+
}
|
|
1003
|
+
};
|
|
1004
|
+
var LIVE_MODEL_PROFILES = Object.freeze(
|
|
1005
|
+
model_profiles_generated_default
|
|
1006
|
+
);
|
|
1007
|
+
var HISTORICAL_MODEL_PROFILES = Object.freeze({
|
|
1008
|
+
"anthropic/claude-haiku-4.5": {
|
|
1009
|
+
measuredAt: "2026-03-16T13:50:48Z",
|
|
1010
|
+
latencyMs: 2305,
|
|
1011
|
+
outputTokensPerSecond: 140.6
|
|
1012
|
+
},
|
|
1013
|
+
"anthropic/claude-opus-4.6": {
|
|
1014
|
+
measuredAt: "2026-03-16T13:50:48Z",
|
|
1015
|
+
latencyMs: 2139,
|
|
1016
|
+
outputTokensPerSecond: 119.7
|
|
1017
|
+
},
|
|
1018
|
+
"anthropic/claude-sonnet-4.6": {
|
|
1019
|
+
measuredAt: "2026-03-16T13:50:48Z",
|
|
1020
|
+
latencyMs: 2110,
|
|
1021
|
+
outputTokensPerSecond: 121.3
|
|
1022
|
+
},
|
|
1023
|
+
"deepseek/deepseek-chat": {
|
|
1024
|
+
measuredAt: "2026-03-16T13:50:48Z",
|
|
1025
|
+
latencyMs: 1431,
|
|
1026
|
+
outputTokensPerSecond: 179.2,
|
|
1027
|
+
intelligenceIndex: 32
|
|
1028
|
+
},
|
|
1029
|
+
"google/gemini-2.5-flash": {
|
|
1030
|
+
measuredAt: "2026-03-16T13:50:48Z",
|
|
1031
|
+
latencyMs: 1238,
|
|
1032
|
+
outputTokensPerSecond: 207.6,
|
|
1033
|
+
intelligenceIndex: 20
|
|
1034
|
+
},
|
|
1035
|
+
"google/gemini-2.5-flash-lite": {
|
|
1036
|
+
measuredAt: "2026-03-16T13:50:48Z",
|
|
1037
|
+
latencyMs: 1353,
|
|
1038
|
+
outputTokensPerSecond: 192.5,
|
|
1039
|
+
intelligenceIndex: 20
|
|
1040
|
+
},
|
|
1041
|
+
"google/gemini-2.5-pro": {
|
|
1042
|
+
measuredAt: "2026-03-16T13:50:48Z",
|
|
1043
|
+
latencyMs: 1294,
|
|
1044
|
+
outputTokensPerSecond: 197.8
|
|
1045
|
+
},
|
|
1046
|
+
"google/gemini-3.1-pro": {
|
|
1047
|
+
measuredAt: "2026-03-16T13:50:48Z",
|
|
1048
|
+
latencyMs: 1609,
|
|
1049
|
+
outputTokensPerSecond: 167.2
|
|
1050
|
+
},
|
|
1051
|
+
"moonshot/kimi-k2.5": {
|
|
1052
|
+
measuredAt: "2026-03-16T13:50:48Z",
|
|
1053
|
+
latencyMs: 1646,
|
|
1054
|
+
outputTokensPerSecond: 155.7
|
|
1055
|
+
},
|
|
1056
|
+
"openai/gpt-4o-mini": {
|
|
1057
|
+
measuredAt: "2026-03-16T13:50:48Z",
|
|
1058
|
+
latencyMs: 2764,
|
|
1059
|
+
outputTokensPerSecond: 92.8
|
|
1060
|
+
},
|
|
1061
|
+
"openai/gpt-5.3-codex": {
|
|
1062
|
+
measuredAt: "2026-03-16T13:50:48Z",
|
|
1063
|
+
latencyMs: 7935,
|
|
1064
|
+
outputTokensPerSecond: 32.3
|
|
1065
|
+
},
|
|
1066
|
+
"xai/grok-4-1-fast-non-reasoning": {
|
|
1067
|
+
measuredAt: "2026-03-16T13:50:48Z",
|
|
1068
|
+
latencyMs: 1244,
|
|
1069
|
+
outputTokensPerSecond: 205.8,
|
|
1070
|
+
intelligenceIndex: 41
|
|
1071
|
+
},
|
|
1072
|
+
"xai/grok-4-1-fast-reasoning": {
|
|
1073
|
+
measuredAt: "2026-03-16T13:50:48Z",
|
|
1074
|
+
latencyMs: 1454,
|
|
1075
|
+
outputTokensPerSecond: 176.2,
|
|
1076
|
+
intelligenceIndex: 41
|
|
1077
|
+
}
|
|
1078
|
+
});
|
|
1079
|
+
function inferToolRequirement(prompt, _systemPrompt, toolChoice) {
|
|
1080
|
+
if (toolChoice === "none") return false;
|
|
1081
|
+
if (toolChoice === "required") return true;
|
|
1082
|
+
if (typeof toolChoice === "object" && toolChoice !== null && toolChoice.type === "function") {
|
|
1083
|
+
return true;
|
|
1084
|
+
}
|
|
1085
|
+
const text = prompt;
|
|
1086
|
+
const explicitTool = /\b(?:use|call|invoke)\s+(?:the\s+)?[\w.-]+\s+(?:tool|function|api)\b|\btool[_ -]?call\b|使用.{0,20}(?:工具|函数|接口)|调用.{0,20}(?:工具|函数|接口)/i;
|
|
1087
|
+
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;
|
|
1088
|
+
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;
|
|
1089
|
+
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;
|
|
1090
|
+
return explicitTool.test(text) || codeEnvironment.test(text) || webAction.test(text) || statefulAction.test(text);
|
|
1091
|
+
}
|
|
1092
|
+
var DEFAULT_PORTFOLIO_WEIGHTS = {
|
|
1093
|
+
auto: {
|
|
1094
|
+
quality: 0.47,
|
|
1095
|
+
capability: 0.2,
|
|
1096
|
+
cost: 0.18,
|
|
1097
|
+
speed: 0.07,
|
|
1098
|
+
reliability: 0.03,
|
|
1099
|
+
legacy: 0.05
|
|
1100
|
+
},
|
|
1101
|
+
eco: { quality: 0.36, capability: 0.2, cost: 0.28, speed: 0.1, reliability: 0.04, legacy: 0.02 },
|
|
1102
|
+
premium: {
|
|
1103
|
+
quality: 0.58,
|
|
1104
|
+
capability: 0.2,
|
|
1105
|
+
cost: 0.08,
|
|
1106
|
+
speed: 0.06,
|
|
1107
|
+
reliability: 0.06,
|
|
1108
|
+
legacy: 0.02
|
|
1109
|
+
},
|
|
1110
|
+
highStakesBoost: { quality: 0.08, reliability: 0.05 },
|
|
1111
|
+
latencySensitiveSpeedBoost: 0.08,
|
|
1112
|
+
affinityFloorGap: { auto: 0.1, eco: 0.22, premium: 0.05 }
|
|
1113
|
+
};
|
|
1114
|
+
function likelyNeedsParallelToolCalls(prompt, needsTools, toolCount, toolNames) {
|
|
1115
|
+
if (!needsTools || toolCount === void 0 || toolCount < 1) return false;
|
|
1116
|
+
const text = prompt.trim();
|
|
1117
|
+
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(
|
|
1118
|
+
text
|
|
1119
|
+
);
|
|
1120
|
+
if (explicitRepeat) return true;
|
|
1121
|
+
const sentenceClauses = text.split(/[.!?。!?]+/).map((part) => part.trim()).filter((part) => part.length >= 8);
|
|
1122
|
+
if (/\b(?:also|additionally|furthermore)\b|另外|此外|그리고/i.test(text) && sentenceClauses.length >= 2 || /\band\s+(?:also|for the)\b/i.test(text))
|
|
1123
|
+
return true;
|
|
1124
|
+
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(
|
|
1125
|
+
text
|
|
1126
|
+
);
|
|
1127
|
+
if (pairedQuantity) return true;
|
|
1128
|
+
const operationTokens = /* @__PURE__ */ new Set([
|
|
1129
|
+
"add",
|
|
1130
|
+
"delete",
|
|
1131
|
+
"remove",
|
|
1132
|
+
"cancel",
|
|
1133
|
+
"return",
|
|
1134
|
+
"exchange",
|
|
1135
|
+
"modify",
|
|
1136
|
+
"book",
|
|
1137
|
+
"transfer",
|
|
1138
|
+
"send",
|
|
1139
|
+
"upload",
|
|
1140
|
+
"download",
|
|
1141
|
+
"create",
|
|
1142
|
+
"close"
|
|
1143
|
+
]);
|
|
1144
|
+
const lowered = text.toLowerCase();
|
|
1145
|
+
const matchedOperationTokens = new Set(
|
|
1146
|
+
(toolNames ?? []).flatMap((name) => name.toLowerCase().split(/[^a-z0-9\u3400-\u9fff]+/)).filter((token) => operationTokens.has(token) && lowered.includes(token))
|
|
1147
|
+
);
|
|
1148
|
+
if (matchedOperationTokens.size >= 2) return true;
|
|
1149
|
+
const nonEmptyLines = text.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
|
|
1150
|
+
const quantityMentions = text.match(
|
|
1151
|
+
/\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
|
|
1152
|
+
) ?? [];
|
|
1153
|
+
if (nonEmptyLines.length >= 2 && quantityMentions.length >= 2) return true;
|
|
1154
|
+
const repeatedLookup = /\b(?:weather|climate|clima|tiempo|temperature|snow|news|report)\b|天气|气象|温度|降雪|新闻|报告/i.test(
|
|
1155
|
+
text
|
|
1156
|
+
);
|
|
1157
|
+
const multiLocationConnector = /\b(?:and also|both|y|e)\b|还有|以及|和|、/i.test(text);
|
|
1158
|
+
const commaSeparatedLocations = (text.match(/[,,]/g) ?? []).length >= 2;
|
|
1159
|
+
if (repeatedLookup && (multiLocationConnector || commaSeparatedLocations)) return true;
|
|
1160
|
+
const distinctOrderParts = /\b(?:food|meal)\b[\s\S]*\bdrink\b|\bdrink\b[\s\S]*\b(?:food|meal)\b/i.test(text);
|
|
1161
|
+
const koreanParallelClauses = (text.match(/,/g) ?? []).length >= 3 && /하고|그리고/.test(text);
|
|
1162
|
+
return distinctOrderParts || koreanParallelClauses;
|
|
1163
|
+
}
|
|
1164
|
+
function classifyTask(prompt, systemPrompt, options) {
|
|
1165
|
+
const fullText = `${systemPrompt ?? ""} ${prompt}`;
|
|
1166
|
+
const estimatedInputTokens = Math.ceil(fullText.length / 4);
|
|
1167
|
+
const scanLimit = Math.max(1, Math.min(8e3, options.config.classifier.promptTruncationChars));
|
|
1168
|
+
const sample = (value) => {
|
|
1169
|
+
if (value.length <= scanLimit) return value;
|
|
1170
|
+
const prefixLength = Math.ceil(scanLimit / 2);
|
|
1171
|
+
return `${value.slice(0, prefixLength)}
|
|
1172
|
+
${value.slice(-(scanLimit - prefixLength))}`;
|
|
1173
|
+
};
|
|
1174
|
+
const scannedPrompt = sample(prompt);
|
|
1175
|
+
const scannedSystemPrompt = sample(systemPrompt ?? "");
|
|
1176
|
+
const scannedFullText = `${scannedSystemPrompt} ${scannedPrompt}`;
|
|
1177
|
+
const text = scannedPrompt.toLowerCase();
|
|
1178
|
+
const explicitCodeSignal = /```|\b(?:typescript|javascript|python|rust|java|sql|stack trace|traceback|exception)\b|\.(?:ts|tsx|js|py|go|rs)\b/i.test(
|
|
1179
|
+
scannedPrompt
|
|
1180
|
+
);
|
|
1181
|
+
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(
|
|
1182
|
+
scannedPrompt
|
|
1183
|
+
);
|
|
1184
|
+
const nativeCodeSignal = /\b(?:programmed|written|implemented?|code)\s+(?:in|using)\s+(?:c\+\+|c|rust|go)\b/i.test(
|
|
1185
|
+
scannedPrompt
|
|
1186
|
+
);
|
|
1187
|
+
const hasCode = explicitCodeSignal || codeConstructSignal || nativeCodeSignal;
|
|
1188
|
+
const toolsAvailable = options.hasTools ?? false;
|
|
1189
|
+
const needsTools = options.requiresTools ?? (toolsAvailable && inferToolRequirement(scannedPrompt, scannedSystemPrompt));
|
|
1190
|
+
const likelyParallelToolCalls = likelyNeedsParallelToolCalls(
|
|
1191
|
+
scannedPrompt,
|
|
1192
|
+
needsTools,
|
|
1193
|
+
options.toolCount,
|
|
1194
|
+
options.toolNames
|
|
1195
|
+
);
|
|
1196
|
+
const normalizedToolNames = (options.toolNames ?? []).map((name) => name.toLowerCase());
|
|
1197
|
+
const airlineToolSignal = normalizedToolNames.some(
|
|
1198
|
+
(name) => /(?:flight|reservation|airport|baggage|passenger)/.test(name)
|
|
1199
|
+
);
|
|
1200
|
+
const retailToolSignal = normalizedToolNames.some(
|
|
1201
|
+
(name) => /(?:order|product|item|return|exchange|address)/.test(name)
|
|
1202
|
+
);
|
|
1203
|
+
const webResearchToolSignal = normalizedToolNames.some(
|
|
1204
|
+
(name) => /^(?:web_?search|web_?fetch)$/.test(name)
|
|
1205
|
+
);
|
|
1206
|
+
const agentDomain = airlineToolSignal && !retailToolSignal ? "airline" : retailToolSignal && !airlineToolSignal ? "retail" : webResearchToolSignal ? "web_research" : "other";
|
|
1207
|
+
const clueConnectors = scannedFullText.match(
|
|
1208
|
+
/\b(?:after|before|while|where|whose|which|in \d{4}|as of|over \d+|another|also|furthermore)\b|(?:之后|之前|其中|截至|超过|另一个|此外)/gi
|
|
1209
|
+
) ?? [];
|
|
1210
|
+
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(
|
|
1211
|
+
scannedFullText
|
|
1212
|
+
);
|
|
1213
|
+
const exactAnswerSignal = /\b(?:exact answer|single best-supported answer|following clues|multiple public sources)\b|(?:精确答案|根据.*线索|多个公开来源)/i.test(
|
|
1214
|
+
scannedFullText
|
|
1215
|
+
);
|
|
1216
|
+
const deepWebResearch = agentDomain === "web_research" && (exactAnswerSignal || entityResolutionSignal && (clueConnectors.length >= 3 || prompt.length >= 320));
|
|
1217
|
+
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(
|
|
1218
|
+
scannedPrompt
|
|
1219
|
+
);
|
|
1220
|
+
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(
|
|
1221
|
+
scannedPrompt
|
|
1222
|
+
);
|
|
1223
|
+
const globalChoiceSignal = globalOptimizationSignal || globalScopeSignal;
|
|
1224
|
+
const crossRecordSignal = /\b(?:another|other|different|previous)\s+(?:order|reservation|booking|account|address)\b|另一(?:个)?(?:订单|预订|账户|地址)|其他(?:订单|预订|账户|地址)/i.test(
|
|
1225
|
+
scannedPrompt
|
|
1226
|
+
);
|
|
1227
|
+
const reservationIds = scannedPrompt.match(/\b[A-Z0-9]{6}\b/g) ?? [];
|
|
1228
|
+
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(
|
|
1229
|
+
scannedPrompt
|
|
1230
|
+
) || new Set(reservationIds).size >= 2);
|
|
1231
|
+
const conditionalGlobalWorkflowSignal = agentDomain === "airline" && globalScopeSignal && /\b(?:if|that (?:contain|have)|longer than|shorter than|under|over|at (?:most|least)|wherever possible)\b|如果|超过|少于|不超过|尽可能/i.test(
|
|
1232
|
+
scannedPrompt
|
|
1233
|
+
) && /\b(?:cancel|change|upgrade|move|book)\b[\s\S]*\b(?:cancel|change|upgrade|move|book)\b|取消[\s\S]*(?:升级|更改)|升级[\s\S]*(?:取消|更改)/i.test(
|
|
1234
|
+
scannedPrompt
|
|
1235
|
+
);
|
|
1236
|
+
const policyExceptionSignal = agentDomain === "retail" && /\b(?:return|refund|send back|get (?:my |the )?money back)\b|退货|退款|退回/i.test(
|
|
1237
|
+
scannedPrompt
|
|
1238
|
+
) && /\b(?:amex|american express|visa|mastercard|credit card|debit card|different card|another card|other card)\b|信用卡|借记卡|其他卡|另一张卡/i.test(
|
|
1239
|
+
scannedPrompt
|
|
1240
|
+
);
|
|
1241
|
+
const singleSelectedPolicyException = policyExceptionSignal && /\b(?:return|refund|send back)\b[^.!?。!?]{0,96}\b(?:the )?(?:pricier|cheaper|more expensive|less expensive|costlier|one)\b/i.test(
|
|
1242
|
+
scannedPrompt
|
|
1243
|
+
);
|
|
1244
|
+
const negotiatedWorkflowSignal = agentDomain === "retail" && /\b(?:return|exchange)\b|退货|退回|换货|交换/i.test(scannedPrompt);
|
|
1245
|
+
const numberedSteps = (scannedPrompt.match(/(?:^|\s)\d+(?:\.\d+)*[.)]\s+/g) ?? []).length;
|
|
1246
|
+
const complexMultiToolPlan = likelyParallelToolCalls && ((options.toolCount ?? 0) >= 6 || numberedSteps >= 3 || prompt.length > 1200);
|
|
1247
|
+
let agentRisk = needsTools && singleSelectedPolicyException ? "policy_exception_simple" : needsTools && policyExceptionSignal ? "policy_exception" : (
|
|
1248
|
+
// Airline prompts that require a global optimum (for example the
|
|
1249
|
+
// cheapest itinerary across several candidates) are materially harder
|
|
1250
|
+
// than applying one change to every passenger in a known reservation.
|
|
1251
|
+
// Full-session evidence supports Sonnet for the former, while upgrading
|
|
1252
|
+
// the latter merely because it says "all passengers" caused a large cost
|
|
1253
|
+
// increase without a quality gain.
|
|
1254
|
+
needsTools && agentDomain === "airline" && (globalOptimizationSignal || conditionalGlobalWorkflowSignal) ? "complex_high" : needsTools && (likelyParallelToolCalls || globalChoiceSignal || crossRecordSignal || crossReservationBatchSignal || negotiatedWorkflowSignal) ? "high" : "standard"
|
|
1255
|
+
);
|
|
1256
|
+
const needsVision = options.hasVision ?? false;
|
|
1257
|
+
const needsStructuredOutput = options.requiresStructuredOutput ?? false;
|
|
1258
|
+
const latencySensitive = /\b(?:urgent|asap|fast|quick|low latency|real[- ]time)\b|尽快|马上|快速|低延迟/i.test(
|
|
1259
|
+
scannedFullText
|
|
1260
|
+
);
|
|
1261
|
+
const highStakes = /\b(?:production|security|payment|legal|medical|financial|audit)\b|生产|安全|支付|法律|医疗|财务|审计/i.test(
|
|
1262
|
+
scannedFullText
|
|
1263
|
+
);
|
|
1264
|
+
const terminalToolSignal = normalizedToolNames.some(
|
|
1265
|
+
(name) => /^(?:terminalexec|terminalinspect|terminalsendkeys)$/.test(name)
|
|
1266
|
+
);
|
|
1267
|
+
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(
|
|
1268
|
+
scannedPrompt
|
|
1269
|
+
);
|
|
1270
|
+
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(
|
|
1271
|
+
scannedPrompt
|
|
1272
|
+
);
|
|
1273
|
+
const mentionedTerminalRuntimes = new Set(
|
|
1274
|
+
(scannedPrompt.match(/\b(?:gcc|clang|rustc|javac|go\s+build|node|python)\b/gi) ?? []).map(
|
|
1275
|
+
(name) => name.toLowerCase().replace(/\s+/g, " ")
|
|
1276
|
+
)
|
|
1277
|
+
);
|
|
1278
|
+
const terminalCrossRuntimeArtifact = terminalToolSignal && (/\bpolyglot\b/i.test(scannedPrompt) || /\b(?:both|each)\b[\s\S]{0,120}\b(?:compilers?|runtimes?|toolchains?)\b/i.test(
|
|
1279
|
+
scannedPrompt
|
|
1280
|
+
) || mentionedTerminalRuntimes.size >= 2 && /\b(?:compile|build|run|execute)\b/i.test(scannedPrompt));
|
|
1281
|
+
const terminalFrameworkToNativeArtifact = terminalToolSignal && /\b(?:pytorch|tensorflow|jax|onnx|state[_ -]?dict|checkpoint|safetensors?)\b|\.(?:pth|pt|onnx)\b/i.test(
|
|
1282
|
+
scannedPrompt
|
|
1283
|
+
) && /\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(
|
|
1284
|
+
scannedPrompt
|
|
1285
|
+
) && /\b(?:inference|model|weights?|tensor|export|convert|load)\b/i.test(scannedPrompt);
|
|
1286
|
+
if (needsTools && (terminalComplexRepair || terminalCrossRuntimeArtifact || terminalFrameworkToNativeArtifact) && (agentRisk === "standard" || agentRisk === "high"))
|
|
1287
|
+
agentRisk = "complex_high";
|
|
1288
|
+
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(
|
|
1289
|
+
scannedPrompt
|
|
1290
|
+
);
|
|
1291
|
+
const terminalCredentialSignal = /\b(?:ssh|nginx|certificate|authentication|credentials?|passwords?|api keys?|deploy|production|encrypt|gpg|shred|securely delete|decommission)\b/i.test(
|
|
1292
|
+
scannedPrompt
|
|
1293
|
+
) || /\b(?:access|auth|authentication|bearer|secret|api)\s+tokens?\b|\btokens?\s+(?:secret|credential|authentication)\b/i.test(
|
|
1294
|
+
scannedPrompt
|
|
1295
|
+
);
|
|
1296
|
+
const terminalSafetySensitive = terminalToolSignal && (highStakes || terminalCredentialSignal);
|
|
1297
|
+
const implicitTerminalCode = needsTools && terminalToolSignal && agentRisk === "standard" && !highStakes && !complexTerminalOperation && numberedSteps < 3 && prompt.length <= 1e3 && simpleTerminalArtifact;
|
|
1298
|
+
const language = /[\u3400-\u9fff]/.test(scannedFullText) ? "zh" : "other";
|
|
1299
|
+
const multipleChoiceSignals = (scannedPrompt.match(/(?:^|\n)\s*[A-D][.)]\s+/gim) ?? []).length;
|
|
1300
|
+
const numericSignals = (scannedPrompt.match(/-?\d+(?:[.,]\d+)?/g) ?? []).length;
|
|
1301
|
+
const compactMathProblem = !hasCode && prompt.length < 2500 && numericSignals >= 2 && (/[+×÷=%$€£¥]|\b(?:total|each|per|times|half|twice|percent|how many|how much|calculate)\b/i.test(
|
|
1302
|
+
scannedPrompt
|
|
1303
|
+
) || /[??]\s*$/.test(scannedPrompt.trim()) || numericSignals >= 3);
|
|
1304
|
+
let taskType = "chat";
|
|
1305
|
+
if (needsVision) taskType = "vision";
|
|
1306
|
+
else if (estimatedInputTokens > 8e4) taskType = "long_context";
|
|
1307
|
+
else if (needsTools && (hasCode || implicitTerminalCode)) taskType = "code_agent";
|
|
1308
|
+
else if (needsTools && likelyParallelToolCalls && !complexMultiToolPlan)
|
|
1309
|
+
taskType = "tool_agent_parallel";
|
|
1310
|
+
else if (needsTools) taskType = "tool_agent";
|
|
1311
|
+
else if (multipleChoiceSignals >= 3) taskType = "reasoning_mcq";
|
|
1312
|
+
else if (compactMathProblem) taskType = "reasoning_math";
|
|
1313
|
+
else if (/\b(?:bug|debug|error|failure|failing|regression|crash|修复|报错|错误|调试)\b/i.test(text))
|
|
1314
|
+
taskType = "debug";
|
|
1315
|
+
else if (hasCode || /\b(?:refactor|implement|patch|edit|rewrite|重构|实现|修改)\b/i.test(text))
|
|
1316
|
+
taskType = "code_edit";
|
|
1317
|
+
else if (needsStructuredOutput || /\b(?:extract|json|schema|csv|字段|提取)\b/i.test(text))
|
|
1318
|
+
taskType = "extraction";
|
|
1319
|
+
else if (/\b(?:prove|derive|theorem|formal|mathematical|reasoning|证明|推导|定理|数学)\b/i.test(text))
|
|
1320
|
+
taskType = "reasoning";
|
|
1321
|
+
return {
|
|
1322
|
+
taskType,
|
|
1323
|
+
estimatedInputTokens,
|
|
1324
|
+
hasCode,
|
|
1325
|
+
needsTools,
|
|
1326
|
+
toolsAvailable,
|
|
1327
|
+
needsVision,
|
|
1328
|
+
needsStructuredOutput,
|
|
1329
|
+
latencySensitive,
|
|
1330
|
+
highStakes,
|
|
1331
|
+
language,
|
|
1332
|
+
likelyParallelToolCalls,
|
|
1333
|
+
complexMultiToolPlan,
|
|
1334
|
+
agentDomain,
|
|
1335
|
+
deepWebResearch,
|
|
1336
|
+
agentRisk,
|
|
1337
|
+
terminalToolSignal,
|
|
1338
|
+
terminalSafetySensitive,
|
|
1339
|
+
implicitTerminalCode
|
|
1340
|
+
};
|
|
1341
|
+
}
|
|
1342
|
+
function affinity(modelId, task, language = "other", agentDomain = "other", deepWebResearch = false, agentRisk = "standard", terminalToolSignal = false, terminalSafetySensitive = false) {
|
|
1343
|
+
const id = modelId.toLowerCase();
|
|
1344
|
+
const modelName = id.slice(id.indexOf("/") + 1);
|
|
1345
|
+
const match = (values, score) => values.some((value) => modelName === value) ? score : 0;
|
|
1346
|
+
const base = 0.68;
|
|
1347
|
+
switch (task) {
|
|
1348
|
+
case "code_agent":
|
|
1349
|
+
if (terminalToolSignal && agentRisk === "complex_high") {
|
|
1350
|
+
return Math.max(
|
|
1351
|
+
base,
|
|
1352
|
+
match(["claude-sonnet-5"], 1),
|
|
1353
|
+
match(["gpt-5.3-codex"], 0.87),
|
|
1354
|
+
match(["gpt-5-mini"], 0.78),
|
|
1355
|
+
match(["gemini-3.5-flash"], 0.76)
|
|
1356
|
+
);
|
|
1357
|
+
}
|
|
1358
|
+
return Math.max(
|
|
1359
|
+
base,
|
|
1360
|
+
match(["gpt-5.3-codex"], 1),
|
|
1361
|
+
match(["claude-sonnet-5"], 0.98),
|
|
1362
|
+
match(["gpt-5-mini"], 0.96),
|
|
1363
|
+
match(["gemini-3.5-flash"], 0.92),
|
|
1364
|
+
match(["kimi-k3"], 0.9),
|
|
1365
|
+
match(["deepseek-v4-pro", "glm-5.2"], 0.88)
|
|
1366
|
+
);
|
|
1367
|
+
case "tool_agent":
|
|
1368
|
+
if (terminalToolSignal && agentRisk === "complex_high") {
|
|
1369
|
+
return Math.max(
|
|
1370
|
+
base,
|
|
1371
|
+
match(["claude-sonnet-5"], 1),
|
|
1372
|
+
match(["gpt-5.3-codex"], 0.87),
|
|
1373
|
+
match(["gpt-5-mini"], 0.78),
|
|
1374
|
+
match(["gemini-3.5-flash"], 0.76)
|
|
1375
|
+
);
|
|
1376
|
+
}
|
|
1377
|
+
if (terminalToolSignal && !terminalSafetySensitive) {
|
|
1378
|
+
return Math.max(
|
|
1379
|
+
base,
|
|
1380
|
+
match(["gpt-5-mini"], 1),
|
|
1381
|
+
match(["gpt-5.3-codex"], 0.98),
|
|
1382
|
+
match(["claude-sonnet-5"], 0.9),
|
|
1383
|
+
match(["gemini-3.5-flash"], 0.89)
|
|
1384
|
+
);
|
|
1385
|
+
}
|
|
1386
|
+
if (terminalToolSignal && terminalSafetySensitive) {
|
|
1387
|
+
return Math.max(
|
|
1388
|
+
base,
|
|
1389
|
+
match(["claude-sonnet-5"], 1),
|
|
1390
|
+
match(["claude-opus-4.8"], 0.9),
|
|
1391
|
+
match(["gpt-5.3-codex"], 0.84)
|
|
1392
|
+
);
|
|
1393
|
+
}
|
|
1394
|
+
if (agentDomain === "web_research") {
|
|
1395
|
+
return deepWebResearch ? Math.max(
|
|
1396
|
+
base,
|
|
1397
|
+
match(["claude-sonnet-5"], 1),
|
|
1398
|
+
match(["gpt-5-mini"], 0.88),
|
|
1399
|
+
match(["gemini-3.5-flash"], 0.84),
|
|
1400
|
+
match(["claude-opus-5"], 0.8),
|
|
1401
|
+
match(["claude-opus-4.8"], 0.78)
|
|
1402
|
+
) : Math.max(
|
|
1403
|
+
base,
|
|
1404
|
+
match(["claude-sonnet-5"], 1),
|
|
1405
|
+
match(["gpt-5-mini"], 0.88),
|
|
1406
|
+
match(["gemini-3.5-flash"], 0.86),
|
|
1407
|
+
match(["claude-opus-5"], 0.84),
|
|
1408
|
+
match(["claude-opus-4.8"], 0.82)
|
|
1409
|
+
);
|
|
1410
|
+
}
|
|
1411
|
+
if (agentDomain === "retail") {
|
|
1412
|
+
if (agentRisk === "standard") {
|
|
1413
|
+
return Math.max(
|
|
1414
|
+
base,
|
|
1415
|
+
match(["gpt-5-mini"], 1),
|
|
1416
|
+
match(["claude-sonnet-5"], 0.88),
|
|
1417
|
+
match(["gemini-3.5-flash"], 0.82),
|
|
1418
|
+
match(["gpt-5.3-codex"], 0.81),
|
|
1419
|
+
match(["kimi-k3"], 0.78),
|
|
1420
|
+
match(["deepseek-v4-pro"], 0.76)
|
|
1421
|
+
);
|
|
1422
|
+
}
|
|
1423
|
+
if (agentRisk === "policy_exception") {
|
|
1424
|
+
return Math.max(
|
|
1425
|
+
base,
|
|
1426
|
+
match(["gpt-4.1"], 1),
|
|
1427
|
+
match(["claude-sonnet-5"], 0.9),
|
|
1428
|
+
match(["deepseek-v4-pro"], 0.82),
|
|
1429
|
+
match(["gpt-5-mini"], 0.8),
|
|
1430
|
+
match(["gpt-4o-mini"], 0.76)
|
|
1431
|
+
);
|
|
1432
|
+
}
|
|
1433
|
+
if (agentRisk === "policy_exception_simple") {
|
|
1434
|
+
return Math.max(
|
|
1435
|
+
base,
|
|
1436
|
+
match(["gpt-5-mini"], 1),
|
|
1437
|
+
match(["gpt-4.1"], 0.86),
|
|
1438
|
+
match(["deepseek-v4-pro"], 0.82),
|
|
1439
|
+
match(["gpt-4o-mini"], 0.8)
|
|
1440
|
+
);
|
|
1441
|
+
}
|
|
1442
|
+
return Math.max(
|
|
1443
|
+
base,
|
|
1444
|
+
match(["deepseek-v4-pro"], 1),
|
|
1445
|
+
match(["claude-sonnet-5"], 0.88),
|
|
1446
|
+
match(["gemini-3.5-flash"], 0.82),
|
|
1447
|
+
match(["gpt-5.3-codex"], 0.81),
|
|
1448
|
+
match(["kimi-k3"], 0.78),
|
|
1449
|
+
match(["gpt-5-mini"], 0.76)
|
|
1450
|
+
);
|
|
1451
|
+
}
|
|
1452
|
+
if (agentDomain === "airline") {
|
|
1453
|
+
if (agentRisk === "complex_high") {
|
|
1454
|
+
return Math.max(
|
|
1455
|
+
base,
|
|
1456
|
+
match(["claude-sonnet-5"], 1),
|
|
1457
|
+
match(["gpt-5-mini"], 0.78),
|
|
1458
|
+
match(["gemini-3.5-flash"], 0.76),
|
|
1459
|
+
match(["deepseek-v4-pro"], 0.74)
|
|
1460
|
+
);
|
|
1461
|
+
}
|
|
1462
|
+
return Math.max(
|
|
1463
|
+
base,
|
|
1464
|
+
match(["gpt-5-mini"], 1),
|
|
1465
|
+
match(["claude-sonnet-5"], 0.9),
|
|
1466
|
+
match(["gemini-3.5-flash"], 0.8),
|
|
1467
|
+
match(["deepseek-v4-pro"], 0.76)
|
|
1468
|
+
);
|
|
1469
|
+
}
|
|
1470
|
+
return Math.max(
|
|
1471
|
+
base,
|
|
1472
|
+
match(["claude-sonnet-5"], 1),
|
|
1473
|
+
match(["gemini-3.5-flash"], 0.88),
|
|
1474
|
+
match(["gpt-5.3-codex"], 0.87),
|
|
1475
|
+
match(["gpt-5-mini"], 0.84),
|
|
1476
|
+
match(["kimi-k3"], 0.85),
|
|
1477
|
+
match(["deepseek-v4-pro"], 0.82)
|
|
1478
|
+
);
|
|
1479
|
+
case "tool_agent_parallel":
|
|
1480
|
+
if (terminalToolSignal) {
|
|
1481
|
+
return terminalSafetySensitive ? Math.max(
|
|
1482
|
+
base,
|
|
1483
|
+
match(["claude-sonnet-5"], 1),
|
|
1484
|
+
match(["claude-opus-4.8"], 0.9),
|
|
1485
|
+
match(["gpt-5.3-codex"], 0.86)
|
|
1486
|
+
) : Math.max(
|
|
1487
|
+
base,
|
|
1488
|
+
match(["gpt-5-mini"], 1),
|
|
1489
|
+
match(["gpt-5.3-codex"], 0.98),
|
|
1490
|
+
match(["claude-sonnet-5"], 0.92),
|
|
1491
|
+
match(["gemini-3.5-flash"], 0.88)
|
|
1492
|
+
);
|
|
1493
|
+
}
|
|
1494
|
+
if (agentDomain === "web_research") {
|
|
1495
|
+
return deepWebResearch ? Math.max(
|
|
1496
|
+
base,
|
|
1497
|
+
match(["claude-sonnet-5"], 1),
|
|
1498
|
+
match(["gpt-5-mini"], 0.88),
|
|
1499
|
+
match(["gemini-3.5-flash"], 0.84),
|
|
1500
|
+
match(["claude-opus-5"], 0.8),
|
|
1501
|
+
match(["claude-opus-4.8"], 0.78)
|
|
1502
|
+
) : Math.max(
|
|
1503
|
+
base,
|
|
1504
|
+
match(["claude-sonnet-5"], 1),
|
|
1505
|
+
match(["gpt-5-mini"], 0.88),
|
|
1506
|
+
match(["gemini-3.5-flash"], 0.86),
|
|
1507
|
+
match(["claude-opus-5"], 0.84),
|
|
1508
|
+
match(["claude-opus-4.8"], 0.82)
|
|
1509
|
+
);
|
|
1510
|
+
}
|
|
1511
|
+
if (agentDomain === "retail") {
|
|
1512
|
+
if (agentRisk === "policy_exception") {
|
|
1513
|
+
return Math.max(
|
|
1514
|
+
base,
|
|
1515
|
+
match(["gpt-4.1"], 1),
|
|
1516
|
+
match(["claude-sonnet-5"], 0.9),
|
|
1517
|
+
match(["deepseek-v4-pro"], 0.82),
|
|
1518
|
+
match(["gpt-5-mini"], 0.8),
|
|
1519
|
+
match(["gpt-4o-mini"], 0.76)
|
|
1520
|
+
);
|
|
1521
|
+
}
|
|
1522
|
+
if (agentRisk === "policy_exception_simple") {
|
|
1523
|
+
return Math.max(
|
|
1524
|
+
base,
|
|
1525
|
+
match(["gpt-5-mini"], 1),
|
|
1526
|
+
match(["gpt-4.1"], 0.86),
|
|
1527
|
+
match(["deepseek-v4-pro"], 0.82),
|
|
1528
|
+
match(["gpt-4o-mini"], 0.8)
|
|
1529
|
+
);
|
|
1530
|
+
}
|
|
1531
|
+
return Math.max(
|
|
1532
|
+
base,
|
|
1533
|
+
match(["deepseek-v4-pro"], 1),
|
|
1534
|
+
match(["claude-sonnet-5"], 0.88),
|
|
1535
|
+
match(["claude-opus-4.8"], 0.84),
|
|
1536
|
+
match(["gpt-5-mini"], 0.78),
|
|
1537
|
+
match(["gemini-3.5-flash"], 0.76)
|
|
1538
|
+
);
|
|
1539
|
+
}
|
|
1540
|
+
if (agentDomain === "airline") {
|
|
1541
|
+
return agentRisk === "complex_high" ? Math.max(
|
|
1542
|
+
base,
|
|
1543
|
+
match(["claude-sonnet-5"], 1),
|
|
1544
|
+
match(["gpt-5-mini"], 0.78),
|
|
1545
|
+
match(["claude-opus-4.8"], 0.76),
|
|
1546
|
+
match(["gemini-3.5-flash"], 0.74)
|
|
1547
|
+
) : Math.max(
|
|
1548
|
+
base,
|
|
1549
|
+
match(["gpt-5-mini"], 1),
|
|
1550
|
+
match(["claude-sonnet-5"], 0.9),
|
|
1551
|
+
match(["gemini-3.5-flash"], 0.8)
|
|
1552
|
+
);
|
|
1553
|
+
}
|
|
1554
|
+
return Math.max(
|
|
1555
|
+
base,
|
|
1556
|
+
match(["claude-opus-4.8"], 1),
|
|
1557
|
+
match(["claude-sonnet-5"], 0.84),
|
|
1558
|
+
match(["grok-4.5"], 0.82),
|
|
1559
|
+
match(["gemini-3.5-flash"], 0.8),
|
|
1560
|
+
match(["deepseek-v4-pro"], 0.78)
|
|
1561
|
+
);
|
|
1562
|
+
case "code_edit":
|
|
1563
|
+
case "debug":
|
|
1564
|
+
return Math.max(
|
|
1565
|
+
base,
|
|
1566
|
+
match(["gpt-5.3-codex"], 1),
|
|
1567
|
+
match(["claude-sonnet-4.6"], 0.94),
|
|
1568
|
+
match(["glm-5.2"], 0.9),
|
|
1569
|
+
match(["kimi-k2.7", "deepseek-v4-pro"], 0.86)
|
|
1570
|
+
);
|
|
1571
|
+
case "reasoning":
|
|
1572
|
+
return Math.max(
|
|
1573
|
+
base,
|
|
1574
|
+
match(["claude-sonnet-5", "claude-sonnet-4.6"], 0.98),
|
|
1575
|
+
match(["deepseek-v4-pro"], 0.95),
|
|
1576
|
+
match(["grok-4.5"], 0.94),
|
|
1577
|
+
match(["gemini-3.1-pro", "gemini-3.5-flash"], 0.92)
|
|
1578
|
+
);
|
|
1579
|
+
case "reasoning_mcq":
|
|
1580
|
+
return Math.max(
|
|
1581
|
+
base,
|
|
1582
|
+
match(["gemini-3-flash-preview"], 1),
|
|
1583
|
+
match(["gemini-3.5-flash"], 0.91),
|
|
1584
|
+
match(["grok-4.5"], 0.9),
|
|
1585
|
+
match(["claude-sonnet-5"], 0.88),
|
|
1586
|
+
match(["deepseek-v4-pro"], 0.84)
|
|
1587
|
+
);
|
|
1588
|
+
case "reasoning_math":
|
|
1589
|
+
return Math.max(
|
|
1590
|
+
base,
|
|
1591
|
+
match(["gemini-3.5-flash"], 1),
|
|
1592
|
+
match(["grok-4.5"], 0.93),
|
|
1593
|
+
match(["claude-sonnet-5", "deepseek-v4-pro", "kimi-k3"], 0.9),
|
|
1594
|
+
match(["kimi-k2.7"], 0.84)
|
|
1595
|
+
);
|
|
1596
|
+
case "vision":
|
|
1597
|
+
return Math.max(
|
|
1598
|
+
base,
|
|
1599
|
+
match(["gemini-3.1-pro"], 0.96),
|
|
1600
|
+
match(["qwen3.7-max", "claude-sonnet-4.6", "kimi-k2.7", "grok-4.3"], 0.9)
|
|
1601
|
+
);
|
|
1602
|
+
case "long_context":
|
|
1603
|
+
return Math.max(
|
|
1604
|
+
base,
|
|
1605
|
+
match(["gemini-3.1-pro"], 1),
|
|
1606
|
+
match(["qwen3.7-max", "glm-5.2"], 0.89),
|
|
1607
|
+
match(["gemini-3.5-flash"], 0.88),
|
|
1608
|
+
match(["deepseek-v4-pro"], 0.85)
|
|
1609
|
+
);
|
|
1610
|
+
case "extraction": {
|
|
1611
|
+
const kimiExtractionAffinity = language === "zh" ? 1 : 0.9;
|
|
1612
|
+
return Math.max(
|
|
1613
|
+
base,
|
|
1614
|
+
match(["gemini-3.5-flash", "gemini-2.5-flash", "gpt-4o-mini"], 0.9),
|
|
1615
|
+
match(["claude-sonnet-5", "claude-sonnet-4.6"], 0.9),
|
|
1616
|
+
match(["kimi-k3", "kimi-k2.7"], kimiExtractionAffinity)
|
|
1617
|
+
);
|
|
1618
|
+
}
|
|
1619
|
+
default:
|
|
1620
|
+
return Math.max(
|
|
1621
|
+
base,
|
|
1622
|
+
match(["gemini-3.5-flash", "gemini-2.5-flash", "kimi-k3", "kimi-k2.7"], 0.86)
|
|
1623
|
+
);
|
|
1624
|
+
}
|
|
1625
|
+
}
|
|
1626
|
+
function evidenceCandidates(task) {
|
|
1627
|
+
if (task === "code_agent") {
|
|
1628
|
+
return [
|
|
1629
|
+
"openai/gpt-5.3-codex",
|
|
1630
|
+
"anthropic/claude-sonnet-5",
|
|
1631
|
+
"openai/gpt-5-mini",
|
|
1632
|
+
"google/gemini-3.5-flash",
|
|
1633
|
+
"moonshot/kimi-k3",
|
|
1634
|
+
"deepseek/deepseek-v4-pro"
|
|
1635
|
+
];
|
|
1636
|
+
}
|
|
1637
|
+
if (task === "tool_agent") {
|
|
1638
|
+
return [
|
|
1639
|
+
"anthropic/claude-sonnet-5",
|
|
1640
|
+
"anthropic/claude-opus-5",
|
|
1641
|
+
"openai/gpt-5-mini",
|
|
1642
|
+
"openai/gpt-4.1",
|
|
1643
|
+
"openai/gpt-4o-mini",
|
|
1644
|
+
"google/gemini-3.5-flash",
|
|
1645
|
+
"openai/gpt-5.3-codex",
|
|
1646
|
+
"moonshot/kimi-k3",
|
|
1647
|
+
"deepseek/deepseek-v4-pro"
|
|
1648
|
+
];
|
|
1649
|
+
}
|
|
1650
|
+
if (task === "tool_agent_parallel") {
|
|
1651
|
+
return [
|
|
1652
|
+
"anthropic/claude-opus-5",
|
|
1653
|
+
"anthropic/claude-opus-4.8",
|
|
1654
|
+
"anthropic/claude-sonnet-5",
|
|
1655
|
+
"openai/gpt-5-mini",
|
|
1656
|
+
"openai/gpt-4.1",
|
|
1657
|
+
"openai/gpt-4o-mini",
|
|
1658
|
+
"xai/grok-4.5",
|
|
1659
|
+
"google/gemini-3.5-flash",
|
|
1660
|
+
"deepseek/deepseek-v4-pro"
|
|
1661
|
+
];
|
|
1662
|
+
}
|
|
1663
|
+
if (task === "long_context") {
|
|
1664
|
+
return [
|
|
1665
|
+
"google/gemini-3.1-pro",
|
|
1666
|
+
"deepseek/deepseek-v4-pro",
|
|
1667
|
+
"qwen/qwen3.7-max",
|
|
1668
|
+
"zai/glm-5.2",
|
|
1669
|
+
"google/gemini-3.5-flash"
|
|
1670
|
+
];
|
|
1671
|
+
}
|
|
1672
|
+
if (task === "reasoning_mcq") {
|
|
1673
|
+
return [
|
|
1674
|
+
"google/gemini-3-flash-preview",
|
|
1675
|
+
"google/gemini-3.5-flash",
|
|
1676
|
+
"xai/grok-4.5",
|
|
1677
|
+
"anthropic/claude-sonnet-5",
|
|
1678
|
+
"deepseek/deepseek-v4-pro"
|
|
1679
|
+
];
|
|
1680
|
+
}
|
|
1681
|
+
if (task === "reasoning_math") {
|
|
1682
|
+
return [
|
|
1683
|
+
"google/gemini-3.5-flash",
|
|
1684
|
+
"xai/grok-4.5",
|
|
1685
|
+
"anthropic/claude-sonnet-5",
|
|
1686
|
+
"deepseek/deepseek-v4-pro",
|
|
1687
|
+
"moonshot/kimi-k3"
|
|
1688
|
+
];
|
|
1689
|
+
}
|
|
1690
|
+
return [];
|
|
1691
|
+
}
|
|
1692
|
+
function isEligible(modelId, features, maxOutputTokens, options) {
|
|
1693
|
+
const model = options.modelCapabilities?.[modelId] ?? DEFAULT_MODEL_CAPABILITIES[modelId];
|
|
1694
|
+
if (!model) return true;
|
|
1695
|
+
if (features.needsTools && !model.supportsTools) return false;
|
|
1696
|
+
if (features.needsVision && !model.supportsVision) return false;
|
|
1697
|
+
if (features.needsStructuredOutput && !model.supportsTools) return false;
|
|
1698
|
+
if (model.maxOutputTokens < maxOutputTokens) return false;
|
|
1699
|
+
return model.contextWindow >= (features.estimatedInputTokens + maxOutputTokens) * 1.1;
|
|
1700
|
+
}
|
|
1701
|
+
function estimatedCost(modelId, options, inputTokens, outputTokens) {
|
|
1702
|
+
const price = options.modelPricing.get(modelId);
|
|
1703
|
+
if (!price) return Number.POSITIVE_INFINITY;
|
|
1704
|
+
if (price.flatPrice !== void 0) return price.flatPrice;
|
|
1705
|
+
return (inputTokens * price.inputPrice + outputTokens * price.outputPrice) / 1e6;
|
|
1706
|
+
}
|
|
1707
|
+
function profileScore(modelId, options, now) {
|
|
1708
|
+
const profile = options.modelPerformance?.[modelId] ?? LIVE_MODEL_PROFILES[modelId] ?? HISTORICAL_MODEL_PROFILES[modelId];
|
|
1709
|
+
if (!profile) return void 0;
|
|
1710
|
+
const measuredAt = Date.parse(profile.measuredAt);
|
|
1711
|
+
if (!Number.isFinite(measuredAt)) return void 0;
|
|
1712
|
+
const ageDays = Math.max(0, (now.getTime() - measuredAt) / 864e5);
|
|
1713
|
+
const sampleConfidence = profile.samples === void 0 ? 1 : Math.min(1, Math.max(0, profile.samples) / 10);
|
|
1714
|
+
const freshness = Math.pow(0.5, ageDays / 30) * sampleConfidence;
|
|
1715
|
+
const quality = profile.intelligenceIndex === void 0 ? void 0 : Math.min(1, profile.intelligenceIndex / 50);
|
|
1716
|
+
const speed = Math.min(
|
|
1717
|
+
1,
|
|
1718
|
+
(2e3 / Math.max(500, profile.latencyMs) + profile.outputTokensPerSecond / 250) / 2
|
|
1719
|
+
);
|
|
1720
|
+
const tailSpeed = Math.min(1, 3e3 / Math.max(750, profile.p95LatencyMs ?? profile.latencyMs));
|
|
1721
|
+
const reliability = Math.max(0, 1 - (profile.errorRate ?? 0));
|
|
1722
|
+
return { quality, speed, tailSpeed, reliability, freshness };
|
|
1723
|
+
}
|
|
1724
|
+
var PortfolioStrategy = class {
|
|
1725
|
+
name = "portfolio";
|
|
1726
|
+
route(prompt, systemPrompt, maxOutputTokens, options) {
|
|
1727
|
+
const features = classifyTask(prompt, systemPrompt, options);
|
|
1728
|
+
const base = new RulesStrategy().route(prompt, systemPrompt, maxOutputTokens, {
|
|
1729
|
+
...options,
|
|
1730
|
+
requiresTools: features.needsTools
|
|
1731
|
+
});
|
|
1732
|
+
const tierConfigs = base.tierConfigs;
|
|
1733
|
+
if (!tierConfigs) return base;
|
|
1734
|
+
const targetTier = (features.taskType === "reasoning_mcq" || features.taskType === "reasoning_math") && (base.tier === "SIMPLE" || base.tier === "MEDIUM") ? "REASONING" : base.tier;
|
|
1735
|
+
const tierConfig = tierConfigs[targetTier];
|
|
1736
|
+
const configuredCandidates = tierConfig ? getFallbackChain(targetTier, tierConfigs) : [];
|
|
1737
|
+
const chain = [
|
|
1738
|
+
.../* @__PURE__ */ new Set([...configuredCandidates, ...evidenceCandidates(features.taskType)])
|
|
1739
|
+
].filter((model2) => typeof model2 === "string" && model2.length > 0);
|
|
1740
|
+
const eligible = chain.filter(
|
|
1741
|
+
(model2) => isEligible(model2, features, maxOutputTokens, options)
|
|
1742
|
+
);
|
|
1743
|
+
const eligibleCandidates = eligible.length > 0 ? eligible : chain;
|
|
1744
|
+
if (eligibleCandidates.length === 0) return base;
|
|
1745
|
+
const profileName = options.routingProfile === "eco" ? "eco" : options.routingProfile === "premium" ? "premium" : "auto";
|
|
1746
|
+
const portfolio = options.config.portfolio ?? DEFAULT_PORTFOLIO_WEIGHTS;
|
|
1747
|
+
const getAffinity = (model2) => affinity(
|
|
1748
|
+
model2,
|
|
1749
|
+
features.taskType,
|
|
1750
|
+
features.language,
|
|
1751
|
+
features.agentDomain,
|
|
1752
|
+
features.deepWebResearch,
|
|
1753
|
+
features.agentRisk,
|
|
1754
|
+
features.terminalToolSignal,
|
|
1755
|
+
features.terminalSafetySensitive
|
|
1756
|
+
);
|
|
1757
|
+
const bestAffinity = Math.max(...eligibleCandidates.map(getAffinity));
|
|
1758
|
+
const specificAffinity = eligibleCandidates.filter((model2) => getAffinity(model2) > 0.68);
|
|
1759
|
+
const affinityPool = specificAffinity.length > 0 ? specificAffinity : [eligibleCandidates[0]];
|
|
1760
|
+
const affinityFloorGap = features.terminalToolSignal ? Math.max(
|
|
1761
|
+
portfolio.affinityFloorGap[profileName],
|
|
1762
|
+
features.terminalSafetySensitive ? 0.15 : 0.12
|
|
1763
|
+
) : portfolio.affinityFloorGap[profileName];
|
|
1764
|
+
const candidates = affinityPool.filter(
|
|
1765
|
+
(model2) => getAffinity(model2) >= bestAffinity - affinityFloorGap
|
|
1766
|
+
);
|
|
1767
|
+
const costs = candidates.map(
|
|
1768
|
+
(model2) => estimatedCost(model2, options, features.estimatedInputTokens, maxOutputTokens)
|
|
1769
|
+
);
|
|
1770
|
+
const finiteCosts = costs.filter(Number.isFinite);
|
|
1771
|
+
const minCost = finiteCosts.length > 0 ? Math.min(...finiteCosts) : 0;
|
|
1772
|
+
const maxCost = finiteCosts.length > 0 ? Math.max(...finiteCosts) : 1;
|
|
1773
|
+
const now = options.now ?? /* @__PURE__ */ new Date();
|
|
1774
|
+
const profileWeights = portfolio[profileName];
|
|
1775
|
+
const rankedEntries = candidates.map((model2, index) => {
|
|
1776
|
+
const cost = estimatedCost(model2, options, features.estimatedInputTokens, maxOutputTokens);
|
|
1777
|
+
const costScore = Number.isFinite(cost) && maxCost > minCost ? 1 - (cost - minCost) / (maxCost - minCost) : 0.5;
|
|
1778
|
+
const capabilityScore = isEligible(model2, features, maxOutputTokens, options) ? 1 : 0;
|
|
1779
|
+
const profile = profileScore(model2, options, now);
|
|
1780
|
+
const observedQuality = profile?.quality === void 0 ? getAffinity(model2) : getAffinity(model2) * (1 - profile.freshness) + profile.quality * profile.freshness;
|
|
1781
|
+
const observedSpeed = profile ? profile.speed * profile.freshness : 0.5;
|
|
1782
|
+
const observedTailSpeed = profile ? profile.tailSpeed * profile.freshness : 0.5;
|
|
1783
|
+
const observedReliability = profile ? profile.reliability * profile.freshness + (1 - profile.freshness) : 1;
|
|
1784
|
+
const legacyScore = 1 - index / Math.max(1, candidates.length - 1);
|
|
1785
|
+
const qualityWeight = profileWeights.quality + (features.highStakes ? portfolio.highStakesBoost.quality : 0);
|
|
1786
|
+
const speedScore = features.latencySensitive ? observedTailSpeed : observedSpeed;
|
|
1787
|
+
const speedWeight = profileWeights.speed + (features.latencySensitive ? portfolio.latencySensitiveSpeedBoost : 0);
|
|
1788
|
+
const reliabilityWeight = profileWeights.reliability + (features.highStakes ? portfolio.highStakesBoost.reliability : 0);
|
|
1789
|
+
const score = observedQuality * qualityWeight + capabilityScore * profileWeights.capability + costScore * profileWeights.cost + speedScore * speedWeight + observedReliability * reliabilityWeight + legacyScore * profileWeights.legacy;
|
|
1790
|
+
return {
|
|
1791
|
+
model: model2,
|
|
1792
|
+
score,
|
|
1793
|
+
quality: observedQuality,
|
|
1794
|
+
cost: costScore,
|
|
1795
|
+
speed: speedScore,
|
|
1796
|
+
reliability: observedReliability
|
|
1797
|
+
};
|
|
1798
|
+
}).sort((a, b) => b.score - a.score);
|
|
1799
|
+
const scoredModels = rankedEntries.map((item) => item.model);
|
|
1800
|
+
const webResearchFallbackOrder = [
|
|
1801
|
+
"anthropic/claude-sonnet-5",
|
|
1802
|
+
"openai/gpt-5-mini",
|
|
1803
|
+
"google/gemini-3.5-flash",
|
|
1804
|
+
"anthropic/claude-opus-5",
|
|
1805
|
+
"anthropic/claude-opus-4.8",
|
|
1806
|
+
"openai/gpt-5.3-codex"
|
|
1807
|
+
];
|
|
1808
|
+
const ranked = features.agentDomain === "web_research" ? [
|
|
1809
|
+
...scoredModels,
|
|
1810
|
+
...webResearchFallbackOrder.filter(
|
|
1811
|
+
(model2) => eligibleCandidates.includes(model2) && !scoredModels.includes(model2)
|
|
1812
|
+
),
|
|
1813
|
+
...eligibleCandidates.filter(
|
|
1814
|
+
(model2) => !scoredModels.includes(model2) && !webResearchFallbackOrder.includes(model2)
|
|
1815
|
+
)
|
|
1816
|
+
] : features.taskType === "tool_agent" || features.taskType === "tool_agent_parallel" && features.agentDomain !== "other" ? [
|
|
1817
|
+
...scoredModels,
|
|
1818
|
+
...eligibleCandidates.filter((model2) => !scoredModels.includes(model2))
|
|
1819
|
+
] : [
|
|
1820
|
+
...scoredModels,
|
|
1821
|
+
...eligibleCandidates.filter((model2) => !scoredModels.includes(model2))
|
|
1822
|
+
];
|
|
1823
|
+
const model = ranked[0] ?? base.model;
|
|
1824
|
+
const selectedTierConfigs = {
|
|
1825
|
+
...tierConfigs,
|
|
1826
|
+
[targetTier]: { primary: model, fallback: ranked.slice(1) }
|
|
1827
|
+
};
|
|
1828
|
+
const decision = selectModel(
|
|
1829
|
+
targetTier,
|
|
1830
|
+
base.confidence,
|
|
1831
|
+
"portfolio",
|
|
1832
|
+
`${base.reasoning} | v3 task=${features.taskType} agentRisk=${features.agentRisk} deepWebResearch=${features.deepWebResearch} terminalCode=${features.implicitTerminalCode} terminalSafety=${features.terminalSafetySensitive} candidates=${ranked.length}`,
|
|
1833
|
+
selectedTierConfigs,
|
|
1834
|
+
options.modelPricing,
|
|
1835
|
+
features.estimatedInputTokens,
|
|
1836
|
+
maxOutputTokens,
|
|
1837
|
+
options.routingProfile,
|
|
1838
|
+
base.agenticScore
|
|
1839
|
+
);
|
|
1840
|
+
return {
|
|
1841
|
+
...decision,
|
|
1842
|
+
tierConfigs: selectedTierConfigs,
|
|
1843
|
+
profile: base.profile,
|
|
1844
|
+
candidates: ranked,
|
|
1845
|
+
candidateScores: rankedEntries.map(({ model: model2, score, quality, cost, speed, reliability }) => ({
|
|
1846
|
+
model: model2,
|
|
1847
|
+
score,
|
|
1848
|
+
quality,
|
|
1849
|
+
cost,
|
|
1850
|
+
speed,
|
|
1851
|
+
reliability
|
|
1852
|
+
})),
|
|
1853
|
+
taskType: features.taskType,
|
|
1854
|
+
routerVersion: "v3-portfolio"
|
|
1855
|
+
};
|
|
1856
|
+
}
|
|
1857
|
+
};
|
|
1858
|
+
var DEFAULT_ROUTING_CONFIG = {
|
|
1859
|
+
version: "3.4",
|
|
1860
|
+
strategy: "portfolio",
|
|
1861
|
+
portfolio: {
|
|
1862
|
+
auto: {
|
|
1863
|
+
quality: 0.47,
|
|
1864
|
+
capability: 0.2,
|
|
1865
|
+
cost: 0.18,
|
|
1866
|
+
speed: 0.07,
|
|
1867
|
+
reliability: 0.03,
|
|
1868
|
+
legacy: 0.05
|
|
1869
|
+
},
|
|
1870
|
+
eco: {
|
|
1871
|
+
quality: 0.36,
|
|
1872
|
+
capability: 0.2,
|
|
1873
|
+
cost: 0.28,
|
|
1874
|
+
speed: 0.1,
|
|
1875
|
+
reliability: 0.04,
|
|
1876
|
+
legacy: 0.02
|
|
1877
|
+
},
|
|
1878
|
+
premium: {
|
|
1879
|
+
quality: 0.58,
|
|
1880
|
+
capability: 0.2,
|
|
1881
|
+
cost: 0.08,
|
|
1882
|
+
speed: 0.06,
|
|
1883
|
+
reliability: 0.06,
|
|
1884
|
+
legacy: 0.02
|
|
1885
|
+
},
|
|
1886
|
+
highStakesBoost: { quality: 0.08, reliability: 0.05 },
|
|
1887
|
+
latencySensitiveSpeedBoost: 0.08,
|
|
1888
|
+
affinityFloorGap: { auto: 0.1, eco: 0.22, premium: 0.05 }
|
|
1889
|
+
},
|
|
1890
|
+
classifier: {
|
|
1891
|
+
llmModel: "google/gemini-2.5-flash",
|
|
1892
|
+
llmMaxTokens: 10,
|
|
1893
|
+
llmTemperature: 0,
|
|
1894
|
+
promptTruncationChars: 500,
|
|
1895
|
+
cacheTtlMs: 36e5
|
|
1896
|
+
// 1 hour
|
|
1897
|
+
},
|
|
1898
|
+
scoring: {
|
|
1899
|
+
tokenCountThresholds: { simple: 50, complex: 500 },
|
|
1900
|
+
// Multilingual keywords: EN + ZH + JA + RU + DE + ES + PT + KO + AR
|
|
1901
|
+
codeKeywords: [
|
|
1902
|
+
// English
|
|
1903
|
+
"function",
|
|
1904
|
+
"class",
|
|
1905
|
+
"import",
|
|
1906
|
+
"def",
|
|
1907
|
+
"SELECT",
|
|
1908
|
+
"async",
|
|
1909
|
+
"await",
|
|
1910
|
+
"const",
|
|
1911
|
+
"let",
|
|
1912
|
+
"var",
|
|
1913
|
+
"return",
|
|
1914
|
+
"```",
|
|
1915
|
+
// Chinese
|
|
1916
|
+
"\u51FD\u6570",
|
|
1917
|
+
"\u7C7B",
|
|
1918
|
+
"\u5BFC\u5165",
|
|
1919
|
+
"\u5B9A\u4E49",
|
|
1920
|
+
"\u67E5\u8BE2",
|
|
1921
|
+
"\u5F02\u6B65",
|
|
1922
|
+
"\u7B49\u5F85",
|
|
1923
|
+
"\u5E38\u91CF",
|
|
1924
|
+
"\u53D8\u91CF",
|
|
1925
|
+
"\u8FD4\u56DE",
|
|
1926
|
+
// Japanese
|
|
1927
|
+
"\u95A2\u6570",
|
|
1928
|
+
"\u30AF\u30E9\u30B9",
|
|
1929
|
+
"\u30A4\u30F3\u30DD\u30FC\u30C8",
|
|
1930
|
+
"\u975E\u540C\u671F",
|
|
1931
|
+
"\u5B9A\u6570",
|
|
1932
|
+
"\u5909\u6570",
|
|
1933
|
+
// Russian
|
|
1934
|
+
"\u0444\u0443\u043D\u043A\u0446\u0438\u044F",
|
|
1935
|
+
"\u043A\u043B\u0430\u0441\u0441",
|
|
1936
|
+
"\u0438\u043C\u043F\u043E\u0440\u0442",
|
|
1937
|
+
"\u043E\u043F\u0440\u0435\u0434\u0435\u043B",
|
|
1938
|
+
"\u0437\u0430\u043F\u0440\u043E\u0441",
|
|
1939
|
+
"\u0430\u0441\u0438\u043D\u0445\u0440\u043E\u043D\u043D\u044B\u0439",
|
|
1940
|
+
"\u043E\u0436\u0438\u0434\u0430\u0442\u044C",
|
|
1941
|
+
"\u043A\u043E\u043D\u0441\u0442\u0430\u043D\u0442\u0430",
|
|
1942
|
+
"\u043F\u0435\u0440\u0435\u043C\u0435\u043D\u043D\u0430\u044F",
|
|
1943
|
+
"\u0432\u0435\u0440\u043D\u0443\u0442\u044C",
|
|
1944
|
+
// German
|
|
1945
|
+
"funktion",
|
|
1946
|
+
"klasse",
|
|
1947
|
+
"importieren",
|
|
1948
|
+
"definieren",
|
|
1949
|
+
"abfrage",
|
|
1950
|
+
"asynchron",
|
|
1951
|
+
"erwarten",
|
|
1952
|
+
"konstante",
|
|
1953
|
+
"variable",
|
|
1954
|
+
"zur\xFCckgeben",
|
|
1955
|
+
// Spanish
|
|
1956
|
+
"funci\xF3n",
|
|
1957
|
+
"clase",
|
|
1958
|
+
"importar",
|
|
1959
|
+
"definir",
|
|
1960
|
+
"consulta",
|
|
1961
|
+
"as\xEDncrono",
|
|
1962
|
+
"esperar",
|
|
1963
|
+
"constante",
|
|
1964
|
+
"variable",
|
|
1965
|
+
"retornar",
|
|
1966
|
+
// Portuguese
|
|
1967
|
+
"fun\xE7\xE3o",
|
|
1968
|
+
"classe",
|
|
1969
|
+
"importar",
|
|
1970
|
+
"definir",
|
|
1971
|
+
"consulta",
|
|
1972
|
+
"ass\xEDncrono",
|
|
1973
|
+
"aguardar",
|
|
1974
|
+
"constante",
|
|
1975
|
+
"vari\xE1vel",
|
|
1976
|
+
"retornar",
|
|
1977
|
+
// Korean
|
|
1978
|
+
"\uD568\uC218",
|
|
1979
|
+
"\uD074\uB798\uC2A4",
|
|
1980
|
+
"\uAC00\uC838\uC624\uAE30",
|
|
1981
|
+
"\uC815\uC758",
|
|
1982
|
+
"\uCFFC\uB9AC",
|
|
1983
|
+
"\uBE44\uB3D9\uAE30",
|
|
1984
|
+
"\uB300\uAE30",
|
|
1985
|
+
"\uC0C1\uC218",
|
|
1986
|
+
"\uBCC0\uC218",
|
|
1987
|
+
"\uBC18\uD658",
|
|
1988
|
+
// Arabic
|
|
1989
|
+
"\u062F\u0627\u0644\u0629",
|
|
1990
|
+
"\u0641\u0626\u0629",
|
|
1991
|
+
"\u0627\u0633\u062A\u064A\u0631\u0627\u062F",
|
|
1992
|
+
"\u062A\u0639\u0631\u064A\u0641",
|
|
1993
|
+
"\u0627\u0633\u062A\u0639\u0644\u0627\u0645",
|
|
1994
|
+
"\u063A\u064A\u0631 \u0645\u062A\u0632\u0627\u0645\u0646",
|
|
1995
|
+
"\u0627\u0646\u062A\u0638\u0627\u0631",
|
|
1996
|
+
"\u062B\u0627\u0628\u062A",
|
|
1997
|
+
"\u0645\u062A\u063A\u064A\u0631",
|
|
1998
|
+
"\u0625\u0631\u062C\u0627\u0639"
|
|
1999
|
+
],
|
|
2000
|
+
reasoningKeywords: [
|
|
2001
|
+
// English
|
|
2002
|
+
"prove",
|
|
2003
|
+
"theorem",
|
|
2004
|
+
"derive",
|
|
2005
|
+
"step by step",
|
|
2006
|
+
"chain of thought",
|
|
2007
|
+
"formally",
|
|
2008
|
+
"mathematical",
|
|
2009
|
+
"proof",
|
|
2010
|
+
"logically",
|
|
2011
|
+
// Chinese
|
|
2012
|
+
"\u8BC1\u660E",
|
|
2013
|
+
"\u5B9A\u7406",
|
|
2014
|
+
"\u63A8\u5BFC",
|
|
2015
|
+
"\u9010\u6B65",
|
|
2016
|
+
"\u601D\u7EF4\u94FE",
|
|
2017
|
+
"\u5F62\u5F0F\u5316",
|
|
2018
|
+
"\u6570\u5B66",
|
|
2019
|
+
"\u903B\u8F91",
|
|
2020
|
+
// Japanese
|
|
2021
|
+
"\u8A3C\u660E",
|
|
2022
|
+
"\u5B9A\u7406",
|
|
2023
|
+
"\u5C0E\u51FA",
|
|
2024
|
+
"\u30B9\u30C6\u30C3\u30D7\u30D0\u30A4\u30B9\u30C6\u30C3\u30D7",
|
|
2025
|
+
"\u8AD6\u7406\u7684",
|
|
2026
|
+
// Russian
|
|
2027
|
+
"\u0434\u043E\u043A\u0430\u0437\u0430\u0442\u044C",
|
|
2028
|
+
"\u0434\u043E\u043A\u0430\u0436\u0438",
|
|
2029
|
+
"\u0434\u043E\u043A\u0430\u0437\u0430\u0442\u0435\u043B\u044C\u0441\u0442\u0432",
|
|
2030
|
+
"\u0442\u0435\u043E\u0440\u0435\u043C\u0430",
|
|
2031
|
+
"\u0432\u044B\u0432\u0435\u0441\u0442\u0438",
|
|
2032
|
+
"\u0448\u0430\u0433 \u0437\u0430 \u0448\u0430\u0433\u043E\u043C",
|
|
2033
|
+
"\u043F\u043E\u0448\u0430\u0433\u043E\u0432\u043E",
|
|
2034
|
+
"\u043F\u043E\u044D\u0442\u0430\u043F\u043D\u043E",
|
|
2035
|
+
"\u0446\u0435\u043F\u043E\u0447\u043A\u0430 \u0440\u0430\u0441\u0441\u0443\u0436\u0434\u0435\u043D\u0438\u0439",
|
|
2036
|
+
"\u0440\u0430\u0441\u0441\u0443\u0436\u0434\u0435\u043D\u0438",
|
|
2037
|
+
"\u0444\u043E\u0440\u043C\u0430\u043B\u044C\u043D\u043E",
|
|
2038
|
+
"\u043C\u0430\u0442\u0435\u043C\u0430\u0442\u0438\u0447\u0435\u0441\u043A\u0438",
|
|
2039
|
+
"\u043B\u043E\u0433\u0438\u0447\u0435\u0441\u043A\u0438",
|
|
2040
|
+
// German
|
|
2041
|
+
"beweisen",
|
|
2042
|
+
"beweis",
|
|
2043
|
+
"theorem",
|
|
2044
|
+
"ableiten",
|
|
2045
|
+
"schritt f\xFCr schritt",
|
|
2046
|
+
"gedankenkette",
|
|
2047
|
+
"formal",
|
|
2048
|
+
"mathematisch",
|
|
2049
|
+
"logisch",
|
|
2050
|
+
// Spanish
|
|
2051
|
+
"demostrar",
|
|
2052
|
+
"teorema",
|
|
2053
|
+
"derivar",
|
|
2054
|
+
"paso a paso",
|
|
2055
|
+
"cadena de pensamiento",
|
|
2056
|
+
"formalmente",
|
|
2057
|
+
"matem\xE1tico",
|
|
2058
|
+
"prueba",
|
|
2059
|
+
"l\xF3gicamente",
|
|
2060
|
+
// Portuguese
|
|
2061
|
+
"provar",
|
|
2062
|
+
"teorema",
|
|
2063
|
+
"derivar",
|
|
2064
|
+
"passo a passo",
|
|
2065
|
+
"cadeia de pensamento",
|
|
2066
|
+
"formalmente",
|
|
2067
|
+
"matem\xE1tico",
|
|
2068
|
+
"prova",
|
|
2069
|
+
"logicamente",
|
|
2070
|
+
// Korean
|
|
2071
|
+
"\uC99D\uBA85",
|
|
2072
|
+
"\uC815\uB9AC",
|
|
2073
|
+
"\uB3C4\uCD9C",
|
|
2074
|
+
"\uB2E8\uACC4\uBCC4",
|
|
2075
|
+
"\uC0AC\uACE0\uC758 \uC5F0\uC1C4",
|
|
2076
|
+
"\uD615\uC2DD\uC801",
|
|
2077
|
+
"\uC218\uD559\uC801",
|
|
2078
|
+
"\uB17C\uB9AC\uC801",
|
|
2079
|
+
// Arabic
|
|
2080
|
+
"\u0625\u062B\u0628\u0627\u062A",
|
|
2081
|
+
"\u0646\u0638\u0631\u064A\u0629",
|
|
2082
|
+
"\u0627\u0634\u062A\u0642\u0627\u0642",
|
|
2083
|
+
"\u062E\u0637\u0648\u0629 \u0628\u062E\u0637\u0648\u0629",
|
|
2084
|
+
"\u0633\u0644\u0633\u0644\u0629 \u0627\u0644\u062A\u0641\u0643\u064A\u0631",
|
|
2085
|
+
"\u0631\u0633\u0645\u064A\u0627\u064B",
|
|
2086
|
+
"\u0631\u064A\u0627\u0636\u064A",
|
|
2087
|
+
"\u0628\u0631\u0647\u0627\u0646",
|
|
2088
|
+
"\u0645\u0646\u0637\u0642\u064A\u0627\u064B"
|
|
2089
|
+
],
|
|
2090
|
+
simpleKeywords: [
|
|
2091
|
+
// English
|
|
2092
|
+
"what is",
|
|
2093
|
+
"define",
|
|
2094
|
+
"translate",
|
|
2095
|
+
"hello",
|
|
2096
|
+
"yes or no",
|
|
2097
|
+
"capital of",
|
|
2098
|
+
"how old",
|
|
2099
|
+
"who is",
|
|
2100
|
+
"when was",
|
|
2101
|
+
// Chinese
|
|
2102
|
+
"\u4EC0\u4E48\u662F",
|
|
2103
|
+
"\u5B9A\u4E49",
|
|
2104
|
+
"\u7FFB\u8BD1",
|
|
2105
|
+
"\u4F60\u597D",
|
|
2106
|
+
"\u662F\u5426",
|
|
2107
|
+
"\u9996\u90FD",
|
|
2108
|
+
"\u591A\u5927",
|
|
2109
|
+
"\u8C01\u662F",
|
|
2110
|
+
"\u4F55\u65F6",
|
|
2111
|
+
// Japanese
|
|
2112
|
+
"\u3068\u306F",
|
|
2113
|
+
"\u5B9A\u7FA9",
|
|
2114
|
+
"\u7FFB\u8A33",
|
|
2115
|
+
"\u3053\u3093\u306B\u3061\u306F",
|
|
2116
|
+
"\u306F\u3044\u304B\u3044\u3044\u3048",
|
|
2117
|
+
"\u9996\u90FD",
|
|
2118
|
+
"\u8AB0",
|
|
2119
|
+
// Russian
|
|
2120
|
+
"\u0447\u0442\u043E \u0442\u0430\u043A\u043E\u0435",
|
|
2121
|
+
"\u043E\u043F\u0440\u0435\u0434\u0435\u043B\u0435\u043D\u0438\u0435",
|
|
2122
|
+
"\u043F\u0435\u0440\u0435\u0432\u0435\u0441\u0442\u0438",
|
|
2123
|
+
"\u043F\u0435\u0440\u0435\u0432\u0435\u0434\u0438",
|
|
2124
|
+
"\u043F\u0440\u0438\u0432\u0435\u0442",
|
|
2125
|
+
"\u0434\u0430 \u0438\u043B\u0438 \u043D\u0435\u0442",
|
|
2126
|
+
"\u0441\u0442\u043E\u043B\u0438\u0446\u0430",
|
|
2127
|
+
"\u0441\u043A\u043E\u043B\u044C\u043A\u043E \u043B\u0435\u0442",
|
|
2128
|
+
"\u043A\u0442\u043E \u0442\u0430\u043A\u043E\u0439",
|
|
2129
|
+
"\u043A\u043E\u0433\u0434\u0430",
|
|
2130
|
+
"\u043E\u0431\u044A\u044F\u0441\u043D\u0438",
|
|
2131
|
+
// German
|
|
2132
|
+
"was ist",
|
|
2133
|
+
"definiere",
|
|
2134
|
+
"\xFCbersetze",
|
|
2135
|
+
"hallo",
|
|
2136
|
+
"ja oder nein",
|
|
2137
|
+
"hauptstadt",
|
|
2138
|
+
"wie alt",
|
|
2139
|
+
"wer ist",
|
|
2140
|
+
"wann",
|
|
2141
|
+
"erkl\xE4re",
|
|
2142
|
+
// Spanish
|
|
2143
|
+
"qu\xE9 es",
|
|
2144
|
+
"definir",
|
|
2145
|
+
"traducir",
|
|
2146
|
+
"hola",
|
|
2147
|
+
"s\xED o no",
|
|
2148
|
+
"capital de",
|
|
2149
|
+
"cu\xE1ntos a\xF1os",
|
|
2150
|
+
"qui\xE9n es",
|
|
2151
|
+
"cu\xE1ndo",
|
|
2152
|
+
// Portuguese
|
|
2153
|
+
"o que \xE9",
|
|
2154
|
+
"definir",
|
|
2155
|
+
"traduzir",
|
|
2156
|
+
"ol\xE1",
|
|
2157
|
+
"sim ou n\xE3o",
|
|
2158
|
+
"capital de",
|
|
2159
|
+
"quantos anos",
|
|
2160
|
+
"quem \xE9",
|
|
2161
|
+
"quando",
|
|
2162
|
+
// Korean
|
|
2163
|
+
"\uBB34\uC5C7",
|
|
2164
|
+
"\uC815\uC758",
|
|
2165
|
+
"\uBC88\uC5ED",
|
|
2166
|
+
"\uC548\uB155\uD558\uC138\uC694",
|
|
2167
|
+
"\uC608 \uB610\uB294 \uC544\uB2C8\uC624",
|
|
2168
|
+
"\uC218\uB3C4",
|
|
2169
|
+
"\uB204\uAD6C",
|
|
2170
|
+
"\uC5B8\uC81C",
|
|
2171
|
+
// Arabic
|
|
2172
|
+
"\u0645\u0627 \u0647\u0648",
|
|
2173
|
+
"\u062A\u0639\u0631\u064A\u0641",
|
|
2174
|
+
"\u062A\u0631\u062C\u0645",
|
|
2175
|
+
"\u0645\u0631\u062D\u0628\u0627",
|
|
2176
|
+
"\u0646\u0639\u0645 \u0623\u0648 \u0644\u0627",
|
|
2177
|
+
"\u0639\u0627\u0635\u0645\u0629",
|
|
2178
|
+
"\u0645\u0646 \u0647\u0648",
|
|
2179
|
+
"\u0645\u062A\u0649"
|
|
2180
|
+
],
|
|
2181
|
+
technicalKeywords: [
|
|
2182
|
+
// English
|
|
2183
|
+
"algorithm",
|
|
2184
|
+
"optimize",
|
|
2185
|
+
"architecture",
|
|
2186
|
+
"distributed",
|
|
2187
|
+
"kubernetes",
|
|
2188
|
+
"microservice",
|
|
2189
|
+
"database",
|
|
2190
|
+
"infrastructure",
|
|
2191
|
+
// Chinese
|
|
2192
|
+
"\u7B97\u6CD5",
|
|
2193
|
+
"\u4F18\u5316",
|
|
2194
|
+
"\u67B6\u6784",
|
|
2195
|
+
"\u5206\u5E03\u5F0F",
|
|
2196
|
+
"\u5FAE\u670D\u52A1",
|
|
2197
|
+
"\u6570\u636E\u5E93",
|
|
2198
|
+
"\u57FA\u7840\u8BBE\u65BD",
|
|
2199
|
+
// Japanese
|
|
2200
|
+
"\u30A2\u30EB\u30B4\u30EA\u30BA\u30E0",
|
|
2201
|
+
"\u6700\u9069\u5316",
|
|
2202
|
+
"\u30A2\u30FC\u30AD\u30C6\u30AF\u30C1\u30E3",
|
|
2203
|
+
"\u5206\u6563",
|
|
2204
|
+
"\u30DE\u30A4\u30AF\u30ED\u30B5\u30FC\u30D3\u30B9",
|
|
2205
|
+
"\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9",
|
|
2206
|
+
// Russian
|
|
2207
|
+
"\u0430\u043B\u0433\u043E\u0440\u0438\u0442\u043C",
|
|
2208
|
+
"\u043E\u043F\u0442\u0438\u043C\u0438\u0437\u0438\u0440\u043E\u0432\u0430\u0442\u044C",
|
|
2209
|
+
"\u043E\u043F\u0442\u0438\u043C\u0438\u0437\u0430\u0446\u0438",
|
|
2210
|
+
"\u043E\u043F\u0442\u0438\u043C\u0438\u0437\u0438\u0440\u0443\u0439",
|
|
2211
|
+
"\u0430\u0440\u0445\u0438\u0442\u0435\u043A\u0442\u0443\u0440\u0430",
|
|
2212
|
+
"\u0440\u0430\u0441\u043F\u0440\u0435\u0434\u0435\u043B\u0451\u043D\u043D\u044B\u0439",
|
|
2213
|
+
"\u043C\u0438\u043A\u0440\u043E\u0441\u0435\u0440\u0432\u0438\u0441",
|
|
2214
|
+
"\u0431\u0430\u0437\u0430 \u0434\u0430\u043D\u043D\u044B\u0445",
|
|
2215
|
+
"\u0438\u043D\u0444\u0440\u0430\u0441\u0442\u0440\u0443\u043A\u0442\u0443\u0440\u0430",
|
|
2216
|
+
// German
|
|
2217
|
+
"algorithmus",
|
|
2218
|
+
"optimieren",
|
|
2219
|
+
"architektur",
|
|
2220
|
+
"verteilt",
|
|
2221
|
+
"kubernetes",
|
|
2222
|
+
"mikroservice",
|
|
2223
|
+
"datenbank",
|
|
2224
|
+
"infrastruktur",
|
|
2225
|
+
// Spanish
|
|
2226
|
+
"algoritmo",
|
|
2227
|
+
"optimizar",
|
|
2228
|
+
"arquitectura",
|
|
2229
|
+
"distribuido",
|
|
2230
|
+
"microservicio",
|
|
2231
|
+
"base de datos",
|
|
2232
|
+
"infraestructura",
|
|
2233
|
+
// Portuguese
|
|
2234
|
+
"algoritmo",
|
|
2235
|
+
"otimizar",
|
|
2236
|
+
"arquitetura",
|
|
2237
|
+
"distribu\xEDdo",
|
|
2238
|
+
"microsservi\xE7o",
|
|
2239
|
+
"banco de dados",
|
|
2240
|
+
"infraestrutura",
|
|
2241
|
+
// Korean
|
|
2242
|
+
"\uC54C\uACE0\uB9AC\uC998",
|
|
2243
|
+
"\uCD5C\uC801\uD654",
|
|
2244
|
+
"\uC544\uD0A4\uD14D\uCC98",
|
|
2245
|
+
"\uBD84\uC0B0",
|
|
2246
|
+
"\uB9C8\uC774\uD06C\uB85C\uC11C\uBE44\uC2A4",
|
|
2247
|
+
"\uB370\uC774\uD130\uBCA0\uC774\uC2A4",
|
|
2248
|
+
"\uC778\uD504\uB77C",
|
|
2249
|
+
// Arabic
|
|
2250
|
+
"\u062E\u0648\u0627\u0631\u0632\u0645\u064A\u0629",
|
|
2251
|
+
"\u062A\u062D\u0633\u064A\u0646",
|
|
2252
|
+
"\u0628\u0646\u064A\u0629",
|
|
2253
|
+
"\u0645\u0648\u0632\u0639",
|
|
2254
|
+
"\u062E\u062F\u0645\u0629 \u0645\u0635\u063A\u0631\u0629",
|
|
2255
|
+
"\u0642\u0627\u0639\u062F\u0629 \u0628\u064A\u0627\u0646\u0627\u062A",
|
|
2256
|
+
"\u0628\u0646\u064A\u0629 \u062A\u062D\u062A\u064A\u0629"
|
|
2257
|
+
],
|
|
2258
|
+
creativeKeywords: [
|
|
2259
|
+
// English
|
|
2260
|
+
"story",
|
|
2261
|
+
"poem",
|
|
2262
|
+
"compose",
|
|
2263
|
+
"brainstorm",
|
|
2264
|
+
"creative",
|
|
2265
|
+
"imagine",
|
|
2266
|
+
"write a",
|
|
2267
|
+
// Chinese
|
|
2268
|
+
"\u6545\u4E8B",
|
|
2269
|
+
"\u8BD7",
|
|
2270
|
+
"\u521B\u4F5C",
|
|
2271
|
+
"\u5934\u8111\u98CE\u66B4",
|
|
2272
|
+
"\u521B\u610F",
|
|
2273
|
+
"\u60F3\u8C61",
|
|
2274
|
+
"\u5199\u4E00\u4E2A",
|
|
2275
|
+
// Japanese
|
|
2276
|
+
"\u7269\u8A9E",
|
|
2277
|
+
"\u8A69",
|
|
2278
|
+
"\u4F5C\u66F2",
|
|
2279
|
+
"\u30D6\u30EC\u30A4\u30F3\u30B9\u30C8\u30FC\u30E0",
|
|
2280
|
+
"\u5275\u9020\u7684",
|
|
2281
|
+
"\u60F3\u50CF",
|
|
2282
|
+
// Russian
|
|
2283
|
+
"\u0438\u0441\u0442\u043E\u0440\u0438\u044F",
|
|
2284
|
+
"\u0440\u0430\u0441\u0441\u043A\u0430\u0437",
|
|
2285
|
+
"\u0441\u0442\u0438\u0445\u043E\u0442\u0432\u043E\u0440\u0435\u043D\u0438\u0435",
|
|
2286
|
+
"\u0441\u043E\u0447\u0438\u043D\u0438\u0442\u044C",
|
|
2287
|
+
"\u0441\u043E\u0447\u0438\u043D\u0438",
|
|
2288
|
+
"\u043C\u043E\u0437\u0433\u043E\u0432\u043E\u0439 \u0448\u0442\u0443\u0440\u043C",
|
|
2289
|
+
"\u0442\u0432\u043E\u0440\u0447\u0435\u0441\u043A\u0438\u0439",
|
|
2290
|
+
"\u043F\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u0438\u0442\u044C",
|
|
2291
|
+
"\u043F\u0440\u0438\u0434\u0443\u043C\u0430\u0439",
|
|
2292
|
+
"\u043D\u0430\u043F\u0438\u0448\u0438",
|
|
2293
|
+
// German
|
|
2294
|
+
"geschichte",
|
|
2295
|
+
"gedicht",
|
|
2296
|
+
"komponieren",
|
|
2297
|
+
"brainstorming",
|
|
2298
|
+
"kreativ",
|
|
2299
|
+
"vorstellen",
|
|
2300
|
+
"schreibe",
|
|
2301
|
+
"erz\xE4hlung",
|
|
2302
|
+
// Spanish
|
|
2303
|
+
"historia",
|
|
2304
|
+
"poema",
|
|
2305
|
+
"componer",
|
|
2306
|
+
"lluvia de ideas",
|
|
2307
|
+
"creativo",
|
|
2308
|
+
"imaginar",
|
|
2309
|
+
"escribe",
|
|
2310
|
+
// Portuguese
|
|
2311
|
+
"hist\xF3ria",
|
|
2312
|
+
"poema",
|
|
2313
|
+
"compor",
|
|
2314
|
+
"criativo",
|
|
2315
|
+
"imaginar",
|
|
2316
|
+
"escreva",
|
|
2317
|
+
// Korean
|
|
2318
|
+
"\uC774\uC57C\uAE30",
|
|
2319
|
+
"\uC2DC",
|
|
2320
|
+
"\uC791\uACE1",
|
|
2321
|
+
"\uBE0C\uB808\uC778\uC2A4\uD1A0\uBC0D",
|
|
2322
|
+
"\uCC3D\uC758\uC801",
|
|
2323
|
+
"\uC0C1\uC0C1",
|
|
2324
|
+
"\uC791\uC131",
|
|
2325
|
+
// Arabic
|
|
2326
|
+
"\u0642\u0635\u0629",
|
|
2327
|
+
"\u0642\u0635\u064A\u062F\u0629",
|
|
2328
|
+
"\u062A\u0623\u0644\u064A\u0641",
|
|
2329
|
+
"\u0639\u0635\u0641 \u0630\u0647\u0646\u064A",
|
|
2330
|
+
"\u0625\u0628\u062F\u0627\u0639\u064A",
|
|
2331
|
+
"\u062A\u062E\u064A\u0644",
|
|
2332
|
+
"\u0627\u0643\u062A\u0628"
|
|
2333
|
+
],
|
|
2334
|
+
// New dimension keyword lists (multilingual)
|
|
2335
|
+
imperativeVerbs: [
|
|
2336
|
+
// English
|
|
2337
|
+
"build",
|
|
2338
|
+
"create",
|
|
2339
|
+
"implement",
|
|
2340
|
+
"design",
|
|
2341
|
+
"develop",
|
|
2342
|
+
"construct",
|
|
2343
|
+
"generate",
|
|
2344
|
+
"deploy",
|
|
2345
|
+
"configure",
|
|
2346
|
+
"set up",
|
|
2347
|
+
// Chinese
|
|
2348
|
+
"\u6784\u5EFA",
|
|
2349
|
+
"\u521B\u5EFA",
|
|
2350
|
+
"\u5B9E\u73B0",
|
|
2351
|
+
"\u8BBE\u8BA1",
|
|
2352
|
+
"\u5F00\u53D1",
|
|
2353
|
+
"\u751F\u6210",
|
|
2354
|
+
"\u90E8\u7F72",
|
|
2355
|
+
"\u914D\u7F6E",
|
|
2356
|
+
"\u8BBE\u7F6E",
|
|
2357
|
+
// Japanese
|
|
2358
|
+
"\u69CB\u7BC9",
|
|
2359
|
+
"\u4F5C\u6210",
|
|
2360
|
+
"\u5B9F\u88C5",
|
|
2361
|
+
"\u8A2D\u8A08",
|
|
2362
|
+
"\u958B\u767A",
|
|
2363
|
+
"\u751F\u6210",
|
|
2364
|
+
"\u30C7\u30D7\u30ED\u30A4",
|
|
2365
|
+
"\u8A2D\u5B9A",
|
|
2366
|
+
// Russian
|
|
2367
|
+
"\u043F\u043E\u0441\u0442\u0440\u043E\u0438\u0442\u044C",
|
|
2368
|
+
"\u043F\u043E\u0441\u0442\u0440\u043E\u0439",
|
|
2369
|
+
"\u0441\u043E\u0437\u0434\u0430\u0442\u044C",
|
|
2370
|
+
"\u0441\u043E\u0437\u0434\u0430\u0439",
|
|
2371
|
+
"\u0440\u0435\u0430\u043B\u0438\u0437\u043E\u0432\u0430\u0442\u044C",
|
|
2372
|
+
"\u0440\u0435\u0430\u043B\u0438\u0437\u0443\u0439",
|
|
2373
|
+
"\u0441\u043F\u0440\u043E\u0435\u043A\u0442\u0438\u0440\u043E\u0432\u0430\u0442\u044C",
|
|
2374
|
+
"\u0440\u0430\u0437\u0440\u0430\u0431\u043E\u0442\u0430\u0442\u044C",
|
|
2375
|
+
"\u0440\u0430\u0437\u0440\u0430\u0431\u043E\u0442\u0430\u0439",
|
|
2376
|
+
"\u0441\u043A\u043E\u043D\u0441\u0442\u0440\u0443\u0438\u0440\u043E\u0432\u0430\u0442\u044C",
|
|
2377
|
+
"\u0441\u0433\u0435\u043D\u0435\u0440\u0438\u0440\u043E\u0432\u0430\u0442\u044C",
|
|
2378
|
+
"\u0441\u0433\u0435\u043D\u0435\u0440\u0438\u0440\u0443\u0439",
|
|
2379
|
+
"\u0440\u0430\u0437\u0432\u0435\u0440\u043D\u0443\u0442\u044C",
|
|
2380
|
+
"\u0440\u0430\u0437\u0432\u0435\u0440\u043D\u0438",
|
|
2381
|
+
"\u043D\u0430\u0441\u0442\u0440\u043E\u0438\u0442\u044C",
|
|
2382
|
+
"\u043D\u0430\u0441\u0442\u0440\u043E\u0439",
|
|
2383
|
+
// German
|
|
2384
|
+
"erstellen",
|
|
2385
|
+
"bauen",
|
|
2386
|
+
"implementieren",
|
|
2387
|
+
"entwerfen",
|
|
2388
|
+
"entwickeln",
|
|
2389
|
+
"konstruieren",
|
|
2390
|
+
"generieren",
|
|
2391
|
+
"bereitstellen",
|
|
2392
|
+
"konfigurieren",
|
|
2393
|
+
"einrichten",
|
|
2394
|
+
// Spanish
|
|
2395
|
+
"construir",
|
|
2396
|
+
"crear",
|
|
2397
|
+
"implementar",
|
|
2398
|
+
"dise\xF1ar",
|
|
2399
|
+
"desarrollar",
|
|
2400
|
+
"generar",
|
|
2401
|
+
"desplegar",
|
|
2402
|
+
"configurar",
|
|
2403
|
+
// Portuguese
|
|
2404
|
+
"construir",
|
|
2405
|
+
"criar",
|
|
2406
|
+
"implementar",
|
|
2407
|
+
"projetar",
|
|
2408
|
+
"desenvolver",
|
|
2409
|
+
"gerar",
|
|
2410
|
+
"implantar",
|
|
2411
|
+
"configurar",
|
|
2412
|
+
// Korean
|
|
2413
|
+
"\uAD6C\uCD95",
|
|
2414
|
+
"\uC0DD\uC131",
|
|
2415
|
+
"\uAD6C\uD604",
|
|
2416
|
+
"\uC124\uACC4",
|
|
2417
|
+
"\uAC1C\uBC1C",
|
|
2418
|
+
"\uBC30\uD3EC",
|
|
2419
|
+
"\uC124\uC815",
|
|
2420
|
+
// Arabic
|
|
2421
|
+
"\u0628\u0646\u0627\u0621",
|
|
2422
|
+
"\u0625\u0646\u0634\u0627\u0621",
|
|
2423
|
+
"\u062A\u0646\u0641\u064A\u0630",
|
|
2424
|
+
"\u062A\u0635\u0645\u064A\u0645",
|
|
2425
|
+
"\u062A\u0637\u0648\u064A\u0631",
|
|
2426
|
+
"\u062A\u0648\u0644\u064A\u062F",
|
|
2427
|
+
"\u0646\u0634\u0631",
|
|
2428
|
+
"\u0625\u0639\u062F\u0627\u062F"
|
|
2429
|
+
],
|
|
2430
|
+
constraintIndicators: [
|
|
2431
|
+
// English
|
|
2432
|
+
"under",
|
|
2433
|
+
"at most",
|
|
2434
|
+
"at least",
|
|
2435
|
+
"within",
|
|
2436
|
+
"no more than",
|
|
2437
|
+
"o(",
|
|
2438
|
+
"maximum",
|
|
2439
|
+
"minimum",
|
|
2440
|
+
"limit",
|
|
2441
|
+
"budget",
|
|
2442
|
+
// Chinese
|
|
2443
|
+
"\u4E0D\u8D85\u8FC7",
|
|
2444
|
+
"\u81F3\u5C11",
|
|
2445
|
+
"\u6700\u591A",
|
|
2446
|
+
"\u5728\u5185",
|
|
2447
|
+
"\u6700\u5927",
|
|
2448
|
+
"\u6700\u5C0F",
|
|
2449
|
+
"\u9650\u5236",
|
|
2450
|
+
"\u9884\u7B97",
|
|
2451
|
+
// Japanese
|
|
2452
|
+
"\u4EE5\u4E0B",
|
|
2453
|
+
"\u6700\u5927",
|
|
2454
|
+
"\u6700\u5C0F",
|
|
2455
|
+
"\u5236\u9650",
|
|
2456
|
+
"\u4E88\u7B97",
|
|
2457
|
+
// Russian
|
|
2458
|
+
"\u043D\u0435 \u0431\u043E\u043B\u0435\u0435",
|
|
2459
|
+
"\u043D\u0435 \u043C\u0435\u043D\u0435\u0435",
|
|
2460
|
+
"\u043A\u0430\u043A \u043C\u0438\u043D\u0438\u043C\u0443\u043C",
|
|
2461
|
+
"\u0432 \u043F\u0440\u0435\u0434\u0435\u043B\u0430\u0445",
|
|
2462
|
+
"\u043C\u0430\u043A\u0441\u0438\u043C\u0443\u043C",
|
|
2463
|
+
"\u043C\u0438\u043D\u0438\u043C\u0443\u043C",
|
|
2464
|
+
"\u043E\u0433\u0440\u0430\u043D\u0438\u0447\u0435\u043D\u0438\u0435",
|
|
2465
|
+
"\u0431\u044E\u0434\u0436\u0435\u0442",
|
|
2466
|
+
// German
|
|
2467
|
+
"h\xF6chstens",
|
|
2468
|
+
"mindestens",
|
|
2469
|
+
"innerhalb",
|
|
2470
|
+
"nicht mehr als",
|
|
2471
|
+
"maximal",
|
|
2472
|
+
"minimal",
|
|
2473
|
+
"grenze",
|
|
2474
|
+
"budget",
|
|
2475
|
+
// Spanish
|
|
2476
|
+
"como m\xE1ximo",
|
|
2477
|
+
"al menos",
|
|
2478
|
+
"dentro de",
|
|
2479
|
+
"no m\xE1s de",
|
|
2480
|
+
"m\xE1ximo",
|
|
2481
|
+
"m\xEDnimo",
|
|
2482
|
+
"l\xEDmite",
|
|
2483
|
+
"presupuesto",
|
|
2484
|
+
// Portuguese
|
|
2485
|
+
"no m\xE1ximo",
|
|
2486
|
+
"pelo menos",
|
|
2487
|
+
"dentro de",
|
|
2488
|
+
"n\xE3o mais que",
|
|
2489
|
+
"m\xE1ximo",
|
|
2490
|
+
"m\xEDnimo",
|
|
2491
|
+
"limite",
|
|
2492
|
+
"or\xE7amento",
|
|
2493
|
+
// Korean
|
|
2494
|
+
"\uC774\uD558",
|
|
2495
|
+
"\uC774\uC0C1",
|
|
2496
|
+
"\uCD5C\uB300",
|
|
2497
|
+
"\uCD5C\uC18C",
|
|
2498
|
+
"\uC81C\uD55C",
|
|
2499
|
+
"\uC608\uC0B0",
|
|
2500
|
+
// Arabic
|
|
2501
|
+
"\u0639\u0644\u0649 \u0627\u0644\u0623\u0643\u062B\u0631",
|
|
2502
|
+
"\u0639\u0644\u0649 \u0627\u0644\u0623\u0642\u0644",
|
|
2503
|
+
"\u0636\u0645\u0646",
|
|
2504
|
+
"\u0644\u0627 \u064A\u0632\u064A\u062F \u0639\u0646",
|
|
2505
|
+
"\u0623\u0642\u0635\u0649",
|
|
2506
|
+
"\u0623\u062F\u0646\u0649",
|
|
2507
|
+
"\u062D\u062F",
|
|
2508
|
+
"\u0645\u064A\u0632\u0627\u0646\u064A\u0629"
|
|
2509
|
+
],
|
|
2510
|
+
outputFormatKeywords: [
|
|
2511
|
+
// English
|
|
2512
|
+
"json",
|
|
2513
|
+
"yaml",
|
|
2514
|
+
"xml",
|
|
2515
|
+
"table",
|
|
2516
|
+
"csv",
|
|
2517
|
+
"markdown",
|
|
2518
|
+
"schema",
|
|
2519
|
+
"format as",
|
|
2520
|
+
"structured",
|
|
2521
|
+
// Chinese
|
|
2522
|
+
"\u8868\u683C",
|
|
2523
|
+
"\u683C\u5F0F\u5316\u4E3A",
|
|
2524
|
+
"\u7ED3\u6784\u5316",
|
|
2525
|
+
// Japanese
|
|
2526
|
+
"\u30C6\u30FC\u30D6\u30EB",
|
|
2527
|
+
"\u30D5\u30A9\u30FC\u30DE\u30C3\u30C8",
|
|
2528
|
+
"\u69CB\u9020\u5316",
|
|
2529
|
+
// Russian
|
|
2530
|
+
"\u0442\u0430\u0431\u043B\u0438\u0446\u0430",
|
|
2531
|
+
"\u0444\u043E\u0440\u043C\u0430\u0442\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u043A\u0430\u043A",
|
|
2532
|
+
"\u0441\u0442\u0440\u0443\u043A\u0442\u0443\u0440\u0438\u0440\u043E\u0432\u0430\u043D\u043D\u044B\u0439",
|
|
2533
|
+
// German
|
|
2534
|
+
"tabelle",
|
|
2535
|
+
"formatieren als",
|
|
2536
|
+
"strukturiert",
|
|
2537
|
+
// Spanish
|
|
2538
|
+
"tabla",
|
|
2539
|
+
"formatear como",
|
|
2540
|
+
"estructurado",
|
|
2541
|
+
// Portuguese
|
|
2542
|
+
"tabela",
|
|
2543
|
+
"formatar como",
|
|
2544
|
+
"estruturado",
|
|
2545
|
+
// Korean
|
|
2546
|
+
"\uD14C\uC774\uBE14",
|
|
2547
|
+
"\uD615\uC2DD",
|
|
2548
|
+
"\uAD6C\uC870\uD654",
|
|
2549
|
+
// Arabic
|
|
2550
|
+
"\u062C\u062F\u0648\u0644",
|
|
2551
|
+
"\u062A\u0646\u0633\u064A\u0642",
|
|
2552
|
+
"\u0645\u0646\u0638\u0645"
|
|
2553
|
+
],
|
|
2554
|
+
referenceKeywords: [
|
|
2555
|
+
// English
|
|
2556
|
+
"above",
|
|
2557
|
+
"below",
|
|
2558
|
+
"previous",
|
|
2559
|
+
"following",
|
|
2560
|
+
"the docs",
|
|
2561
|
+
"the api",
|
|
2562
|
+
"the code",
|
|
2563
|
+
"earlier",
|
|
2564
|
+
"attached",
|
|
2565
|
+
// Chinese
|
|
2566
|
+
"\u4E0A\u9762",
|
|
2567
|
+
"\u4E0B\u9762",
|
|
2568
|
+
"\u4E4B\u524D",
|
|
2569
|
+
"\u63A5\u4E0B\u6765",
|
|
2570
|
+
"\u6587\u6863",
|
|
2571
|
+
"\u4EE3\u7801",
|
|
2572
|
+
"\u9644\u4EF6",
|
|
2573
|
+
// Japanese
|
|
2574
|
+
"\u4E0A\u8A18",
|
|
2575
|
+
"\u4E0B\u8A18",
|
|
2576
|
+
"\u524D\u306E",
|
|
2577
|
+
"\u6B21\u306E",
|
|
2578
|
+
"\u30C9\u30AD\u30E5\u30E1\u30F3\u30C8",
|
|
2579
|
+
"\u30B3\u30FC\u30C9",
|
|
2580
|
+
// Russian
|
|
2581
|
+
"\u0432\u044B\u0448\u0435",
|
|
2582
|
+
"\u043D\u0438\u0436\u0435",
|
|
2583
|
+
"\u043F\u0440\u0435\u0434\u044B\u0434\u0443\u0449\u0438\u0439",
|
|
2584
|
+
"\u0441\u043B\u0435\u0434\u0443\u044E\u0449\u0438\u0439",
|
|
2585
|
+
"\u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u0430\u0446\u0438\u044F",
|
|
2586
|
+
"\u043A\u043E\u0434",
|
|
2587
|
+
"\u0440\u0430\u043D\u0435\u0435",
|
|
2588
|
+
"\u0432\u043B\u043E\u0436\u0435\u043D\u0438\u0435",
|
|
2589
|
+
// German
|
|
2590
|
+
"oben",
|
|
2591
|
+
"unten",
|
|
2592
|
+
"vorherige",
|
|
2593
|
+
"folgende",
|
|
2594
|
+
"dokumentation",
|
|
2595
|
+
"der code",
|
|
2596
|
+
"fr\xFCher",
|
|
2597
|
+
"anhang",
|
|
2598
|
+
// Spanish
|
|
2599
|
+
"arriba",
|
|
2600
|
+
"abajo",
|
|
2601
|
+
"anterior",
|
|
2602
|
+
"siguiente",
|
|
2603
|
+
"documentaci\xF3n",
|
|
2604
|
+
"el c\xF3digo",
|
|
2605
|
+
"adjunto",
|
|
2606
|
+
// Portuguese
|
|
2607
|
+
"acima",
|
|
2608
|
+
"abaixo",
|
|
2609
|
+
"anterior",
|
|
2610
|
+
"seguinte",
|
|
2611
|
+
"documenta\xE7\xE3o",
|
|
2612
|
+
"o c\xF3digo",
|
|
2613
|
+
"anexo",
|
|
2614
|
+
// Korean
|
|
2615
|
+
"\uC704",
|
|
2616
|
+
"\uC544\uB798",
|
|
2617
|
+
"\uC774\uC804",
|
|
2618
|
+
"\uB2E4\uC74C",
|
|
2619
|
+
"\uBB38\uC11C",
|
|
2620
|
+
"\uCF54\uB4DC",
|
|
2621
|
+
"\uCCA8\uBD80",
|
|
2622
|
+
// Arabic
|
|
2623
|
+
"\u0623\u0639\u0644\u0627\u0647",
|
|
2624
|
+
"\u0623\u062F\u0646\u0627\u0647",
|
|
2625
|
+
"\u0627\u0644\u0633\u0627\u0628\u0642",
|
|
2626
|
+
"\u0627\u0644\u062A\u0627\u0644\u064A",
|
|
2627
|
+
"\u0627\u0644\u0648\u062B\u0627\u0626\u0642",
|
|
2628
|
+
"\u0627\u0644\u0643\u0648\u062F",
|
|
2629
|
+
"\u0645\u0631\u0641\u0642"
|
|
2630
|
+
],
|
|
2631
|
+
negationKeywords: [
|
|
2632
|
+
// English
|
|
2633
|
+
"don't",
|
|
2634
|
+
"do not",
|
|
2635
|
+
"avoid",
|
|
2636
|
+
"never",
|
|
2637
|
+
"without",
|
|
2638
|
+
"except",
|
|
2639
|
+
"exclude",
|
|
2640
|
+
"no longer",
|
|
2641
|
+
// Chinese
|
|
2642
|
+
"\u4E0D\u8981",
|
|
2643
|
+
"\u907F\u514D",
|
|
2644
|
+
"\u4ECE\u4E0D",
|
|
2645
|
+
"\u6CA1\u6709",
|
|
2646
|
+
"\u9664\u4E86",
|
|
2647
|
+
"\u6392\u9664",
|
|
2648
|
+
// Japanese
|
|
2649
|
+
"\u3057\u306A\u3044\u3067",
|
|
2650
|
+
"\u907F\u3051\u308B",
|
|
2651
|
+
"\u6C7A\u3057\u3066",
|
|
2652
|
+
"\u306A\u3057\u3067",
|
|
2653
|
+
"\u9664\u304F",
|
|
2654
|
+
// Russian
|
|
2655
|
+
"\u043D\u0435 \u0434\u0435\u043B\u0430\u0439",
|
|
2656
|
+
"\u043D\u0435 \u043D\u0430\u0434\u043E",
|
|
2657
|
+
"\u043D\u0435\u043B\u044C\u0437\u044F",
|
|
2658
|
+
"\u0438\u0437\u0431\u0435\u0433\u0430\u0442\u044C",
|
|
2659
|
+
"\u043D\u0438\u043A\u043E\u0433\u0434\u0430",
|
|
2660
|
+
"\u0431\u0435\u0437",
|
|
2661
|
+
"\u043A\u0440\u043E\u043C\u0435",
|
|
2662
|
+
"\u0438\u0441\u043A\u043B\u044E\u0447\u0438\u0442\u044C",
|
|
2663
|
+
"\u0431\u043E\u043B\u044C\u0448\u0435 \u043D\u0435",
|
|
2664
|
+
// German
|
|
2665
|
+
"nicht",
|
|
2666
|
+
"vermeide",
|
|
2667
|
+
"niemals",
|
|
2668
|
+
"ohne",
|
|
2669
|
+
"au\xDFer",
|
|
2670
|
+
"ausschlie\xDFen",
|
|
2671
|
+
"nicht mehr",
|
|
2672
|
+
// Spanish
|
|
2673
|
+
"no hagas",
|
|
2674
|
+
"evitar",
|
|
2675
|
+
"nunca",
|
|
2676
|
+
"sin",
|
|
2677
|
+
"excepto",
|
|
2678
|
+
"excluir",
|
|
2679
|
+
// Portuguese
|
|
2680
|
+
"n\xE3o fa\xE7a",
|
|
2681
|
+
"evitar",
|
|
2682
|
+
"nunca",
|
|
2683
|
+
"sem",
|
|
2684
|
+
"exceto",
|
|
2685
|
+
"excluir",
|
|
2686
|
+
// Korean
|
|
2687
|
+
"\uD558\uC9C0 \uB9C8",
|
|
2688
|
+
"\uD53C\uD558\uB2E4",
|
|
2689
|
+
"\uC808\uB300",
|
|
2690
|
+
"\uC5C6\uC774",
|
|
2691
|
+
"\uC81C\uC678",
|
|
2692
|
+
// Arabic
|
|
2693
|
+
"\u0644\u0627 \u062A\u0641\u0639\u0644",
|
|
2694
|
+
"\u062A\u062C\u0646\u0628",
|
|
2695
|
+
"\u0623\u0628\u062F\u0627\u064B",
|
|
2696
|
+
"\u0628\u062F\u0648\u0646",
|
|
2697
|
+
"\u0628\u0627\u0633\u062A\u062B\u0646\u0627\u0621",
|
|
2698
|
+
"\u0627\u0633\u062A\u0628\u0639\u0627\u062F"
|
|
2699
|
+
],
|
|
2700
|
+
domainSpecificKeywords: [
|
|
2701
|
+
// English
|
|
2702
|
+
"quantum",
|
|
2703
|
+
"fpga",
|
|
2704
|
+
"vlsi",
|
|
2705
|
+
"risc-v",
|
|
2706
|
+
"asic",
|
|
2707
|
+
"photonics",
|
|
2708
|
+
"genomics",
|
|
2709
|
+
"proteomics",
|
|
2710
|
+
"topological",
|
|
2711
|
+
"homomorphic",
|
|
2712
|
+
"zero-knowledge",
|
|
2713
|
+
"lattice-based",
|
|
2714
|
+
// Chinese
|
|
2715
|
+
"\u91CF\u5B50",
|
|
2716
|
+
"\u5149\u5B50\u5B66",
|
|
2717
|
+
"\u57FA\u56E0\u7EC4\u5B66",
|
|
2718
|
+
"\u86CB\u767D\u8D28\u7EC4\u5B66",
|
|
2719
|
+
"\u62D3\u6251",
|
|
2720
|
+
"\u540C\u6001",
|
|
2721
|
+
"\u96F6\u77E5\u8BC6",
|
|
2722
|
+
"\u683C\u5BC6\u7801",
|
|
2723
|
+
// Japanese
|
|
2724
|
+
"\u91CF\u5B50",
|
|
2725
|
+
"\u30D5\u30A9\u30C8\u30CB\u30AF\u30B9",
|
|
2726
|
+
"\u30B2\u30CE\u30DF\u30AF\u30B9",
|
|
2727
|
+
"\u30C8\u30DD\u30ED\u30B8\u30AB\u30EB",
|
|
2728
|
+
// Russian
|
|
2729
|
+
"\u043A\u0432\u0430\u043D\u0442\u043E\u0432\u044B\u0439",
|
|
2730
|
+
"\u0444\u043E\u0442\u043E\u043D\u0438\u043A\u0430",
|
|
2731
|
+
"\u0433\u0435\u043D\u043E\u043C\u0438\u043A\u0430",
|
|
2732
|
+
"\u043F\u0440\u043E\u0442\u0435\u043E\u043C\u0438\u043A\u0430",
|
|
2733
|
+
"\u0442\u043E\u043F\u043E\u043B\u043E\u0433\u0438\u0447\u0435\u0441\u043A\u0438\u0439",
|
|
2734
|
+
"\u0433\u043E\u043C\u043E\u043C\u043E\u0440\u0444\u043D\u044B\u0439",
|
|
2735
|
+
"\u0441 \u043D\u0443\u043B\u0435\u0432\u044B\u043C \u0440\u0430\u0437\u0433\u043B\u0430\u0448\u0435\u043D\u0438\u0435\u043C",
|
|
2736
|
+
"\u043D\u0430 \u043E\u0441\u043D\u043E\u0432\u0435 \u0440\u0435\u0448\u0451\u0442\u043E\u043A",
|
|
2737
|
+
// German
|
|
2738
|
+
"quanten",
|
|
2739
|
+
"photonik",
|
|
2740
|
+
"genomik",
|
|
2741
|
+
"proteomik",
|
|
2742
|
+
"topologisch",
|
|
2743
|
+
"homomorph",
|
|
2744
|
+
"zero-knowledge",
|
|
2745
|
+
"gitterbasiert",
|
|
2746
|
+
// Spanish
|
|
2747
|
+
"cu\xE1ntico",
|
|
2748
|
+
"fot\xF3nica",
|
|
2749
|
+
"gen\xF3mica",
|
|
2750
|
+
"prote\xF3mica",
|
|
2751
|
+
"topol\xF3gico",
|
|
2752
|
+
"homom\xF3rfico",
|
|
2753
|
+
// Portuguese
|
|
2754
|
+
"qu\xE2ntico",
|
|
2755
|
+
"fot\xF4nica",
|
|
2756
|
+
"gen\xF4mica",
|
|
2757
|
+
"prote\xF4mica",
|
|
2758
|
+
"topol\xF3gico",
|
|
2759
|
+
"homom\xF3rfico",
|
|
2760
|
+
// Korean
|
|
2761
|
+
"\uC591\uC790",
|
|
2762
|
+
"\uD3EC\uD1A0\uB2C9\uC2A4",
|
|
2763
|
+
"\uC720\uC804\uCCB4\uD559",
|
|
2764
|
+
"\uC704\uC0C1",
|
|
2765
|
+
"\uB3D9\uD615",
|
|
2766
|
+
// Arabic
|
|
2767
|
+
"\u0643\u0645\u064A",
|
|
2768
|
+
"\u0636\u0648\u0626\u064A\u0627\u062A",
|
|
2769
|
+
"\u062C\u064A\u0646\u0648\u0645\u064A\u0627\u062A",
|
|
2770
|
+
"\u0637\u0648\u0628\u0648\u0644\u0648\u062C\u064A",
|
|
2771
|
+
"\u062A\u0645\u0627\u062B\u0644\u064A"
|
|
2772
|
+
],
|
|
2773
|
+
// Agentic task keywords - file ops, execution, multi-step, iterative work
|
|
2774
|
+
// Pruned: removed overly common words like "then", "first", "run", "test", "build"
|
|
2775
|
+
agenticTaskKeywords: [
|
|
2776
|
+
// English - File operations (clearly agentic)
|
|
2777
|
+
"read file",
|
|
2778
|
+
"read the file",
|
|
2779
|
+
"look at",
|
|
2780
|
+
"check the",
|
|
2781
|
+
"open the",
|
|
2782
|
+
"edit",
|
|
2783
|
+
"modify",
|
|
2784
|
+
"update the",
|
|
2785
|
+
"change the",
|
|
2786
|
+
"write to",
|
|
2787
|
+
"create file",
|
|
2788
|
+
// English - Execution (specific commands only)
|
|
2789
|
+
"execute",
|
|
2790
|
+
"deploy",
|
|
2791
|
+
"install",
|
|
2792
|
+
"npm",
|
|
2793
|
+
"pip",
|
|
2794
|
+
"compile",
|
|
2795
|
+
// English - Multi-step patterns (specific only)
|
|
2796
|
+
"after that",
|
|
2797
|
+
"and also",
|
|
2798
|
+
"once done",
|
|
2799
|
+
"step 1",
|
|
2800
|
+
"step 2",
|
|
2801
|
+
// English - Iterative work
|
|
2802
|
+
"fix",
|
|
2803
|
+
"debug",
|
|
2804
|
+
"until it works",
|
|
2805
|
+
"keep trying",
|
|
2806
|
+
"iterate",
|
|
2807
|
+
"make sure",
|
|
2808
|
+
"verify",
|
|
2809
|
+
"confirm",
|
|
2810
|
+
// Chinese (keep specific ones)
|
|
2811
|
+
"\u8BFB\u53D6\u6587\u4EF6",
|
|
2812
|
+
"\u67E5\u770B",
|
|
2813
|
+
"\u6253\u5F00",
|
|
2814
|
+
"\u7F16\u8F91",
|
|
2815
|
+
"\u4FEE\u6539",
|
|
2816
|
+
"\u66F4\u65B0",
|
|
2817
|
+
"\u521B\u5EFA",
|
|
2818
|
+
"\u6267\u884C",
|
|
2819
|
+
"\u90E8\u7F72",
|
|
2820
|
+
"\u5B89\u88C5",
|
|
2821
|
+
"\u7B2C\u4E00\u6B65",
|
|
2822
|
+
"\u7B2C\u4E8C\u6B65",
|
|
2823
|
+
"\u4FEE\u590D",
|
|
2824
|
+
"\u8C03\u8BD5",
|
|
2825
|
+
"\u76F4\u5230",
|
|
2826
|
+
"\u786E\u8BA4",
|
|
2827
|
+
"\u9A8C\u8BC1",
|
|
2828
|
+
// Spanish
|
|
2829
|
+
"leer archivo",
|
|
2830
|
+
"editar",
|
|
2831
|
+
"modificar",
|
|
2832
|
+
"actualizar",
|
|
2833
|
+
"ejecutar",
|
|
2834
|
+
"desplegar",
|
|
2835
|
+
"instalar",
|
|
2836
|
+
"paso 1",
|
|
2837
|
+
"paso 2",
|
|
2838
|
+
"arreglar",
|
|
2839
|
+
"depurar",
|
|
2840
|
+
"verificar",
|
|
2841
|
+
// Portuguese
|
|
2842
|
+
"ler arquivo",
|
|
2843
|
+
"editar",
|
|
2844
|
+
"modificar",
|
|
2845
|
+
"atualizar",
|
|
2846
|
+
"executar",
|
|
2847
|
+
"implantar",
|
|
2848
|
+
"instalar",
|
|
2849
|
+
"passo 1",
|
|
2850
|
+
"passo 2",
|
|
2851
|
+
"corrigir",
|
|
2852
|
+
"depurar",
|
|
2853
|
+
"verificar",
|
|
2854
|
+
// Korean
|
|
2855
|
+
"\uD30C\uC77C \uC77D\uAE30",
|
|
2856
|
+
"\uD3B8\uC9D1",
|
|
2857
|
+
"\uC218\uC815",
|
|
2858
|
+
"\uC5C5\uB370\uC774\uD2B8",
|
|
2859
|
+
"\uC2E4\uD589",
|
|
2860
|
+
"\uBC30\uD3EC",
|
|
2861
|
+
"\uC124\uCE58",
|
|
2862
|
+
"\uB2E8\uACC4 1",
|
|
2863
|
+
"\uB2E8\uACC4 2",
|
|
2864
|
+
"\uB514\uBC84\uADF8",
|
|
2865
|
+
"\uD655\uC778",
|
|
2866
|
+
// Arabic
|
|
2867
|
+
"\u0642\u0631\u0627\u0621\u0629 \u0645\u0644\u0641",
|
|
2868
|
+
"\u062A\u062D\u0631\u064A\u0631",
|
|
2869
|
+
"\u062A\u0639\u062F\u064A\u0644",
|
|
2870
|
+
"\u062A\u062D\u062F\u064A\u062B",
|
|
2871
|
+
"\u062A\u0646\u0641\u064A\u0630",
|
|
2872
|
+
"\u0646\u0634\u0631",
|
|
2873
|
+
"\u062A\u062B\u0628\u064A\u062A",
|
|
2874
|
+
"\u0627\u0644\u062E\u0637\u0648\u0629 1",
|
|
2875
|
+
"\u0627\u0644\u062E\u0637\u0648\u0629 2",
|
|
2876
|
+
"\u0625\u0635\u0644\u0627\u062D",
|
|
2877
|
+
"\u062A\u0635\u062D\u064A\u062D",
|
|
2878
|
+
"\u062A\u062D\u0642\u0642"
|
|
2879
|
+
],
|
|
2880
|
+
// Dimension weights (sum to 1.0)
|
|
2881
|
+
dimensionWeights: {
|
|
2882
|
+
tokenCount: 0.08,
|
|
2883
|
+
codePresence: 0.15,
|
|
2884
|
+
reasoningMarkers: 0.18,
|
|
2885
|
+
technicalTerms: 0.1,
|
|
2886
|
+
creativeMarkers: 0.05,
|
|
2887
|
+
simpleIndicators: 0.02,
|
|
2888
|
+
// Reduced from 0.12 to make room for agenticTask
|
|
2889
|
+
multiStepPatterns: 0.12,
|
|
2890
|
+
questionComplexity: 0.05,
|
|
2891
|
+
imperativeVerbs: 0.03,
|
|
2892
|
+
constraintCount: 0.04,
|
|
2893
|
+
outputFormat: 0.03,
|
|
2894
|
+
referenceComplexity: 0.02,
|
|
2895
|
+
negationComplexity: 0.01,
|
|
2896
|
+
domainSpecificity: 0.02,
|
|
2897
|
+
agenticTask: 0.04
|
|
2898
|
+
// Reduced - agentic signals influence tier selection, not dominate it
|
|
2899
|
+
},
|
|
2900
|
+
// Tier boundaries on weighted score axis
|
|
2901
|
+
tierBoundaries: {
|
|
2902
|
+
simpleMedium: 0,
|
|
2903
|
+
mediumComplex: 0.3,
|
|
2904
|
+
// Raised from 0.18 - prevent simple tasks from reaching expensive COMPLEX tier
|
|
2905
|
+
complexReasoning: 0.5
|
|
2906
|
+
// Raised from 0.4 - reserve for true reasoning tasks
|
|
2907
|
+
},
|
|
2908
|
+
// Sigmoid steepness for confidence calibration
|
|
2909
|
+
confidenceSteepness: 12,
|
|
2910
|
+
// Below this confidence → ambiguous (null tier)
|
|
2911
|
+
confidenceThreshold: 0.7
|
|
2912
|
+
},
|
|
2913
|
+
// Auto (balanced) tier configs - current default smart routing
|
|
2914
|
+
// Benchmark-tuned 2026-03-16: balancing quality (retention) + latency
|
|
2915
|
+
tiers: {
|
|
2916
|
+
SIMPLE: {
|
|
2917
|
+
primary: "google/gemini-2.5-flash",
|
|
2918
|
+
// 1,238ms, IQ 20, 60% retention (best) — fast AND quality
|
|
2919
|
+
fallback: [
|
|
2920
|
+
"google/gemini-3-flash-preview",
|
|
2921
|
+
// 1,398ms, IQ 46 — smarter fallback
|
|
2922
|
+
"deepseek/deepseek-chat",
|
|
2923
|
+
// V4 Flash chat ($0.20/$0.40, 1M ctx) — repriced 2026-04-24
|
|
2924
|
+
"moonshot/kimi-k2.5",
|
|
2925
|
+
// 1,646ms, IQ 47, strong quality
|
|
2926
|
+
"google/gemini-3.1-flash-lite",
|
|
2927
|
+
// $0.25/$1.50, 1M context — newest flash-lite
|
|
2928
|
+
"google/gemini-2.5-flash-lite",
|
|
2929
|
+
// 1,353ms, $0.10/$0.40
|
|
2930
|
+
"openai/gpt-5.4-nano",
|
|
2931
|
+
// $0.20/$1.25, 1M context
|
|
2932
|
+
"xai/grok-4-fast-non-reasoning",
|
|
2933
|
+
// 1,143ms, $0.20/$0.50 — fast fallback
|
|
2934
|
+
"free/gpt-oss-120b"
|
|
2935
|
+
// 1,252ms, FREE fallback (hidden from /v1/models but direct calls work)
|
|
2936
|
+
]
|
|
2937
|
+
},
|
|
2938
|
+
MEDIUM: {
|
|
2939
|
+
primary: "moonshot/kimi-k2.7",
|
|
2940
|
+
// $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.
|
|
2941
|
+
fallback: [
|
|
2942
|
+
"moonshot/kimi-k2.6",
|
|
2943
|
+
// identical-cost in-family hot swap (K2.6 still routable)
|
|
2944
|
+
"moonshot/kimi-k2.5",
|
|
2945
|
+
// $0.60/$3.00 — graceful-degradation backstop
|
|
2946
|
+
"google/gemini-3-flash-preview",
|
|
2947
|
+
// 1,398ms, IQ 46 — nearly same IQ, faster + cheaper
|
|
2948
|
+
"deepseek/deepseek-chat",
|
|
2949
|
+
// 1,431ms, IQ 32, 41% retention
|
|
2950
|
+
"google/gemini-2.5-flash",
|
|
2951
|
+
// 1,238ms, 60% retention
|
|
2952
|
+
"google/gemini-3.1-flash-lite",
|
|
2953
|
+
// $0.25/$1.50, 1M context
|
|
2954
|
+
"google/gemini-2.5-flash-lite",
|
|
2955
|
+
// 1,353ms, $0.10/$0.40
|
|
2956
|
+
"xai/grok-4-1-fast-non-reasoning",
|
|
2957
|
+
// 1,244ms, fast fallback
|
|
2958
|
+
"xai/grok-3-mini"
|
|
2959
|
+
// 1,202ms, $0.30/$0.50
|
|
2960
|
+
]
|
|
2961
|
+
},
|
|
2962
|
+
COMPLEX: {
|
|
2963
|
+
primary: "google/gemini-3.1-pro",
|
|
2964
|
+
// 1,609ms, IQ 57 — fast flagship quality
|
|
2965
|
+
fallback: [
|
|
2966
|
+
"google/gemini-3-flash-preview",
|
|
2967
|
+
// 1,398ms, IQ 46 — fast + smart
|
|
2968
|
+
"xai/grok-4-0709",
|
|
2969
|
+
// 1,348ms, IQ 41
|
|
2970
|
+
"google/gemini-2.5-pro",
|
|
2971
|
+
// 1,294ms
|
|
2972
|
+
"anthropic/claude-sonnet-5",
|
|
2973
|
+
// near-Opus quality at Sonnet cost, 1M ctx
|
|
2974
|
+
"anthropic/claude-sonnet-4.6",
|
|
2975
|
+
// 2,110ms, IQ 52 — quality fallback
|
|
2976
|
+
"deepseek/deepseek-chat",
|
|
2977
|
+
// 1,431ms, IQ 32
|
|
2978
|
+
"google/gemini-2.5-flash",
|
|
2979
|
+
// 1,238ms, IQ 20 — cheap last resort
|
|
2980
|
+
"openai/gpt-5.6-terra",
|
|
2981
|
+
// GPT-5.6 balanced tier — newest generation, stable (Sol excluded: #202)
|
|
2982
|
+
"openai/gpt-5.5",
|
|
2983
|
+
// Prior OpenAI flagship — 1M+ ctx, native agent + computer use; benchmark TBD
|
|
2984
|
+
"openai/gpt-5.4"
|
|
2985
|
+
// 6,213ms, IQ 57 — previous flagship, benchmarked
|
|
2986
|
+
]
|
|
2987
|
+
},
|
|
2988
|
+
REASONING: {
|
|
2989
|
+
primary: "xai/grok-4-1-fast-reasoning",
|
|
2990
|
+
// 1,454ms, $0.20/$0.50
|
|
2991
|
+
fallback: [
|
|
2992
|
+
"xai/grok-4-fast-reasoning",
|
|
2993
|
+
// 1,298ms, $0.20/$0.50
|
|
2994
|
+
"deepseek/deepseek-reasoner",
|
|
2995
|
+
// V4 Flash thinking ($0.20/$0.40, 1M ctx)
|
|
2996
|
+
"deepseek/deepseek-v4-pro",
|
|
2997
|
+
// V4 Pro flagship ($0.50/$1.00 promo through 2026-05-31, list $2/$4) — strongest open-weight reasoner
|
|
2998
|
+
"openai/o4-mini",
|
|
2999
|
+
// 2,328ms ($1.10/$4.40)
|
|
3000
|
+
"openai/o3"
|
|
3001
|
+
// 2,862ms
|
|
3002
|
+
]
|
|
3003
|
+
}
|
|
3004
|
+
},
|
|
3005
|
+
// Eco tier configs - absolute cheapest (blockrun/eco)
|
|
3006
|
+
ecoTiers: {
|
|
3007
|
+
SIMPLE: {
|
|
3008
|
+
primary: "free/gpt-oss-120b",
|
|
3009
|
+
// FREE! $0.00/$0.00 — heavy user default
|
|
3010
|
+
fallback: [
|
|
3011
|
+
"free/gpt-oss-20b",
|
|
3012
|
+
// FREE — smaller, faster
|
|
3013
|
+
"free/deepseek-v4-flash",
|
|
3014
|
+
// FREE — 1M ctx; slow (~10 tok/s, 07-28 probe) but completes
|
|
3015
|
+
// seed-oss-36b sat here as the free coder until it EOL'd 2026-08-03 (HTTP 410).
|
|
3016
|
+
// gpt-oss-120b/20b already head this chain, so the rung is dropped, not retargeted.
|
|
3017
|
+
"google/gemini-3.1-flash-lite",
|
|
3018
|
+
// $0.25/$1.50 — newest flash-lite
|
|
3019
|
+
"openai/gpt-5.4-nano",
|
|
3020
|
+
// $0.20/$1.25 — fast nano
|
|
3021
|
+
"google/gemini-2.5-flash-lite",
|
|
3022
|
+
// $0.10/$0.40
|
|
3023
|
+
"xai/grok-4-fast-non-reasoning"
|
|
3024
|
+
// $0.20/$0.50
|
|
3025
|
+
]
|
|
3026
|
+
},
|
|
3027
|
+
MEDIUM: {
|
|
3028
|
+
primary: "google/gemini-3.1-flash-lite",
|
|
3029
|
+
// $0.25/$1.50 — newest flash-lite
|
|
3030
|
+
fallback: [
|
|
3031
|
+
"openai/gpt-5.4-nano",
|
|
3032
|
+
// $0.20/$1.25
|
|
3033
|
+
"google/gemini-2.5-flash-lite",
|
|
3034
|
+
// $0.10/$0.40
|
|
3035
|
+
"xai/grok-4-fast-non-reasoning",
|
|
3036
|
+
"google/gemini-2.5-flash"
|
|
3037
|
+
]
|
|
3038
|
+
},
|
|
3039
|
+
COMPLEX: {
|
|
3040
|
+
primary: "google/gemini-3.1-flash-lite",
|
|
3041
|
+
// $0.25/$1.50
|
|
3042
|
+
fallback: [
|
|
3043
|
+
"google/gemini-2.5-flash-lite",
|
|
3044
|
+
"xai/grok-4-0709",
|
|
3045
|
+
"google/gemini-2.5-flash",
|
|
3046
|
+
"deepseek/deepseek-chat"
|
|
3047
|
+
]
|
|
3048
|
+
},
|
|
3049
|
+
REASONING: {
|
|
3050
|
+
primary: "xai/grok-4-1-fast-reasoning",
|
|
3051
|
+
// $0.20/$0.50
|
|
3052
|
+
fallback: [
|
|
3053
|
+
"xai/grok-4-fast-reasoning",
|
|
3054
|
+
"deepseek/deepseek-reasoner",
|
|
3055
|
+
// V4 Flash thinking — $0.20/$0.40
|
|
3056
|
+
"deepseek/deepseek-v4-pro"
|
|
3057
|
+
// V4 Pro flagship — $0.50/$1.00 promo, post-promo $2/$4
|
|
3058
|
+
]
|
|
3059
|
+
}
|
|
3060
|
+
},
|
|
3061
|
+
// Premium tier configs - best quality (blockrun/premium)
|
|
3062
|
+
// codex=complex coding, kimi=simple coding, sonnet=reasoning/instructions, opus=architecture/PM/audits
|
|
3063
|
+
premiumTiers: {
|
|
3064
|
+
SIMPLE: {
|
|
3065
|
+
primary: "moonshot/kimi-k2.7",
|
|
3066
|
+
// $0.95/$4.00 - Moonshot flagship (256K ctx, multi-modal + reasoning); promoted from K2.6 (2026-06-14), same price
|
|
3067
|
+
fallback: [
|
|
3068
|
+
"moonshot/kimi-k2.6",
|
|
3069
|
+
// identical-cost in-family hot swap (K2.6 still routable)
|
|
3070
|
+
"moonshot/kimi-k2.5",
|
|
3071
|
+
// $0.60/$3.00 - proven reliable backstop when Moonshot direct API falters
|
|
3072
|
+
"google/gemini-2.5-flash",
|
|
3073
|
+
// 60% retention, fast growth
|
|
3074
|
+
"anthropic/claude-haiku-4.5",
|
|
3075
|
+
"google/gemini-2.5-flash-lite",
|
|
3076
|
+
"deepseek/deepseek-chat"
|
|
3077
|
+
]
|
|
3078
|
+
},
|
|
3079
|
+
MEDIUM: {
|
|
3080
|
+
primary: "openai/gpt-5.3-codex",
|
|
3081
|
+
// $1.75/$14 - 400K context, 128K output, replaces 5.2
|
|
3082
|
+
fallback: [
|
|
3083
|
+
"moonshot/kimi-k2.7",
|
|
3084
|
+
// Moonshot flagship
|
|
3085
|
+
"moonshot/kimi-k2.6",
|
|
3086
|
+
"moonshot/kimi-k2.5",
|
|
3087
|
+
"google/gemini-2.5-flash",
|
|
3088
|
+
// 60% retention, good coding capability
|
|
3089
|
+
"google/gemini-2.5-pro",
|
|
3090
|
+
"xai/grok-4-0709",
|
|
3091
|
+
"anthropic/claude-sonnet-5",
|
|
3092
|
+
"anthropic/claude-sonnet-4.6"
|
|
3093
|
+
]
|
|
3094
|
+
},
|
|
3095
|
+
COMPLEX: {
|
|
3096
|
+
// fable-5 was promoted here 2026-06-11, force-reverted 2026-06-13 when Anthropic
|
|
3097
|
+
// withdrew the offer, and restored 2026-07-14 now that BlockRun has relisted it.
|
|
3098
|
+
primary: "anthropic/claude-fable-5",
|
|
3099
|
+
// Best quality for complex tasks — Mythos-class flagship above Opus ($10/$50, 1M ctx, always-on thinking)
|
|
3100
|
+
// Fallback chain de-Gemini'd 2026-04-22: when Anthropic 503s, Gemini is
|
|
3101
|
+
// also prone to "high demand" 503s (correlated failure — everyone falls
|
|
3102
|
+
// back to Google at the same time). Prefer xAI Grok → Moonshot → OpenAI
|
|
3103
|
+
// flagship → DeepSeek → NVIDIA free instead.
|
|
3104
|
+
fallback: [
|
|
3105
|
+
"anthropic/claude-opus-5",
|
|
3106
|
+
// in-family hot swap first (half the price, 1M ctx + adaptive thinking)
|
|
3107
|
+
"anthropic/claude-opus-4.8",
|
|
3108
|
+
// in-family hot swap (identical cost to 5)
|
|
3109
|
+
"anthropic/claude-opus-4.7",
|
|
3110
|
+
// in-family hot swap (identical cost to 4.8)
|
|
3111
|
+
"anthropic/claude-opus-4.6",
|
|
3112
|
+
// in-family hot swap
|
|
3113
|
+
"anthropic/claude-sonnet-5",
|
|
3114
|
+
// Sonnet-tier drop-down, near-Opus quality
|
|
3115
|
+
"anthropic/claude-sonnet-4.6",
|
|
3116
|
+
"xai/grok-4.5",
|
|
3117
|
+
// xAI flagship — 503-resistant, direct-xAI SKU (added 2026-07-14)
|
|
3118
|
+
"xai/grok-4-0709",
|
|
3119
|
+
// 503-resistant flagship
|
|
3120
|
+
"moonshot/kimi-k2.7",
|
|
3121
|
+
// Moonshot flagship, independent infra
|
|
3122
|
+
"moonshot/kimi-k2.6",
|
|
3123
|
+
"moonshot/kimi-k2.5",
|
|
3124
|
+
"openai/gpt-5.6-terra",
|
|
3125
|
+
// GPT-5.6 balanced tier — newest generation, stable (Sol excluded: #202)
|
|
3126
|
+
"openai/gpt-5.5",
|
|
3127
|
+
// Prior OpenAI flagship — 1M+ ctx, native agent + computer use
|
|
3128
|
+
"openai/gpt-5.4",
|
|
3129
|
+
// Previous flagship (slow but stable, benchmarked at 6,213ms)
|
|
3130
|
+
"openai/gpt-5.3-codex",
|
|
3131
|
+
"deepseek/deepseek-chat",
|
|
3132
|
+
// Cheap, reliable
|
|
3133
|
+
"free/gpt-oss-120b"
|
|
3134
|
+
// NVIDIA free ultimate backstop (was seed-oss-36b; EOL'd 2026-08-03)
|
|
3135
|
+
]
|
|
3136
|
+
},
|
|
3137
|
+
REASONING: {
|
|
3138
|
+
primary: "anthropic/claude-sonnet-4.6",
|
|
3139
|
+
// 2,110ms, $3/$15 - best for reasoning/instructions
|
|
3140
|
+
fallback: [
|
|
3141
|
+
"anthropic/claude-sonnet-5",
|
|
3142
|
+
// in-family hot swap — same cost, adaptive thinking, 1M ctx
|
|
3143
|
+
"anthropic/claude-opus-5",
|
|
3144
|
+
// Newest flagship Opus w/ adaptive thinking
|
|
3145
|
+
"anthropic/claude-opus-4.8",
|
|
3146
|
+
// Prior flagship Opus — identical cost to 5
|
|
3147
|
+
"anthropic/claude-opus-4.7",
|
|
3148
|
+
// Flagship Opus w/ adaptive thinking
|
|
3149
|
+
"anthropic/claude-opus-4.6",
|
|
3150
|
+
// 2,139ms
|
|
3151
|
+
"xai/grok-4-1-fast-reasoning",
|
|
3152
|
+
// 1,454ms, cheap fast reasoning
|
|
3153
|
+
"openai/o4-mini",
|
|
3154
|
+
// 2,328ms ($1.10/$4.40)
|
|
3155
|
+
"openai/o3"
|
|
3156
|
+
// 2,862ms
|
|
3157
|
+
]
|
|
3158
|
+
}
|
|
3159
|
+
},
|
|
3160
|
+
// Agentic tier configs - models that excel at multi-step autonomous tasks
|
|
3161
|
+
agenticTiers: {
|
|
3162
|
+
SIMPLE: {
|
|
3163
|
+
primary: "openai/gpt-4o-mini",
|
|
3164
|
+
// $0.15/$0.60 - best tool compliance at lowest cost
|
|
3165
|
+
fallback: [
|
|
3166
|
+
"moonshot/kimi-k2.5",
|
|
3167
|
+
// 1,646ms, strong tool use quality
|
|
3168
|
+
"anthropic/claude-haiku-4.5",
|
|
3169
|
+
// 2,305ms
|
|
3170
|
+
"xai/grok-4-1-fast-non-reasoning"
|
|
3171
|
+
// 1,244ms, fast fallback
|
|
3172
|
+
]
|
|
3173
|
+
},
|
|
3174
|
+
MEDIUM: {
|
|
3175
|
+
primary: "moonshot/kimi-k2.7",
|
|
3176
|
+
// $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.
|
|
3177
|
+
fallback: [
|
|
3178
|
+
"moonshot/kimi-k2.6",
|
|
3179
|
+
// identical-cost in-family hot swap (K2.6 still routable)
|
|
3180
|
+
"moonshot/kimi-k2.5",
|
|
3181
|
+
// $0.60/$3.00 — graceful-degradation backstop
|
|
3182
|
+
"xai/grok-4-1-fast-non-reasoning",
|
|
3183
|
+
// 1,244ms, fast fallback
|
|
3184
|
+
"openai/gpt-4o-mini",
|
|
3185
|
+
// 2,764ms, reliable tool calling
|
|
3186
|
+
"anthropic/claude-haiku-4.5",
|
|
3187
|
+
// 2,305ms
|
|
3188
|
+
"deepseek/deepseek-chat"
|
|
3189
|
+
// 1,431ms
|
|
3190
|
+
]
|
|
3191
|
+
},
|
|
3192
|
+
COMPLEX: {
|
|
3193
|
+
primary: "anthropic/claude-sonnet-4.6",
|
|
3194
|
+
// 2,110ms — best agentic quality
|
|
3195
|
+
// Fallback chain de-Gemini'd 2026-04-22: Gemini's "high demand" 503s
|
|
3196
|
+
// correlate with Anthropic outages (everyone falls back together).
|
|
3197
|
+
// Prefer 503-resistant providers first.
|
|
3198
|
+
fallback: [
|
|
3199
|
+
"anthropic/claude-sonnet-5",
|
|
3200
|
+
// in-family hot swap — same cost, near-Opus agentic quality
|
|
3201
|
+
"anthropic/claude-opus-5",
|
|
3202
|
+
// Newest flagship Opus — in-family hot swap
|
|
3203
|
+
"anthropic/claude-opus-4.8",
|
|
3204
|
+
// Prior flagship Opus — identical cost to 5
|
|
3205
|
+
"anthropic/claude-opus-4.7",
|
|
3206
|
+
// Flagship Opus — in-family hot swap
|
|
3207
|
+
"anthropic/claude-opus-4.6",
|
|
3208
|
+
// 2,139ms
|
|
3209
|
+
"xai/grok-4-0709",
|
|
3210
|
+
// 1,348ms — strong tool use, independent infra
|
|
3211
|
+
"moonshot/kimi-k2.7",
|
|
3212
|
+
// Moonshot flagship — strong tool use, independent infra
|
|
3213
|
+
"moonshot/kimi-k2.5",
|
|
3214
|
+
// cost-stability backstop
|
|
3215
|
+
"openai/gpt-5.6-terra",
|
|
3216
|
+
// GPT-5.6 balanced tier — newest generation, stable (Sol excluded: #202)
|
|
3217
|
+
"openai/gpt-5.5",
|
|
3218
|
+
// Prior flagship — native agent + computer use (exactly the agentic-tier use case)
|
|
3219
|
+
"openai/gpt-5.4",
|
|
3220
|
+
// Previous flagship — 6,213ms, reliable
|
|
3221
|
+
"deepseek/deepseek-chat",
|
|
3222
|
+
// 1,431ms — cheap, reliable
|
|
3223
|
+
"free/gpt-oss-120b"
|
|
3224
|
+
// NVIDIA free ultimate backstop (was seed-oss-36b; EOL'd 2026-08-03)
|
|
3225
|
+
]
|
|
3226
|
+
},
|
|
3227
|
+
REASONING: {
|
|
3228
|
+
primary: "anthropic/claude-sonnet-4.6",
|
|
3229
|
+
// 2,110ms — strong tool use + reasoning
|
|
3230
|
+
fallback: [
|
|
3231
|
+
"anthropic/claude-sonnet-5",
|
|
3232
|
+
// in-family hot swap — same cost, adaptive thinking
|
|
3233
|
+
"anthropic/claude-opus-5",
|
|
3234
|
+
// Newest flagship Opus w/ adaptive thinking
|
|
3235
|
+
"anthropic/claude-opus-4.8",
|
|
3236
|
+
// Prior flagship Opus — identical cost to 5
|
|
3237
|
+
"anthropic/claude-opus-4.7",
|
|
3238
|
+
// Flagship Opus w/ adaptive thinking
|
|
3239
|
+
"anthropic/claude-opus-4.6",
|
|
3240
|
+
// 2,139ms
|
|
3241
|
+
"xai/grok-4-1-fast-reasoning",
|
|
3242
|
+
// 1,454ms
|
|
3243
|
+
"deepseek/deepseek-reasoner"
|
|
3244
|
+
// 1,454ms
|
|
3245
|
+
]
|
|
3246
|
+
}
|
|
3247
|
+
},
|
|
3248
|
+
// Time-windowed promotions — auto-applied when active, ignored when expired
|
|
3249
|
+
promotions: [
|
|
3250
|
+
{
|
|
3251
|
+
name: "GLM-5.1 Launch Promo ($0.001 flat)",
|
|
3252
|
+
startDate: "2026-04-01",
|
|
3253
|
+
endDate: "2026-05-01",
|
|
3254
|
+
tierOverrides: {
|
|
3255
|
+
SIMPLE: { primary: "zai/glm-5.1" }
|
|
3256
|
+
},
|
|
3257
|
+
profiles: ["auto"]
|
|
3258
|
+
// only auto profile — eco stays free, premium stays premium
|
|
3259
|
+
}
|
|
3260
|
+
],
|
|
3261
|
+
overrides: {
|
|
3262
|
+
maxTokensForceComplex: 1e5,
|
|
3263
|
+
structuredOutputMinTier: "MEDIUM",
|
|
3264
|
+
ambiguousDefaultTier: "MEDIUM"
|
|
3265
|
+
// agenticMode left undefined → auto-detect via tools/agenticScore.
|
|
3266
|
+
// Set to `true` to force agentic tiers; `false` to disable them entirely.
|
|
3267
|
+
}
|
|
3268
|
+
};
|
|
3269
|
+
registerStrategy(new PortfolioStrategy());
|
|
3270
|
+
function route(prompt, systemPrompt, maxOutputTokens, options) {
|
|
3271
|
+
const strategy = getStrategy(options.config.strategy ?? "portfolio");
|
|
3272
|
+
return strategy.route(prompt, systemPrompt, maxOutputTokens, options);
|
|
3273
|
+
}
|
|
3274
|
+
|
|
3275
|
+
// src/router-adapter.ts
|
|
3276
|
+
var AUTO_ROUTING_PROFILES = {
|
|
3277
|
+
"blockrun/auto": "auto",
|
|
3278
|
+
"blockrun/eco": "eco",
|
|
3279
|
+
"blockrun/premium": "premium"
|
|
3280
|
+
};
|
|
3281
|
+
var BASE_MINIMUM_PAYMENT_USD = 2e-3;
|
|
3282
|
+
var SOLANA_MINIMUM_PAYMENT_USD = 1e-3;
|
|
3283
|
+
function isTransientError(err) {
|
|
3284
|
+
if (err instanceof PaymentError) return false;
|
|
3285
|
+
if (err instanceof APIError) {
|
|
3286
|
+
return [429, 502, 503, 504, 522, 524].includes(err.statusCode);
|
|
3287
|
+
}
|
|
3288
|
+
if (err instanceof Error) {
|
|
3289
|
+
if (err.name === "AbortError") return true;
|
|
3290
|
+
if (err.name === "TypeError" && /fetch|network/i.test(err.message)) return true;
|
|
3291
|
+
}
|
|
3292
|
+
return false;
|
|
3293
|
+
}
|
|
3294
|
+
function errSummary(err) {
|
|
3295
|
+
if (err instanceof APIError) return `APIError ${err.statusCode}`;
|
|
3296
|
+
if (err instanceof Error) {
|
|
3297
|
+
const msg = err.message.length > 80 ? err.message.slice(0, 80) : err.message;
|
|
3298
|
+
return `${err.name}: ${msg}`;
|
|
3299
|
+
}
|
|
3300
|
+
return String(err).slice(0, 100);
|
|
3301
|
+
}
|
|
3302
|
+
function routingProfileForModel(model) {
|
|
3303
|
+
return AUTO_ROUTING_PROFILES[model.toLowerCase()];
|
|
3304
|
+
}
|
|
3305
|
+
function routingText(messages) {
|
|
3306
|
+
const systemPrompt = messages.filter((message) => message.role === "system" && typeof message.content === "string").map((message) => message.content).join("\n") || void 0;
|
|
3307
|
+
const lastUser = [...messages].reverse().find((message) => message.role === "user" && typeof message.content === "string");
|
|
3308
|
+
const lastText = [...messages].reverse().find((message) => typeof message.content === "string");
|
|
3309
|
+
let conversationChars = 0;
|
|
3310
|
+
let hasVision = false;
|
|
3311
|
+
for (const message of messages) {
|
|
3312
|
+
if (typeof message.content === "string") {
|
|
3313
|
+
conversationChars += message.content.length;
|
|
3314
|
+
} else if (Array.isArray(message.content)) {
|
|
3315
|
+
for (const part of message.content) {
|
|
3316
|
+
if (part?.type === "image_url" || part?.type === "image") hasVision = true;
|
|
3317
|
+
if (typeof part?.text === "string") conversationChars += part.text.length;
|
|
3318
|
+
}
|
|
3319
|
+
}
|
|
3320
|
+
}
|
|
3321
|
+
return {
|
|
3322
|
+
prompt: lastUser?.content ?? lastText?.content ?? "",
|
|
3323
|
+
systemPrompt,
|
|
3324
|
+
conversationChars,
|
|
3325
|
+
hasVision
|
|
3326
|
+
};
|
|
3327
|
+
}
|
|
3328
|
+
function routeWithCatalog(prompt, systemPrompt, maxOutputTokens, modelPricing, options = {}) {
|
|
3329
|
+
const tools = options.tools ?? [];
|
|
3330
|
+
const requiresTools = options.toolChoice === "none" ? false : options.toolChoice === "required" || typeof options.toolChoice === "object" ? true : void 0;
|
|
3331
|
+
const decision = route(prompt, systemPrompt, maxOutputTokens, {
|
|
3332
|
+
config: DEFAULT_ROUTING_CONFIG,
|
|
3333
|
+
modelPricing,
|
|
3334
|
+
routingProfile: options.routingProfile,
|
|
3335
|
+
hasTools: tools.length > 0,
|
|
3336
|
+
toolCount: tools.length,
|
|
3337
|
+
toolNames: tools.map((tool) => tool.function.name),
|
|
3338
|
+
requiresTools,
|
|
3339
|
+
hasVision: options.hasVision,
|
|
3340
|
+
requiresStructuredOutput: options.requiresStructuredOutput
|
|
3341
|
+
});
|
|
3342
|
+
const tierConfigs = decision.tierConfigs ?? DEFAULT_ROUTING_CONFIG.tiers;
|
|
3343
|
+
const ranked = decision.candidates?.length ? decision.candidates : [decision.model, ...getFallbackChain(decision.tier, tierConfigs)];
|
|
3344
|
+
const callable = [];
|
|
3345
|
+
for (const id of ranked) {
|
|
3346
|
+
const resolved = !id.startsWith("free/") ? id : modelPricing.has(`nvidia/${id.slice(5)}`) ? `nvidia/${id.slice(5)}` : null;
|
|
3347
|
+
if (resolved && !callable.includes(resolved)) callable.push(resolved);
|
|
3348
|
+
}
|
|
3349
|
+
const estimatedInputTokens = Math.ceil(
|
|
3350
|
+
Math.max(options.conversationChars ?? 0, `${systemPrompt ?? ""} ${prompt}`.length) / 4
|
|
3351
|
+
);
|
|
3352
|
+
const fitting = filterCandidatesByCapacity(
|
|
3353
|
+
callable,
|
|
3354
|
+
estimatedInputTokens,
|
|
3355
|
+
maxOutputTokens,
|
|
3356
|
+
(id) => {
|
|
3357
|
+
const caps = DEFAULT_MODEL_CAPABILITIES[id];
|
|
3358
|
+
return caps ? { contextWindow: caps.contextWindow, maxOutput: caps.maxOutputTokens } : void 0;
|
|
3359
|
+
}
|
|
3360
|
+
);
|
|
3361
|
+
const availableCandidates = fitting.length > 0 ? fitting : callable;
|
|
3362
|
+
const model = availableCandidates[0] ?? decision.model;
|
|
3363
|
+
const costs = calculateModelCost(
|
|
3364
|
+
model,
|
|
3365
|
+
modelPricing,
|
|
3366
|
+
estimatedInputTokens,
|
|
3367
|
+
maxOutputTokens,
|
|
3368
|
+
options.routingProfile
|
|
3369
|
+
);
|
|
3370
|
+
const minimumPaymentUsd = options.minimumPaymentUsd ?? SOLANA_MINIMUM_PAYMENT_USD;
|
|
3371
|
+
const entry = modelPricing.get(model);
|
|
3372
|
+
const isFree = entry !== void 0 && entry.inputPrice === 0 && entry.outputPrice === 0 && !entry.flatPrice;
|
|
3373
|
+
const costEstimate = isFree ? 0 : Math.max(costs.costEstimate, minimumPaymentUsd);
|
|
3374
|
+
const savings = options.routingProfile === "premium" || costs.baselineCost <= 0 ? 0 : entry !== void 0 ? Math.max(0, (costs.baselineCost - costEstimate) / costs.baselineCost) : decision.savings;
|
|
3375
|
+
return {
|
|
3376
|
+
...decision,
|
|
3377
|
+
...costs,
|
|
3378
|
+
costEstimate,
|
|
3379
|
+
savings,
|
|
3380
|
+
model,
|
|
3381
|
+
reasoning: model === decision.model ? decision.reasoning : `${decision.reasoning} | catalog fallback: ${model}`,
|
|
3382
|
+
candidates: availableCandidates,
|
|
3383
|
+
candidateScores: decision.candidateScores?.filter(
|
|
3384
|
+
(score) => availableCandidates.includes(score.model)
|
|
3385
|
+
),
|
|
3386
|
+
fallbacks: availableCandidates.slice(1)
|
|
3387
|
+
};
|
|
3388
|
+
}
|
|
3389
|
+
|
|
34
3390
|
// src/x402.ts
|
|
35
3391
|
import { signTypedData } from "viem/accounts";
|
|
36
3392
|
|
|
@@ -494,29 +3850,10 @@ function getCostSummary() {
|
|
|
494
3850
|
}
|
|
495
3851
|
|
|
496
3852
|
// src/version.ts
|
|
497
|
-
var SDK_VERSION = "3.
|
|
3853
|
+
var SDK_VERSION = "3.13.0";
|
|
498
3854
|
var USER_AGENT = `blockrun-ts/${SDK_VERSION}`;
|
|
499
3855
|
|
|
500
3856
|
// src/client.ts
|
|
501
|
-
function isTransientError(err) {
|
|
502
|
-
if (err instanceof PaymentError) return false;
|
|
503
|
-
if (err instanceof APIError) {
|
|
504
|
-
return [429, 502, 503, 504, 522, 524].includes(err.statusCode);
|
|
505
|
-
}
|
|
506
|
-
if (err instanceof Error) {
|
|
507
|
-
if (err.name === "AbortError") return true;
|
|
508
|
-
if (err.name === "TypeError" && /fetch|network/i.test(err.message)) return true;
|
|
509
|
-
}
|
|
510
|
-
return false;
|
|
511
|
-
}
|
|
512
|
-
function errSummary(err) {
|
|
513
|
-
if (err instanceof APIError) return `APIError ${err.statusCode}`;
|
|
514
|
-
if (err instanceof Error) {
|
|
515
|
-
const msg = err.message.length > 80 ? err.message.slice(0, 80) : err.message;
|
|
516
|
-
return `${err.name}: ${msg}`;
|
|
517
|
-
}
|
|
518
|
-
return String(err).slice(0, 100);
|
|
519
|
-
}
|
|
520
3857
|
function mapRawToModel(m) {
|
|
521
3858
|
return {
|
|
522
3859
|
id: m.id,
|
|
@@ -571,7 +3908,7 @@ var LLMClient = class _LLMClient {
|
|
|
571
3908
|
modelPricingPromise = null;
|
|
572
3909
|
// Pre-auth cache: avoids the 402 round-trip on repeat requests to the same model.
|
|
573
3910
|
// Key = "endpoint:model", value = cached payment header + timestamp.
|
|
574
|
-
// TTL: 1 hour
|
|
3911
|
+
// TTL: 1 hour — pre-auth quotes are stable server-side on that horizon.
|
|
575
3912
|
preAuthCache = /* @__PURE__ */ new Map();
|
|
576
3913
|
static PRE_AUTH_TTL_MS = 36e5;
|
|
577
3914
|
/**
|
|
@@ -625,11 +3962,35 @@ var LLMClient = class _LLMClient {
|
|
|
625
3962
|
});
|
|
626
3963
|
return result.choices[0].message.content || "";
|
|
627
3964
|
}
|
|
3965
|
+
async makeRoutingDecision(prompt, systemPrompt, maxOutputTokens, options = {}) {
|
|
3966
|
+
return routeWithCatalog(
|
|
3967
|
+
prompt,
|
|
3968
|
+
systemPrompt,
|
|
3969
|
+
maxOutputTokens,
|
|
3970
|
+
await this.getModelPricing(),
|
|
3971
|
+
{ ...options, minimumPaymentUsd: BASE_MINIMUM_PAYMENT_USD }
|
|
3972
|
+
);
|
|
3973
|
+
}
|
|
3974
|
+
/**
|
|
3975
|
+
* Inspect a local routing decision without making or paying for a model call.
|
|
3976
|
+
* The first invocation may fetch the public model catalog for current prices.
|
|
3977
|
+
*/
|
|
3978
|
+
async route(prompt, options) {
|
|
3979
|
+
return this.makeRoutingDecision(
|
|
3980
|
+
prompt,
|
|
3981
|
+
options?.system,
|
|
3982
|
+
options?.maxOutputTokens ?? options?.maxTokens ?? DEFAULT_MAX_TOKENS,
|
|
3983
|
+
{
|
|
3984
|
+
routingProfile: options?.routingProfile,
|
|
3985
|
+
requiresStructuredOutput: options?.responseFormat !== void 0
|
|
3986
|
+
}
|
|
3987
|
+
);
|
|
3988
|
+
}
|
|
628
3989
|
/**
|
|
629
3990
|
* Smart chat with automatic model routing.
|
|
630
3991
|
*
|
|
631
|
-
* Uses
|
|
632
|
-
*
|
|
3992
|
+
* Uses BlockRun's product-neutral Router Core portfolio strategy: it
|
|
3993
|
+
* classifies the task shape locally (no
|
|
633
3994
|
* extra model call), enforces capability constraints as hard filters, and
|
|
634
3995
|
* ranks an ordered candidate portfolio — the cheapest model that can handle
|
|
635
3996
|
* the request wins, and the rest become the transient-error fallback chain.
|
|
@@ -657,33 +4018,8 @@ var LLMClient = class _LLMClient {
|
|
|
657
4018
|
* ```
|
|
658
4019
|
*/
|
|
659
4020
|
async smartChat(prompt, options) {
|
|
660
|
-
const
|
|
661
|
-
const
|
|
662
|
-
let route;
|
|
663
|
-
let DEFAULT_ROUTING_CONFIG;
|
|
664
|
-
let getFallbackChain;
|
|
665
|
-
try {
|
|
666
|
-
({ route, DEFAULT_ROUTING_CONFIG, getFallbackChain } = await import("@blockrun/clawrouter"));
|
|
667
|
-
} catch (err) {
|
|
668
|
-
throw new Error(
|
|
669
|
-
`smartChat() requires the optional '@blockrun/clawrouter' routing engine, which is not installed or failed to load. Install it, or call chat() with an explicit model instead. Cause: ${err.message}`
|
|
670
|
-
);
|
|
671
|
-
}
|
|
672
|
-
const decision = route(prompt, options?.system, maxOutputTokens, {
|
|
673
|
-
config: DEFAULT_ROUTING_CONFIG,
|
|
674
|
-
modelPricing,
|
|
675
|
-
routingProfile: options?.routingProfile
|
|
676
|
-
});
|
|
677
|
-
const tierConfigs = decision.tierConfigs ?? DEFAULT_ROUTING_CONFIG.tiers;
|
|
678
|
-
const ranked = decision.candidates?.length ? decision.candidates : [decision.model, ...getFallbackChain(decision.tier, tierConfigs)];
|
|
679
|
-
const callable = [];
|
|
680
|
-
for (const id of ranked) {
|
|
681
|
-
const resolved = !id.startsWith("free/") ? id : modelPricing.has(`nvidia/${id.slice(5)}`) ? `nvidia/${id.slice(5)}` : null;
|
|
682
|
-
if (resolved && !callable.includes(resolved)) callable.push(resolved);
|
|
683
|
-
}
|
|
684
|
-
const primary = callable[0] ?? decision.model;
|
|
685
|
-
const fallbacks = callable.slice(1);
|
|
686
|
-
const response = await this.chat(primary, prompt, {
|
|
4021
|
+
const decision = await this.route(prompt, options);
|
|
4022
|
+
const response = await this.chat(decision.model, prompt, {
|
|
687
4023
|
system: options?.system,
|
|
688
4024
|
maxTokens: options?.maxTokens,
|
|
689
4025
|
temperature: options?.temperature,
|
|
@@ -692,14 +4028,47 @@ var LLMClient = class _LLMClient {
|
|
|
692
4028
|
searchParameters: options?.searchParameters,
|
|
693
4029
|
responseFormat: options?.responseFormat,
|
|
694
4030
|
stop: options?.stop,
|
|
695
|
-
|
|
4031
|
+
// An explicit caller-supplied chain wins over the routed one.
|
|
4032
|
+
fallbackModels: options?.fallbackModels ?? decision.fallbacks
|
|
696
4033
|
});
|
|
697
4034
|
return {
|
|
698
4035
|
response,
|
|
699
|
-
model:
|
|
700
|
-
routing:
|
|
4036
|
+
model: decision.model,
|
|
4037
|
+
routing: decision
|
|
701
4038
|
};
|
|
702
4039
|
}
|
|
4040
|
+
/** Route a full Agent/tool conversation while preserving its complete response. */
|
|
4041
|
+
async smartChatCompletion(messages, options = {}) {
|
|
4042
|
+
const { prompt, systemPrompt, conversationChars, hasVision } = routingText(messages);
|
|
4043
|
+
const decision = await this.makeRoutingDecision(
|
|
4044
|
+
prompt,
|
|
4045
|
+
systemPrompt,
|
|
4046
|
+
options.maxOutputTokens ?? options.maxTokens ?? DEFAULT_MAX_TOKENS,
|
|
4047
|
+
{
|
|
4048
|
+
routingProfile: options.routingProfile,
|
|
4049
|
+
requiresStructuredOutput: options.responseFormat !== void 0,
|
|
4050
|
+
tools: options.tools,
|
|
4051
|
+
toolChoice: options.toolChoice,
|
|
4052
|
+
conversationChars,
|
|
4053
|
+
hasVision
|
|
4054
|
+
}
|
|
4055
|
+
);
|
|
4056
|
+
const response = await this.chatCompletion(decision.model, messages, {
|
|
4057
|
+
maxTokens: options.maxTokens,
|
|
4058
|
+
temperature: options.temperature,
|
|
4059
|
+
topP: options.topP,
|
|
4060
|
+
search: options.search,
|
|
4061
|
+
searchParameters: options.searchParameters,
|
|
4062
|
+
tools: options.tools,
|
|
4063
|
+
toolChoice: options.toolChoice,
|
|
4064
|
+
responseFormat: options.responseFormat,
|
|
4065
|
+
stop: options.stop,
|
|
4066
|
+
// An explicit caller-supplied chain wins over the routed one.
|
|
4067
|
+
fallbackModels: options.fallbackModels ?? decision.fallbacks
|
|
4068
|
+
});
|
|
4069
|
+
response.routing = decision;
|
|
4070
|
+
return { response, model: decision.model, routing: decision };
|
|
4071
|
+
}
|
|
703
4072
|
/**
|
|
704
4073
|
* Get model pricing map (cached).
|
|
705
4074
|
* Fetches from API on first call, then returns cached result.
|
|
@@ -719,31 +4088,18 @@ var LLMClient = class _LLMClient {
|
|
|
719
4088
|
this.modelPricingPromise = null;
|
|
720
4089
|
}
|
|
721
4090
|
}
|
|
722
|
-
/**
|
|
723
|
-
* Fetch model pricing from API.
|
|
724
|
-
*
|
|
725
|
-
* For flat-billed models (e.g. ZAI GLM-5 family at $0.001/call) the
|
|
726
|
-
* router still expects per-token rates, so we synthesise an equivalent
|
|
727
|
-
* per-token price assuming ~1500 total tokens per call. Without this,
|
|
728
|
-
* flat models would resolve to inputPrice=outputPrice=0 and the router
|
|
729
|
-
* would treat them as free, biasing routing decisions and reporting
|
|
730
|
-
* inflated savings %.
|
|
731
|
-
*/
|
|
4091
|
+
/** Fetch model pricing from the live catalog, preserving flat billing. */
|
|
732
4092
|
async fetchModelPricing() {
|
|
733
4093
|
const models = await this.listModels();
|
|
734
4094
|
const pricing = /* @__PURE__ */ new Map();
|
|
735
4095
|
for (const model of models) {
|
|
736
|
-
if (model.
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
});
|
|
4096
|
+
if (model.available === false) continue;
|
|
4097
|
+
const inputPrice = Number.isFinite(model.inputPrice) ? model.inputPrice : 0;
|
|
4098
|
+
const outputPrice = Number.isFinite(model.outputPrice) ? model.outputPrice : 0;
|
|
4099
|
+
if (model.billingMode === "flat" && Number.isFinite(model.flatPrice) && model.flatPrice > 0) {
|
|
4100
|
+
pricing.set(model.id, { inputPrice, outputPrice, flatPrice: model.flatPrice });
|
|
742
4101
|
} else {
|
|
743
|
-
pricing.set(model.id, {
|
|
744
|
-
inputPrice: model.inputPrice,
|
|
745
|
-
outputPrice: model.outputPrice
|
|
746
|
-
});
|
|
4102
|
+
pricing.set(model.id, { inputPrice, outputPrice });
|
|
747
4103
|
}
|
|
748
4104
|
}
|
|
749
4105
|
return pricing;
|
|
@@ -763,6 +4119,13 @@ var LLMClient = class _LLMClient {
|
|
|
763
4119
|
* @returns ChatResponse object with choices and usage
|
|
764
4120
|
*/
|
|
765
4121
|
async chatCompletion(model, messages, options) {
|
|
4122
|
+
const routingProfile = routingProfileForModel(model);
|
|
4123
|
+
if (routingProfile) {
|
|
4124
|
+
return (await this.smartChatCompletion(messages, {
|
|
4125
|
+
...options,
|
|
4126
|
+
routingProfile
|
|
4127
|
+
})).response;
|
|
4128
|
+
}
|
|
766
4129
|
validateMaxTokens(options?.maxTokens);
|
|
767
4130
|
const buildBody = (m) => {
|
|
768
4131
|
const body = {
|
|
@@ -1035,9 +4398,28 @@ var LLMClient = class _LLMClient {
|
|
|
1035
4398
|
*/
|
|
1036
4399
|
async chatCompletionStream(model, messages, options) {
|
|
1037
4400
|
validateMaxTokens(options?.maxTokens);
|
|
4401
|
+
let requestModel = model;
|
|
4402
|
+
const routingProfile = routingProfileForModel(model);
|
|
4403
|
+
if (routingProfile) {
|
|
4404
|
+
const { prompt, systemPrompt, conversationChars, hasVision } = routingText(messages);
|
|
4405
|
+
const decision = await this.makeRoutingDecision(
|
|
4406
|
+
prompt,
|
|
4407
|
+
systemPrompt,
|
|
4408
|
+
options?.maxTokens ?? DEFAULT_MAX_TOKENS,
|
|
4409
|
+
{
|
|
4410
|
+
routingProfile,
|
|
4411
|
+
requiresStructuredOutput: options?.responseFormat !== void 0,
|
|
4412
|
+
tools: options?.tools,
|
|
4413
|
+
toolChoice: options?.toolChoice,
|
|
4414
|
+
conversationChars,
|
|
4415
|
+
hasVision
|
|
4416
|
+
}
|
|
4417
|
+
);
|
|
4418
|
+
requestModel = decision.model;
|
|
4419
|
+
}
|
|
1038
4420
|
const url = `${this.apiUrl}/v1/chat/completions`;
|
|
1039
4421
|
const body = {
|
|
1040
|
-
model,
|
|
4422
|
+
model: requestModel,
|
|
1041
4423
|
messages,
|
|
1042
4424
|
max_tokens: options?.maxTokens ?? DEFAULT_MAX_TOKENS,
|
|
1043
4425
|
stream: true
|
|
@@ -1048,7 +4430,7 @@ var LLMClient = class _LLMClient {
|
|
|
1048
4430
|
if (options?.toolChoice !== void 0) body.tool_choice = options.toolChoice;
|
|
1049
4431
|
if (options?.responseFormat !== void 0) body.response_format = options.responseFormat;
|
|
1050
4432
|
if (options?.stop !== void 0) body.stop = options.stop;
|
|
1051
|
-
const cacheKey2 = `/v1/chat/completions:${
|
|
4433
|
+
const cacheKey2 = `/v1/chat/completions:${requestModel}`;
|
|
1052
4434
|
const cached = this.preAuthCache.get(cacheKey2);
|
|
1053
4435
|
const now = Date.now();
|
|
1054
4436
|
if (cached && now - cached.cachedAt < _LLMClient.PRE_AUTH_TTL_MS) {
|
|
@@ -1558,8 +4940,8 @@ var LLMClient = class _LLMClient {
|
|
|
1558
4940
|
* @example
|
|
1559
4941
|
* const results = await client.exa("search", { query: "latest AI research", numResults: 5 });
|
|
1560
4942
|
*/
|
|
1561
|
-
async exa(
|
|
1562
|
-
return this.requestWithPaymentRaw(`/v1/exa/${
|
|
4943
|
+
async exa(path6, body) {
|
|
4944
|
+
return this.requestWithPaymentRaw(`/v1/exa/${path6}`, body);
|
|
1563
4945
|
}
|
|
1564
4946
|
/**
|
|
1565
4947
|
* Neural web search via Exa. Returns semantically relevant URLs and metadata.
|
|
@@ -1658,7 +5040,13 @@ var LLMClient = class _LLMClient {
|
|
|
1658
5040
|
*/
|
|
1659
5041
|
async getBalance() {
|
|
1660
5042
|
const usdcContract = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913";
|
|
1661
|
-
const
|
|
5043
|
+
const configuredRpc = typeof process !== "undefined" && process.env ? process.env.BASE_RPC_URL : void 0;
|
|
5044
|
+
const rpcs = [
|
|
5045
|
+
configuredRpc,
|
|
5046
|
+
"https://base-rpc.publicnode.com",
|
|
5047
|
+
"https://mainnet.base.org",
|
|
5048
|
+
"https://base.llamarpc.com"
|
|
5049
|
+
].filter((rpc) => Boolean(rpc));
|
|
1662
5050
|
const selector = "0x70a08231";
|
|
1663
5051
|
const paddedAddress = this.account.address.slice(2).toLowerCase().padStart(64, "0");
|
|
1664
5052
|
const data = selector + paddedAddress;
|
|
@@ -1676,7 +5064,9 @@ var LLMClient = class _LLMClient {
|
|
|
1676
5064
|
headers: { "Content-Type": "application/json" },
|
|
1677
5065
|
body: JSON.stringify(payload)
|
|
1678
5066
|
});
|
|
5067
|
+
if (!response.ok) throw new Error(`Base RPC returned ${response.status}`);
|
|
1679
5068
|
const result = await response.json();
|
|
5069
|
+
if (!result.result || result.error) throw new Error("Base RPC returned no balance result");
|
|
1680
5070
|
const balanceRaw = parseInt(result.result || "0x0", 16);
|
|
1681
5071
|
return balanceRaw / 1e6;
|
|
1682
5072
|
} catch (e) {
|
|
@@ -1699,8 +5089,8 @@ var LLMClient = class _LLMClient {
|
|
|
1699
5089
|
* const market = await client.pm("kalshi/markets/KXBTC-25MAR14");
|
|
1700
5090
|
* const results = await client.pm("polymarket/search", { q: "bitcoin" });
|
|
1701
5091
|
*/
|
|
1702
|
-
async pm(
|
|
1703
|
-
return this.getWithPaymentRaw(`/v1/pm/${
|
|
5092
|
+
async pm(path6, params) {
|
|
5093
|
+
return this.getWithPaymentRaw(`/v1/pm/${path6}`, params);
|
|
1704
5094
|
}
|
|
1705
5095
|
/**
|
|
1706
5096
|
* Structured query for Predexon prediction market data (POST endpoints).
|
|
@@ -1716,8 +5106,8 @@ var LLMClient = class _LLMClient {
|
|
|
1716
5106
|
* addresses: ["0xabc...", "0xdef..."],
|
|
1717
5107
|
* });
|
|
1718
5108
|
*/
|
|
1719
|
-
async pmQuery(
|
|
1720
|
-
return this.requestWithPaymentRaw(`/v1/pm/${
|
|
5109
|
+
async pmQuery(path6, query) {
|
|
5110
|
+
return this.requestWithPaymentRaw(`/v1/pm/${path6}`, query);
|
|
1721
5111
|
}
|
|
1722
5112
|
// ── PM convenience helpers (Predexon v2) ─────────────────────────────────
|
|
1723
5113
|
// Thin wrappers over pm() / pmQuery() for the most common v2 endpoints.
|
|
@@ -1805,8 +5195,8 @@ var LLMClient = class _LLMClient {
|
|
|
1805
5195
|
* "prices/coingecko:bitcoin,base:0x..."
|
|
1806
5196
|
* @param params - Query parameters passed through to DefiLlama
|
|
1807
5197
|
*/
|
|
1808
|
-
async defi(
|
|
1809
|
-
return this.getWithPaymentRaw(`/v1/defillama/${
|
|
5198
|
+
async defi(path6, params) {
|
|
5199
|
+
return this.getWithPaymentRaw(`/v1/defillama/${path6}`, params);
|
|
1810
5200
|
}
|
|
1811
5201
|
/** All DeFi protocols with TVL ($0.005/call). */
|
|
1812
5202
|
async defiProtocols() {
|
|
@@ -1842,9 +5232,9 @@ var LLMClient = class _LLMClient {
|
|
|
1842
5232
|
* @param params - Query params (chainId, sellToken, buyToken, sellAmount, taker, ...)
|
|
1843
5233
|
* @param body - JSON body — pass to switch to POST (gasless/submit only)
|
|
1844
5234
|
*/
|
|
1845
|
-
async dex(
|
|
1846
|
-
if (body) return this.requestWithPaymentRaw(`/v1/zerox/${
|
|
1847
|
-
return this.getWithPaymentRaw(`/v1/zerox/${
|
|
5235
|
+
async dex(path6, params, body) {
|
|
5236
|
+
if (body) return this.requestWithPaymentRaw(`/v1/zerox/${path6}`, body);
|
|
5237
|
+
return this.getWithPaymentRaw(`/v1/zerox/${path6}`, params);
|
|
1848
5238
|
}
|
|
1849
5239
|
/** Indicative Permit2 swap price — no commitment (free). */
|
|
1850
5240
|
async dexPrice(params) {
|
|
@@ -1888,8 +5278,8 @@ var LLMClient = class _LLMClient {
|
|
|
1888
5278
|
* "sandbox/status", "sandbox/terminate" ($0.001 each)
|
|
1889
5279
|
* @param body - JSON body for the endpoint
|
|
1890
5280
|
*/
|
|
1891
|
-
async modal(
|
|
1892
|
-
return this.requestWithPaymentRaw(`/v1/modal/${
|
|
5281
|
+
async modal(path6, body) {
|
|
5282
|
+
return this.requestWithPaymentRaw(`/v1/modal/${path6}`, body ?? {});
|
|
1893
5283
|
}
|
|
1894
5284
|
/** Create a sandboxed compute environment ($0.01 CPU / $0.05 GPU). */
|
|
1895
5285
|
async modalSandboxCreate(body) {
|
|
@@ -3251,8 +6641,8 @@ var PhoneClient = class {
|
|
|
3251
6641
|
return data;
|
|
3252
6642
|
}
|
|
3253
6643
|
// ─── Internals ─────────────────────────────────────────────────────────
|
|
3254
|
-
async request(
|
|
3255
|
-
const url = `${this.apiUrl}/v1/phone/${
|
|
6644
|
+
async request(path6, body) {
|
|
6645
|
+
const url = `${this.apiUrl}/v1/phone/${path6}`;
|
|
3256
6646
|
const response = await this.fetchWithTimeout(url, {
|
|
3257
6647
|
method: "POST",
|
|
3258
6648
|
headers: { "Content-Type": "application/json" },
|
|
@@ -3659,10 +7049,10 @@ var PriceClient = class {
|
|
|
3659
7049
|
}
|
|
3660
7050
|
async price(category, symbol, options) {
|
|
3661
7051
|
if (!symbol) throw new Error("symbol is required");
|
|
3662
|
-
const
|
|
7052
|
+
const path6 = categoryPath(category, options?.market, "price", symbol);
|
|
3663
7053
|
const query = {};
|
|
3664
7054
|
if (options?.session) query.session = options.session;
|
|
3665
|
-
const data = await this.getWithPayment(
|
|
7055
|
+
const data = await this.getWithPayment(path6, query);
|
|
3666
7056
|
return {
|
|
3667
7057
|
symbol: data.symbol ?? symbol.toUpperCase(),
|
|
3668
7058
|
price: data.price,
|
|
@@ -3681,14 +7071,14 @@ var PriceClient = class {
|
|
|
3681
7071
|
if (!options.from || options.from <= 0) {
|
|
3682
7072
|
throw new Error("history requires options.from (unix seconds)");
|
|
3683
7073
|
}
|
|
3684
|
-
const
|
|
7074
|
+
const path6 = categoryPath(category, options.market, "history", symbol);
|
|
3685
7075
|
const query = {
|
|
3686
7076
|
resolution: options.resolution ?? "D",
|
|
3687
7077
|
from: String(options.from)
|
|
3688
7078
|
};
|
|
3689
7079
|
if (options.to) query.to = String(options.to);
|
|
3690
7080
|
if (options.session) query.session = options.session;
|
|
3691
|
-
const data = await this.getWithPayment(
|
|
7081
|
+
const data = await this.getWithPayment(path6, query);
|
|
3692
7082
|
return {
|
|
3693
7083
|
symbol: data.symbol ?? symbol.toUpperCase(),
|
|
3694
7084
|
resolution: data.resolution ?? (options.resolution ?? "D"),
|
|
@@ -3700,12 +7090,12 @@ var PriceClient = class {
|
|
|
3700
7090
|
};
|
|
3701
7091
|
}
|
|
3702
7092
|
async listSymbols(category, options) {
|
|
3703
|
-
const
|
|
7093
|
+
const path6 = categoryPath(category, options?.market, "list");
|
|
3704
7094
|
const query = {
|
|
3705
7095
|
limit: String(options?.limit && options.limit > 0 ? options.limit : 100)
|
|
3706
7096
|
};
|
|
3707
7097
|
if (options?.query) query.q = options.query;
|
|
3708
|
-
const data = await this.getWithPayment(
|
|
7098
|
+
const data = await this.getWithPayment(path6, query);
|
|
3709
7099
|
if (Array.isArray(data)) {
|
|
3710
7100
|
return { symbols: data, count: data.length };
|
|
3711
7101
|
}
|
|
@@ -3864,19 +7254,19 @@ var SurfClient = class {
|
|
|
3864
7254
|
* `/v1/surf` is tolerated and stripped). Query params are URL-encoded;
|
|
3865
7255
|
* arrays become repeated keys (`?a=1&a=2`).
|
|
3866
7256
|
*/
|
|
3867
|
-
async get(
|
|
3868
|
-
const url = this.buildUrl(
|
|
7257
|
+
async get(path6, params) {
|
|
7258
|
+
const url = this.buildUrl(path6, params);
|
|
3869
7259
|
return this.requestWithPayment(url, "GET");
|
|
3870
7260
|
}
|
|
3871
7261
|
/**
|
|
3872
7262
|
* POST a Surf endpoint with a JSON body. Same path normalization as `get`.
|
|
3873
7263
|
*/
|
|
3874
|
-
async post(
|
|
3875
|
-
const url = this.buildUrl(
|
|
7264
|
+
async post(path6, body) {
|
|
7265
|
+
const url = this.buildUrl(path6);
|
|
3876
7266
|
return this.requestWithPayment(url, "POST", body);
|
|
3877
7267
|
}
|
|
3878
|
-
buildUrl(
|
|
3879
|
-
let normalized =
|
|
7268
|
+
buildUrl(path6, params) {
|
|
7269
|
+
let normalized = path6.startsWith("/") ? path6 : `/${path6}`;
|
|
3880
7270
|
if (!normalized.startsWith(SURF_PREFIX)) {
|
|
3881
7271
|
normalized = `${SURF_PREFIX}${normalized}`;
|
|
3882
7272
|
}
|
|
@@ -4276,15 +7666,15 @@ var BlockrunClient = class {
|
|
|
4276
7666
|
* `/api` is tolerated and stripped). Query params are URL-encoded; arrays
|
|
4277
7667
|
* become repeated keys (`?a=1&a=2`); undefined/null are dropped.
|
|
4278
7668
|
*/
|
|
4279
|
-
async get(
|
|
4280
|
-
const url = this.buildUrl(
|
|
7669
|
+
async get(path6, params) {
|
|
7670
|
+
const url = this.buildUrl(path6, params);
|
|
4281
7671
|
return this.requestWithPayment(url, "GET");
|
|
4282
7672
|
}
|
|
4283
7673
|
/**
|
|
4284
7674
|
* POST a BlockRun endpoint with a JSON body.
|
|
4285
7675
|
*/
|
|
4286
|
-
async post(
|
|
4287
|
-
const url = this.buildUrl(
|
|
7676
|
+
async post(path6, body) {
|
|
7677
|
+
const url = this.buildUrl(path6);
|
|
4288
7678
|
return this.requestWithPayment(url, "POST", body);
|
|
4289
7679
|
}
|
|
4290
7680
|
/**
|
|
@@ -4299,8 +7689,8 @@ var BlockrunClient = class {
|
|
|
4299
7689
|
* short-circuits and returns the body. Most long-running endpoints (image,
|
|
4300
7690
|
* video, music, voice) return 202 with a poll_url.
|
|
4301
7691
|
*/
|
|
4302
|
-
async poll(
|
|
4303
|
-
const submitUrl = this.buildUrl(
|
|
7692
|
+
async poll(path6, body, options) {
|
|
7693
|
+
const submitUrl = this.buildUrl(path6);
|
|
4304
7694
|
const budgetMs = options?.budgetMs ?? DEFAULT_POLL_BUDGET_MS;
|
|
4305
7695
|
const intervalMs = options?.intervalMs ?? DEFAULT_POLL_INTERVAL_MS;
|
|
4306
7696
|
const resp402 = await this.fetchWithTimeout(submitUrl, {
|
|
@@ -4399,8 +7789,8 @@ var BlockrunClient = class {
|
|
|
4399
7789
|
* process.stdout.write(chunk.choices?.[0]?.delta?.content ?? "");
|
|
4400
7790
|
* }
|
|
4401
7791
|
*/
|
|
4402
|
-
async *stream(
|
|
4403
|
-
const url = this.buildUrl(
|
|
7792
|
+
async *stream(path6, body) {
|
|
7793
|
+
const url = this.buildUrl(path6);
|
|
4404
7794
|
const requestBody = JSON.stringify(body ?? {});
|
|
4405
7795
|
const resp402 = await this.fetchWithTimeout(url, {
|
|
4406
7796
|
method: "POST",
|
|
@@ -4466,8 +7856,8 @@ var BlockrunClient = class {
|
|
|
4466
7856
|
// --------------------------------------------------------------------
|
|
4467
7857
|
// Internal: shared infrastructure
|
|
4468
7858
|
// --------------------------------------------------------------------
|
|
4469
|
-
buildUrl(
|
|
4470
|
-
let normalized =
|
|
7859
|
+
buildUrl(path6, params) {
|
|
7860
|
+
let normalized = path6.startsWith("/") ? path6 : `/${path6}`;
|
|
4471
7861
|
if (normalized.startsWith("/api/")) {
|
|
4472
7862
|
normalized = normalized.slice(4);
|
|
4473
7863
|
}
|
|
@@ -4620,46 +8010,64 @@ function sleep(ms) {
|
|
|
4620
8010
|
}
|
|
4621
8011
|
|
|
4622
8012
|
// src/wallet.ts
|
|
4623
|
-
import { privateKeyToAccount as
|
|
8013
|
+
import { privateKeyToAccount as privateKeyToAccount15, generatePrivateKey as generatePrivateKey2 } from "viem/accounts";
|
|
8014
|
+
|
|
8015
|
+
// node_modules/.pnpm/@blockrun+core@0.1.1_bufferutil@4.1.0_typescript@5.9.3_utf-8-validate@6.0.6_zod@3.25.76/node_modules/@blockrun/core/dist/config.js
|
|
4624
8016
|
import * as fs2 from "fs";
|
|
4625
|
-
import * as path2 from "path";
|
|
4626
8017
|
import * as os2 from "os";
|
|
4627
|
-
|
|
4628
|
-
|
|
4629
|
-
|
|
4630
|
-
|
|
4631
|
-
function
|
|
4632
|
-
|
|
4633
|
-
|
|
8018
|
+
import * as path2 from "path";
|
|
8019
|
+
function homeDir() {
|
|
8020
|
+
return process.env.BLOCKRUN_HOME || os2.homedir();
|
|
8021
|
+
}
|
|
8022
|
+
function blockrunDir() {
|
|
8023
|
+
return path2.join(homeDir(), ".blockrun");
|
|
8024
|
+
}
|
|
8025
|
+
function paths() {
|
|
8026
|
+
const dir = blockrunDir();
|
|
4634
8027
|
return {
|
|
4635
|
-
|
|
4636
|
-
|
|
8028
|
+
dir,
|
|
8029
|
+
session: path2.join(dir, ".session"),
|
|
8030
|
+
legacy: path2.join(dir, "wallet.key"),
|
|
8031
|
+
solana: path2.join(dir, ".solana"),
|
|
8032
|
+
config: path2.join(dir, "config.json"),
|
|
8033
|
+
costLog: path2.join(dir, "cost_log.jsonl")
|
|
4637
8034
|
};
|
|
4638
8035
|
}
|
|
4639
|
-
|
|
4640
|
-
|
|
4641
|
-
|
|
8036
|
+
|
|
8037
|
+
// node_modules/.pnpm/@blockrun+core@0.1.1_bufferutil@4.1.0_typescript@5.9.3_utf-8-validate@6.0.6_zod@3.25.76/node_modules/@blockrun/core/dist/wallet.js
|
|
8038
|
+
import * as fs3 from "fs";
|
|
8039
|
+
import * as path3 from "path";
|
|
8040
|
+
import { privateKeyToAccount as privateKeyToAccount14, generatePrivateKey } from "viem/accounts";
|
|
8041
|
+
function normalize(raw) {
|
|
8042
|
+
const k = raw.trim();
|
|
8043
|
+
return k.startsWith("0x") ? k : `0x${k}`;
|
|
8044
|
+
}
|
|
8045
|
+
function addressFromKey(raw) {
|
|
8046
|
+
try {
|
|
8047
|
+
return privateKeyToAccount14(normalize(raw)).address;
|
|
8048
|
+
} catch {
|
|
8049
|
+
return null;
|
|
4642
8050
|
}
|
|
4643
|
-
fs2.writeFileSync(WALLET_FILE, privateKey, { mode: 384 });
|
|
4644
|
-
return WALLET_FILE;
|
|
4645
8051
|
}
|
|
4646
8052
|
function scanWallets() {
|
|
4647
|
-
const home =
|
|
8053
|
+
const home = homeDir();
|
|
4648
8054
|
const results = [];
|
|
4649
8055
|
try {
|
|
4650
|
-
const
|
|
4651
|
-
|
|
4652
|
-
|
|
4653
|
-
const
|
|
4654
|
-
if (!
|
|
8056
|
+
for (const entry of fs3.readdirSync(home, { withFileTypes: true })) {
|
|
8057
|
+
if (!entry.name.startsWith(".") || !entry.isDirectory())
|
|
8058
|
+
continue;
|
|
8059
|
+
const walletFile2 = path3.join(home, entry.name, "wallet.json");
|
|
8060
|
+
if (!fs3.existsSync(walletFile2))
|
|
8061
|
+
continue;
|
|
4655
8062
|
try {
|
|
4656
|
-
const data = JSON.parse(
|
|
8063
|
+
const data = JSON.parse(fs3.readFileSync(walletFile2, "utf-8"));
|
|
4657
8064
|
const pk = data.privateKey || "";
|
|
4658
|
-
|
|
4659
|
-
|
|
4660
|
-
|
|
4661
|
-
|
|
4662
|
-
|
|
8065
|
+
if (!pk)
|
|
8066
|
+
continue;
|
|
8067
|
+
const derived = addressFromKey(pk);
|
|
8068
|
+
if (!derived)
|
|
8069
|
+
continue;
|
|
8070
|
+
results.push({ mtime: fs3.statSync(walletFile2).mtimeMs, privateKey: pk, address: derived, source: walletFile2 });
|
|
4663
8071
|
} catch {
|
|
4664
8072
|
continue;
|
|
4665
8073
|
}
|
|
@@ -4670,71 +8078,97 @@ function scanWallets() {
|
|
|
4670
8078
|
return results.map(({ privateKey, address, source }) => ({ privateKey, address, source }));
|
|
4671
8079
|
}
|
|
4672
8080
|
function listDiscoveredWallets() {
|
|
4673
|
-
|
|
4674
|
-
for (const entry of scanWallets()) {
|
|
4675
|
-
try {
|
|
4676
|
-
listed.push({
|
|
4677
|
-
address: privateKeyToAccount14(entry.privateKey).address,
|
|
4678
|
-
source: entry.source
|
|
4679
|
-
});
|
|
4680
|
-
} catch {
|
|
4681
|
-
continue;
|
|
4682
|
-
}
|
|
4683
|
-
}
|
|
4684
|
-
return listed;
|
|
8081
|
+
return scanWallets().map(({ address, source }) => ({ address, source }));
|
|
4685
8082
|
}
|
|
4686
|
-
function
|
|
8083
|
+
function adoptWallet(address) {
|
|
4687
8084
|
const wanted = address.trim().toLowerCase();
|
|
8085
|
+
const p = paths();
|
|
4688
8086
|
for (const entry of scanWallets()) {
|
|
4689
|
-
|
|
4690
|
-
try {
|
|
4691
|
-
derived = privateKeyToAccount14(entry.privateKey).address;
|
|
4692
|
-
} catch {
|
|
8087
|
+
if (entry.address.toLowerCase() !== wanted)
|
|
4693
8088
|
continue;
|
|
4694
|
-
|
|
4695
|
-
if (
|
|
4696
|
-
|
|
4697
|
-
|
|
4698
|
-
|
|
4699
|
-
|
|
4700
|
-
fs2.writeFileSync(backup, current, { mode: 384 });
|
|
8089
|
+
const privateKey = normalize(entry.privateKey);
|
|
8090
|
+
if (fs3.existsSync(p.session)) {
|
|
8091
|
+
const current = fs3.readFileSync(p.session, "utf8").trim();
|
|
8092
|
+
if (current && normalize(current) !== privateKey) {
|
|
8093
|
+
const backup = path3.join(p.dir, `.session.backup-${Math.floor(Date.now() / 1e3)}`);
|
|
8094
|
+
fs3.writeFileSync(backup, current, { mode: 384 });
|
|
4701
8095
|
}
|
|
4702
8096
|
}
|
|
4703
|
-
|
|
4704
|
-
|
|
8097
|
+
fs3.mkdirSync(p.dir, { recursive: true });
|
|
8098
|
+
fs3.writeFileSync(p.session, privateKey, { mode: 384 });
|
|
8099
|
+
return { address: entry.address, privateKey, source: "session" };
|
|
4705
8100
|
}
|
|
4706
8101
|
const available = listDiscoveredWallets().map((w) => w.address);
|
|
4707
|
-
throw new Error(
|
|
4708
|
-
`No discovered wallet controls ${address}. Available: ${available.length ? available.join(", ") : "none"}`
|
|
4709
|
-
);
|
|
8102
|
+
throw new Error(`No discovered wallet controls ${address}. Available: ${available.length ? available.join(", ") : "none"}`);
|
|
4710
8103
|
}
|
|
4711
|
-
function
|
|
4712
|
-
|
|
4713
|
-
|
|
4714
|
-
|
|
4715
|
-
|
|
4716
|
-
|
|
4717
|
-
|
|
4718
|
-
|
|
4719
|
-
|
|
8104
|
+
function resolveFromFiles() {
|
|
8105
|
+
const p = paths();
|
|
8106
|
+
if (fs3.existsSync(p.session)) {
|
|
8107
|
+
const raw = fs3.readFileSync(p.session, "utf8").trim();
|
|
8108
|
+
if (raw)
|
|
8109
|
+
return { privateKey: normalize(raw), source: "session" };
|
|
8110
|
+
}
|
|
8111
|
+
if (fs3.existsSync(p.legacy)) {
|
|
8112
|
+
const raw = fs3.readFileSync(p.legacy, "utf8").trim();
|
|
8113
|
+
if (raw)
|
|
8114
|
+
return { privateKey: normalize(raw), source: "legacy" };
|
|
4720
8115
|
}
|
|
4721
8116
|
return null;
|
|
4722
8117
|
}
|
|
8118
|
+
function resolvePrivateKey(env = process.env) {
|
|
8119
|
+
const fromEnv = env.BLOCKRUN_WALLET_KEY || env.BASE_CHAIN_WALLET_KEY;
|
|
8120
|
+
if (fromEnv && fromEnv.trim()) {
|
|
8121
|
+
return { privateKey: normalize(fromEnv), source: "env" };
|
|
8122
|
+
}
|
|
8123
|
+
return resolveFromFiles();
|
|
8124
|
+
}
|
|
8125
|
+
|
|
8126
|
+
// src/wallet.ts
|
|
8127
|
+
import * as fs4 from "fs";
|
|
8128
|
+
var USDC_BASE_CONTRACT = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913";
|
|
8129
|
+
var BASE_CHAIN_ID2 = "8453";
|
|
8130
|
+
function walletDir() {
|
|
8131
|
+
return paths().dir;
|
|
8132
|
+
}
|
|
8133
|
+
function walletFile() {
|
|
8134
|
+
return paths().session;
|
|
8135
|
+
}
|
|
8136
|
+
function createWallet() {
|
|
8137
|
+
const privateKey = generatePrivateKey2();
|
|
8138
|
+
const account = privateKeyToAccount15(privateKey);
|
|
8139
|
+
return {
|
|
8140
|
+
address: account.address,
|
|
8141
|
+
privateKey
|
|
8142
|
+
};
|
|
8143
|
+
}
|
|
8144
|
+
function saveWallet(privateKey) {
|
|
8145
|
+
const dir = walletDir();
|
|
8146
|
+
const file = walletFile();
|
|
8147
|
+
if (!fs4.existsSync(dir)) {
|
|
8148
|
+
fs4.mkdirSync(dir, { recursive: true });
|
|
8149
|
+
}
|
|
8150
|
+
fs4.writeFileSync(file, privateKey, { mode: 384 });
|
|
8151
|
+
return file;
|
|
8152
|
+
}
|
|
8153
|
+
function scanWallets2() {
|
|
8154
|
+
return scanWallets();
|
|
8155
|
+
}
|
|
8156
|
+
function listDiscoveredWallets2() {
|
|
8157
|
+
return listDiscoveredWallets();
|
|
8158
|
+
}
|
|
8159
|
+
function importWallet(address) {
|
|
8160
|
+
return adoptWallet(address).address;
|
|
8161
|
+
}
|
|
8162
|
+
function loadWallet() {
|
|
8163
|
+
return resolveFromFiles()?.privateKey ?? null;
|
|
8164
|
+
}
|
|
4723
8165
|
function formatWalletMigrationNotice(newAddress) {
|
|
4724
|
-
let
|
|
8166
|
+
let addresses;
|
|
4725
8167
|
try {
|
|
4726
|
-
|
|
8168
|
+
addresses = listDiscoveredWallets().map((w) => w.address);
|
|
4727
8169
|
} catch {
|
|
4728
8170
|
return null;
|
|
4729
8171
|
}
|
|
4730
|
-
const addresses = [];
|
|
4731
|
-
for (const entry of discovered) {
|
|
4732
|
-
try {
|
|
4733
|
-
addresses.push(privateKeyToAccount14(entry.privateKey).address);
|
|
4734
|
-
} catch {
|
|
4735
|
-
continue;
|
|
4736
|
-
}
|
|
4737
|
-
}
|
|
4738
8172
|
if (addresses.length === 0) return null;
|
|
4739
8173
|
const found = addresses.map((addr) => ` ${addr}`).join("\n");
|
|
4740
8174
|
return `
|
|
@@ -4761,30 +8195,18 @@ BLOCKRUN_WALLET_KEY=<private-key> for a single run without changing anything.
|
|
|
4761
8195
|
`;
|
|
4762
8196
|
}
|
|
4763
8197
|
function getOrCreateWallet() {
|
|
4764
|
-
const
|
|
4765
|
-
if (
|
|
4766
|
-
const account =
|
|
4767
|
-
return { address: account.address, privateKey:
|
|
4768
|
-
}
|
|
4769
|
-
const fileKey = loadWallet();
|
|
4770
|
-
if (fileKey) {
|
|
4771
|
-
const account = privateKeyToAccount14(fileKey);
|
|
4772
|
-
return { address: account.address, privateKey: fileKey, isNew: false };
|
|
8198
|
+
const resolved = resolvePrivateKey();
|
|
8199
|
+
if (resolved) {
|
|
8200
|
+
const account = privateKeyToAccount15(resolved.privateKey);
|
|
8201
|
+
return { address: account.address, privateKey: resolved.privateKey, isNew: false };
|
|
4773
8202
|
}
|
|
4774
8203
|
const { address, privateKey } = createWallet();
|
|
4775
8204
|
saveWallet(privateKey);
|
|
4776
8205
|
return { address, privateKey, isNew: true };
|
|
4777
8206
|
}
|
|
4778
8207
|
function getWalletAddress() {
|
|
4779
|
-
const
|
|
4780
|
-
|
|
4781
|
-
return privateKeyToAccount14(envKey).address;
|
|
4782
|
-
}
|
|
4783
|
-
const fileKey = loadWallet();
|
|
4784
|
-
if (fileKey) {
|
|
4785
|
-
return privateKeyToAccount14(fileKey).address;
|
|
4786
|
-
}
|
|
4787
|
-
return null;
|
|
8208
|
+
const resolved = resolvePrivateKey();
|
|
8209
|
+
return resolved ? privateKeyToAccount15(resolved.privateKey).address : null;
|
|
4788
8210
|
}
|
|
4789
8211
|
function getEip681Uri(address, amountUsdc = 1) {
|
|
4790
8212
|
const amountWei = Math.floor(amountUsdc * 1e6);
|
|
@@ -4846,15 +8268,15 @@ function formatFundingMessageCompact(address) {
|
|
|
4846
8268
|
return `I need a little top-up to keep helping you! Send USDC on Base to: ${address}
|
|
4847
8269
|
Check my balance: ${links.basescan}`;
|
|
4848
8270
|
}
|
|
4849
|
-
var WALLET_FILE_PATH =
|
|
4850
|
-
var WALLET_DIR_PATH =
|
|
8271
|
+
var WALLET_FILE_PATH = walletFile();
|
|
8272
|
+
var WALLET_DIR_PATH = walletDir();
|
|
4851
8273
|
|
|
4852
8274
|
// src/solana-wallet.ts
|
|
4853
|
-
import * as
|
|
4854
|
-
import * as
|
|
8275
|
+
import * as fs5 from "fs";
|
|
8276
|
+
import * as path4 from "path";
|
|
4855
8277
|
import * as os3 from "os";
|
|
4856
|
-
var
|
|
4857
|
-
var SOLANA_WALLET_FILE =
|
|
8278
|
+
var WALLET_DIR = path4.join(os3.homedir(), ".blockrun");
|
|
8279
|
+
var SOLANA_WALLET_FILE = path4.join(WALLET_DIR, ".solana-session");
|
|
4858
8280
|
async function createSolanaWallet() {
|
|
4859
8281
|
const { Keypair } = await loadSolanaWeb3("Solana wallet operations");
|
|
4860
8282
|
const bs58 = await import("bs58");
|
|
@@ -4918,39 +8340,39 @@ async function solanaPublicKey(privateKey) {
|
|
|
4918
8340
|
return Keypair.fromSecretKey(bytes).publicKey.toBase58();
|
|
4919
8341
|
}
|
|
4920
8342
|
function saveSolanaWallet(privateKey) {
|
|
4921
|
-
if (!
|
|
4922
|
-
|
|
8343
|
+
if (!fs5.existsSync(WALLET_DIR)) fs5.mkdirSync(WALLET_DIR, { recursive: true });
|
|
8344
|
+
fs5.writeFileSync(SOLANA_WALLET_FILE, privateKey, { mode: 384 });
|
|
4923
8345
|
return SOLANA_WALLET_FILE;
|
|
4924
8346
|
}
|
|
4925
8347
|
function scanSolanaWallets() {
|
|
4926
8348
|
const home = os3.homedir();
|
|
4927
8349
|
const results = [];
|
|
4928
8350
|
try {
|
|
4929
|
-
const entries =
|
|
8351
|
+
const entries = fs5.readdirSync(home, { withFileTypes: true });
|
|
4930
8352
|
for (const entry of entries) {
|
|
4931
8353
|
if (!entry.name.startsWith(".") || !entry.isDirectory()) continue;
|
|
4932
|
-
const solanaWalletFile =
|
|
4933
|
-
if (
|
|
8354
|
+
const solanaWalletFile = path4.join(home, entry.name, "solana-wallet.json");
|
|
8355
|
+
if (fs5.existsSync(solanaWalletFile)) {
|
|
4934
8356
|
try {
|
|
4935
|
-
const data = JSON.parse(
|
|
8357
|
+
const data = JSON.parse(fs5.readFileSync(solanaWalletFile, "utf-8"));
|
|
4936
8358
|
const pk = data.privateKey || "";
|
|
4937
8359
|
const addr = data.address || "";
|
|
4938
8360
|
if (pk && addr) {
|
|
4939
|
-
const mtime =
|
|
8361
|
+
const mtime = fs5.statSync(solanaWalletFile).mtimeMs;
|
|
4940
8362
|
results.push({ mtime, secretKey: pk, publicKey: addr, source: solanaWalletFile });
|
|
4941
8363
|
}
|
|
4942
8364
|
} catch {
|
|
4943
8365
|
}
|
|
4944
8366
|
}
|
|
4945
8367
|
if (entry.name === ".brcc") {
|
|
4946
|
-
const brccWalletFile =
|
|
4947
|
-
if (
|
|
8368
|
+
const brccWalletFile = path4.join(home, entry.name, "wallet.json");
|
|
8369
|
+
if (fs5.existsSync(brccWalletFile)) {
|
|
4948
8370
|
try {
|
|
4949
|
-
const data = JSON.parse(
|
|
8371
|
+
const data = JSON.parse(fs5.readFileSync(brccWalletFile, "utf-8"));
|
|
4950
8372
|
const pk = data.privateKey || "";
|
|
4951
8373
|
const addr = data.address || "";
|
|
4952
8374
|
if (pk && addr) {
|
|
4953
|
-
const mtime =
|
|
8375
|
+
const mtime = fs5.statSync(brccWalletFile).mtimeMs;
|
|
4954
8376
|
results.push({ mtime, secretKey: pk, publicKey: addr, source: brccWalletFile });
|
|
4955
8377
|
}
|
|
4956
8378
|
} catch {
|
|
@@ -4964,8 +8386,8 @@ function scanSolanaWallets() {
|
|
|
4964
8386
|
return results.map(({ secretKey, publicKey, source }) => ({ secretKey, publicKey, source }));
|
|
4965
8387
|
}
|
|
4966
8388
|
function loadSolanaWallet() {
|
|
4967
|
-
if (
|
|
4968
|
-
const key =
|
|
8389
|
+
if (fs5.existsSync(SOLANA_WALLET_FILE)) {
|
|
8390
|
+
const key = fs5.readFileSync(SOLANA_WALLET_FILE, "utf-8").trim();
|
|
4969
8391
|
if (key) return key;
|
|
4970
8392
|
}
|
|
4971
8393
|
return null;
|
|
@@ -4991,14 +8413,14 @@ async function importSolanaWallet(address) {
|
|
|
4991
8413
|
continue;
|
|
4992
8414
|
}
|
|
4993
8415
|
if (derived !== wanted) continue;
|
|
4994
|
-
if (
|
|
4995
|
-
const current =
|
|
8416
|
+
if (fs5.existsSync(SOLANA_WALLET_FILE)) {
|
|
8417
|
+
const current = fs5.readFileSync(SOLANA_WALLET_FILE, "utf-8").trim();
|
|
4996
8418
|
if (current && current !== entry.secretKey) {
|
|
4997
|
-
const backup =
|
|
4998
|
-
|
|
8419
|
+
const backup = path4.join(
|
|
8420
|
+
WALLET_DIR,
|
|
4999
8421
|
`.solana-session.backup-${Math.floor(Date.now() / 1e3)}`
|
|
5000
8422
|
);
|
|
5001
|
-
|
|
8423
|
+
fs5.writeFileSync(backup, current, { mode: 384 });
|
|
5002
8424
|
}
|
|
5003
8425
|
}
|
|
5004
8426
|
saveSolanaWallet(entry.secretKey);
|
|
@@ -5066,8 +8488,8 @@ async function getOrCreateSolanaWallet() {
|
|
|
5066
8488
|
);
|
|
5067
8489
|
return { privateKey: envKey, address: address2, isNew: false };
|
|
5068
8490
|
}
|
|
5069
|
-
if (
|
|
5070
|
-
const fileKey =
|
|
8491
|
+
if (fs5.existsSync(SOLANA_WALLET_FILE)) {
|
|
8492
|
+
const fileKey = fs5.readFileSync(SOLANA_WALLET_FILE, "utf-8").trim();
|
|
5071
8493
|
if (fileKey) {
|
|
5072
8494
|
const address2 = await solanaPublicKeyFrom(fileKey, SOLANA_WALLET_FILE);
|
|
5073
8495
|
return { privateKey: fileKey, address: address2, isNew: false };
|
|
@@ -5114,6 +8536,8 @@ var SolanaLLMClient = class {
|
|
|
5114
8536
|
sessionTotalUsd = 0;
|
|
5115
8537
|
sessionCalls = 0;
|
|
5116
8538
|
addressCache = null;
|
|
8539
|
+
modelPricingCache = null;
|
|
8540
|
+
modelPricingPromise = null;
|
|
5117
8541
|
constructor(options = {}) {
|
|
5118
8542
|
const envKey = typeof process !== "undefined" && process.env ? process.env.SOLANA_WALLET_KEY : void 0;
|
|
5119
8543
|
const privateKey = options.privateKey || envKey;
|
|
@@ -5148,25 +8572,141 @@ var SolanaLLMClient = class {
|
|
|
5148
8572
|
temperature: options?.temperature,
|
|
5149
8573
|
topP: options?.topP,
|
|
5150
8574
|
search: options?.search,
|
|
5151
|
-
searchParameters: options?.searchParameters
|
|
8575
|
+
searchParameters: options?.searchParameters,
|
|
8576
|
+
responseFormat: options?.responseFormat,
|
|
8577
|
+
stop: options?.stop,
|
|
8578
|
+
fallbackModels: options?.fallbackModels
|
|
5152
8579
|
});
|
|
5153
8580
|
return result.choices[0].message.content || "";
|
|
5154
8581
|
}
|
|
5155
8582
|
/** Full chat completion (OpenAI-compatible). */
|
|
5156
8583
|
async chatCompletion(model, messages, options) {
|
|
8584
|
+
const routingProfile = routingProfileForModel(model);
|
|
8585
|
+
if (routingProfile) {
|
|
8586
|
+
return (await this.smartChatCompletion(messages, {
|
|
8587
|
+
...options,
|
|
8588
|
+
routingProfile
|
|
8589
|
+
})).response;
|
|
8590
|
+
}
|
|
5157
8591
|
validateMaxTokens(options?.maxTokens);
|
|
5158
|
-
const
|
|
5159
|
-
|
|
5160
|
-
|
|
5161
|
-
|
|
8592
|
+
const buildBody = (candidate) => {
|
|
8593
|
+
const body = {
|
|
8594
|
+
model: candidate,
|
|
8595
|
+
messages,
|
|
8596
|
+
max_tokens: options?.maxTokens || DEFAULT_MAX_TOKENS2
|
|
8597
|
+
};
|
|
8598
|
+
if (options?.temperature !== void 0) body.temperature = options.temperature;
|
|
8599
|
+
if (options?.topP !== void 0) body.top_p = options.topP;
|
|
8600
|
+
if (options?.searchParameters !== void 0) body.search_parameters = options.searchParameters;
|
|
8601
|
+
else if (options?.search === true) body.search_parameters = { mode: "on" };
|
|
8602
|
+
if (options?.tools !== void 0) body.tools = options.tools;
|
|
8603
|
+
if (options?.toolChoice !== void 0) body.tool_choice = options.toolChoice;
|
|
8604
|
+
if (options?.responseFormat !== void 0) body.response_format = options.responseFormat;
|
|
8605
|
+
if (options?.stop !== void 0) body.stop = options.stop;
|
|
8606
|
+
return body;
|
|
5162
8607
|
};
|
|
5163
|
-
|
|
5164
|
-
|
|
5165
|
-
|
|
5166
|
-
|
|
5167
|
-
|
|
5168
|
-
|
|
5169
|
-
|
|
8608
|
+
const chain = [model, ...options?.fallbackModels ?? []];
|
|
8609
|
+
let lastError;
|
|
8610
|
+
for (let index = 0; index < chain.length; index += 1) {
|
|
8611
|
+
const candidate = chain[index];
|
|
8612
|
+
try {
|
|
8613
|
+
return await this.requestWithPayment("/v1/chat/completions", buildBody(candidate));
|
|
8614
|
+
} catch (error) {
|
|
8615
|
+
lastError = error;
|
|
8616
|
+
if (!isTransientError(error) || index === chain.length - 1) throw error;
|
|
8617
|
+
console.error(`[@blockrun/llm] ${candidate} -> ${chain[index + 1]} (${errSummary(error)})`);
|
|
8618
|
+
}
|
|
8619
|
+
}
|
|
8620
|
+
throw lastError;
|
|
8621
|
+
}
|
|
8622
|
+
async getModelPricing() {
|
|
8623
|
+
if (this.modelPricingCache) return this.modelPricingCache;
|
|
8624
|
+
if (this.modelPricingPromise) return this.modelPricingPromise;
|
|
8625
|
+
this.modelPricingPromise = (async () => {
|
|
8626
|
+
const models = await this.listModels();
|
|
8627
|
+
const pricing = /* @__PURE__ */ new Map();
|
|
8628
|
+
for (const model of models) {
|
|
8629
|
+
const raw = model;
|
|
8630
|
+
if (model.available === false) continue;
|
|
8631
|
+
const num = (value) => {
|
|
8632
|
+
const n = Number(value ?? 0);
|
|
8633
|
+
return Number.isFinite(n) ? n : 0;
|
|
8634
|
+
};
|
|
8635
|
+
const inputPrice = num(model.inputPrice ?? raw.input_price ?? raw.pricing?.input);
|
|
8636
|
+
const outputPrice = num(model.outputPrice ?? raw.output_price ?? raw.pricing?.output);
|
|
8637
|
+
const flatPrice = num(model.flatPrice ?? raw.flat_price ?? raw.pricing?.flat);
|
|
8638
|
+
pricing.set(model.id, {
|
|
8639
|
+
inputPrice,
|
|
8640
|
+
outputPrice,
|
|
8641
|
+
...(model.billingMode ?? raw.billing_mode) === "flat" && flatPrice > 0 ? { flatPrice } : {}
|
|
8642
|
+
});
|
|
8643
|
+
}
|
|
8644
|
+
return pricing;
|
|
8645
|
+
})();
|
|
8646
|
+
try {
|
|
8647
|
+
this.modelPricingCache = await this.modelPricingPromise;
|
|
8648
|
+
return this.modelPricingCache;
|
|
8649
|
+
} finally {
|
|
8650
|
+
this.modelPricingPromise = null;
|
|
8651
|
+
}
|
|
8652
|
+
}
|
|
8653
|
+
/** Inspect a Solana route without making or paying for a model call. */
|
|
8654
|
+
async route(prompt, options) {
|
|
8655
|
+
return routeWithCatalog(
|
|
8656
|
+
prompt,
|
|
8657
|
+
options?.system,
|
|
8658
|
+
options?.maxOutputTokens ?? options?.maxTokens ?? DEFAULT_MAX_TOKENS2,
|
|
8659
|
+
await this.getModelPricing(),
|
|
8660
|
+
{
|
|
8661
|
+
routingProfile: options?.routingProfile,
|
|
8662
|
+
requiresStructuredOutput: options?.responseFormat !== void 0,
|
|
8663
|
+
minimumPaymentUsd: SOLANA_MINIMUM_PAYMENT_USD
|
|
8664
|
+
}
|
|
8665
|
+
);
|
|
8666
|
+
}
|
|
8667
|
+
/** Smart one-line chat paid on Solana. */
|
|
8668
|
+
async smartChat(prompt, options) {
|
|
8669
|
+
const decision = await this.route(prompt, options);
|
|
8670
|
+
const response = await this.chat(decision.model, prompt, {
|
|
8671
|
+
...options,
|
|
8672
|
+
// An explicit caller-supplied chain wins over the routed one.
|
|
8673
|
+
fallbackModels: options?.fallbackModels ?? decision.fallbacks
|
|
8674
|
+
});
|
|
8675
|
+
return { response, model: decision.model, routing: decision };
|
|
8676
|
+
}
|
|
8677
|
+
/** Smart full message/tool completion paid on Solana. */
|
|
8678
|
+
async smartChatCompletion(messages, options = {}) {
|
|
8679
|
+
const { prompt, systemPrompt, conversationChars, hasVision } = routingText(messages);
|
|
8680
|
+
const decision = routeWithCatalog(
|
|
8681
|
+
prompt,
|
|
8682
|
+
systemPrompt,
|
|
8683
|
+
options.maxOutputTokens ?? options.maxTokens ?? DEFAULT_MAX_TOKENS2,
|
|
8684
|
+
await this.getModelPricing(),
|
|
8685
|
+
{
|
|
8686
|
+
routingProfile: options.routingProfile,
|
|
8687
|
+
requiresStructuredOutput: options.responseFormat !== void 0,
|
|
8688
|
+
tools: options.tools,
|
|
8689
|
+
toolChoice: options.toolChoice,
|
|
8690
|
+
conversationChars,
|
|
8691
|
+
hasVision,
|
|
8692
|
+
minimumPaymentUsd: SOLANA_MINIMUM_PAYMENT_USD
|
|
8693
|
+
}
|
|
8694
|
+
);
|
|
8695
|
+
const response = await this.chatCompletion(decision.model, messages, {
|
|
8696
|
+
maxTokens: options.maxTokens,
|
|
8697
|
+
temperature: options.temperature,
|
|
8698
|
+
topP: options.topP,
|
|
8699
|
+
search: options.search,
|
|
8700
|
+
searchParameters: options.searchParameters,
|
|
8701
|
+
tools: options.tools,
|
|
8702
|
+
toolChoice: options.toolChoice,
|
|
8703
|
+
responseFormat: options.responseFormat,
|
|
8704
|
+
stop: options.stop,
|
|
8705
|
+
// An explicit caller-supplied chain wins over the routed one.
|
|
8706
|
+
fallbackModels: options.fallbackModels ?? decision.fallbacks
|
|
8707
|
+
});
|
|
8708
|
+
response.routing = decision;
|
|
8709
|
+
return { response, model: decision.model, routing: decision };
|
|
5170
8710
|
}
|
|
5171
8711
|
/** List available models. */
|
|
5172
8712
|
async listModels() {
|
|
@@ -5231,11 +8771,11 @@ var SolanaLLMClient = class {
|
|
|
5231
8771
|
return data;
|
|
5232
8772
|
}
|
|
5233
8773
|
// ── Prediction Markets (Powered by Predexon) ────────────────────────────
|
|
5234
|
-
async pm(
|
|
5235
|
-
return this.getWithPaymentRaw(`/v1/pm/${
|
|
8774
|
+
async pm(path6, params) {
|
|
8775
|
+
return this.getWithPaymentRaw(`/v1/pm/${path6}`, params);
|
|
5236
8776
|
}
|
|
5237
|
-
async pmQuery(
|
|
5238
|
-
return this.requestWithPaymentRaw(`/v1/pm/${
|
|
8777
|
+
async pmQuery(path6, query) {
|
|
8778
|
+
return this.requestWithPaymentRaw(`/v1/pm/${path6}`, query);
|
|
5239
8779
|
}
|
|
5240
8780
|
// ── Exa Web Search (Powered by Exa) ──────────────────────────────────────
|
|
5241
8781
|
/**
|
|
@@ -5247,8 +8787,8 @@ var SolanaLLMClient = class {
|
|
|
5247
8787
|
* @example
|
|
5248
8788
|
* const results = await client.exa("search", { query: "latest AI research", numResults: 5 });
|
|
5249
8789
|
*/
|
|
5250
|
-
async exa(
|
|
5251
|
-
return this.requestWithPaymentRaw(`/v1/exa/${
|
|
8790
|
+
async exa(path6, body) {
|
|
8791
|
+
return this.requestWithPaymentRaw(`/v1/exa/${path6}`, body);
|
|
5252
8792
|
}
|
|
5253
8793
|
/**
|
|
5254
8794
|
* Neural and keyword web search via Exa (Solana payment, $0.01/request).
|
|
@@ -5298,8 +8838,8 @@ var SolanaLLMClient = class {
|
|
|
5298
8838
|
* "prices/coingecko:bitcoin,base:0x..."
|
|
5299
8839
|
* @param params - Query parameters passed through to DefiLlama
|
|
5300
8840
|
*/
|
|
5301
|
-
async defi(
|
|
5302
|
-
return this.getWithPaymentRaw(`/v1/defillama/${
|
|
8841
|
+
async defi(path6, params) {
|
|
8842
|
+
return this.getWithPaymentRaw(`/v1/defillama/${path6}`, params);
|
|
5303
8843
|
}
|
|
5304
8844
|
/** All DeFi protocols with TVL ($0.005/call). */
|
|
5305
8845
|
async defiProtocols() {
|
|
@@ -5335,9 +8875,9 @@ var SolanaLLMClient = class {
|
|
|
5335
8875
|
* @param params - Query params (chainId, sellToken, buyToken, sellAmount, taker, ...)
|
|
5336
8876
|
* @param body - JSON body — pass to switch to POST (gasless/submit only)
|
|
5337
8877
|
*/
|
|
5338
|
-
async dex(
|
|
5339
|
-
if (body) return this.requestWithPaymentRaw(`/v1/zerox/${
|
|
5340
|
-
return this.getWithPaymentRaw(`/v1/zerox/${
|
|
8878
|
+
async dex(path6, params, body) {
|
|
8879
|
+
if (body) return this.requestWithPaymentRaw(`/v1/zerox/${path6}`, body);
|
|
8880
|
+
return this.getWithPaymentRaw(`/v1/zerox/${path6}`, params);
|
|
5341
8881
|
}
|
|
5342
8882
|
/** Indicative Permit2 swap price — no commitment (free). */
|
|
5343
8883
|
async dexPrice(params) {
|
|
@@ -5381,8 +8921,8 @@ var SolanaLLMClient = class {
|
|
|
5381
8921
|
* "sandbox/status", "sandbox/terminate" ($0.001 each)
|
|
5382
8922
|
* @param body - JSON body for the endpoint
|
|
5383
8923
|
*/
|
|
5384
|
-
async modal(
|
|
5385
|
-
return this.requestWithPaymentRaw(`/v1/modal/${
|
|
8924
|
+
async modal(path6, body) {
|
|
8925
|
+
return this.requestWithPaymentRaw(`/v1/modal/${path6}`, body ?? {});
|
|
5386
8926
|
}
|
|
5387
8927
|
/** Create a sandboxed compute environment ($0.01 CPU / $0.05 GPU). */
|
|
5388
8928
|
async modalSandboxCreate(body) {
|
|
@@ -5699,13 +9239,13 @@ function solanaClient(options = {}) {
|
|
|
5699
9239
|
}
|
|
5700
9240
|
|
|
5701
9241
|
// src/cache.ts
|
|
5702
|
-
import * as
|
|
5703
|
-
import * as
|
|
9242
|
+
import * as fs6 from "fs";
|
|
9243
|
+
import * as path5 from "path";
|
|
5704
9244
|
import * as os4 from "os";
|
|
5705
9245
|
import * as crypto2 from "crypto";
|
|
5706
|
-
var CACHE_DIR =
|
|
5707
|
-
var DATA_DIR =
|
|
5708
|
-
var COST_LOG_FILE2 =
|
|
9246
|
+
var CACHE_DIR = path5.join(os4.homedir(), ".blockrun", "cache");
|
|
9247
|
+
var DATA_DIR = path5.join(os4.homedir(), ".blockrun", "data");
|
|
9248
|
+
var COST_LOG_FILE2 = path5.join(os4.homedir(), ".blockrun", "cost_log.jsonl");
|
|
5709
9249
|
var DEFAULT_TTL = {
|
|
5710
9250
|
"/v1/partner/": 3600 * 1e3,
|
|
5711
9251
|
"/v1/pm/": 1800 * 1e3,
|
|
@@ -5725,19 +9265,19 @@ function cacheKey(endpoint, body) {
|
|
|
5725
9265
|
return crypto2.createHash("sha256").update(keyData).digest("hex").slice(0, 16);
|
|
5726
9266
|
}
|
|
5727
9267
|
function cachePath(key) {
|
|
5728
|
-
return
|
|
9268
|
+
return path5.join(CACHE_DIR, `${key}.json`);
|
|
5729
9269
|
}
|
|
5730
9270
|
function getCached(key) {
|
|
5731
9271
|
const filePath = cachePath(key);
|
|
5732
|
-
if (!
|
|
9272
|
+
if (!fs6.existsSync(filePath)) return null;
|
|
5733
9273
|
try {
|
|
5734
|
-
const raw =
|
|
9274
|
+
const raw = fs6.readFileSync(filePath, "utf-8");
|
|
5735
9275
|
const entry = JSON.parse(raw);
|
|
5736
9276
|
const ttl = entry.ttlMs ?? getTtl(entry.endpoint ?? "");
|
|
5737
9277
|
if (ttl <= 0) return null;
|
|
5738
9278
|
if (Date.now() - entry.cachedAt > ttl) {
|
|
5739
9279
|
try {
|
|
5740
|
-
|
|
9280
|
+
fs6.unlinkSync(filePath);
|
|
5741
9281
|
} catch {
|
|
5742
9282
|
}
|
|
5743
9283
|
return null;
|
|
@@ -5756,7 +9296,7 @@ function getCachedByRequest(endpoint, body) {
|
|
|
5756
9296
|
function setCache(key, data, ttlMs) {
|
|
5757
9297
|
if (ttlMs <= 0) return;
|
|
5758
9298
|
try {
|
|
5759
|
-
|
|
9299
|
+
fs6.mkdirSync(CACHE_DIR, { recursive: true });
|
|
5760
9300
|
} catch {
|
|
5761
9301
|
}
|
|
5762
9302
|
const entry = {
|
|
@@ -5765,7 +9305,7 @@ function setCache(key, data, ttlMs) {
|
|
|
5765
9305
|
ttlMs
|
|
5766
9306
|
};
|
|
5767
9307
|
try {
|
|
5768
|
-
|
|
9308
|
+
fs6.writeFileSync(cachePath(key), JSON.stringify(entry));
|
|
5769
9309
|
} catch {
|
|
5770
9310
|
}
|
|
5771
9311
|
}
|
|
@@ -5786,7 +9326,7 @@ function readableFilename(endpoint, body) {
|
|
|
5786
9326
|
}
|
|
5787
9327
|
function saveReadable(endpoint, body, response, costUsd) {
|
|
5788
9328
|
try {
|
|
5789
|
-
|
|
9329
|
+
fs6.mkdirSync(DATA_DIR, { recursive: true });
|
|
5790
9330
|
} catch {
|
|
5791
9331
|
}
|
|
5792
9332
|
const filename = readableFilename(endpoint, body);
|
|
@@ -5798,14 +9338,14 @@ function saveReadable(endpoint, body, response, costUsd) {
|
|
|
5798
9338
|
response
|
|
5799
9339
|
};
|
|
5800
9340
|
try {
|
|
5801
|
-
|
|
9341
|
+
fs6.writeFileSync(path5.join(DATA_DIR, filename), JSON.stringify(entry, null, 2));
|
|
5802
9342
|
} catch {
|
|
5803
9343
|
}
|
|
5804
9344
|
}
|
|
5805
9345
|
function appendCostLog(endpoint, costUsd) {
|
|
5806
9346
|
if (costUsd <= 0) return;
|
|
5807
9347
|
try {
|
|
5808
|
-
|
|
9348
|
+
fs6.mkdirSync(path5.dirname(COST_LOG_FILE2), { recursive: true });
|
|
5809
9349
|
} catch {
|
|
5810
9350
|
}
|
|
5811
9351
|
const entry = {
|
|
@@ -5814,7 +9354,7 @@ function appendCostLog(endpoint, costUsd) {
|
|
|
5814
9354
|
cost_usd: costUsd
|
|
5815
9355
|
};
|
|
5816
9356
|
try {
|
|
5817
|
-
|
|
9357
|
+
fs6.appendFileSync(COST_LOG_FILE2, JSON.stringify(entry) + "\n");
|
|
5818
9358
|
} catch {
|
|
5819
9359
|
}
|
|
5820
9360
|
}
|
|
@@ -5822,7 +9362,7 @@ function saveToCache(endpoint, body, response, costUsd = 0) {
|
|
|
5822
9362
|
const ttl = getTtl(endpoint);
|
|
5823
9363
|
if (ttl > 0) {
|
|
5824
9364
|
try {
|
|
5825
|
-
|
|
9365
|
+
fs6.mkdirSync(CACHE_DIR, { recursive: true });
|
|
5826
9366
|
} catch {
|
|
5827
9367
|
}
|
|
5828
9368
|
const key = cacheKey(endpoint, body);
|
|
@@ -5834,7 +9374,7 @@ function saveToCache(endpoint, body, response, costUsd = 0) {
|
|
|
5834
9374
|
costUsd
|
|
5835
9375
|
};
|
|
5836
9376
|
try {
|
|
5837
|
-
|
|
9377
|
+
fs6.writeFileSync(cachePath(key), JSON.stringify(entry));
|
|
5838
9378
|
} catch {
|
|
5839
9379
|
}
|
|
5840
9380
|
}
|
|
@@ -5842,14 +9382,14 @@ function saveToCache(endpoint, body, response, costUsd = 0) {
|
|
|
5842
9382
|
appendCostLog(endpoint, costUsd);
|
|
5843
9383
|
}
|
|
5844
9384
|
function clearCache() {
|
|
5845
|
-
if (!
|
|
9385
|
+
if (!fs6.existsSync(CACHE_DIR)) return 0;
|
|
5846
9386
|
let count = 0;
|
|
5847
9387
|
try {
|
|
5848
|
-
const files =
|
|
9388
|
+
const files = fs6.readdirSync(CACHE_DIR);
|
|
5849
9389
|
for (const file of files) {
|
|
5850
9390
|
if (file.endsWith(".json")) {
|
|
5851
9391
|
try {
|
|
5852
|
-
|
|
9392
|
+
fs6.unlinkSync(path5.join(CACHE_DIR, file));
|
|
5853
9393
|
count++;
|
|
5854
9394
|
} catch {
|
|
5855
9395
|
}
|
|
@@ -5860,14 +9400,14 @@ function clearCache() {
|
|
|
5860
9400
|
return count;
|
|
5861
9401
|
}
|
|
5862
9402
|
function getCostLogSummary() {
|
|
5863
|
-
if (!
|
|
9403
|
+
if (!fs6.existsSync(COST_LOG_FILE2)) {
|
|
5864
9404
|
return { totalUsd: 0, calls: 0, byEndpoint: {} };
|
|
5865
9405
|
}
|
|
5866
9406
|
let totalUsd = 0;
|
|
5867
9407
|
let calls = 0;
|
|
5868
9408
|
const byEndpoint = {};
|
|
5869
9409
|
try {
|
|
5870
|
-
const content =
|
|
9410
|
+
const content = fs6.readFileSync(COST_LOG_FILE2, "utf-8").trim();
|
|
5871
9411
|
if (!content) return { totalUsd: 0, calls: 0, byEndpoint: {} };
|
|
5872
9412
|
for (const line of content.split("\n")) {
|
|
5873
9413
|
if (!line) continue;
|
|
@@ -6047,7 +9587,8 @@ var ChatCompletions = class {
|
|
|
6047
9587
|
},
|
|
6048
9588
|
finish_reason: choice.finish_reason || "stop"
|
|
6049
9589
|
})),
|
|
6050
|
-
usage: response.usage
|
|
9590
|
+
usage: response.usage,
|
|
9591
|
+
routing: response.routing
|
|
6051
9592
|
};
|
|
6052
9593
|
}
|
|
6053
9594
|
};
|
|
@@ -6080,7 +9621,7 @@ var OpenAI = class {
|
|
|
6080
9621
|
};
|
|
6081
9622
|
|
|
6082
9623
|
// src/anthropic-compat.ts
|
|
6083
|
-
import { privateKeyToAccount as
|
|
9624
|
+
import { privateKeyToAccount as privateKeyToAccount16 } from "viem/accounts";
|
|
6084
9625
|
var AnthropicClient = class {
|
|
6085
9626
|
_client = null;
|
|
6086
9627
|
_clientPromise = null;
|
|
@@ -6093,7 +9634,7 @@ var AnthropicClient = class {
|
|
|
6093
9634
|
const key = options.privateKey ?? wallet.privateKey;
|
|
6094
9635
|
validatePrivateKey(key);
|
|
6095
9636
|
this._privateKey = key;
|
|
6096
|
-
this._account =
|
|
9637
|
+
this._account = privateKeyToAccount16(this._privateKey);
|
|
6097
9638
|
const apiUrl = options.apiUrl ?? "https://blockrun.ai/api";
|
|
6098
9639
|
validateApiUrl(apiUrl);
|
|
6099
9640
|
this._apiUrl = apiUrl.replace(/\/$/, "");
|
|
@@ -6246,7 +9787,7 @@ export {
|
|
|
6246
9787
|
importSolanaWallet,
|
|
6247
9788
|
importWallet,
|
|
6248
9789
|
listDiscoveredSolanaWallets,
|
|
6249
|
-
listDiscoveredWallets,
|
|
9790
|
+
listDiscoveredWallets2 as listDiscoveredWallets,
|
|
6250
9791
|
loadSolanaWallet,
|
|
6251
9792
|
loadWallet,
|
|
6252
9793
|
logCost,
|
|
@@ -6255,7 +9796,7 @@ export {
|
|
|
6255
9796
|
saveToCache,
|
|
6256
9797
|
saveWallet,
|
|
6257
9798
|
scanSolanaWallets,
|
|
6258
|
-
scanWallets,
|
|
9799
|
+
scanWallets2 as scanWallets,
|
|
6259
9800
|
setCache,
|
|
6260
9801
|
setupAgentSolanaWallet,
|
|
6261
9802
|
setupAgentWallet,
|