diff --git a/README.md b/README.md index 4026dd9..2821d0d 100644 --- a/README.md +++ b/README.md @@ -263,7 +263,9 @@ Two rules govern this file, and both are load-bearing: 1. **These are weak priors, never task-quality labels.** They inform the `speed` and `reliability` terms only. A model is not "better" because it is fast. 2. **Historical numbers are never presented as a current provider SLA.** Hosts are expected to inject fresher observations (see below); the committed snapshot exists so the engine is safe and useful when a catalog is temporarily unavailable. -The repository ships 66 live profiles (2026-08-29 probe, three samples plus one function-calling request per model) plus 9 auditable historical seeds, and a built-in capability snapshot of every text model on the public catalog (2026-10-02 sync). Models added since the last probe carry no profile and are written `supportsTools: false` until probed — they can serve plain chat but never a tool-required turn. +The repository ships 66 live performance profiles (2026-08-29, three samples per model), 9 auditable historical seeds, 74 function-calling probe results, and a built-in snapshot of all 86 text models in the public catalog (2026-10-03 sync). Eleven newly listed models passed a real structured tool-call probe and are admitted as availability fallbacks for tool-required turns. DeepSeek V4 Flash Vision Experimental and Qwen 3.8 Flash did not return a valid tool call and remain fail-closed. A model with no probe evidence can serve plain chat but never a tool-required turn. + +Passing the function-call probe does **not** promote a model to primary. New tool-capable models are appended after the configured and trajectory-benchmarked candidate chains with neutral task affinity; they can recover an unavailable route immediately (cheapest first outside Premium), while primary promotion still requires an end-to-end agent evaluation. --- @@ -275,7 +277,7 @@ The engine never makes a network call. Everything current is **injected** by the const decision = route(prompt, systemPrompt, maxOutputTokens, { config: DEFAULT_ROUTING_CONFIG, modelPricing, // required — current prices from your catalog - modelCapabilities, // optional — overrides the built-in 70-model snapshot + modelCapabilities, // optional — overrides the built-in 86-model snapshot modelPerformance, // optional — fresh speed/reliability, e.g. the Observatory feed routingProfile: "auto", hasTools, toolCount, toolNames, requiresTools, @@ -358,7 +360,7 @@ Omitted entries fall back to a weak historical prior rather than disqualifying a ```bash npm ci npm run typecheck # tsc --noEmit -npm test # vitest — 104 tests across 6 files +npm test # vitest — 122 tests across 7 files npm run build # tsup → dist/ npm run check # all three, and what CI runs diff --git a/decisions.snapshot.json b/decisions.snapshot.json index 04f259a..601cb88 100644 --- a/decisions.snapshot.json +++ b/decisions.snapshot.json @@ -42,7 +42,7 @@ "tier": "SIMPLE", "confidence": 0.7231218051243898, "method": "portfolio", - "reasoning": "score=-0.08 | short (1 tokens) | agentic (tools) | v3 task=tool_agent agentRisk=standard deepWebResearch=false terminalCode=false terminalSafety=false candidates=13", + "reasoning": "score=-0.08 | short (1 tokens) | agentic (tools) | v3 task=tool_agent agentRisk=standard deepWebResearch=false terminalCode=false terminalSafety=false candidates=24", "costEstimate": 0.0032001, "baselineCost": 0.032005, "savings": 0.9000124980471801, @@ -60,7 +60,18 @@ "google/gemini-3.5-flash", "openai/gpt-5.3-codex", "moonshot/kimi-k3", - "deepseek/deepseek-v4-pro" + "deepseek/deepseek-v4-pro", + "google/gemini-3.8-flash", + "openai/gpt-6-luna", + "openai/gpt-6-sol", + "openai/gpt-5.1", + "xai/grok-4.6", + "anthropic/claude-opus-5.5", + "xai/grok-4.7", + "anthropic/claude-sonnet-5.5", + "openai/gpt-6-astra", + "xiaomi/mimo-v2.5", + "anthropic/claude-fable-5.1" ], "candidateScores": [ { @@ -230,7 +241,7 @@ "tier": "SIMPLE", "confidence": 0.7231218051243898, "method": "portfolio", - "reasoning": "score=-0.08 | short (20 tokens) | agentic (tools) | v3 task=tool_agent_parallel agentRisk=high deepWebResearch=false terminalCode=false terminalSafety=false candidates=13", + "reasoning": "score=-0.08 | short (20 tokens) | agentic (tools) | v3 task=tool_agent_parallel agentRisk=high deepWebResearch=false terminalCode=false terminalSafety=false candidates=24", "costEstimate": 0.020291200000000002, "baselineCost": 0.0577, "savings": 0.6483327556325823, @@ -248,7 +259,18 @@ "openai/gpt-4.1", "xai/grok-4.5", "google/gemini-3.5-flash", - "deepseek/deepseek-v4-pro" + "deepseek/deepseek-v4-pro", + "google/gemini-3.8-flash", + "openai/gpt-6-luna", + "openai/gpt-6-sol", + "openai/gpt-5.1", + "xai/grok-4.6", + "anthropic/claude-opus-5.5", + "xai/grok-4.7", + "anthropic/claude-sonnet-5.5", + "openai/gpt-6-astra", + "xiaomi/mimo-v2.5", + "anthropic/claude-fable-5.1" ], "candidateScores": [ { @@ -424,7 +446,7 @@ "tier": "MEDIUM", "confidence": 0.7373034537835593, "method": "portfolio", - "reasoning": "score=0.09 | long (1217 tokens), references (following) | agentic (tools) | v3 task=tool_agent agentRisk=standard deepWebResearch=false terminalCode=false terminalSafety=false candidates=13", + "reasoning": "score=0.09 | long (1217 tokens), references (following) | agentic (tools) | v3 task=tool_agent agentRisk=standard deepWebResearch=false terminalCode=false terminalSafety=false candidates=24", "costEstimate": 0.0084417, "baselineCost": 0.089285, "savings": 0.905452203617629, @@ -442,7 +464,18 @@ "anthropic/claude-opus-5", "openai/gpt-4.1", "openai/gpt-5.3-codex", - "deepseek/deepseek-v4-pro" + "deepseek/deepseek-v4-pro", + "google/gemini-3.8-flash", + "openai/gpt-6-luna", + "openai/gpt-6-sol", + "openai/gpt-5.1", + "xai/grok-4.6", + "anthropic/claude-opus-5.5", + "xai/grok-4.7", + "anthropic/claude-sonnet-5.5", + "openai/gpt-6-astra", + "xiaomi/mimo-v2.5", + "anthropic/claude-fable-5.1" ], "candidateScores": [ { @@ -677,7 +710,7 @@ "tier": "MEDIUM", "confidence": 0.5, "method": "portfolio", - "reasoning": "score=-0.06 | short (38 tokens), imperative (deploy), references (the api), agentic-light (check the, deploy) | ambiguous -> default: MEDIUM | agentic (tools) | v3 task=tool_agent agentRisk=standard deepWebResearch=false terminalCode=false terminalSafety=false candidates=13", + "reasoning": "score=-0.06 | short (38 tokens), imperative (deploy), references (the api), agentic-light (check the, deploy) | ambiguous -> default: MEDIUM | agentic (tools) | v3 task=tool_agent agentRisk=standard deepWebResearch=false terminalCode=false terminalSafety=false candidates=24", "costEstimate": 0.0006437999999999999, "baselineCost": 0.0065899999999999995, "savings": 0.9023065250379363, @@ -695,7 +728,18 @@ "anthropic/claude-opus-5", "openai/gpt-4.1", "openai/gpt-5.3-codex", - "deepseek/deepseek-v4-pro" + "deepseek/deepseek-v4-pro", + "google/gemini-3.8-flash", + "openai/gpt-6-luna", + "openai/gpt-6-sol", + "openai/gpt-5.1", + "xai/grok-4.6", + "anthropic/claude-opus-5.5", + "xai/grok-4.7", + "anthropic/claude-sonnet-5.5", + "openai/gpt-6-astra", + "xiaomi/mimo-v2.5", + "anthropic/claude-fable-5.1" ], "candidateScores": [ { @@ -922,7 +966,7 @@ "tier": "MEDIUM", "confidence": 0.7231218051243898, "method": "portfolio", - "reasoning": "score=0.08 | long (14423 tokens) | agentic (tools) | v3 task=tool_agent agentRisk=standard deepWebResearch=false terminalCode=false terminalSafety=false candidates=13", + "reasoning": "score=0.08 | long (14423 tokens) | agentic (tools) | v3 task=tool_agent agentRisk=standard deepWebResearch=false terminalCode=false terminalSafety=false candidates=24", "costEstimate": 0.0046423, "baselineCost": 0.104115, "savings": 0.9554118042549105, @@ -940,7 +984,18 @@ "anthropic/claude-opus-5", "openai/gpt-4.1", "openai/gpt-5.3-codex", - "deepseek/deepseek-v4-pro" + "deepseek/deepseek-v4-pro", + "anthropic/claude-opus-5.5", + "openai/gpt-5.1", + "google/gemini-3.8-flash", + "openai/gpt-6-luna", + "xai/grok-4.6", + "anthropic/claude-sonnet-5.5", + "openai/gpt-6-sol", + "openai/gpt-6-astra", + "xiaomi/mimo-v2.5", + "xai/grok-4.7", + "anthropic/claude-fable-5.1" ], "candidateScores": [ { @@ -996,7 +1051,7 @@ "tier": "SIMPLE", "confidence": 0.7231218051243898, "method": "portfolio", - "reasoning": "score=-0.08 | short (1 tokens) | eco | v3 task=tool_agent agentRisk=standard deepWebResearch=false terminalCode=false terminalSafety=false candidates=14", + "reasoning": "score=-0.08 | short (1 tokens) | eco | v3 task=tool_agent agentRisk=standard deepWebResearch=false terminalCode=false terminalSafety=false candidates=25", "costEstimate": 0.0032001, "baselineCost": 0.032005, "savings": 0.9000124980471801, @@ -1015,7 +1070,18 @@ "google/gemini-3.1-flash-lite", "anthropic/claude-opus-5", "openai/gpt-4.1", - "openai/gpt-4o-mini" + "openai/gpt-4o-mini", + "google/gemini-3.8-flash", + "openai/gpt-6-luna", + "openai/gpt-6-sol", + "openai/gpt-5.1", + "xai/grok-4.6", + "anthropic/claude-opus-5.5", + "xai/grok-4.7", + "anthropic/claude-sonnet-5.5", + "openai/gpt-6-astra", + "xiaomi/mimo-v2.5", + "anthropic/claude-fable-5.1" ], "candidateScores": [ { @@ -1206,7 +1272,7 @@ "tier": "SIMPLE", "confidence": 0.7231218051243898, "method": "portfolio", - "reasoning": "score=-0.08 | short (20 tokens) | eco | v3 task=tool_agent_parallel agentRisk=high deepWebResearch=false terminalCode=false terminalSafety=false candidates=14", + "reasoning": "score=-0.08 | short (20 tokens) | eco | v3 task=tool_agent_parallel agentRisk=high deepWebResearch=false terminalCode=false terminalSafety=false candidates=25", "costEstimate": 0.0009656, "baselineCost": 0.0577, "savings": 0.9832651646447141, @@ -1225,7 +1291,18 @@ "anthropic/claude-opus-5", "openai/gpt-5-mini", "openai/gpt-4.1", - "openai/gpt-4o-mini" + "openai/gpt-4o-mini", + "google/gemini-3.8-flash", + "openai/gpt-6-luna", + "openai/gpt-6-sol", + "openai/gpt-5.1", + "xai/grok-4.6", + "anthropic/claude-opus-5.5", + "xai/grok-4.7", + "anthropic/claude-sonnet-5.5", + "openai/gpt-6-astra", + "xiaomi/mimo-v2.5", + "anthropic/claude-fable-5.1" ], "candidateScores": [ { @@ -1437,7 +1514,7 @@ "tier": "MEDIUM", "confidence": 0.7373034537835593, "method": "portfolio", - "reasoning": "score=0.09 | long (1217 tokens), references (following) | eco | v3 task=tool_agent agentRisk=standard deepWebResearch=false terminalCode=false terminalSafety=false candidates=16", + "reasoning": "score=0.09 | long (1217 tokens), references (following) | eco | v3 task=tool_agent agentRisk=standard deepWebResearch=false terminalCode=false terminalSafety=false candidates=27", "costEstimate": 0.0084417, "baselineCost": 0.089285, "savings": 0.905452203617629, @@ -1458,7 +1535,18 @@ "google/gemini-2.5-flash", "anthropic/claude-opus-5", "openai/gpt-4.1", - "openai/gpt-4o-mini" + "openai/gpt-4o-mini", + "google/gemini-3.8-flash", + "openai/gpt-6-luna", + "openai/gpt-6-sol", + "openai/gpt-5.1", + "xai/grok-4.6", + "anthropic/claude-opus-5.5", + "xai/grok-4.7", + "anthropic/claude-sonnet-5.5", + "openai/gpt-6-astra", + "xiaomi/mimo-v2.5", + "anthropic/claude-fable-5.1" ], "candidateScores": [ { @@ -1713,7 +1801,7 @@ "tier": "MEDIUM", "confidence": 0.5, "method": "portfolio", - "reasoning": "score=-0.06 | short (38 tokens), imperative (deploy), references (the api), agentic-light (check the, deploy) | ambiguous -> default: MEDIUM | eco | v3 task=tool_agent agentRisk=standard deepWebResearch=false terminalCode=false terminalSafety=false candidates=16", + "reasoning": "score=-0.06 | short (38 tokens), imperative (deploy), references (the api), agentic-light (check the, deploy) | ambiguous -> default: MEDIUM | eco | v3 task=tool_agent agentRisk=standard deepWebResearch=false terminalCode=false terminalSafety=false candidates=27", "costEstimate": 0.0006437999999999999, "baselineCost": 0.0065899999999999995, "savings": 0.9023065250379363, @@ -1734,7 +1822,18 @@ "google/gemini-2.5-flash", "anthropic/claude-opus-5", "openai/gpt-4.1", - "openai/gpt-4o-mini" + "openai/gpt-4o-mini", + "google/gemini-3.8-flash", + "openai/gpt-6-luna", + "openai/gpt-6-sol", + "openai/gpt-5.1", + "xai/grok-4.6", + "anthropic/claude-opus-5.5", + "xai/grok-4.7", + "anthropic/claude-sonnet-5.5", + "openai/gpt-6-astra", + "xiaomi/mimo-v2.5", + "anthropic/claude-fable-5.1" ], "candidateScores": [ { @@ -1989,7 +2088,7 @@ "tier": "MEDIUM", "confidence": 0.7231218051243898, "method": "portfolio", - "reasoning": "score=0.08 | long (14423 tokens) | eco | v3 task=tool_agent agentRisk=standard deepWebResearch=false terminalCode=false terminalSafety=false candidates=16", + "reasoning": "score=0.08 | long (14423 tokens) | eco | v3 task=tool_agent agentRisk=standard deepWebResearch=false terminalCode=false terminalSafety=false candidates=27", "costEstimate": 0.0046423, "baselineCost": 0.104115, "savings": 0.9554118042549105, @@ -2010,7 +2109,18 @@ "google/gemini-2.5-flash", "anthropic/claude-opus-5", "openai/gpt-4.1", - "openai/gpt-4o-mini" + "openai/gpt-4o-mini", + "anthropic/claude-opus-5.5", + "openai/gpt-5.1", + "google/gemini-3.8-flash", + "openai/gpt-6-luna", + "xai/grok-4.6", + "anthropic/claude-sonnet-5.5", + "openai/gpt-6-sol", + "openai/gpt-6-astra", + "xiaomi/mimo-v2.5", + "xai/grok-4.7", + "anthropic/claude-fable-5.1" ], "candidateScores": [ { @@ -2108,7 +2218,7 @@ "tier": "SIMPLE", "confidence": 0.7231218051243898, "method": "portfolio", - "reasoning": "score=-0.08 | short (1 tokens) | agentic (tools) | v3 task=tool_agent agentRisk=standard deepWebResearch=false terminalCode=false terminalSafety=false candidates=13", + "reasoning": "score=-0.08 | short (1 tokens) | agentic (tools) | v3 task=tool_agent agentRisk=standard deepWebResearch=false terminalCode=false terminalSafety=false candidates=24", "costEstimate": 0.0032001, "baselineCost": 0.032005, "savings": 0.9000124980471801, @@ -2126,7 +2236,18 @@ "google/gemini-3.5-flash", "openai/gpt-5.3-codex", "moonshot/kimi-k3", - "deepseek/deepseek-v4-pro" + "deepseek/deepseek-v4-pro", + "google/gemini-3.8-flash", + "openai/gpt-6-luna", + "openai/gpt-6-sol", + "openai/gpt-5.1", + "xai/grok-4.6", + "anthropic/claude-opus-5.5", + "xai/grok-4.7", + "anthropic/claude-sonnet-5.5", + "openai/gpt-6-astra", + "xiaomi/mimo-v2.5", + "anthropic/claude-fable-5.1" ], "candidateScores": [ { @@ -2296,7 +2417,7 @@ "tier": "SIMPLE", "confidence": 0.7231218051243898, "method": "portfolio", - "reasoning": "score=-0.08 | short (20 tokens) | agentic (tools) | v3 task=tool_agent_parallel agentRisk=high deepWebResearch=false terminalCode=false terminalSafety=false candidates=13", + "reasoning": "score=-0.08 | short (20 tokens) | agentic (tools) | v3 task=tool_agent_parallel agentRisk=high deepWebResearch=false terminalCode=false terminalSafety=false candidates=24", "costEstimate": 0.020291200000000002, "baselineCost": 0.0577, "savings": 0.6483327556325823, @@ -2314,7 +2435,18 @@ "openai/gpt-4.1", "xai/grok-4.5", "google/gemini-3.5-flash", - "deepseek/deepseek-v4-pro" + "deepseek/deepseek-v4-pro", + "google/gemini-3.8-flash", + "openai/gpt-6-luna", + "openai/gpt-6-sol", + "openai/gpt-5.1", + "xai/grok-4.6", + "anthropic/claude-opus-5.5", + "xai/grok-4.7", + "anthropic/claude-sonnet-5.5", + "openai/gpt-6-astra", + "xiaomi/mimo-v2.5", + "anthropic/claude-fable-5.1" ], "candidateScores": [ { @@ -2490,7 +2622,7 @@ "tier": "MEDIUM", "confidence": 0.7373034537835593, "method": "portfolio", - "reasoning": "score=0.09 | long (1217 tokens), references (following) | agentic (tools) | v3 task=tool_agent agentRisk=standard deepWebResearch=false terminalCode=false terminalSafety=false candidates=13", + "reasoning": "score=0.09 | long (1217 tokens), references (following) | agentic (tools) | v3 task=tool_agent agentRisk=standard deepWebResearch=false terminalCode=false terminalSafety=false candidates=24", "costEstimate": 0.0084417, "baselineCost": 0.089285, "savings": 0.905452203617629, @@ -2508,7 +2640,18 @@ "anthropic/claude-opus-5", "openai/gpt-4.1", "openai/gpt-5.3-codex", - "deepseek/deepseek-v4-pro" + "deepseek/deepseek-v4-pro", + "google/gemini-3.8-flash", + "openai/gpt-6-luna", + "openai/gpt-6-sol", + "openai/gpt-5.1", + "xai/grok-4.6", + "anthropic/claude-opus-5.5", + "xai/grok-4.7", + "anthropic/claude-sonnet-5.5", + "openai/gpt-6-astra", + "xiaomi/mimo-v2.5", + "anthropic/claude-fable-5.1" ], "candidateScores": [ { @@ -2743,7 +2886,7 @@ "tier": "MEDIUM", "confidence": 0.5, "method": "portfolio", - "reasoning": "score=-0.06 | short (38 tokens), imperative (deploy), references (the api), agentic-light (check the, deploy) | ambiguous -> default: MEDIUM | agentic (tools) | v3 task=tool_agent agentRisk=standard deepWebResearch=false terminalCode=false terminalSafety=false candidates=13", + "reasoning": "score=-0.06 | short (38 tokens), imperative (deploy), references (the api), agentic-light (check the, deploy) | ambiguous -> default: MEDIUM | agentic (tools) | v3 task=tool_agent agentRisk=standard deepWebResearch=false terminalCode=false terminalSafety=false candidates=24", "costEstimate": 0.0006437999999999999, "baselineCost": 0.0065899999999999995, "savings": 0.9023065250379363, @@ -2761,7 +2904,18 @@ "anthropic/claude-opus-5", "openai/gpt-4.1", "openai/gpt-5.3-codex", - "deepseek/deepseek-v4-pro" + "deepseek/deepseek-v4-pro", + "google/gemini-3.8-flash", + "openai/gpt-6-luna", + "openai/gpt-6-sol", + "openai/gpt-5.1", + "xai/grok-4.6", + "anthropic/claude-opus-5.5", + "xai/grok-4.7", + "anthropic/claude-sonnet-5.5", + "openai/gpt-6-astra", + "xiaomi/mimo-v2.5", + "anthropic/claude-fable-5.1" ], "candidateScores": [ { @@ -2988,7 +3142,7 @@ "tier": "MEDIUM", "confidence": 0.7231218051243898, "method": "portfolio", - "reasoning": "score=0.08 | long (14423 tokens) | agentic (tools) | v3 task=tool_agent agentRisk=standard deepWebResearch=false terminalCode=false terminalSafety=false candidates=13", + "reasoning": "score=0.08 | long (14423 tokens) | agentic (tools) | v3 task=tool_agent agentRisk=standard deepWebResearch=false terminalCode=false terminalSafety=false candidates=24", "costEstimate": 0.0046423, "baselineCost": 0.104115, "savings": 0.9554118042549105, @@ -3006,7 +3160,18 @@ "anthropic/claude-opus-5", "openai/gpt-4.1", "openai/gpt-5.3-codex", - "deepseek/deepseek-v4-pro" + "deepseek/deepseek-v4-pro", + "anthropic/claude-opus-5.5", + "openai/gpt-5.1", + "google/gemini-3.8-flash", + "openai/gpt-6-luna", + "xai/grok-4.6", + "anthropic/claude-sonnet-5.5", + "openai/gpt-6-sol", + "openai/gpt-6-astra", + "xiaomi/mimo-v2.5", + "xai/grok-4.7", + "anthropic/claude-fable-5.1" ], "candidateScores": [ { @@ -3070,7 +3235,7 @@ "tier": "SIMPLE", "confidence": 0.7231218051243898, "method": "portfolio", - "reasoning": "score=-0.08 | short (1 tokens) | premium | v3 task=tool_agent agentRisk=standard deepWebResearch=false terminalCode=false terminalSafety=false candidates=15", + "reasoning": "score=-0.08 | short (1 tokens) | premium | v3 task=tool_agent agentRisk=standard deepWebResearch=false terminalCode=false terminalSafety=false candidates=26", "costEstimate": 0.0032001, "baselineCost": 0.032005, "savings": 0, @@ -3090,7 +3255,18 @@ "openai/gpt-4o-mini", "openai/gpt-5.3-codex", "moonshot/kimi-k3", - "deepseek/deepseek-v4-pro" + "deepseek/deepseek-v4-pro", + "anthropic/claude-fable-5.1", + "anthropic/claude-opus-5.5", + "anthropic/claude-sonnet-5.5", + "google/gemini-3.8-flash", + "openai/gpt-5.1", + "openai/gpt-6-astra", + "openai/gpt-6-luna", + "openai/gpt-6-sol", + "xai/grok-4.6", + "xai/grok-4.7", + "xiaomi/mimo-v2.5" ], "candidateScores": [ { @@ -3278,7 +3454,7 @@ "tier": "SIMPLE", "confidence": 0.7231218051243898, "method": "portfolio", - "reasoning": "score=-0.08 | short (20 tokens) | premium | v3 task=tool_agent_parallel agentRisk=high deepWebResearch=false terminalCode=false terminalSafety=false candidates=15", + "reasoning": "score=-0.08 | short (20 tokens) | premium | v3 task=tool_agent_parallel agentRisk=high deepWebResearch=false terminalCode=false terminalSafety=false candidates=26", "costEstimate": 0.020291200000000002, "baselineCost": 0.0577, "savings": 0, @@ -3298,7 +3474,18 @@ "openai/gpt-4.1", "openai/gpt-4o-mini", "xai/grok-4.5", - "deepseek/deepseek-v4-pro" + "deepseek/deepseek-v4-pro", + "anthropic/claude-fable-5.1", + "anthropic/claude-opus-5.5", + "anthropic/claude-sonnet-5.5", + "google/gemini-3.8-flash", + "openai/gpt-5.1", + "openai/gpt-6-astra", + "openai/gpt-6-luna", + "openai/gpt-6-sol", + "xai/grok-4.6", + "xai/grok-4.7", + "xiaomi/mimo-v2.5" ], "candidateScores": [ { @@ -3470,7 +3657,7 @@ "tier": "MEDIUM", "confidence": 0.7373034537835593, "method": "portfolio", - "reasoning": "score=0.09 | long (1217 tokens), references (following) | premium | v3 task=tool_agent agentRisk=standard deepWebResearch=false terminalCode=false terminalSafety=false candidates=15", + "reasoning": "score=0.09 | long (1217 tokens), references (following) | premium | v3 task=tool_agent agentRisk=standard deepWebResearch=false terminalCode=false terminalSafety=false candidates=26", "costEstimate": 0.0084417, "baselineCost": 0.089285, "savings": 0, @@ -3490,7 +3677,18 @@ "openai/gpt-5-mini", "openai/gpt-4.1", "openai/gpt-4o-mini", - "deepseek/deepseek-v4-pro" + "deepseek/deepseek-v4-pro", + "anthropic/claude-fable-5.1", + "anthropic/claude-opus-5.5", + "anthropic/claude-sonnet-5.5", + "google/gemini-3.8-flash", + "openai/gpt-5.1", + "openai/gpt-6-astra", + "openai/gpt-6-luna", + "openai/gpt-6-sol", + "xai/grok-4.6", + "xai/grok-4.7", + "xiaomi/mimo-v2.5" ], "candidateScores": [ { @@ -3700,7 +3898,7 @@ "tier": "MEDIUM", "confidence": 0.5, "method": "portfolio", - "reasoning": "score=-0.06 | short (38 tokens), imperative (deploy), references (the api), agentic-light (check the, deploy) | ambiguous -> default: MEDIUM | premium | v3 task=tool_agent agentRisk=standard deepWebResearch=false terminalCode=false terminalSafety=false candidates=15", + "reasoning": "score=-0.06 | short (38 tokens), imperative (deploy), references (the api), agentic-light (check the, deploy) | ambiguous -> default: MEDIUM | premium | v3 task=tool_agent agentRisk=standard deepWebResearch=false terminalCode=false terminalSafety=false candidates=26", "costEstimate": 0.0006437999999999999, "baselineCost": 0.0065899999999999995, "savings": 0, @@ -3720,7 +3918,18 @@ "openai/gpt-5-mini", "openai/gpt-4.1", "openai/gpt-4o-mini", - "deepseek/deepseek-v4-pro" + "deepseek/deepseek-v4-pro", + "anthropic/claude-fable-5.1", + "anthropic/claude-opus-5.5", + "anthropic/claude-sonnet-5.5", + "google/gemini-3.8-flash", + "openai/gpt-5.1", + "openai/gpt-6-astra", + "openai/gpt-6-luna", + "openai/gpt-6-sol", + "xai/grok-4.6", + "xai/grok-4.7", + "xiaomi/mimo-v2.5" ], "candidateScores": [ { @@ -3922,7 +4131,7 @@ "tier": "MEDIUM", "confidence": 0.7231218051243898, "method": "portfolio", - "reasoning": "score=0.08 | long (14423 tokens) | premium | v3 task=tool_agent agentRisk=standard deepWebResearch=false terminalCode=false terminalSafety=false candidates=15", + "reasoning": "score=0.08 | long (14423 tokens) | premium | v3 task=tool_agent agentRisk=standard deepWebResearch=false terminalCode=false terminalSafety=false candidates=26", "costEstimate": 0.0046423, "baselineCost": 0.104115, "savings": 0, @@ -3942,7 +4151,18 @@ "openai/gpt-5-mini", "openai/gpt-4.1", "openai/gpt-4o-mini", - "deepseek/deepseek-v4-pro" + "deepseek/deepseek-v4-pro", + "anthropic/claude-fable-5.1", + "anthropic/claude-opus-5.5", + "anthropic/claude-sonnet-5.5", + "google/gemini-3.8-flash", + "openai/gpt-5.1", + "openai/gpt-6-astra", + "openai/gpt-6-luna", + "openai/gpt-6-sol", + "xai/grok-4.6", + "xai/grok-4.7", + "xiaomi/mimo-v2.5" ], "candidateScores": [ { diff --git a/dist/index.d.ts b/dist/index.d.ts index 979e532..a350619 100644 --- a/dist/index.d.ts +++ b/dist/index.d.ts @@ -32,7 +32,7 @@ declare const HISTORICAL_MODEL_PROFILES: Readonly options.modelPricing.has(model2)) : []; + if (options.routingProfile !== "premium") { + const fallbackCost = (model2) => estimatedCost(model2, options, features.estimatedInputTokens, maxOutputTokens); + verifiedToolFallbacks.sort((a, b) => fallbackCost(a) - fallbackCost(b)); + } const chain = [ - .../* @__PURE__ */ new Set([...configuredCandidates, ...evidenceCandidates(features.taskType)]) + .../* @__PURE__ */ new Set([ + ...configuredCandidates, + ...evidenceCandidates(features.taskType), + ...verifiedToolFallbacks + ]) ].filter( (model2) => typeof model2 === "string" && model2.length > 0 && !unavailable.has(model2) ); diff --git a/dist/index.js.map b/dist/index.js.map index d8b7831..235e824 100644 --- a/dist/index.js.map +++ b/dist/index.js.map @@ -1 +1 @@ -{"version":3,"sources":["../rules.ts","../selector.ts","../strategy.ts","../model-capabilities.ts","../model-profiles.generated.json","../model-profiles.ts","../tool-intent.ts","../portfolio.ts","../config.ts","../index.ts"],"sourcesContent":["/**\n * Rule-Based Classifier (v2 — Weighted Scoring)\n *\n * Scores a request across 15 weighted dimensions and maps the aggregate\n * score to a tier using configurable boundaries. Confidence is calibrated\n * via sigmoid — low confidence triggers the fallback classifier.\n *\n * Handles 70-80% of requests in < 1ms with zero cost.\n */\n\nimport type { Tier, ScoringResult, ScoringConfig } from \"./types.js\";\n\ntype DimensionScore = { name: string; score: number; signal: string | null };\n\n// ─── Dimension Scorers ───\n// Each returns a score in [-1, 1] and an optional signal string.\n\nfunction scoreTokenCount(\n estimatedTokens: number,\n thresholds: { simple: number; complex: number },\n): DimensionScore {\n if (estimatedTokens < thresholds.simple) {\n return { name: \"tokenCount\", score: -1.0, signal: `short (${estimatedTokens} tokens)` };\n }\n if (estimatedTokens > thresholds.complex) {\n return { name: \"tokenCount\", score: 1.0, signal: `long (${estimatedTokens} tokens)` };\n }\n return { name: \"tokenCount\", score: 0, signal: null };\n}\n\nfunction scoreKeywordMatch(\n text: string,\n keywords: string[],\n name: string,\n signalLabel: string,\n thresholds: { low: number; high: number },\n scores: { none: number; low: number; high: number },\n): DimensionScore {\n const matches = keywords.filter((kw) => text.includes(kw.toLowerCase()));\n if (matches.length >= thresholds.high) {\n return {\n name,\n score: scores.high,\n signal: `${signalLabel} (${matches.slice(0, 3).join(\", \")})`,\n };\n }\n if (matches.length >= thresholds.low) {\n return {\n name,\n score: scores.low,\n signal: `${signalLabel} (${matches.slice(0, 3).join(\", \")})`,\n };\n }\n return { name, score: scores.none, signal: null };\n}\n\nfunction scoreMultiStep(text: string): DimensionScore {\n const patterns = [/first.*then/i, /step \\d/i, /\\d\\.\\s/];\n const hits = patterns.filter((p) => p.test(text));\n if (hits.length > 0) {\n return { name: \"multiStepPatterns\", score: 0.5, signal: \"multi-step\" };\n }\n return { name: \"multiStepPatterns\", score: 0, signal: null };\n}\n\nfunction scoreQuestionComplexity(prompt: string): DimensionScore {\n const count = (prompt.match(/\\?/g) || []).length;\n if (count > 3) {\n return { name: \"questionComplexity\", score: 0.5, signal: `${count} questions` };\n }\n return { name: \"questionComplexity\", score: 0, signal: null };\n}\n\n/**\n * Score agentic task indicators.\n * Returns agenticScore (0-1) based on keyword matches:\n * - 4+ matches = 1.0 (high agentic)\n * - 3 matches = 0.6 (moderate agentic, triggers auto-agentic mode)\n * - 1-2 matches = 0.2 (low agentic)\n *\n * Thresholds raised because common keywords were pruned from the list.\n */\nfunction scoreAgenticTask(\n text: string,\n keywords: string[],\n): { dimensionScore: DimensionScore; agenticScore: number } {\n let matchCount = 0;\n const signals: string[] = [];\n\n for (const keyword of keywords) {\n if (text.includes(keyword.toLowerCase())) {\n matchCount++;\n if (signals.length < 3) {\n signals.push(keyword);\n }\n }\n }\n\n // Threshold-based scoring (raised thresholds after keyword pruning)\n if (matchCount >= 4) {\n return {\n dimensionScore: {\n name: \"agenticTask\",\n score: 1.0,\n signal: `agentic (${signals.join(\", \")})`,\n },\n agenticScore: 1.0,\n };\n } else if (matchCount >= 3) {\n return {\n dimensionScore: {\n name: \"agenticTask\",\n score: 0.6,\n signal: `agentic (${signals.join(\", \")})`,\n },\n agenticScore: 0.6,\n };\n } else if (matchCount >= 1) {\n return {\n dimensionScore: {\n name: \"agenticTask\",\n score: 0.2,\n signal: `agentic-light (${signals.join(\", \")})`,\n },\n agenticScore: 0.2,\n };\n }\n\n return {\n dimensionScore: { name: \"agenticTask\", score: 0, signal: null },\n agenticScore: 0,\n };\n}\n\n// ─── Main Classifier ───\n\nexport function classifyByRules(\n prompt: string,\n systemPrompt: string | undefined,\n estimatedTokens: number,\n config: ScoringConfig,\n): ScoringResult {\n // Score against user prompt only — system prompts contain boilerplate keywords\n // (tool definitions, skill descriptions, behavioral rules) that dominate scoring\n // and make every request score identically. See GitHub issue #50.\n const userText = prompt.toLowerCase();\n\n // Score the base dimensions against user text only; the agentic dimension is\n // appended below, so the scored total is one more than this list.\n const dimensions: DimensionScore[] = [\n // Token count uses total estimated tokens (system + user) — context size matters for model selection\n scoreTokenCount(estimatedTokens, config.tokenCountThresholds),\n scoreKeywordMatch(\n userText,\n config.codeKeywords,\n \"codePresence\",\n \"code\",\n { low: 1, high: 2 },\n { none: 0, low: 0.5, high: 1.0 },\n ),\n scoreKeywordMatch(\n userText,\n config.reasoningKeywords,\n \"reasoningMarkers\",\n \"reasoning\",\n { low: 1, high: 2 },\n { none: 0, low: 0.7, high: 1.0 },\n ),\n scoreKeywordMatch(\n userText,\n config.technicalKeywords,\n \"technicalTerms\",\n \"technical\",\n { low: 2, high: 4 },\n { none: 0, low: 0.5, high: 1.0 },\n ),\n scoreKeywordMatch(\n userText,\n config.creativeKeywords,\n \"creativeMarkers\",\n \"creative\",\n { low: 1, high: 2 },\n { none: 0, low: 0.5, high: 0.7 },\n ),\n scoreKeywordMatch(\n userText,\n config.simpleKeywords,\n \"simpleIndicators\",\n \"simple\",\n { low: 1, high: 2 },\n { none: 0, low: -1.0, high: -1.0 },\n ),\n scoreMultiStep(userText),\n scoreQuestionComplexity(prompt),\n\n // 6 new dimensions\n scoreKeywordMatch(\n userText,\n config.imperativeVerbs,\n \"imperativeVerbs\",\n \"imperative\",\n { low: 1, high: 2 },\n { none: 0, low: 0.3, high: 0.5 },\n ),\n scoreKeywordMatch(\n userText,\n config.constraintIndicators,\n \"constraintCount\",\n \"constraints\",\n { low: 1, high: 3 },\n { none: 0, low: 0.3, high: 0.7 },\n ),\n scoreKeywordMatch(\n userText,\n config.outputFormatKeywords,\n \"outputFormat\",\n \"format\",\n { low: 1, high: 2 },\n { none: 0, low: 0.4, high: 0.7 },\n ),\n scoreKeywordMatch(\n userText,\n config.referenceKeywords,\n \"referenceComplexity\",\n \"references\",\n { low: 1, high: 2 },\n { none: 0, low: 0.3, high: 0.5 },\n ),\n scoreKeywordMatch(\n userText,\n config.negationKeywords,\n \"negationComplexity\",\n \"negation\",\n { low: 2, high: 3 },\n { none: 0, low: 0.3, high: 0.5 },\n ),\n scoreKeywordMatch(\n userText,\n config.domainSpecificKeywords,\n \"domainSpecificity\",\n \"domain-specific\",\n { low: 1, high: 2 },\n { none: 0, low: 0.5, high: 0.8 },\n ),\n ];\n\n // Score agentic task indicators — user prompt only\n // System prompt describes assistant behavior, not user's intent.\n // e.g. a coding assistant system prompt with \"edit files\" / \"fix bugs\" should NOT\n // force every request into agentic mode.\n const agenticResult = scoreAgenticTask(userText, config.agenticTaskKeywords);\n dimensions.push(agenticResult.dimensionScore);\n const agenticScore = agenticResult.agenticScore;\n\n // Collect signals\n const signals = dimensions.filter((d) => d.signal !== null).map((d) => d.signal!);\n\n // Compute weighted score\n const weights = config.dimensionWeights;\n let weightedScore = 0;\n for (const d of dimensions) {\n const w = weights[d.name] ?? 0;\n weightedScore += d.score * w;\n }\n\n // Count reasoning markers for override — only check USER prompt, not system prompt\n // This prevents system prompts with \"step by step\" from triggering REASONING for simple queries\n const reasoningMatches = config.reasoningKeywords.filter((kw) =>\n userText.includes(kw.toLowerCase()),\n );\n\n // Direct reasoning override: 2+ reasoning markers = high confidence REASONING\n if (reasoningMatches.length >= 2) {\n const confidence = calibrateConfidence(\n Math.max(weightedScore, 0.3), // ensure positive for confidence calc\n config.confidenceSteepness,\n );\n return {\n score: weightedScore,\n tier: \"REASONING\",\n confidence: Math.max(confidence, 0.85),\n signals,\n agenticScore,\n dimensions,\n };\n }\n\n // Map weighted score to tier using boundaries\n const { simpleMedium, mediumComplex, complexReasoning } = config.tierBoundaries;\n let tier: Tier;\n let distanceFromBoundary: number;\n\n if (weightedScore < simpleMedium) {\n tier = \"SIMPLE\";\n distanceFromBoundary = simpleMedium - weightedScore;\n } else if (weightedScore < mediumComplex) {\n tier = \"MEDIUM\";\n distanceFromBoundary = Math.min(weightedScore - simpleMedium, mediumComplex - weightedScore);\n } else if (weightedScore < complexReasoning) {\n tier = \"COMPLEX\";\n distanceFromBoundary = Math.min(\n weightedScore - mediumComplex,\n complexReasoning - weightedScore,\n );\n } else {\n tier = \"REASONING\";\n distanceFromBoundary = weightedScore - complexReasoning;\n }\n\n // Calibrate confidence via sigmoid of distance from nearest boundary\n const confidence = calibrateConfidence(distanceFromBoundary, config.confidenceSteepness);\n\n // If confidence is below threshold → ambiguous\n if (confidence < config.confidenceThreshold) {\n return { score: weightedScore, tier: null, confidence, signals, agenticScore, dimensions };\n }\n\n return { score: weightedScore, tier, confidence, signals, agenticScore, dimensions };\n}\n\n/**\n * Sigmoid confidence calibration.\n * Maps distance from tier boundary to [0.5, 1.0] confidence range.\n */\nfunction calibrateConfidence(distance: number, steepness: number): number {\n return 1 / (1 + Math.exp(-steepness * distance));\n}\n","/**\n * Tier → Model Selection\n *\n * Maps a classification tier to the cheapest capable model.\n * Builds RoutingDecision metadata with cost estimates and savings.\n */\n\nimport type { Tier, TierConfig, RoutingDecision } from \"./types.js\";\n\nexport type ModelPricing = {\n inputPrice: number; // per 1M tokens\n outputPrice: number; // per 1M tokens\n /** Active promo flat price per request (overrides token-based pricing when set) */\n flatPrice?: number;\n};\n\n// The savings baseline is a price anchor, not \"the current flagship\" — it is\n// deliberately NOT bumped every time a new Opus ships. Opus 4.7, 4.8 and 5 all\n// bill $5/$25, so moving it would change no reported number while breaking\n// comparability with historical journal entries. Only move it if the Opus tier\n// itself is repriced.\nconst BASELINE_MODEL_ID = \"anthropic/claude-opus-4.7\";\n\n// Hardcoded fallback: Claude Opus 4.7 pricing (per 1M tokens)\n// Used when baseline model not found in dynamic pricing map\nconst BASELINE_INPUT_PRICE = 5.0;\nconst BASELINE_OUTPUT_PRICE = 25.0;\n\n/**\n * Select the primary model for a tier and build the RoutingDecision.\n *\n * Cost contract: the estimates here are raw token economics — no server\n * margin, no minimum-payment floor. `calculateModelCost` below applies both\n * to match the actual x402 charge, and hosts that display money (ClawRouter's\n * proxy does) recompute through it rather than reading these fields. Folding\n * the margin in here would double-apply it in every such host.\n */\nexport function selectModel(\n tier: Tier,\n confidence: number,\n method: \"rules\" | \"llm\" | \"portfolio\",\n reasoning: string,\n tierConfigs: Record,\n modelPricing: Map,\n estimatedInputTokens: number,\n maxOutputTokens: number,\n routingProfile?: \"free\" | \"eco\" | \"auto\" | \"premium\",\n agenticScore?: number,\n): RoutingDecision {\n const tierConfig = tierConfigs[tier];\n const model = tierConfig.primary;\n const pricing = modelPricing.get(model);\n\n let costEstimate: number;\n if (pricing?.flatPrice !== undefined) {\n costEstimate = pricing.flatPrice;\n } else {\n const inputPrice = pricing?.inputPrice ?? 0;\n const outputPrice = pricing?.outputPrice ?? 0;\n costEstimate =\n (estimatedInputTokens / 1_000_000) * inputPrice + (maxOutputTokens / 1_000_000) * outputPrice;\n }\n\n // Baseline: what the anchor Opus tier would cost (see BASELINE_MODEL_ID)\n const opusPricing = modelPricing.get(BASELINE_MODEL_ID);\n const opusInputPrice = opusPricing?.inputPrice ?? BASELINE_INPUT_PRICE;\n const opusOutputPrice = opusPricing?.outputPrice ?? BASELINE_OUTPUT_PRICE;\n const baselineInput = (estimatedInputTokens / 1_000_000) * opusInputPrice;\n const baselineOutput = (maxOutputTokens / 1_000_000) * opusOutputPrice;\n const baselineCost = baselineInput + baselineOutput;\n\n // Premium profile doesn't calculate savings (it's about quality, not cost)\n const savings =\n routingProfile === \"premium\"\n ? 0\n : baselineCost > 0\n ? Math.max(0, (baselineCost - costEstimate) / baselineCost)\n : 0;\n\n return {\n model,\n tier,\n confidence,\n method,\n reasoning,\n costEstimate,\n baselineCost,\n savings,\n ...(agenticScore !== undefined && { agenticScore }),\n };\n}\n\n/**\n * Get the ordered fallback chain for a tier: [primary, ...fallbacks].\n */\nexport function getFallbackChain(tier: Tier, tierConfigs: Record): string[] {\n const config = tierConfigs[tier];\n return [config.primary, ...config.fallback];\n}\n\n/**\n * Calculate charge-accurate cost fields for a specific model (server margin\n * and minimum-payment floor included — see the cost contract on selectModel).\n * Hosts call this to display money and to recost a decision after a fallback.\n */\n// Server-side margin applied to all x402 payments (must match blockrun server's MARGIN_PERCENT)\nconst SERVER_MARGIN_PERCENT = 5;\n// Minimum payment enforced by CDP Facilitator (must match blockrun server's MIN_PAYMENT_USD)\nconst MIN_PAYMENT_USD = 0.001;\n\nexport function calculateModelCost(\n model: string,\n modelPricing: Map,\n estimatedInputTokens: number,\n maxOutputTokens: number,\n routingProfile?: \"free\" | \"eco\" | \"auto\" | \"premium\",\n): { costEstimate: number; baselineCost: number; savings: number } {\n const pricing = modelPricing.get(model);\n\n let costEstimate: number;\n if (pricing?.flatPrice !== undefined) {\n // Active promo: fixed cost per request\n costEstimate = Math.max(pricing.flatPrice * (1 + SERVER_MARGIN_PERCENT / 100), MIN_PAYMENT_USD);\n } else {\n // Defensive: guard against undefined price fields (not just undefined pricing)\n const inputPrice = pricing?.inputPrice ?? 0;\n const outputPrice = pricing?.outputPrice ?? 0;\n const inputCost = (estimatedInputTokens / 1_000_000) * inputPrice;\n const outputCost = (maxOutputTokens / 1_000_000) * outputPrice;\n // Include server margin + minimum payment to match actual x402 charge\n costEstimate = Math.max(\n (inputCost + outputCost) * (1 + SERVER_MARGIN_PERCENT / 100),\n MIN_PAYMENT_USD,\n );\n }\n\n // Baseline: what the anchor Opus tier would cost (see BASELINE_MODEL_ID)\n const opusPricing = modelPricing.get(BASELINE_MODEL_ID);\n const opusInputPrice = opusPricing?.inputPrice ?? BASELINE_INPUT_PRICE;\n const opusOutputPrice = opusPricing?.outputPrice ?? BASELINE_OUTPUT_PRICE;\n const baselineInput = (estimatedInputTokens / 1_000_000) * opusInputPrice;\n const baselineOutput = (maxOutputTokens / 1_000_000) * opusOutputPrice;\n const baselineCost = baselineInput + baselineOutput;\n\n // Premium profile doesn't calculate savings (it's about quality, not cost)\n const savings =\n routingProfile === \"premium\"\n ? 0\n : baselineCost > 0\n ? Math.max(0, (baselineCost - costEstimate) / baselineCost)\n : 0;\n\n return { costEstimate, baselineCost, savings };\n}\n\n/**\n * Filter a model list to only those that support tool calling.\n * When hasTools is false, returns the list unchanged.\n * When all models lack tool calling support, returns the full list as a fallback\n * (better to let the API error than produce an empty chain).\n */\nexport function filterByToolCalling(\n models: string[],\n hasTools: boolean,\n supportsToolCalling: (modelId: string) => boolean,\n): string[] {\n if (!hasTools) return models;\n const filtered = models.filter(supportsToolCalling);\n return filtered.length > 0 ? filtered : models;\n}\n\n/**\n * Filter a model list to only those that support vision (image inputs).\n * When hasVision is false, returns the list unchanged.\n * When all models lack vision support, returns the full list as a fallback\n * (better to let the API error than produce an empty chain).\n */\nexport function filterByVision(\n models: string[],\n hasVision: boolean,\n supportsVision: (modelId: string) => boolean,\n): string[] {\n if (!hasVision) return models;\n const filtered = models.filter(supportsVision);\n return filtered.length > 0 ? filtered : models;\n}\n\n/**\n * Filter a model list to remove user-excluded models.\n * When all models are excluded, returns the full list as a fallback\n * (same safety pattern as filterByToolCalling/filterByVision).\n */\nexport function filterByExcludeList(models: string[], excludeList: Set): string[] {\n if (excludeList.size === 0) return models;\n const filtered = models.filter((m) => !excludeList.has(m));\n return filtered.length > 0 ? filtered : models;\n}\n\n/**\n * Get the fallback chain filtered by context length.\n * Only returns models that can handle the estimated total context.\n *\n * @param tier - The tier to get fallback chain for\n * @param tierConfigs - Tier configurations\n * @param estimatedTotalTokens - Estimated total context (input + output)\n * @param getContextWindow - Function to get context window for a model ID\n * @returns Filtered list of models that can handle the context\n */\nexport function getFallbackChainFiltered(\n tier: Tier,\n tierConfigs: Record,\n estimatedTotalTokens: number,\n getContextWindow: (modelId: string) => number | undefined,\n): string[] {\n const fullChain = getFallbackChain(tier, tierConfigs);\n\n // Filter to models that can handle the context\n const filtered = fullChain.filter((modelId) => {\n const contextWindow = getContextWindow(modelId);\n if (contextWindow === undefined) {\n // Unknown model - include it (let API reject if needed)\n return true;\n }\n // Add 10% buffer for safety\n return contextWindow >= estimatedTotalTokens * 1.1;\n });\n\n // If all models filtered out, return the original chain\n // (let the API error out - better than no options)\n if (filtered.length === 0) {\n return fullChain;\n }\n\n return filtered;\n}\n\n/**\n * Filter an already-ranked candidate list by total context and requested output.\n * Unlike the legacy tier helper, this supports the V3 portfolio order.\n */\nexport function filterCandidatesByCapacity(\n models: string[],\n estimatedInputTokens: number,\n requestedOutputTokens: number,\n getCapabilities: (modelId: string) => { contextWindow: number; maxOutput: number } | undefined,\n): string[] {\n const filtered = models.filter((modelId) => {\n const capabilities = getCapabilities(modelId);\n if (!capabilities) return true;\n return (\n capabilities.contextWindow >= (estimatedInputTokens + requestedOutputTokens) * 1.1 &&\n capabilities.maxOutput >= requestedOutputTokens\n );\n });\n return filtered;\n}\n","/**\n * Router Strategy Registry\n *\n * Pluggable strategy system for request routing.\n * Default: RulesStrategy — identical to the original inline route() logic, <1ms.\n */\n\nimport type {\n Tier,\n TierConfig,\n Promotion,\n RoutingDecision,\n RouterStrategy,\n RouterOptions,\n} from \"./types.js\";\nimport { classifyByRules } from \"./rules.js\";\nimport { selectModel } from \"./selector.js\";\n\n/**\n * Apply active time-windowed promotions to tier configs.\n * Returns a new tierConfigs object with promotion overrides merged in.\n * Expired or not-yet-active promotions are ignored.\n */\nfunction applyPromotions(\n tierConfigs: Record,\n promotions: Promotion[] | undefined,\n profile: \"auto\" | \"eco\" | \"premium\" | \"agentic\",\n now: Date = new Date(),\n): Record {\n if (!promotions || promotions.length === 0) return tierConfigs;\n\n let result = tierConfigs;\n for (const promo of promotions) {\n // Check time window\n const start = new Date(promo.startDate);\n const end = new Date(promo.endDate);\n if (now < start || now >= end) continue;\n\n // Check profile filter\n if (promo.profiles && !promo.profiles.includes(profile)) continue;\n\n // Shallow-clone on first mutation\n if (result === tierConfigs) {\n result = { ...tierConfigs };\n for (const t of Object.keys(result) as Tier[]) {\n result[t] = { ...result[t] };\n }\n }\n\n // Merge overrides\n for (const [tier, override] of Object.entries(promo.tierOverrides) as [\n Tier,\n Partial,\n ][]) {\n if (!result[tier]) continue;\n if (override.primary) result[tier].primary = override.primary;\n if (override.fallback) result[tier].fallback = override.fallback;\n }\n }\n\n return result;\n}\n\n/**\n * Remove host-declared-dead models from every tier chain, promoting the first\n * surviving rung to primary. A tier whose chain is entirely dead keeps its\n * original config — the router has nothing live to offer there, and inventing\n * a model would hide the outage from the host that reported it.\n */\nexport function applyUnavailableModels(\n tierConfigs: Record,\n unavailableModels: readonly string[] | undefined,\n): Record {\n if (!unavailableModels || unavailableModels.length === 0) return tierConfigs;\n const dead = new Set(unavailableModels);\n let result = tierConfigs;\n for (const tier of Object.keys(tierConfigs) as Tier[]) {\n const config = tierConfigs[tier];\n const alive = [config.primary, ...config.fallback].filter((model) => !dead.has(model));\n if (alive.length === 0 || (alive[0] === config.primary && alive.length === config.fallback.length + 1)) {\n continue;\n }\n if (result === tierConfigs) result = { ...tierConfigs };\n result[tier] = { primary: alive[0], fallback: alive.slice(1) };\n }\n return result;\n}\n\n/**\n * Rules-based routing strategy.\n * Extracted from the original route() in index.ts — logic is identical.\n * Attaches tierConfigs and profile to the decision for downstream use.\n */\nexport class RulesStrategy implements RouterStrategy {\n readonly name = \"rules\";\n\n route(\n prompt: string,\n systemPrompt: string | undefined,\n maxOutputTokens: number,\n options: RouterOptions,\n ): RoutingDecision {\n const { config, modelPricing } = options;\n\n // Estimate input tokens (~4 chars per token)\n const fullText = `${systemPrompt ?? \"\"} ${prompt}`;\n const estimatedTokens = Math.ceil(fullText.length / 4);\n const scanLimit = Math.max(1, Math.min(8_000, config.classifier.promptTruncationChars));\n const sample = (value: string): string => {\n if (value.length <= scanLimit) return value;\n const prefixLength = Math.ceil(scanLimit / 2);\n return `${value.slice(0, prefixLength)}\\n${value.slice(-(scanLimit - prefixLength))}`;\n };\n const scannedPrompt = sample(prompt);\n const scannedSystemPrompt = systemPrompt ? sample(systemPrompt) : undefined;\n\n // --- Rule-based classification (runs first to get agenticScore) ---\n const ruleResult = classifyByRules(\n scannedPrompt,\n scannedSystemPrompt,\n estimatedTokens,\n config.scoring,\n );\n\n // --- Select tier configs based on routing profile ---\n const { routingProfile } = options;\n let tierConfigs: Record;\n let profileSuffix: string;\n let profile: RoutingDecision[\"profile\"];\n\n if (routingProfile === \"eco\") {\n // `ecoTiers: null` explicitly disables the special eco tier set while\n // keeping eco routing semantics. Fall back to regular tiers instead of\n // dropping into auto routing (which could select agentic tiers).\n tierConfigs = config.ecoTiers ?? config.tiers;\n profileSuffix = config.ecoTiers ? \" | eco\" : \" | eco (default tiers)\";\n profile = \"eco\";\n } else if (routingProfile === \"premium\") {\n // `premiumTiers: null` disables the premium-specific tier set but the\n // request is still a premium-profile request, so use regular tiers while\n // preserving premium metadata/cost semantics.\n tierConfigs = config.premiumTiers ?? config.tiers;\n profileSuffix = config.premiumTiers ? \" | premium\" : \" | premium (default tiers)\";\n profile = \"premium\";\n } else {\n // Auto profile (or undefined): intelligent routing with agentic detection.\n //\n // `agenticMode` semantics:\n // - `true` → force agentic tiers (ignore heuristics)\n // - `false` → disable agentic tiers entirely (even if tools are present)\n // - `undefined` → auto-detect via heuristics (tools present OR high agenticScore)\n const agenticScore = ruleResult.agenticScore ?? 0;\n const isAutoAgentic = agenticScore >= 0.5;\n const agenticModeSetting = config.overrides.agenticMode;\n const hasToolsInRequest = options.requiresTools ?? options.hasTools ?? false;\n let useAgenticTiers: boolean;\n if (agenticModeSetting === false) {\n // Explicitly disabled — never use agentic tiers\n useAgenticTiers = false;\n } else if (agenticModeSetting === true) {\n // Explicitly enabled — use agentic tiers if available\n useAgenticTiers = config.agenticTiers != null;\n } else {\n // Auto-detect\n useAgenticTiers = (hasToolsInRequest || isAutoAgentic) && config.agenticTiers != null;\n }\n tierConfigs = useAgenticTiers ? config.agenticTiers! : config.tiers;\n profileSuffix = useAgenticTiers ? ` | agentic${hasToolsInRequest ? \" (tools)\" : \"\"}` : \"\";\n profile = useAgenticTiers ? \"agentic\" : \"auto\";\n }\n\n // Apply time-windowed promotions\n tierConfigs = applyPromotions(tierConfigs, config.promotions, profile!, options.now);\n\n // Hard-remove models the host has observed dead at the gateway. After\n // promotions, so a promo cannot resurrect a rung the host just killed.\n tierConfigs = applyUnavailableModels(tierConfigs, options.unavailableModels);\n\n const agenticScoreValue = ruleResult.agenticScore;\n\n // --- Override: large context → force COMPLEX ---\n if (estimatedTokens > config.overrides.maxTokensForceComplex) {\n const decision = selectModel(\n \"COMPLEX\",\n 0.95,\n \"rules\",\n `Input exceeds ${config.overrides.maxTokensForceComplex} tokens${profileSuffix}`,\n tierConfigs,\n modelPricing,\n estimatedTokens,\n maxOutputTokens,\n routingProfile,\n agenticScoreValue,\n );\n return { ...decision, tierConfigs, profile };\n }\n\n // Structured output detection\n const hasStructuredOutput =\n options.requiresStructuredOutput === true ||\n (scannedSystemPrompt ? /json|structured|schema/i.test(scannedSystemPrompt) : false);\n\n let tier: Tier;\n let confidence: number;\n const method: \"rules\" | \"llm\" = \"rules\";\n let reasoning = `score=${ruleResult.score.toFixed(2)} | ${ruleResult.signals.join(\", \")}`;\n\n if (ruleResult.tier !== null) {\n tier = ruleResult.tier;\n confidence = ruleResult.confidence;\n } else {\n // Ambiguous — default to configurable tier (no external API call)\n tier = config.overrides.ambiguousDefaultTier;\n confidence = 0.5;\n reasoning += ` | ambiguous -> default: ${tier}`;\n }\n\n // Apply structured output minimum tier\n if (hasStructuredOutput) {\n const tierRank: Record = { SIMPLE: 0, MEDIUM: 1, COMPLEX: 2, REASONING: 3 };\n const minTier = config.overrides.structuredOutputMinTier;\n if (tierRank[tier] < tierRank[minTier]) {\n reasoning += ` | upgraded to ${minTier} (structured output)`;\n tier = minTier;\n }\n }\n\n // Add routing profile suffix to reasoning\n reasoning += profileSuffix;\n\n const decision = selectModel(\n tier,\n confidence,\n method,\n reasoning,\n tierConfigs,\n modelPricing,\n estimatedTokens,\n maxOutputTokens,\n routingProfile,\n agenticScoreValue,\n );\n return { ...decision, tierConfigs, profile };\n }\n}\n\n// --- Strategy Registry ---\n\nconst registry = new Map();\nregistry.set(\"rules\", new RulesStrategy());\n\nexport function getStrategy(name: string): RouterStrategy {\n const strategy = registry.get(name);\n if (!strategy) {\n throw new Error(`Unknown routing strategy: ${name}`);\n }\n return strategy;\n}\n\nexport function registerStrategy(strategy: RouterStrategy): void {\n registry.set(strategy.name, strategy);\n}\n","/**\n * Model capabilities used for hard routing constraints.\n *\n * Hosts may inject fresher values through RouterOptions.modelCapabilities.\n * Keeping a small built-in snapshot makes the core safe and useful when a\n * product catalog is temporarily unavailable, without importing product code.\n *\n * GENERATED by scripts/sync-model-capabilities.mjs from the public catalog\n * (GET https://blockrun.ai/api/v1/models) on 2026-10-02; supportsTools comes\n * from a live function-calling probe (scripts/probe-tools.json). Regenerate\n * rather than editing by hand — a hand edit is overwritten on the next sync.\n */\nexport type ModelCapabilities = {\n contextWindow: number;\n maxOutputTokens: number;\n supportsTools: boolean;\n supportsVision: boolean;\n};\n\nexport const DEFAULT_MODEL_CAPABILITIES: Readonly> =\n Object.freeze({\n \"anthropic/claude-fable-5\": {\n contextWindow: 1_000_000,\n maxOutputTokens: 128_000,\n supportsTools: true,\n supportsVision: true,\n },\n \"anthropic/claude-fable-5.1\": { // supportsTools: not probed — fails closed\n contextWindow: 1_000_000,\n maxOutputTokens: 128_000,\n supportsTools: false,\n supportsVision: true,\n },\n \"anthropic/claude-haiku-4.5\": { // override: The public catalog's `categories` omit \"vision\" for this Anthropic model even though the gateway accepts image input for it (the prior hand-maintained snapshot had it, and Anthropic's model card lists it). Without this the vision filter would silently drop it — reported against the catalog; remove once the categories carry vision.\n contextWindow: 200_000,\n maxOutputTokens: 64_000,\n supportsTools: true,\n supportsVision: true,\n },\n \"anthropic/claude-opus-4.5\": {\n contextWindow: 200_000,\n maxOutputTokens: 64_000,\n supportsTools: true,\n supportsVision: true,\n },\n \"anthropic/claude-opus-4.7\": {\n contextWindow: 1_000_000,\n maxOutputTokens: 128_000,\n supportsTools: true,\n supportsVision: true,\n },\n \"anthropic/claude-opus-4.8\": {\n contextWindow: 1_000_000,\n maxOutputTokens: 128_000,\n supportsTools: true,\n supportsVision: true,\n },\n \"anthropic/claude-opus-5\": {\n contextWindow: 1_000_000,\n maxOutputTokens: 128_000,\n supportsTools: true,\n supportsVision: true,\n },\n \"anthropic/claude-opus-5.5\": { // supportsTools: not probed — fails closed\n contextWindow: 1_000_000,\n maxOutputTokens: 128_000,\n supportsTools: false,\n supportsVision: true,\n },\n \"anthropic/claude-sonnet-4.5\": {\n contextWindow: 200_000,\n maxOutputTokens: 64_000,\n supportsTools: true,\n supportsVision: true,\n },\n \"anthropic/claude-sonnet-4.6\": { // override: The public catalog's `categories` omit \"vision\" for this Anthropic model even though the gateway accepts image input for it (the prior hand-maintained snapshot had it, and Anthropic's model card lists it). Without this the vision filter would silently drop it — reported against the catalog; remove once the categories carry vision.\n contextWindow: 1_000_000,\n maxOutputTokens: 128_000,\n supportsTools: true,\n supportsVision: true,\n },\n \"anthropic/claude-sonnet-5\": {\n contextWindow: 1_000_000,\n maxOutputTokens: 128_000,\n supportsTools: true,\n supportsVision: true,\n },\n \"anthropic/claude-sonnet-5.5\": { // supportsTools: not probed — fails closed\n contextWindow: 1_000_000,\n maxOutputTokens: 128_000,\n supportsTools: false,\n supportsVision: true,\n },\n \"cohere/north-mini-code\": { // supportsTools: not probed — fails closed\n contextWindow: 256_000,\n maxOutputTokens: 16_384,\n supportsTools: false,\n supportsVision: false,\n },\n \"deepseek/deepseek-chat\": {\n contextWindow: 1_048_576,\n maxOutputTokens: 65_536,\n supportsTools: true,\n supportsVision: false,\n },\n \"deepseek/deepseek-reasoner\": {\n contextWindow: 1_048_576,\n maxOutputTokens: 65_536,\n supportsTools: true,\n supportsVision: false,\n },\n \"deepseek/deepseek-v4-flash-vision-exp\": { // supportsTools: not probed — fails closed\n contextWindow: 1_048_576,\n maxOutputTokens: 65_536,\n supportsTools: false,\n supportsVision: true,\n },\n \"deepseek/deepseek-v4-pro\": {\n contextWindow: 1_048_576,\n maxOutputTokens: 65_536,\n supportsTools: true,\n supportsVision: false,\n },\n \"google/gemini-2.5-flash\": {\n contextWindow: 1_048_576,\n maxOutputTokens: 65_536,\n supportsTools: true,\n supportsVision: true,\n },\n \"google/gemini-2.5-flash-lite\": {\n contextWindow: 1_048_576,\n maxOutputTokens: 65_536,\n supportsTools: true,\n supportsVision: false,\n },\n \"google/gemini-2.5-pro\": {\n contextWindow: 1_048_576,\n maxOutputTokens: 65_536,\n supportsTools: true,\n supportsVision: true,\n },\n \"google/gemini-3-flash-preview\": {\n contextWindow: 1_048_576,\n maxOutputTokens: 65_536,\n supportsTools: true,\n supportsVision: true,\n },\n \"google/gemini-3.1-flash-lite\": {\n contextWindow: 1_048_576,\n maxOutputTokens: 65_536,\n supportsTools: true,\n supportsVision: false,\n },\n \"google/gemini-3.1-pro\": {\n contextWindow: 1_048_576,\n maxOutputTokens: 65_536,\n supportsTools: true,\n supportsVision: true,\n },\n \"google/gemini-3.5-flash\": {\n contextWindow: 1_048_576,\n maxOutputTokens: 65_536,\n supportsTools: true,\n supportsVision: true,\n },\n \"google/gemini-3.5-flash-lite\": {\n contextWindow: 1_048_576,\n maxOutputTokens: 65_536,\n supportsTools: true,\n supportsVision: false,\n },\n \"google/gemini-3.6-flash\": {\n contextWindow: 1_048_576,\n maxOutputTokens: 65_536,\n supportsTools: true,\n supportsVision: true,\n },\n \"google/gemini-3.8-flash\": { // supportsTools: not probed — fails closed\n contextWindow: 1_048_576,\n maxOutputTokens: 65_536,\n supportsTools: false,\n supportsVision: true,\n },\n \"minimax/minimax-m2.7\": {\n contextWindow: 204_800,\n maxOutputTokens: 16_384,\n supportsTools: true,\n supportsVision: false,\n },\n \"minimax/minimax-m3\": {\n contextWindow: 1_048_576,\n maxOutputTokens: 65_536,\n supportsTools: true,\n supportsVision: false,\n },\n \"moonshot/kimi-k3\": {\n contextWindow: 1_048_576,\n maxOutputTokens: 65_536,\n supportsTools: true,\n supportsVision: true,\n },\n \"nvidia/llama-3.2-11b-vision\": { // supportsTools: not probed — fails closed\n contextWindow: 128_000,\n maxOutputTokens: 16_384,\n supportsTools: false,\n supportsVision: true,\n },\n \"nvidia/nemotron-3-nano-omni-30b-a3b-reasoning\": { // override: The catalog tags this model \"vision\", but a correctly sized probe does not hold up (ClawRouter, 2026-08-31): a 64x64 solid-red PNG was named correctly 1 of 4 times on Base, and on Solana the image was silently dropped and a text model answered \"white\". An HTTP 200 with a confident wrong answer gives the caller nothing to branch on, so image turns must not be routed here. It is ecoTiers.SIMPLE.fallback[0] since nemotron-3-nano-30b was delisted (2026-09-08); remove once a probe of this size comes back right on both chains.\n contextWindow: 256_000,\n maxOutputTokens: 16_384,\n supportsTools: false,\n supportsVision: false,\n },\n \"nvidia/nemotron-3-ultra-550b\": { // supportsTools: not probed — fails closed\n contextWindow: 1_000_000,\n maxOutputTokens: 16_384,\n supportsTools: false,\n supportsVision: false,\n },\n \"nvidia/nemotron-3.5-lightning\": { // supportsTools: not probed — fails closed\n contextWindow: 1_000_000,\n maxOutputTokens: 16_384,\n supportsTools: false,\n supportsVision: false,\n },\n \"openai/chat-latest\": {\n contextWindow: 128_000,\n maxOutputTokens: 128_000,\n supportsTools: true,\n supportsVision: true,\n },\n \"openai/gpt-4.1\": {\n contextWindow: 128_000,\n maxOutputTokens: 32_768,\n supportsTools: true,\n supportsVision: true,\n },\n \"openai/gpt-4.1-mini\": {\n contextWindow: 128_000,\n maxOutputTokens: 32_768,\n supportsTools: true,\n supportsVision: false,\n },\n \"openai/gpt-4.1-nano\": {\n contextWindow: 128_000,\n maxOutputTokens: 32_768,\n supportsTools: true,\n supportsVision: false,\n },\n \"openai/gpt-4o\": {\n contextWindow: 128_000,\n maxOutputTokens: 16_384,\n supportsTools: true,\n supportsVision: true,\n },\n \"openai/gpt-4o-mini\": {\n contextWindow: 128_000,\n maxOutputTokens: 16_384,\n supportsTools: true,\n supportsVision: false,\n },\n \"openai/gpt-5-mini\": {\n contextWindow: 200_000,\n maxOutputTokens: 128_000,\n supportsTools: true,\n supportsVision: false,\n },\n \"openai/gpt-5.1\": { // supportsTools: not probed — fails closed\n contextWindow: 400_000,\n maxOutputTokens: 128_000,\n supportsTools: false,\n supportsVision: true,\n },\n \"openai/gpt-5.2\": {\n contextWindow: 400_000,\n maxOutputTokens: 128_000,\n supportsTools: true,\n supportsVision: true,\n },\n \"openai/gpt-5.2-pro\": { // supportsTools: not probed — fails closed\n contextWindow: 400_000,\n maxOutputTokens: 128_000,\n supportsTools: false,\n supportsVision: true,\n },\n \"openai/gpt-5.3-codex\": { // supportsTools: gateway unavailable at probe time — fails closed; override: 2026-08-29 probe: every request (6 plain + 3 tool attempts) returned a gateway 500, so the probe measured an incident, not the model. Codex's function calling is established by the 2026-07 Terminal-Bench / tau2 calibration trajectories in portfolio.ts. Hosts observing the 500s should drop it with RouterOptions.unavailableModels rather than this snapshot claiming the model cannot call tools.\n contextWindow: 400_000,\n maxOutputTokens: 128_000,\n supportsTools: true,\n supportsVision: false,\n },\n \"openai/gpt-5.4\": {\n contextWindow: 1_050_000,\n maxOutputTokens: 128_000,\n supportsTools: true,\n supportsVision: true,\n },\n \"openai/gpt-5.4-mini\": {\n contextWindow: 400_000,\n maxOutputTokens: 128_000,\n supportsTools: true,\n supportsVision: true,\n },\n \"openai/gpt-5.4-nano\": {\n contextWindow: 1_050_000,\n maxOutputTokens: 128_000,\n supportsTools: true,\n supportsVision: false,\n },\n \"openai/gpt-5.4-pro\": { // supportsTools: not probed — fails closed\n contextWindow: 1_050_000,\n maxOutputTokens: 128_000,\n supportsTools: false,\n supportsVision: true,\n },\n \"openai/gpt-5.5\": {\n contextWindow: 1_050_000,\n maxOutputTokens: 128_000,\n supportsTools: true,\n supportsVision: true,\n },\n \"openai/gpt-5.5-pro\": { // supportsTools: not probed — fails closed\n contextWindow: 1_050_000,\n maxOutputTokens: 128_000,\n supportsTools: false,\n supportsVision: true,\n },\n \"openai/gpt-5.6-luna\": {\n contextWindow: 1_050_000,\n maxOutputTokens: 128_000,\n supportsTools: true,\n supportsVision: true,\n },\n \"openai/gpt-5.6-luna-pro\": {\n contextWindow: 1_050_000,\n maxOutputTokens: 128_000,\n supportsTools: false,\n supportsVision: true,\n },\n \"openai/gpt-5.6-sol\": {\n contextWindow: 1_050_000,\n maxOutputTokens: 128_000,\n supportsTools: true,\n supportsVision: true,\n },\n \"openai/gpt-5.6-sol-pro\": {\n contextWindow: 1_050_000,\n maxOutputTokens: 128_000,\n supportsTools: true,\n supportsVision: true,\n },\n \"openai/gpt-5.6-terra\": {\n contextWindow: 1_050_000,\n maxOutputTokens: 128_000,\n supportsTools: true,\n supportsVision: true,\n },\n \"openai/gpt-5.6-terra-pro\": {\n contextWindow: 1_050_000,\n maxOutputTokens: 128_000,\n supportsTools: true,\n supportsVision: true,\n },\n \"openai/gpt-6-astra\": { // supportsTools: not probed — fails closed\n contextWindow: 1_050_000,\n maxOutputTokens: 128_000,\n supportsTools: false,\n supportsVision: true,\n },\n \"openai/gpt-6-luna\": { // supportsTools: not probed — fails closed\n contextWindow: 1_050_000,\n maxOutputTokens: 128_000,\n supportsTools: false,\n supportsVision: true,\n },\n \"openai/gpt-6-sol\": { // supportsTools: not probed — fails closed\n contextWindow: 1_050_000,\n maxOutputTokens: 128_000,\n supportsTools: false,\n supportsVision: true,\n },\n \"openai/o1\": {\n contextWindow: 200_000,\n maxOutputTokens: 100_000,\n supportsTools: true,\n supportsVision: false,\n },\n \"openai/o3\": {\n contextWindow: 200_000,\n maxOutputTokens: 100_000,\n supportsTools: true,\n supportsVision: false,\n },\n \"openai/o3-mini\": {\n contextWindow: 128_000,\n maxOutputTokens: 100_000,\n supportsTools: true,\n supportsVision: false,\n },\n \"openai/o4-mini\": {\n contextWindow: 128_000,\n maxOutputTokens: 100_000,\n supportsTools: true,\n supportsVision: false,\n },\n \"poolside/laguna-xs-2.1\": { // supportsTools: not probed — fails closed\n contextWindow: 131_072,\n maxOutputTokens: 16_384,\n supportsTools: false,\n supportsVision: false,\n },\n \"qwen/qwen3.7-flash\": {\n contextWindow: 1_000_000,\n maxOutputTokens: 65_536,\n supportsTools: true,\n supportsVision: false,\n },\n \"qwen/qwen3.7-max\": {\n contextWindow: 1_000_000,\n maxOutputTokens: 65_536,\n supportsTools: true,\n supportsVision: false,\n },\n \"qwen/qwen3.7-plus\": {\n contextWindow: 1_000_000,\n maxOutputTokens: 131_072,\n supportsTools: true,\n supportsVision: false,\n },\n \"qwen/qwen3.8-flash\": { // supportsTools: not probed — fails closed\n contextWindow: 1_000_000,\n maxOutputTokens: 131_072,\n supportsTools: false,\n supportsVision: true,\n },\n \"xai/grok-4.3\": {\n contextWindow: 1_000_000,\n maxOutputTokens: 16_384,\n supportsTools: true,\n supportsVision: true,\n },\n \"xai/grok-4.5\": {\n contextWindow: 500_000,\n maxOutputTokens: 16_384,\n supportsTools: true,\n supportsVision: true,\n },\n \"xai/grok-4.6\": { // supportsTools: not probed — fails closed\n contextWindow: 500_000,\n maxOutputTokens: 16_384,\n supportsTools: false,\n supportsVision: true,\n },\n \"xai/grok-4.7\": { // supportsTools: not probed — fails closed\n contextWindow: 500_000,\n maxOutputTokens: 16_384,\n supportsTools: false,\n supportsVision: true,\n },\n \"xai/grok-build-0.1\": {\n contextWindow: 256_000,\n maxOutputTokens: 16_384,\n supportsTools: true,\n supportsVision: false,\n },\n \"xiaomi/mimo-v2.5\": { // supportsTools: not probed — fails closed\n contextWindow: 1_048_576,\n maxOutputTokens: 131_072,\n supportsTools: false,\n supportsVision: true,\n },\n \"xiaomi/mimo-v2.5-pro\": {\n contextWindow: 1_048_576,\n maxOutputTokens: 131_072,\n supportsTools: true,\n supportsVision: false,\n },\n \"zai/glm-5\": {\n contextWindow: 200_000,\n maxOutputTokens: 128_000,\n supportsTools: true,\n supportsVision: false,\n },\n \"zai/glm-5-turbo\": {\n contextWindow: 200_000,\n maxOutputTokens: 128_000,\n supportsTools: true,\n supportsVision: false,\n },\n \"zai/glm-5.1\": {\n contextWindow: 200_000,\n maxOutputTokens: 128_000,\n supportsTools: true,\n supportsVision: false,\n },\n \"zai/glm-5.2\": {\n contextWindow: 1_000_000,\n maxOutputTokens: 131_072,\n supportsTools: true,\n supportsVision: false,\n },\n \"zai/glm-5.3\": {\n contextWindow: 1_000_000,\n maxOutputTokens: 131_072,\n supportsTools: true,\n supportsVision: false,\n },\n \"zai/glm-5.3-flash\": {\n contextWindow: 1_000_000,\n maxOutputTokens: 131_072,\n supportsTools: true,\n supportsVision: true,\n },\n });\n","{\n \"anthropic/claude-fable-5\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 9298.5,\n \"p95LatencyMs\": 9873.4,\n \"outputTokensPerSecond\": 55.17,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"anthropic/claude-haiku-4.5\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 3157.4,\n \"p95LatencyMs\": 3170.7,\n \"outputTokensPerSecond\": 162.16,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"anthropic/claude-opus-4.5\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 6497.7,\n \"p95LatencyMs\": 6953.7,\n \"outputTokensPerSecond\": 78.99,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"anthropic/claude-opus-4.7\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 5316.5,\n \"p95LatencyMs\": 6121.5,\n \"outputTokensPerSecond\": 97.34,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"anthropic/claude-opus-4.8\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 6216.1,\n \"p95LatencyMs\": 6847.7,\n \"outputTokensPerSecond\": 82.81,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"anthropic/claude-opus-5\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 7309,\n \"p95LatencyMs\": 7745.2,\n \"outputTokensPerSecond\": 70.17,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"anthropic/claude-sonnet-4.5\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 6330.4,\n \"p95LatencyMs\": 6631.6,\n \"outputTokensPerSecond\": 81.03,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"anthropic/claude-sonnet-4.6\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 6508,\n \"p95LatencyMs\": 6698.3,\n \"outputTokensPerSecond\": 78.6,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"anthropic/claude-sonnet-5\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 6165.4,\n \"p95LatencyMs\": 6582.9,\n \"outputTokensPerSecond\": 83.62,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"deepseek/deepseek-chat\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 4351.4,\n \"p95LatencyMs\": 4543.7,\n \"outputTokensPerSecond\": 117.78,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"deepseek/deepseek-reasoner\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 5201.2,\n \"p95LatencyMs\": 6079.6,\n \"outputTokensPerSecond\": 99.77,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"deepseek/deepseek-v4-pro\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 8781.2,\n \"p95LatencyMs\": 9881.1,\n \"outputTokensPerSecond\": 58.98,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"google/gemini-2.5-flash\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 5416.4,\n \"p95LatencyMs\": 6442.8,\n \"outputTokensPerSecond\": 213.07,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"google/gemini-2.5-flash-lite\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 5002.6,\n \"p95LatencyMs\": 5780.3,\n \"outputTokensPerSecond\": 408.43,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"google/gemini-2.5-pro\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 28169.5,\n \"p95LatencyMs\": 29491.4,\n \"outputTokensPerSecond\": 147.3,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"google/gemini-3-flash-preview\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 4717.1,\n \"p95LatencyMs\": 5037.1,\n \"outputTokensPerSecond\": 198.71,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"google/gemini-3.1-flash-lite\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 2855.8,\n \"p95LatencyMs\": 3172.7,\n \"outputTokensPerSecond\": 286.91,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"google/gemini-3.1-pro\": {\n \"measuredAt\": \"2026-08-29T16:59:54Z\",\n \"latencyMs\": 24194.1,\n \"p95LatencyMs\": 27269.6,\n \"outputTokensPerSecond\": 109.47,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"google/gemini-3.5-flash\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 5320.6,\n \"p95LatencyMs\": 5429.8,\n \"outputTokensPerSecond\": 226.21,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"google/gemini-3.5-flash-lite\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 3515.8,\n \"p95LatencyMs\": 4363.4,\n \"outputTokensPerSecond\": 248.9,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"google/gemini-3.6-flash\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 13020,\n \"p95LatencyMs\": 15383.1,\n \"outputTokensPerSecond\": 187.87,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"minimax/minimax-m2.7\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 8761.1,\n \"p95LatencyMs\": 10199.3,\n \"outputTokensPerSecond\": 59.18,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"minimax/minimax-m3\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 11101.9,\n \"p95LatencyMs\": 26087.1,\n \"outputTokensPerSecond\": 101.12,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"moonshot/kimi-k3\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 24498.9,\n \"p95LatencyMs\": 40365.3,\n \"outputTokensPerSecond\": 25.11,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"nvidia/mistral-nemotron\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 7349.6,\n \"p95LatencyMs\": 9932.3,\n \"outputTokensPerSecond\": 79.48,\n \"errorRate\": 0.3333,\n \"samples\": 3\n },\n \"nvidia/nemotron-3-nano-omni-30b-a3b-reasoning\": {\n \"measuredAt\": \"2026-08-29T16:59:54Z\",\n \"latencyMs\": 9324.6,\n \"p95LatencyMs\": 12992,\n \"outputTokensPerSecond\": 64.96,\n \"errorRate\": 0.3333,\n \"samples\": 3\n },\n \"nvidia/nemotron-nano-12b-v2-vl\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 5846.9,\n \"p95LatencyMs\": 5846.9,\n \"outputTokensPerSecond\": 87.57,\n \"errorRate\": 0.6667,\n \"samples\": 3\n },\n \"nvidia/nemotron-nano-9b-v2\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 5282.5,\n \"p95LatencyMs\": 5282.5,\n \"outputTokensPerSecond\": 96.92,\n \"errorRate\": 0.6667,\n \"samples\": 3\n },\n \"nvidia/step-3.7-flash\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 4617.4,\n \"p95LatencyMs\": 5237.4,\n \"outputTokensPerSecond\": 112.92,\n \"errorRate\": 0.3333,\n \"samples\": 3\n },\n \"openai/chat-latest\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 3690.9,\n \"p95LatencyMs\": 4344,\n \"outputTokensPerSecond\": 111.85,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"openai/gpt-4.1\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 3527.9,\n \"p95LatencyMs\": 3831.7,\n \"outputTokensPerSecond\": 141.27,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"openai/gpt-4.1-mini\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 4268.2,\n \"p95LatencyMs\": 5101.5,\n \"outputTokensPerSecond\": 103.42,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"openai/gpt-4.1-nano\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 3088.3,\n \"p95LatencyMs\": 3369.2,\n \"outputTokensPerSecond\": 150.31,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"openai/gpt-4o\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 2995.2,\n \"p95LatencyMs\": 3174.2,\n \"outputTokensPerSecond\": 171.32,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"openai/gpt-4o-mini\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 4751.5,\n \"p95LatencyMs\": 4930.4,\n \"outputTokensPerSecond\": 107.84,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"openai/gpt-5-mini\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 4558.1,\n \"p95LatencyMs\": 5081.9,\n \"outputTokensPerSecond\": 113.25,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"openai/gpt-5.2\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 5436.6,\n \"p95LatencyMs\": 5928.8,\n \"outputTokensPerSecond\": 95.47,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"openai/gpt-5.3-codex\": {\n \"measuredAt\": \"2026-08-29T16:59:54Z\",\n \"latencyMs\": 15290.4,\n \"p95LatencyMs\": 15290.4,\n \"outputTokensPerSecond\": 33.49,\n \"errorRate\": 0.6667,\n \"samples\": 3\n },\n \"openai/gpt-5.4\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 5596,\n \"p95LatencyMs\": 5919.4,\n \"outputTokensPerSecond\": 91.67,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"openai/gpt-5.4-mini\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 3377.8,\n \"p95LatencyMs\": 3646.8,\n \"outputTokensPerSecond\": 138.08,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"openai/gpt-5.4-nano\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 4040.4,\n \"p95LatencyMs\": 4205.9,\n \"outputTokensPerSecond\": 118.52,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"openai/gpt-5.5\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 6367.8,\n \"p95LatencyMs\": 7330.7,\n \"outputTokensPerSecond\": 81.29,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"openai/gpt-5.6-luna\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 6064.5,\n \"p95LatencyMs\": 7347.3,\n \"outputTokensPerSecond\": 87.93,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"openai/gpt-5.6-luna-pro\": {\n \"measuredAt\": \"2026-08-29T16:59:54Z\",\n \"latencyMs\": 13914.9,\n \"p95LatencyMs\": 13914.9,\n \"outputTokensPerSecond\": 36.79,\n \"errorRate\": 0.6667,\n \"samples\": 3\n },\n \"openai/gpt-5.6-sol\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 7720.2,\n \"p95LatencyMs\": 9108.2,\n \"outputTokensPerSecond\": 67.47,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"openai/gpt-5.6-sol-pro\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 11442.7,\n \"p95LatencyMs\": 13363.1,\n \"outputTokensPerSecond\": 148.75,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"openai/gpt-5.6-terra\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 4941,\n \"p95LatencyMs\": 5095.3,\n \"outputTokensPerSecond\": 103.69,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"openai/gpt-5.6-terra-pro\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 3574.1,\n \"p95LatencyMs\": 4126.3,\n \"outputTokensPerSecond\": 133.59,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"openai/o1\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 4324.9,\n \"p95LatencyMs\": 5838.1,\n \"outputTokensPerSecond\": 125.86,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"openai/o3\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 5463.4,\n \"p95LatencyMs\": 5613.1,\n \"outputTokensPerSecond\": 93.8,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"openai/o3-mini\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 2912.7,\n \"p95LatencyMs\": 3092.1,\n \"outputTokensPerSecond\": 176.49,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"openai/o4-mini\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 4958.7,\n \"p95LatencyMs\": 5313,\n \"outputTokensPerSecond\": 103.81,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"qwen/qwen3.7-flash\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 3385.5,\n \"p95LatencyMs\": 4042.7,\n \"outputTokensPerSecond\": 153.94,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"qwen/qwen3.7-max\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 9387.1,\n \"p95LatencyMs\": 10490.2,\n \"outputTokensPerSecond\": 54.92,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"qwen/qwen3.7-plus\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 9766.6,\n \"p95LatencyMs\": 9798.2,\n \"outputTokensPerSecond\": 52.42,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"tencent/hy3\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 6062.3,\n \"p95LatencyMs\": 7070.2,\n \"outputTokensPerSecond\": 87.3,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"xai/grok-4.3\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 9467.7,\n \"p95LatencyMs\": 10087.9,\n \"outputTokensPerSecond\": 48.36,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"xai/grok-4.5\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 13564.8,\n \"p95LatencyMs\": 17351.9,\n \"outputTokensPerSecond\": 60.71,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"xai/grok-build-0.1\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 16394.8,\n \"p95LatencyMs\": 18035.4,\n \"outputTokensPerSecond\": 96.86,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"xiaomi/mimo-v2.5-pro\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 12070.7,\n \"p95LatencyMs\": 12386.8,\n \"outputTokensPerSecond\": 42.44,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"zai/glm-5\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 6839.7,\n \"p95LatencyMs\": 7261.4,\n \"outputTokensPerSecond\": 75.16,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"zai/glm-5-turbo\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 55348.5,\n \"p95LatencyMs\": 114086.6,\n \"outputTokensPerSecond\": 14.64,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"zai/glm-5.1\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 15658.4,\n \"p95LatencyMs\": 17307.1,\n \"outputTokensPerSecond\": 32.9,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"zai/glm-5.2\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 10308.5,\n \"p95LatencyMs\": 15127.6,\n \"outputTokensPerSecond\": 54.87,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"zai/glm-5.3\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 7272.4,\n \"p95LatencyMs\": 7998.1,\n \"outputTokensPerSecond\": 71.09,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"zai/glm-5.3-flash\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 10545.3,\n \"p95LatencyMs\": 11672.4,\n \"outputTokensPerSecond\": 49.01,\n \"errorRate\": 0,\n \"samples\": 3\n }\n}\n","/**\n * Model-performance priors consumed by the portfolio router.\n *\n * The entries below are a small, auditable seed extracted from the 2026-03-16\n * BlockRun performance run. They are deliberately weak priors: live data\n * injected by the host should replace them through configuration before a\n * release. Historical numbers must never be presented as a current\n * provider SLA or as task-quality measurements.\n */\n\nimport liveProfiles from \"./model-profiles.generated.json\";\n\nexport type ModelPerformanceProfile = {\n measuredAt: string;\n /** Gateway end-to-end latency for the benchmark workload. */\n latencyMs: number;\n /** Tail latency is more relevant than mean latency for urgent requests. */\n p95LatencyMs?: number;\n outputTokensPerSecond: number;\n /** External intelligence index when one was available; not task success. */\n intelligenceIndex?: number;\n /** Failure fraction observed in the same benchmark run. */\n errorRate?: number;\n /** Number of sampled calls behind the observation. */\n samples?: number;\n};\n\n// Generated from benchmark files that satisfy the uncached-inference\n// invariant. These are weak performance priors (speed/reliability), never\n// task-quality labels.\nexport const LIVE_MODEL_PROFILES: Readonly> = Object.freeze(\n liveProfiles as Record,\n);\n\nexport const HISTORICAL_MODEL_PROFILES: Readonly> =\n Object.freeze({\n \"anthropic/claude-haiku-4.5\": {\n measuredAt: \"2026-03-16T13:50:48Z\",\n latencyMs: 2305,\n outputTokensPerSecond: 140.6,\n },\n \"anthropic/claude-sonnet-4.6\": {\n measuredAt: \"2026-03-16T13:50:48Z\",\n latencyMs: 2110,\n outputTokensPerSecond: 121.3,\n },\n \"deepseek/deepseek-chat\": {\n measuredAt: \"2026-03-16T13:50:48Z\",\n latencyMs: 1431,\n outputTokensPerSecond: 179.2,\n intelligenceIndex: 32,\n },\n \"google/gemini-2.5-flash\": {\n measuredAt: \"2026-03-16T13:50:48Z\",\n latencyMs: 1238,\n outputTokensPerSecond: 207.6,\n intelligenceIndex: 20,\n },\n \"google/gemini-2.5-flash-lite\": {\n measuredAt: \"2026-03-16T13:50:48Z\",\n latencyMs: 1353,\n outputTokensPerSecond: 192.5,\n intelligenceIndex: 20,\n },\n \"google/gemini-2.5-pro\": {\n measuredAt: \"2026-03-16T13:50:48Z\",\n latencyMs: 1294,\n outputTokensPerSecond: 197.8,\n },\n \"google/gemini-3.1-pro\": {\n measuredAt: \"2026-03-16T13:50:48Z\",\n latencyMs: 1609,\n outputTokensPerSecond: 167.2,\n },\n \"openai/gpt-4o-mini\": {\n measuredAt: \"2026-03-16T13:50:48Z\",\n latencyMs: 2764,\n outputTokensPerSecond: 92.8,\n },\n \"openai/gpt-5.3-codex\": {\n measuredAt: \"2026-03-16T13:50:48Z\",\n latencyMs: 7935,\n outputTokensPerSecond: 32.3,\n },\n });\n","/**\n * Whether the request actually requires an external action/tool, as distinct\n * from merely being sent by a host that exposes tools on every turn.\n *\n * The detector intentionally looks for action+target pairs. A generic factual\n * or multiple-choice question must stay false even when the host attaches a\n * large tool schema; otherwise every tool-enabled host turn is over-routed as\n * an agent task and models may browse or mutate state unnecessarily.\n */\nexport function inferToolRequirement(\n prompt: string,\n _systemPrompt?: string,\n toolChoice?: unknown,\n): boolean {\n // OpenAI-compatible clients can state this requirement directly. Treat that\n // protocol signal as authoritative instead of trying to infer it from prose.\n if (toolChoice === \"none\") return false;\n if (toolChoice === \"required\") return true;\n if (\n typeof toolChoice === \"object\" &&\n toolChoice !== null &&\n (toolChoice as { type?: unknown }).type === \"function\"\n ) {\n return true;\n }\n\n // System prompts commonly describe every tool a host exposes. They are not\n // evidence that the user asked to perform an action on this turn. Explicit\n // host requirements should use tool_choice/requiresTools instead.\n const text = prompt;\n const explicitTool =\n /\\b(?:use|call|invoke)\\s+(?:the\\s+)?[\\w.-]+\\s+(?:tool|function|api)\\b|\\btool[_ -]?call\\b|使用.{0,20}(?:工具|函数|接口)|调用.{0,20}(?:工具|函数|接口)/i;\n const codeEnvironment =\n /\\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;\n const webAction =\n /\\b(?:browse|search|look up|fetch|open)\\b.{0,80}\\b(?:web|website|url|online|documentation|docs|news|weather|price)\\b|(?:浏览|搜索|查询|打开).{0,30}(?:网页|网站|链接|文档|新闻|天气|价格)/i;\n const statefulAction =\n /\\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;\n return (\n explicitTool.test(text) ||\n codeEnvironment.test(text) ||\n webAction.test(text) ||\n statefulAction.test(text)\n );\n}\n","/**\n * V3 portfolio router.\n *\n * This is deliberately local and deterministic: feature extraction, eligibility\n * checks and scoring read only request data plus the in-process model registry.\n * It is therefore safe for the hot path and provides a stable baseline for the\n * RouterBench evaluation before health telemetry / an optional judge are added.\n */\n\nimport { DEFAULT_MODEL_CAPABILITIES } from \"./model-capabilities.js\";\nimport { getFallbackChain, selectModel } from \"./selector.js\";\nimport { RulesStrategy } from \"./strategy.js\";\nimport {\n HISTORICAL_MODEL_PROFILES,\n LIVE_MODEL_PROFILES,\n type ModelPerformanceProfile,\n} from \"./model-profiles.js\";\nimport type { RouterOptions, RouterStrategy, TaskType, Tier, TierConfig } from \"./types.js\";\nimport { inferToolRequirement } from \"./tool-intent.js\";\n\ntype TaskFeatures = {\n taskType: TaskType;\n estimatedInputTokens: number;\n hasCode: boolean;\n needsTools: boolean;\n toolsAvailable: boolean;\n needsVision: boolean;\n needsStructuredOutput: boolean;\n latencySensitive: boolean;\n highStakes: boolean;\n language: \"zh\" | \"other\";\n likelyParallelToolCalls: boolean;\n complexMultiToolPlan: boolean;\n agentDomain: \"airline\" | \"retail\" | \"web_research\" | \"other\";\n deepWebResearch: boolean;\n agentRisk: \"standard\" | \"high\" | \"complex_high\" | \"policy_exception_simple\" | \"policy_exception\";\n terminalToolSignal: boolean;\n terminalSafetySensitive: boolean;\n implicitTerminalCode: boolean;\n};\n\nconst DEFAULT_PORTFOLIO_WEIGHTS = {\n auto: {\n quality: 0.47,\n capability: 0.2,\n cost: 0.18,\n speed: 0.07,\n reliability: 0.03,\n legacy: 0.05,\n },\n eco: { quality: 0.36, capability: 0.2, cost: 0.28, speed: 0.1, reliability: 0.04, legacy: 0.02 },\n premium: {\n quality: 0.58,\n capability: 0.2,\n cost: 0.08,\n speed: 0.06,\n reliability: 0.06,\n legacy: 0.02,\n },\n highStakesBoost: { quality: 0.08, reliability: 0.05 },\n latencySensitiveSpeedBoost: 0.08,\n affinityFloorGap: { auto: 0.1, eco: 0.22, premium: 0.05 },\n} as const;\n\n/**\n * Detect turns that probably need several tool calls. This is a\n * deliberately conservative request-side feature: it uses only the prompt\n * and visible tool count, never benchmark categories or expected answers.\n */\nfunction likelyNeedsParallelToolCalls(\n prompt: string,\n needsTools: boolean,\n toolCount: number | undefined,\n toolNames: readonly string[] | undefined,\n): boolean {\n if (!needsTools || toolCount === undefined || toolCount < 1) return false;\n const text = prompt.trim();\n const explicitRepeat =\n /\\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(\n text,\n );\n if (explicitRepeat) return true;\n\n const sentenceClauses = text\n .split(/[.!?。!?]+/)\n .map((part) => part.trim())\n .filter((part) => part.length >= 8);\n if (\n (/\\b(?:also|additionally|furthermore)\\b|另外|此外|그리고/i.test(text) &&\n sentenceClauses.length >= 2) ||\n /\\band\\s+(?:also|for the)\\b/i.test(text)\n )\n return true;\n\n const pairedQuantity =\n /\\b\\d+(?:\\.\\d+)?\\s+(?:and|or)\\s+\\d+(?:\\.\\d+)?\\s*(?:gb|mb|tb|kg|g|ml|oz|cups?|cores?|cpus?)\\b/i.test(\n text,\n );\n if (pairedQuantity) return true;\n\n // Distinctive tokens from two visible tool names are a strong local signal\n // for a multi-operation turn (for example add_task + delete_task).\n const operationTokens = new Set([\n \"add\",\n \"delete\",\n \"remove\",\n \"cancel\",\n \"return\",\n \"exchange\",\n \"modify\",\n \"book\",\n \"transfer\",\n \"send\",\n \"upload\",\n \"download\",\n \"create\",\n \"close\",\n ]);\n const lowered = text.toLowerCase();\n const matchedOperationTokens = new Set(\n (toolNames ?? [])\n .flatMap((name) => name.toLowerCase().split(/[^a-z0-9\\u3400-\\u9fff]+/))\n .filter((token) => operationTokens.has(token) && lowered.includes(token)),\n );\n // A single workflow naturally mentions domain nouns like order/item plus\n // one action. Upgrade only when two different visible operation verbs are\n // requested (for example cancel + book or add + delete).\n if (matchedOperationTokens.size >= 2) return true;\n\n // Repeated food/logging entries are commonly expressed as several lines,\n // each with its own quantity rather than an explicit \"for each\" phrase.\n const nonEmptyLines = text\n .split(/\\r?\\n/)\n .map((line) => line.trim())\n .filter(Boolean);\n const quantityMentions =\n text.match(\n /\\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,\n ) ?? [];\n if (nonEmptyLines.length >= 2 && quantityMentions.length >= 2) return true;\n\n // Weather prompts provide a useful language-independent high-confidence\n // pattern: a single lookup tool plus multiple locations joined in one turn.\n const repeatedLookup =\n /\\b(?:weather|climate|clima|tiempo|temperature|snow|news|report)\\b|天气|气象|温度|降雪|新闻|报告/i.test(\n text,\n );\n const multiLocationConnector = /\\b(?:and also|both|y|e)\\b|还有|以及|和|、/i.test(text);\n const commaSeparatedLocations = (text.match(/[,,]/g) ?? []).length >= 2;\n if (repeatedLookup && (multiLocationConnector || commaSeparatedLocations)) return true;\n\n const distinctOrderParts =\n /\\b(?:food|meal)\\b[\\s\\S]*\\bdrink\\b|\\bdrink\\b[\\s\\S]*\\b(?:food|meal)\\b/i.test(text);\n const koreanParallelClauses = (text.match(/,/g) ?? []).length >= 3 && /하고|그리고/.test(text);\n return distinctOrderParts || koreanParallelClauses;\n}\n\nfunction classifyTask(\n prompt: string,\n systemPrompt: string | undefined,\n options: RouterOptions,\n): TaskFeatures {\n const fullText = `${systemPrompt ?? \"\"} ${prompt}`;\n const estimatedInputTokens = Math.ceil(fullText.length / 4);\n // Feature regexes need request shape and intent, not the entire document.\n // Sample both ends so a long pasted artifact keeps the task instruction at\n // either boundary, while the full length still drives capacity decisions.\n const scanLimit = Math.max(1, Math.min(8_000, options.config.classifier.promptTruncationChars));\n const sample = (value: string): string => {\n if (value.length <= scanLimit) return value;\n const prefixLength = Math.ceil(scanLimit / 2);\n return `${value.slice(0, prefixLength)}\\n${value.slice(-(scanLimit - prefixLength))}`;\n };\n const scannedPrompt = sample(prompt);\n const scannedSystemPrompt = sample(systemPrompt ?? \"\");\n const scannedFullText = `${scannedSystemPrompt} ${scannedPrompt}`;\n const text = scannedPrompt.toLowerCase();\n const explicitCodeSignal =\n /```|\\b(?:typescript|javascript|python|rust|java|sql|stack trace|traceback|exception)\\b|\\.(?:ts|tsx|js|py|go|rs)\\b/i.test(\n scannedPrompt,\n );\n // `class` is common in non-code Agent domains (for example airline cabin\n // class). Treat code constructs as code only when the prompt also contains\n // an implementation/editing cue, instead of letting a single ambiguous\n // noun redirect an entire tool session to the code-agent portfolio.\n const codeConstructSignal =\n /\\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(\n scannedPrompt,\n );\n const nativeCodeSignal =\n /\\b(?:programmed|written|implemented?|code)\\s+(?:in|using)\\s+(?:c\\+\\+|c|rust|go)\\b/i.test(\n scannedPrompt,\n );\n const hasCode = explicitCodeSignal || codeConstructSignal || nativeCodeSignal;\n const toolsAvailable = options.hasTools ?? false;\n const needsTools =\n options.requiresTools ??\n (toolsAvailable && inferToolRequirement(scannedPrompt, scannedSystemPrompt));\n const likelyParallelToolCalls = likelyNeedsParallelToolCalls(\n scannedPrompt,\n needsTools,\n options.toolCount,\n options.toolNames,\n );\n const normalizedToolNames = (options.toolNames ?? []).map((name) => name.toLowerCase());\n const airlineToolSignal = normalizedToolNames.some((name) =>\n /(?:flight|reservation|airport|baggage|passenger)/.test(name),\n );\n const retailToolSignal = normalizedToolNames.some((name) =>\n /(?:order|product|item|return|exchange|address)/.test(name),\n );\n const webResearchToolSignal = normalizedToolNames.some((name) =>\n /^(?:web_?search|web_?fetch)$/.test(name),\n );\n const agentDomain =\n airlineToolSignal && !retailToolSignal\n ? \"airline\"\n : retailToolSignal && !airlineToolSignal\n ? \"retail\"\n : webResearchToolSignal\n ? \"web_research\"\n : \"other\";\n // Distinguish a cheap lookup from a BrowseComp-like investigation. These\n // prompts require joining several clues, resolving an entity, and ending in\n // one exact answer; complete agent trajectories show that treating them as\n // ordinary search causes long, costly loops. This is request/tool-surface\n // evidence only and does not depend on a benchmark id or hidden answer.\n const clueConnectors =\n scannedFullText.match(\n /\\b(?:after|before|while|where|whose|which|in \\d{4}|as of|over \\d+|another|also|furthermore)\\b|(?:之后|之前|其中|截至|超过|另一个|此外)/gi,\n ) ?? [];\n const entityResolutionSignal =\n /\\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(\n scannedFullText,\n );\n const exactAnswerSignal =\n /\\b(?:exact answer|single best-supported answer|following clues|multiple public sources)\\b|(?:精确答案|根据.*线索|多个公开来源)/i.test(\n scannedFullText,\n );\n const deepWebResearch =\n agentDomain === \"web_research\" &&\n (exactAnswerSignal ||\n (entityResolutionSignal && (clueConnectors.length >= 3 || prompt.length >= 320)));\n const globalOptimizationSignal =\n /\\b(?:cheapest|lowest[- ]price|least expensive|most expensive|highest(?:[- ]priced)?|largest|smallest|maximum|minimum|best available|closest|not (?:cost|exceed))\\b|最便宜|最低价|最贵|最高价|最大|最小/i.test(\n scannedPrompt,\n );\n const globalScopeSignal =\n /\\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(\n scannedPrompt,\n );\n const globalChoiceSignal = globalOptimizationSignal || globalScopeSignal;\n const crossRecordSignal =\n /\\b(?:another|other|different|previous)\\s+(?:order|reservation|booking|account|address)\\b|另一(?:个)?(?:订单|预订|账户|地址)|其他(?:订单|预订|账户|地址)/i.test(\n scannedPrompt,\n );\n const reservationIds = scannedPrompt.match(/\\b[A-Z0-9]{6}\\b/g) ?? [];\n const crossReservationBatchSignal =\n agentDomain === \"airline\" &&\n (/\\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(\n scannedPrompt,\n ) ||\n new Set(reservationIds).size >= 2);\n const conditionalGlobalWorkflowSignal =\n agentDomain === \"airline\" &&\n globalScopeSignal &&\n /\\b(?:if|that (?:contain|have)|longer than|shorter than|under|over|at (?:most|least)|wherever possible)\\b|如果|超过|少于|不超过|尽可能/i.test(\n scannedPrompt,\n ) &&\n /\\b(?:cancel|change|upgrade|move|book)\\b[\\s\\S]*\\b(?:cancel|change|upgrade|move|book)\\b|取消[\\s\\S]*(?:升级|更改)|升级[\\s\\S]*(?:取消|更改)/i.test(\n scannedPrompt,\n );\n // A refund explicitly targeted at a named/non-original card can conflict\n // with account state and require escalation rather than a substitute action.\n // This narrow feature is visible on the first turn and avoids sending every\n // ordinary return workflow to the expensive policy specialist.\n const policyExceptionSignal =\n agentDomain === \"retail\" &&\n /\\b(?:return|refund|send back|get (?:my |the )?money back)\\b|退货|退款|退回/i.test(\n scannedPrompt,\n ) &&\n /\\b(?:amex|american express|visa|mastercard|credit card|debit card|different card|another card|other card)\\b|信用卡|借记卡|其他卡|另一张卡/i.test(\n scannedPrompt,\n );\n // A comparative selector can mention two products while requesting only\n // one write (for example \"send back the pricier one\"). Three-repeat tau2\n // calibration found no quality gain from the policy specialist on these\n // single-write cases, so keep them in a distinct, lower-cost risk band.\n const singleSelectedPolicyException =\n policyExceptionSignal &&\n /\\b(?:return|refund|send back)\\b[^.!?。!?]{0,96}\\b(?:the )?(?:pricier|cheaper|more expensive|less expensive|costlier|one)\\b/i.test(\n scannedPrompt,\n );\n // Returns and exchanges often pivot after confirmation (return -> rethink\n // -> exchange -> choose a variant). That future state is not visible to a\n // task-start router, so treat the observable workflow verb as the risk cue.\n // Simpler cancellation and one-field order edits stay on the standard path.\n const negotiatedWorkflowSignal =\n agentDomain === \"retail\" && /\\b(?:return|exchange)\\b|退货|退回|换货|交换/i.test(scannedPrompt);\n const numberedSteps = (scannedPrompt.match(/(?:^|\\s)\\d+(?:\\.\\d+)*[.)]\\s+/g) ?? []).length;\n const complexMultiToolPlan =\n likelyParallelToolCalls &&\n ((options.toolCount ?? 0) >= 6 || numberedSteps >= 3 || prompt.length > 1_200);\n let agentRisk: TaskFeatures[\"agentRisk\"] =\n needsTools && singleSelectedPolicyException\n ? \"policy_exception_simple\"\n : needsTools && policyExceptionSignal\n ? \"policy_exception\"\n : // Airline prompts that require a global optimum (for example the\n // cheapest itinerary across several candidates) are materially harder\n // than applying one change to every passenger in a known reservation.\n // Full-session evidence supports Sonnet for the former, while upgrading\n // the latter merely because it says \"all passengers\" caused a large cost\n // increase without a quality gain.\n needsTools &&\n agentDomain === \"airline\" &&\n (globalOptimizationSignal || conditionalGlobalWorkflowSignal)\n ? \"complex_high\"\n : needsTools &&\n (likelyParallelToolCalls ||\n globalChoiceSignal ||\n crossRecordSignal ||\n crossReservationBatchSignal ||\n negotiatedWorkflowSignal)\n ? \"high\"\n : \"standard\";\n const needsVision = options.hasVision ?? false;\n const needsStructuredOutput = options.requiresStructuredOutput ?? false;\n const latencySensitive =\n /\\b(?:urgent|asap|fast|quick|low latency|real[- ]time)\\b|尽快|马上|快速|低延迟/i.test(\n scannedFullText,\n );\n const highStakes =\n /\\b(?:production|security|payment|legal|medical|financial|audit)\\b|生产|安全|支付|法律|医疗|财务|审计/i.test(\n scannedFullText,\n );\n // Terminal tasks often describe the desired artifact rather than naming a\n // programming language. Treat only small, deterministic local build/file\n // work as implicit code. Operational deployment, credentials, destructive\n // work, evaluation, vision, and broad search stay on the stronger generic\n // tool-agent path. This is a request-side feature, not a benchmark ID list.\n const terminalToolSignal = normalizedToolNames.some((name) =>\n /^(?:terminalexec|terminalinspect|terminalsendkeys)$/.test(name),\n );\n const simpleTerminalArtifact =\n /\\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(\n scannedPrompt,\n );\n // Multi-file repair is qualitatively different from fixing one known local\n // script. The agent must preserve state across inspections, infer ordering\n // and dependencies, edit several artifacts, and close the loop with tests.\n // A frozen Terminal-Bench trajectory showed the economy model spending 27\n // turns repeatedly rereading files without making an edit, while Opus solved\n // the same task in eight turns. Promote this request-visible pattern before\n // model scoring; no benchmark ID or expected answer is consulted.\n const terminalComplexRepair =\n terminalToolSignal &&\n /\\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(\n scannedPrompt,\n );\n // One artifact that must be accepted by multiple compilers/runtimes is not\n // a routine file-writing task. It requires reasoning across incompatible\n // grammars and validating every execution path; cheap code models can\n // produce plausible-looking source that satisfies neither toolchain.\n const mentionedTerminalRuntimes = new Set(\n (scannedPrompt.match(/\\b(?:gcc|clang|rustc|javac|go\\s+build|node|python)\\b/gi) ?? []).map(\n (name) => name.toLowerCase().replace(/\\s+/g, \" \"),\n ),\n );\n const terminalCrossRuntimeArtifact =\n terminalToolSignal &&\n (/\\bpolyglot\\b/i.test(scannedPrompt) ||\n /\\b(?:both|each)\\b[\\s\\S]{0,120}\\b(?:compilers?|runtimes?|toolchains?)\\b/i.test(\n scannedPrompt,\n ) ||\n (mentionedTerminalRuntimes.size >= 2 &&\n /\\b(?:compile|build|run|execute)\\b/i.test(scannedPrompt)));\n // Framework-to-native ports combine binary checkpoint inspection, weight\n // export, tensor-layout reasoning, image/data decoding, and a separately\n // compiled runtime. A task-start router can see this boundary directly in\n // the request (for example PyTorch state_dict -> a pure C CLI); treating it\n // like routine single-file C work caused a 30-turn read/retry loop in a\n // frozen official Terminal-Bench trajectory.\n const terminalFrameworkToNativeArtifact =\n terminalToolSignal &&\n /\\b(?:pytorch|tensorflow|jax|onnx|state[_ -]?dict|checkpoint|safetensors?)\\b|\\.(?:pth|pt|onnx)\\b/i.test(\n scannedPrompt,\n ) &&\n /\\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(\n scannedPrompt,\n ) &&\n /\\b(?:inference|model|weights?|tensor|export|convert|load)\\b/i.test(scannedPrompt);\n if (\n needsTools &&\n (terminalComplexRepair || terminalCrossRuntimeArtifact || terminalFrameworkToNativeArtifact) &&\n (agentRisk === \"standard\" || agentRisk === \"high\")\n )\n agentRisk = \"complex_high\";\n const complexTerminalOperation =\n /\\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(\n scannedPrompt,\n );\n // A bare \"token\" is not a credential signal: blockchain, tokenizer, and\n // LLM tasks use that word routinely (for example \"token transfers\"). Only\n // treat it as sensitive when the prompt gives it an authentication/secret\n // qualifier. API keys remain an unambiguous high-risk signal on their own.\n const terminalCredentialSignal =\n /\\b(?:ssh|nginx|certificate|authentication|credentials?|passwords?|api keys?|deploy|production|encrypt|gpg|shred|securely delete|decommission)\\b/i.test(\n scannedPrompt,\n ) ||\n /\\b(?:access|auth|authentication|bearer|secret|api)\\s+tokens?\\b|\\btokens?\\s+(?:secret|credential|authentication)\\b/i.test(\n scannedPrompt,\n );\n const terminalSafetySensitive = terminalToolSignal && (highStakes || terminalCredentialSignal);\n const implicitTerminalCode =\n needsTools &&\n terminalToolSignal &&\n agentRisk === \"standard\" &&\n !highStakes &&\n !complexTerminalOperation &&\n numberedSteps < 3 &&\n prompt.length <= 1_000 &&\n simpleTerminalArtifact;\n const language = /[\\u3400-\\u9fff]/.test(scannedFullText) ? \"zh\" : \"other\";\n const multipleChoiceSignals = (scannedPrompt.match(/(?:^|\\n)\\s*[A-D][.)]\\s+/gim) ?? []).length;\n const numericSignals = (scannedPrompt.match(/-?\\d+(?:[.,]\\d+)?/g) ?? []).length;\n const compactMathProblem =\n !hasCode &&\n prompt.length < 2_500 &&\n numericSignals >= 2 &&\n (/[+×÷=%$€£¥]|\\b(?:total|each|per|times|half|twice|percent|how many|how much|calculate)\\b/i.test(\n scannedPrompt,\n ) ||\n /[??]\\s*$/.test(scannedPrompt.trim()) ||\n numericSignals >= 3);\n\n let taskType: TaskType = \"chat\";\n if (needsVision) taskType = \"vision\";\n else if (estimatedInputTokens > 80_000) taskType = \"long_context\";\n else if (needsTools && (hasCode || implicitTerminalCode)) taskType = \"code_agent\";\n else if (needsTools && likelyParallelToolCalls && !complexMultiToolPlan)\n taskType = \"tool_agent_parallel\";\n else if (needsTools) taskType = \"tool_agent\";\n else if (multipleChoiceSignals >= 3) taskType = \"reasoning_mcq\";\n else if (compactMathProblem) taskType = \"reasoning_math\";\n else if (\n /\\b(?:bug|debug|error|failure|failing|regression|crash|修复|报错|错误|调试)\\b/i.test(text)\n )\n taskType = \"debug\";\n else if (hasCode || /\\b(?:refactor|implement|patch|edit|rewrite|重构|实现|修改)\\b/i.test(text))\n taskType = \"code_edit\";\n else if (needsStructuredOutput || /\\b(?:extract|json|schema|csv|字段|提取)\\b/i.test(text))\n taskType = \"extraction\";\n else if (\n /\\b(?:prove|derive|theorem|formal|mathematical|reasoning|证明|推导|定理|数学)\\b/i.test(text)\n )\n taskType = \"reasoning\";\n\n return {\n taskType,\n estimatedInputTokens,\n hasCode,\n needsTools,\n toolsAvailable,\n needsVision,\n needsStructuredOutput,\n latencySensitive,\n highStakes,\n language,\n likelyParallelToolCalls,\n complexMultiToolPlan,\n agentDomain,\n deepWebResearch,\n agentRisk,\n terminalToolSignal,\n terminalSafetySensitive,\n implicitTerminalCode,\n };\n}\n\nfunction affinity(\n modelId: string,\n task: TaskType,\n language: TaskFeatures[\"language\"] = \"other\",\n agentDomain: TaskFeatures[\"agentDomain\"] = \"other\",\n deepWebResearch = false,\n agentRisk: TaskFeatures[\"agentRisk\"] = \"standard\",\n terminalToolSignal = false,\n terminalSafetySensitive = false,\n): number {\n const id = modelId.toLowerCase();\n // Model family names are intentionally similar (for example\n // `gemini-2.5-flash` vs `gemini-2.5-flash-lite`). A substring match lets a\n // smaller sibling inherit a capability claim that was measured only for the\n // flagship. Keep these assignments model-exact; a sibling can be added only\n // with its own evidence.\n const modelName = id.slice(id.indexOf(\"/\") + 1);\n const match = (values: string[], score: number) =>\n values.some((value) => modelName === value) ? score : 0;\n const base = 0.68;\n\n switch (task) {\n case \"code_agent\":\n if (terminalToolSignal && agentRisk === \"complex_high\") {\n // Strong native tool loop until the Responses function-output fix is\n // deployed on both gateways; keep Codex available below the floor.\n return Math.max(\n base,\n match([\"claude-sonnet-5\"], 1),\n match([\"gpt-5.3-codex\"], 0.87),\n match([\"gpt-5-mini\"], 0.78),\n match([\"gemini-3.5-flash\"], 0.76),\n );\n }\n // Seven valid full agent + official Terminal-Bench trajectories\n // (2026-07-28) gave GPT-5 Mini 4/7 resolved tasks versus 1/7 for the\n // prior dynamic code-agent choice. Its token-normalized total cost was\n // higher in this small calibration, so keep Codex and Sonnet's quality\n // priors above it; admitting Mini to the scoring band lets the normal\n // quality/cost profile choose it without erasing stronger fallbacks.\n // DeepSeek V4 Pro is kept below the primary band after two consecutive\n // mid-trajectory provider timeouts contaminated its calibration runs.\n return Math.max(\n base,\n match([\"gpt-5.3-codex\"], 1),\n match([\"claude-sonnet-5\"], 0.98),\n match([\"gpt-5-mini\"], 0.96),\n match([\"gemini-3.5-flash\"], 0.92),\n match([\"kimi-k3\"], 0.9),\n match([\"deepseek-v4-pro\", \"glm-5.2\"], 0.88),\n );\n case \"tool_agent\":\n if (terminalToolSignal && agentRisk === \"complex_high\") {\n // Keep the Responses-API Codex path outside auto's affinity floor\n // until the gateway fix that preserves function_call_output is live\n // on both chains. Sonnet has a verified native multi-turn tool loop\n // and is the safe strong default for this band today.\n return Math.max(\n base,\n match([\"claude-sonnet-5\"], 1),\n match([\"gpt-5.3-codex\"], 0.87),\n match([\"gpt-5-mini\"], 0.78),\n match([\"gemini-3.5-flash\"], 0.76),\n );\n }\n if (terminalToolSignal && !terminalSafetySensitive) {\n // Seven official Terminal-Bench calibration trajectories favoured\n // GPT-5 Mini over the prior dynamic choice. Admit Codex/Sonnet as\n // close fallbacks, but let actual request cost break the tie.\n return Math.max(\n base,\n match([\"gpt-5-mini\"], 1),\n match([\"gpt-5.3-codex\"], 0.98),\n match([\"claude-sonnet-5\"], 0.9),\n match([\"gemini-3.5-flash\"], 0.89),\n );\n }\n if (terminalToolSignal && terminalSafetySensitive) {\n // Two complete agent observations on the public\n // Terminal-Bench new-encrypt-command task ended in Codex repeating\n // the same TerminalExec input until the loop guard fired. Keep Codex\n // as an availability fallback, but below the safety-band affinity\n // floor until its Responses function-output path is verified on both\n // gateways. This does not change explicit code-agent routing.\n return Math.max(\n base,\n match([\"claude-sonnet-5\"], 1),\n match([\"claude-opus-4.8\"], 0.9),\n match([\"gpt-5.3-codex\"], 0.84),\n );\n }\n if (agentDomain === \"web_research\") {\n // Complete-session BrowseComp calibration supersedes the earlier\n // single-case Opus promotion: strict deduplicated evidence has Sonnet\n // 5 at 2/9 versus Opus 5 at 0/3, while Opus also costs more and has a\n // much longer tail. Keep Opus as an availability fallback until a\n // larger stable-provider sample supports promotion.\n return deepWebResearch\n ? Math.max(\n base,\n match([\"claude-sonnet-5\"], 1),\n match([\"gpt-5-mini\"], 0.88),\n match([\"gemini-3.5-flash\"], 0.84),\n match([\"claude-opus-5\"], 0.8),\n match([\"claude-opus-4.8\"], 0.78),\n )\n : Math.max(\n base,\n match([\"claude-sonnet-5\"], 1),\n match([\"gpt-5-mini\"], 0.88),\n match([\"gemini-3.5-flash\"], 0.86),\n match([\"claude-opus-5\"], 0.84),\n match([\"claude-opus-4.8\"], 0.82),\n );\n }\n // Full-trajectory tau2 calibration (2026-07-28, official gpt-4.1\n // simulator): Sonnet 5 completed both an airline policy task and a\n // retail multi-write task with reward 1.0. Gemini 3.5 Flash emitted\n // function calls as plain text after the first structured calls and\n // looped to the 100-step ceiling on the airline task. Keep only the\n // trajectory-validated primary inside the scoring band; the remaining\n // eligible models are retained below as availability fallbacks.\n if (agentDomain === \"retail\") {\n // Full-session calibration: GPT-5 Mini completed two local/single\n // retail workflows at a fraction of Sonnet's token cost. It remains\n // ineligible for promotion when the prompt asks for multiple actions,\n // cross-record discovery, or a global optimum; those trajectories\n // exposed unstable write arguments in prior calibration. DeepSeek V4\n // Pro completed all three high-risk retail calibration trajectories\n // that included global-choice, cross-record, and multi-write behavior;\n // Sonnet completed one of the same three.\n if (agentRisk === \"standard\") {\n return Math.max(\n base,\n match([\"gpt-5-mini\"], 1),\n match([\"claude-sonnet-5\"], 0.88),\n match([\"gemini-3.5-flash\"], 0.82),\n match([\"gpt-5.3-codex\"], 0.81),\n match([\"kimi-k3\"], 0.78),\n match([\"deepseek-v4-pro\"], 0.76),\n );\n }\n if (agentRisk === \"policy_exception\") {\n return Math.max(\n base,\n match([\"gpt-4.1\"], 1),\n match([\"claude-sonnet-5\"], 0.9),\n match([\"deepseek-v4-pro\"], 0.82),\n match([\"gpt-5-mini\"], 0.8),\n match([\"gpt-4o-mini\"], 0.76),\n );\n }\n if (agentRisk === \"policy_exception_simple\") {\n return Math.max(\n base,\n match([\"gpt-5-mini\"], 1),\n match([\"gpt-4.1\"], 0.86),\n match([\"deepseek-v4-pro\"], 0.82),\n match([\"gpt-4o-mini\"], 0.8),\n );\n }\n return Math.max(\n base,\n match([\"deepseek-v4-pro\"], 1),\n match([\"claude-sonnet-5\"], 0.88),\n match([\"gemini-3.5-flash\"], 0.82),\n match([\"gpt-5.3-codex\"], 0.81),\n match([\"kimi-k3\"], 0.78),\n match([\"gpt-5-mini\"], 0.76),\n );\n }\n // Standard airline workflows stay on GPT-5 Mini: six full-session\n // development trajectories gave it the same 5/6 success as Sonnet at\n // roughly one order of magnitude lower normalized token cost. A held-out\n // high-risk cabin/date negotiation then produced a persistent empty\n // assistant turn on Mini even after a semantic retry, while Sonnet 5\n // completed the identical official tau2 trajectory with reward 1.0.\n // Promote only global optimization / conditional-global work. A known\n // batch of reservations is operationally high-risk but still a\n // structured tool workflow: current Tau evidence has Mini and Sonnet at\n // equal task reward there, while Sonnet costs roughly two orders of\n // magnitude more on the long-tail case.\n if (agentDomain === \"airline\") {\n if (agentRisk === \"complex_high\") {\n return Math.max(\n base,\n match([\"claude-sonnet-5\"], 1),\n match([\"gpt-5-mini\"], 0.78),\n match([\"gemini-3.5-flash\"], 0.76),\n match([\"deepseek-v4-pro\"], 0.74),\n );\n }\n return Math.max(\n base,\n match([\"gpt-5-mini\"], 1),\n match([\"claude-sonnet-5\"], 0.9),\n match([\"gemini-3.5-flash\"], 0.8),\n match([\"deepseek-v4-pro\"], 0.76),\n );\n }\n return Math.max(\n base,\n match([\"claude-sonnet-5\"], 1),\n match([\"gemini-3.5-flash\"], 0.88),\n match([\"gpt-5.3-codex\"], 0.87),\n match([\"gpt-5-mini\"], 0.84),\n match([\"kimi-k3\"], 0.85),\n match([\"deepseek-v4-pro\"], 0.82),\n );\n case \"tool_agent_parallel\":\n if (terminalToolSignal) {\n // Multi-file Terminal work is not equivalent to a one-turn parallel\n // function-call benchmark. Sonnet is the strongest trajectory-tested\n // cost-controlled default; Opus remains a close safety fallback.\n return terminalSafetySensitive\n ? Math.max(\n base,\n match([\"claude-sonnet-5\"], 1),\n match([\"claude-opus-4.8\"], 0.9),\n match([\"gpt-5.3-codex\"], 0.86),\n )\n : Math.max(\n base,\n match([\"gpt-5-mini\"], 1),\n match([\"gpt-5.3-codex\"], 0.98),\n match([\"claude-sonnet-5\"], 0.92),\n match([\"gemini-3.5-flash\"], 0.88),\n );\n }\n if (agentDomain === \"web_research\") {\n return deepWebResearch\n ? Math.max(\n base,\n match([\"claude-sonnet-5\"], 1),\n match([\"gpt-5-mini\"], 0.88),\n match([\"gemini-3.5-flash\"], 0.84),\n match([\"claude-opus-5\"], 0.8),\n match([\"claude-opus-4.8\"], 0.78),\n )\n : Math.max(\n base,\n match([\"claude-sonnet-5\"], 1),\n match([\"gpt-5-mini\"], 0.88),\n match([\"gemini-3.5-flash\"], 0.86),\n match([\"claude-opus-5\"], 0.84),\n match([\"claude-opus-4.8\"], 0.82),\n );\n }\n if (agentDomain === \"retail\") {\n if (agentRisk === \"policy_exception\") {\n return Math.max(\n base,\n match([\"gpt-4.1\"], 1),\n match([\"claude-sonnet-5\"], 0.9),\n match([\"deepseek-v4-pro\"], 0.82),\n match([\"gpt-5-mini\"], 0.8),\n match([\"gpt-4o-mini\"], 0.76),\n );\n }\n if (agentRisk === \"policy_exception_simple\") {\n return Math.max(\n base,\n match([\"gpt-5-mini\"], 1),\n match([\"gpt-4.1\"], 0.86),\n match([\"deepseek-v4-pro\"], 0.82),\n match([\"gpt-4o-mini\"], 0.8),\n );\n }\n return Math.max(\n base,\n match([\"deepseek-v4-pro\"], 1),\n match([\"claude-sonnet-5\"], 0.88),\n match([\"claude-opus-4.8\"], 0.84),\n match([\"gpt-5-mini\"], 0.78),\n match([\"gemini-3.5-flash\"], 0.76),\n );\n }\n if (agentDomain === \"airline\") {\n return agentRisk === \"complex_high\"\n ? Math.max(\n base,\n match([\"claude-sonnet-5\"], 1),\n match([\"gpt-5-mini\"], 0.78),\n match([\"claude-opus-4.8\"], 0.76),\n match([\"gemini-3.5-flash\"], 0.74),\n )\n : Math.max(\n base,\n match([\"gpt-5-mini\"], 1),\n match([\"claude-sonnet-5\"], 0.9),\n match([\"gemini-3.5-flash\"], 0.8),\n );\n }\n // RouterBench calibration, 2026-07-26: Opus 4.8 produced complete\n // multi-call payloads on 2/3 multilingual BFCL parallel cases. Gemini\n // 3.5 Flash, Sonnet 5, DeepSeek V4 Pro, and Grok 4.5 were 0/3. This\n // narrow prior only applies after the conservative prompt feature above.\n return Math.max(\n base,\n match([\"claude-opus-4.8\"], 1),\n match([\"claude-sonnet-5\"], 0.84),\n match([\"grok-4.5\"], 0.82),\n match([\"gemini-3.5-flash\"], 0.8),\n match([\"deepseek-v4-pro\"], 0.78),\n );\n case \"code_edit\":\n case \"debug\":\n return Math.max(\n base,\n match([\"gpt-5.3-codex\"], 1),\n match([\"claude-sonnet-4.6\"], 0.94),\n match([\"glm-5.2\"], 0.9),\n match([\"deepseek-v4-pro\"], 0.86),\n );\n case \"reasoning\":\n return Math.max(\n base,\n match([\"claude-sonnet-5\", \"claude-sonnet-4.6\"], 0.98),\n match([\"deepseek-v4-pro\"], 0.95),\n match([\"grok-4.5\"], 0.94),\n match([\"gemini-3.1-pro\", \"gemini-3.5-flash\"], 0.92),\n );\n case \"reasoning_mcq\":\n // RouterBench calibration (2026-07-28, six stratified GPQA Diamond\n // tasks, identical agent adapter and 512-token budget): Gemini 3\n // Flash Preview scored 5/6, Gemini 3.5 Flash 4/6, and Gemini 3.1 Pro\n // 3/6 while costing ~170x more than Flash. Keep the measured winner as\n // the narrow default; version recency alone is not a quality signal.\n // Unused host tools must not change this reasoning-only model choice.\n return Math.max(\n base,\n match([\"gemini-3-flash-preview\"], 1),\n match([\"gemini-3.5-flash\"], 0.91),\n match([\"grok-4.5\"], 0.9),\n match([\"claude-sonnet-5\"], 0.88),\n match([\"deepseek-v4-pro\"], 0.84),\n );\n case \"reasoning_math\":\n // Same calibration, five multilingual MGSM tasks: Gemini 3.5 Flash was\n // 5/5 with the lowest cost and latency; four current flagships were 4/5\n // and Kimi K2.7 was 3/5.\n return Math.max(\n base,\n match([\"gemini-3.5-flash\"], 1),\n match([\"grok-4.5\"], 0.93),\n match([\"claude-sonnet-5\", \"deepseek-v4-pro\", \"kimi-k3\"], 0.9),\n );\n case \"vision\":\n return Math.max(\n base,\n match([\"gemini-3.1-pro\"], 0.96),\n match([\"qwen3.7-max\", \"claude-sonnet-4.6\", \"kimi-k3\", \"grok-4.3\"], 0.9),\n );\n case \"long_context\":\n // Long-context eligibility is necessary but not sufficient: a provider\n // can advertise a 1M window yet return an empty completion near that\n // boundary. Keep the proven long-context flagship in the lead and put\n // less-established alternatives in a separate affinity band so price\n // alone cannot displace it.\n return Math.max(\n base,\n match([\"gemini-3.1-pro\"], 1),\n match([\"qwen3.7-max\", \"glm-5.2\"], 0.89),\n match([\"gemini-3.5-flash\"], 0.88),\n match([\"deepseek-v4-pro\"], 0.85),\n );\n case \"extraction\": {\n // A structured extraction must preserve both the output contract and the\n // source-language fields. For Mandarin input, keep the language-native\n // Kimi candidate in a distinct affinity band. This is deliberately a\n // candidate-pool decision (rather than a brittle post-hoc override): it\n // still falls back normally if that model is unavailable or ineligible.\n // Kimi K3 costs ~5x its retired sibling K2.7, so the band must be wider\n // than the auto affinityFloorGap (0.10) or price alone re-selects a\n // non-native model for Mandarin input; 0.12 keeps K3 alone in the\n // primary band for zh and leaves every other language untouched.\n const kimiExtractionAffinity = language === \"zh\" ? 1 : 0.9;\n const otherExtractionAffinity = language === \"zh\" ? 0.88 : 0.9;\n return Math.max(\n base,\n match([\"gemini-3.5-flash\", \"gemini-2.5-flash\", \"gpt-4o-mini\"], otherExtractionAffinity),\n match([\"claude-sonnet-5\", \"claude-sonnet-4.6\"], otherExtractionAffinity),\n match([\"kimi-k3\"], kimiExtractionAffinity),\n );\n }\n default:\n return Math.max(\n base,\n match([\"gemini-3.5-flash\", \"gemini-2.5-flash\", \"kimi-k3\"], 0.86),\n );\n }\n}\n\nfunction evidenceCandidates(task: TaskType): string[] {\n if (task === \"code_agent\") {\n return [\n \"openai/gpt-5.3-codex\",\n \"anthropic/claude-sonnet-5\",\n \"openai/gpt-5-mini\",\n \"google/gemini-3.5-flash\",\n \"moonshot/kimi-k3\",\n \"deepseek/deepseek-v4-pro\",\n ];\n }\n if (task === \"tool_agent\") {\n return [\n \"anthropic/claude-sonnet-5\",\n \"anthropic/claude-opus-5\",\n \"openai/gpt-5-mini\",\n \"openai/gpt-4.1\",\n \"openai/gpt-4o-mini\",\n \"google/gemini-3.5-flash\",\n \"openai/gpt-5.3-codex\",\n \"moonshot/kimi-k3\",\n \"deepseek/deepseek-v4-pro\",\n ];\n }\n if (task === \"tool_agent_parallel\") {\n return [\n \"anthropic/claude-opus-5\",\n \"anthropic/claude-opus-4.8\",\n \"anthropic/claude-sonnet-5\",\n \"openai/gpt-5-mini\",\n \"openai/gpt-4.1\",\n \"openai/gpt-4o-mini\",\n \"xai/grok-4.5\",\n \"google/gemini-3.5-flash\",\n \"deepseek/deepseek-v4-pro\",\n ];\n }\n if (task === \"long_context\") {\n return [\n \"google/gemini-3.1-pro\",\n \"deepseek/deepseek-v4-pro\",\n \"qwen/qwen3.7-max\",\n \"zai/glm-5.2\",\n \"google/gemini-3.5-flash\",\n ];\n }\n if (task === \"reasoning_mcq\") {\n return [\n \"google/gemini-3-flash-preview\",\n \"google/gemini-3.5-flash\",\n \"xai/grok-4.5\",\n \"anthropic/claude-sonnet-5\",\n \"deepseek/deepseek-v4-pro\",\n ];\n }\n if (task === \"extraction\") {\n // Kimi K3 is no longer on the auto MEDIUM chain (K2.7 was); the\n // language-native extraction band in affinity() needs it in the pool.\n return [\"moonshot/kimi-k3\", \"google/gemini-3.5-flash\", \"anthropic/claude-sonnet-5\"];\n }\n if (task === \"reasoning_math\") {\n return [\n \"google/gemini-3.5-flash\",\n \"xai/grok-4.5\",\n \"anthropic/claude-sonnet-5\",\n \"deepseek/deepseek-v4-pro\",\n \"moonshot/kimi-k3\",\n ];\n }\n return [];\n}\n\nfunction isEligible(\n modelId: string,\n features: TaskFeatures,\n maxOutputTokens: number,\n options: RouterOptions,\n): boolean {\n const model = options.modelCapabilities?.[modelId] ?? DEFAULT_MODEL_CAPABILITIES[modelId];\n // Preserve compatibility for temporarily catalog-less fallback IDs. They are\n // kept behind known-model candidates but are not silently dropped.\n if (!model) return true;\n if (features.needsTools && !model.supportsTools) return false;\n if (features.needsVision && !model.supportsVision) return false;\n if (features.needsStructuredOutput && !model.supportsTools) return false;\n if (model.maxOutputTokens < maxOutputTokens) return false;\n return model.contextWindow >= (features.estimatedInputTokens + maxOutputTokens) * 1.1;\n}\n\nfunction estimatedCost(\n modelId: string,\n options: RouterOptions,\n inputTokens: number,\n outputTokens: number,\n): number {\n const price = options.modelPricing.get(modelId);\n if (!price) return Number.POSITIVE_INFINITY;\n if (price.flatPrice !== undefined) return price.flatPrice;\n return (inputTokens * price.inputPrice + outputTokens * price.outputPrice) / 1_000_000;\n}\n\nfunction profileScore(\n modelId: string,\n options: RouterOptions,\n now: Date,\n):\n | { quality?: number; speed: number; tailSpeed: number; reliability: number; freshness: number }\n | undefined {\n const profile: ModelPerformanceProfile | undefined =\n options.modelPerformance?.[modelId] ??\n LIVE_MODEL_PROFILES[modelId] ??\n HISTORICAL_MODEL_PROFILES[modelId];\n if (!profile) return undefined;\n const measuredAt = Date.parse(profile.measuredAt);\n if (!Number.isFinite(measuredAt)) return undefined;\n const ageDays = Math.max(0, (now.getTime() - measuredAt) / 86_400_000);\n // A 30-day half-life makes old data a tie-breaker only. Small probe runs are\n // also weak evidence: three quick samples should not overturn a curated\n // tier ordering merely because of a transient provider tail. Callers that\n // inject an observation without a sample count retain the legacy full\n // confidence behaviour for compatibility.\n const sampleConfidence =\n profile.samples === undefined ? 1 : Math.min(1, Math.max(0, profile.samples) / 10);\n const freshness = Math.pow(0.5, ageDays / 30) * sampleConfidence;\n const quality =\n profile.intelligenceIndex === undefined\n ? undefined\n : Math.min(1, profile.intelligenceIndex / 50);\n const speed = Math.min(\n 1,\n (2_000 / Math.max(500, profile.latencyMs) + profile.outputTokensPerSecond / 250) / 2,\n );\n const tailSpeed = Math.min(1, 3_000 / Math.max(750, profile.p95LatencyMs ?? profile.latencyMs));\n const reliability = Math.max(0, 1 - (profile.errorRate ?? 0));\n return { quality, speed, tailSpeed, reliability, freshness };\n}\n\n/** Candidate router used for Auto. Rules still set the capability tier; V3 ranks within it. */\nexport class PortfolioStrategy implements RouterStrategy {\n readonly name = \"portfolio\";\n\n route(\n prompt: string,\n systemPrompt: string | undefined,\n maxOutputTokens: number,\n options: RouterOptions,\n ) {\n const features = classifyTask(prompt, systemPrompt, options);\n const base = new RulesStrategy().route(prompt, systemPrompt, maxOutputTokens, {\n ...options,\n requiresTools: features.needsTools,\n });\n const tierConfigs = base.tierConfigs;\n if (!tierConfigs) return base;\n const targetTier: Tier =\n (features.taskType === \"reasoning_mcq\" || features.taskType === \"reasoning_math\") &&\n (base.tier === \"SIMPLE\" || base.tier === \"MEDIUM\")\n ? \"REASONING\"\n : base.tier;\n const tierConfig = tierConfigs[targetTier];\n const configuredCandidates = tierConfig ? getFallbackChain(targetTier, tierConfigs) : [];\n // Evidence candidates join the configured chain, but the host's\n // unavailable set applies to both: the configured side arrives filtered\n // through RulesStrategy, and a dead evidence model must not re-enter here.\n const unavailable = new Set(options.unavailableModels ?? []);\n const chain = [\n ...new Set([...configuredCandidates, ...evidenceCandidates(features.taskType)]),\n ].filter(\n (model): model is string =>\n typeof model === \"string\" && model.length > 0 && !unavailable.has(model),\n );\n const eligible = chain.filter((model) =>\n isEligible(model, features, maxOutputTokens, options),\n );\n const eligibleCandidates = eligible.length > 0 ? eligible : chain;\n if (eligibleCandidates.length === 0) return base;\n const profileName =\n options.routingProfile === \"eco\"\n ? \"eco\"\n : options.routingProfile === \"premium\"\n ? \"premium\"\n : \"auto\";\n const portfolio = options.config.portfolio ?? DEFAULT_PORTFOLIO_WEIGHTS;\n const getAffinity = (model: string) =>\n affinity(\n model,\n features.taskType,\n features.language,\n features.agentDomain,\n features.deepWebResearch,\n features.agentRisk,\n features.terminalToolSignal,\n features.terminalSafetySensitive,\n );\n const bestAffinity = Math.max(...eligibleCandidates.map(getAffinity));\n const specificAffinity = eligibleCandidates.filter((model) => getAffinity(model) > 0.68);\n // A tier's fallback list is primarily an availability/recovery chain, not a\n // set of equally validated substitutes. Re-ranking every fallback lets a\n // cheap generic model displace the curated primary merely because it has a\n // favourable short performance probe. Only promote models with explicit\n // task affinity; otherwise retain the first capability-eligible tier model.\n const affinityPool = specificAffinity.length > 0 ? specificAffinity : [eligibleCandidates[0]];\n // Generic Terminal work has much wider trajectory variance than a BFCL-like\n // one-turn parallel call. Keep the strong-model safety band, but admit the\n // next capable tier so Auto's cost/reliability score can reject an Opus\n // primary that is materially more expensive without measured benefit.\n const affinityFloorGap = features.terminalToolSignal\n ? Math.max(\n portfolio.affinityFloorGap[profileName],\n features.terminalSafetySensitive ? 0.15 : 0.12,\n )\n : portfolio.affinityFloorGap[profileName];\n const candidates = affinityPool.filter(\n (model) => getAffinity(model) >= bestAffinity - affinityFloorGap,\n );\n const costs = candidates.map((model) =>\n estimatedCost(model, options, features.estimatedInputTokens, maxOutputTokens),\n );\n const finiteCosts = costs.filter(Number.isFinite);\n const minCost = finiteCosts.length > 0 ? Math.min(...finiteCosts) : 0;\n const maxCost = finiteCosts.length > 0 ? Math.max(...finiteCosts) : 1;\n\n const now = options.now ?? new Date();\n const profileWeights = portfolio[profileName];\n const rankedEntries = candidates\n .map((model, index) => {\n const cost = estimatedCost(model, options, features.estimatedInputTokens, maxOutputTokens);\n const costScore =\n Number.isFinite(cost) && maxCost > minCost\n ? 1 - (cost - minCost) / (maxCost - minCost)\n : 0.5;\n const capabilityScore = isEligible(model, features, maxOutputTokens, options) ? 1 : 0;\n const profile = profileScore(model, options, now);\n // Fresh observations can refine affinity. Historical observations fade\n // quickly and never replace task-level RouterBench evidence.\n const observedQuality =\n profile?.quality === undefined\n ? getAffinity(model)\n : getAffinity(model) * (1 - profile.freshness) + profile.quality * profile.freshness;\n const observedSpeed = profile ? profile.speed * profile.freshness : 0.5;\n const observedTailSpeed = profile ? profile.tailSpeed * profile.freshness : 0.5;\n const observedReliability = profile\n ? profile.reliability * profile.freshness + (1 - profile.freshness)\n : 1;\n // Preserve a small amount of the hand-curated fallback order while V3's\n // task affinity and real request constraints do the primary work.\n const legacyScore = 1 - index / Math.max(1, candidates.length - 1);\n const qualityWeight =\n profileWeights.quality + (features.highStakes ? portfolio.highStakesBoost.quality : 0);\n const speedScore = features.latencySensitive ? observedTailSpeed : observedSpeed;\n const speedWeight =\n profileWeights.speed +\n (features.latencySensitive ? portfolio.latencySensitiveSpeedBoost : 0);\n const reliabilityWeight =\n profileWeights.reliability +\n (features.highStakes ? portfolio.highStakesBoost.reliability : 0);\n const score =\n observedQuality * qualityWeight +\n capabilityScore * profileWeights.capability +\n costScore * profileWeights.cost +\n speedScore * speedWeight +\n observedReliability * reliabilityWeight +\n legacyScore * profileWeights.legacy;\n return {\n model,\n score,\n quality: observedQuality,\n cost: costScore,\n speed: speedScore,\n reliability: observedReliability,\n };\n })\n .sort((a, b) => b.score - a.score);\n const scoredModels = rankedEntries.map((item) => item.model);\n // The affinity floor controls which models may compete for the primary;\n // it must not erase availability fallbacks. Append all remaining eligible\n // models in their curated chain order after the scored primary pool.\n const webResearchFallbackOrder = [\n \"anthropic/claude-sonnet-5\",\n \"openai/gpt-5-mini\",\n \"google/gemini-3.5-flash\",\n \"anthropic/claude-opus-5\",\n \"anthropic/claude-opus-4.8\",\n \"openai/gpt-5.3-codex\",\n ];\n const ranked =\n features.agentDomain === \"web_research\"\n ? [\n ...scoredModels,\n ...webResearchFallbackOrder.filter(\n (model) => eligibleCandidates.includes(model) && !scoredModels.includes(model),\n ),\n ...eligibleCandidates.filter(\n (model) => !scoredModels.includes(model) && !webResearchFallbackOrder.includes(model),\n ),\n ]\n : [...scoredModels, ...eligibleCandidates.filter((model) => !scoredModels.includes(model))];\n\n const model = ranked[0] ?? base.model;\n const selectedTierConfigs: Record = {\n ...tierConfigs,\n [targetTier]: { primary: model, fallback: ranked.slice(1) },\n };\n // selectModel only reads the selected tier; retain the complete tier map for host fallback.\n const decision = selectModel(\n targetTier,\n base.confidence,\n \"portfolio\",\n `${base.reasoning} | v3 task=${features.taskType} agentRisk=${features.agentRisk} deepWebResearch=${features.deepWebResearch} terminalCode=${features.implicitTerminalCode} terminalSafety=${features.terminalSafetySensitive} candidates=${ranked.length}`,\n selectedTierConfigs,\n options.modelPricing,\n features.estimatedInputTokens,\n maxOutputTokens,\n options.routingProfile,\n base.agenticScore,\n );\n return {\n ...decision,\n tierConfigs: selectedTierConfigs,\n profile: base.profile,\n candidates: ranked,\n candidateScores: rankedEntries.map(({ model, score, quality, cost, speed, reliability }) => ({\n model,\n score,\n quality,\n cost,\n speed,\n reliability,\n })),\n taskType: features.taskType,\n routerVersion: \"v3-portfolio\" as const,\n };\n }\n}\n","/**\n * Default Routing Config\n *\n * All routing parameters as a TypeScript constant.\n * Operators override via openclaw.yaml plugin config.\n *\n * Scoring uses 15 weighted dimensions with sigmoid confidence calibration.\n */\n\nimport type { RoutingConfig } from \"./types.js\";\n\nexport const DEFAULT_ROUTING_CONFIG: RoutingConfig = {\n version: \"3.5\",\n strategy: \"portfolio\",\n portfolio: {\n auto: {\n quality: 0.47,\n capability: 0.2,\n cost: 0.18,\n speed: 0.07,\n reliability: 0.03,\n legacy: 0.05,\n },\n eco: {\n quality: 0.36,\n capability: 0.2,\n cost: 0.28,\n speed: 0.1,\n reliability: 0.04,\n legacy: 0.02,\n },\n premium: {\n quality: 0.58,\n capability: 0.2,\n cost: 0.08,\n speed: 0.06,\n reliability: 0.06,\n legacy: 0.02,\n },\n highStakesBoost: { quality: 0.08, reliability: 0.05 },\n latencySensitiveSpeedBoost: 0.08,\n affinityFloorGap: { auto: 0.1, eco: 0.22, premium: 0.05 },\n },\n\n classifier: {\n llmModel: \"google/gemini-2.5-flash\",\n llmMaxTokens: 10,\n llmTemperature: 0,\n promptTruncationChars: 500,\n cacheTtlMs: 3_600_000, // 1 hour\n },\n\n scoring: {\n tokenCountThresholds: { simple: 50, complex: 500 },\n\n // Multilingual keywords: EN + ZH + JA + RU + DE + ES + PT + KO + AR\n codeKeywords: [\n // English\n \"function\",\n \"class\",\n \"import\",\n \"def\",\n \"SELECT\",\n \"async\",\n \"await\",\n \"const\",\n \"let\",\n \"var\",\n \"return\",\n \"```\",\n // Chinese\n \"函数\",\n \"类\",\n \"导入\",\n \"定义\",\n \"查询\",\n \"异步\",\n \"等待\",\n \"常量\",\n \"变量\",\n \"返回\",\n // Japanese\n \"関数\",\n \"クラス\",\n \"インポート\",\n \"非同期\",\n \"定数\",\n \"変数\",\n // Russian\n \"функция\",\n \"класс\",\n \"импорт\",\n \"определ\",\n \"запрос\",\n \"асинхронный\",\n \"ожидать\",\n \"константа\",\n \"переменная\",\n \"вернуть\",\n // German\n \"funktion\",\n \"klasse\",\n \"importieren\",\n \"definieren\",\n \"abfrage\",\n \"asynchron\",\n \"erwarten\",\n \"konstante\",\n \"variable\",\n \"zurückgeben\",\n // Spanish\n \"función\",\n \"clase\",\n \"importar\",\n \"definir\",\n \"consulta\",\n \"asíncrono\",\n \"esperar\",\n \"constante\",\n \"variable\",\n \"retornar\",\n // Portuguese\n \"função\",\n \"classe\",\n \"importar\",\n \"definir\",\n \"consulta\",\n \"assíncrono\",\n \"aguardar\",\n \"constante\",\n \"variável\",\n \"retornar\",\n // Korean\n \"함수\",\n \"클래스\",\n \"가져오기\",\n \"정의\",\n \"쿼리\",\n \"비동기\",\n \"대기\",\n \"상수\",\n \"변수\",\n \"반환\",\n // Arabic\n \"دالة\",\n \"فئة\",\n \"استيراد\",\n \"تعريف\",\n \"استعلام\",\n \"غير متزامن\",\n \"انتظار\",\n \"ثابت\",\n \"متغير\",\n \"إرجاع\",\n ],\n reasoningKeywords: [\n // English\n \"prove\",\n \"theorem\",\n \"derive\",\n \"step by step\",\n \"chain of thought\",\n \"formally\",\n \"mathematical\",\n \"proof\",\n \"logically\",\n // Chinese\n \"证明\",\n \"定理\",\n \"推导\",\n \"逐步\",\n \"思维链\",\n \"形式化\",\n \"数学\",\n \"逻辑\",\n // Japanese\n \"証明\",\n \"定理\",\n \"導出\",\n \"ステップバイステップ\",\n \"論理的\",\n // Russian\n \"доказать\",\n \"докажи\",\n \"доказательств\",\n \"теорема\",\n \"вывести\",\n \"шаг за шагом\",\n \"пошагово\",\n \"поэтапно\",\n \"цепочка рассуждений\",\n \"рассуждени\",\n \"формально\",\n \"математически\",\n \"логически\",\n // German\n \"beweisen\",\n \"beweis\",\n \"theorem\",\n \"ableiten\",\n \"schritt für schritt\",\n \"gedankenkette\",\n \"formal\",\n \"mathematisch\",\n \"logisch\",\n // Spanish\n \"demostrar\",\n \"teorema\",\n \"derivar\",\n \"paso a paso\",\n \"cadena de pensamiento\",\n \"formalmente\",\n \"matemático\",\n \"prueba\",\n \"lógicamente\",\n // Portuguese\n \"provar\",\n \"teorema\",\n \"derivar\",\n \"passo a passo\",\n \"cadeia de pensamento\",\n \"formalmente\",\n \"matemático\",\n \"prova\",\n \"logicamente\",\n // Korean\n \"증명\",\n \"정리\",\n \"도출\",\n \"단계별\",\n \"사고의 연쇄\",\n \"형식적\",\n \"수학적\",\n \"논리적\",\n // Arabic\n \"إثبات\",\n \"نظرية\",\n \"اشتقاق\",\n \"خطوة بخطوة\",\n \"سلسلة التفكير\",\n \"رسمياً\",\n \"رياضي\",\n \"برهان\",\n \"منطقياً\",\n ],\n simpleKeywords: [\n // English\n \"what is\",\n \"define\",\n \"translate\",\n \"hello\",\n \"yes or no\",\n \"capital of\",\n \"how old\",\n \"who is\",\n \"when was\",\n // Chinese\n \"什么是\",\n \"定义\",\n \"翻译\",\n \"你好\",\n \"是否\",\n \"首都\",\n \"多大\",\n \"谁是\",\n \"何时\",\n // Japanese\n \"とは\",\n \"定義\",\n \"翻訳\",\n \"こんにちは\",\n \"はいかいいえ\",\n \"首都\",\n \"誰\",\n // Russian\n \"что такое\",\n \"определение\",\n \"перевести\",\n \"переведи\",\n \"привет\",\n \"да или нет\",\n \"столица\",\n \"сколько лет\",\n \"кто такой\",\n \"когда\",\n \"объясни\",\n // German\n \"was ist\",\n \"definiere\",\n \"übersetze\",\n \"hallo\",\n \"ja oder nein\",\n \"hauptstadt\",\n \"wie alt\",\n \"wer ist\",\n \"wann\",\n \"erkläre\",\n // Spanish\n \"qué es\",\n \"definir\",\n \"traducir\",\n \"hola\",\n \"sí o no\",\n \"capital de\",\n \"cuántos años\",\n \"quién es\",\n \"cuándo\",\n // Portuguese\n \"o que é\",\n \"definir\",\n \"traduzir\",\n \"olá\",\n \"sim ou não\",\n \"capital de\",\n \"quantos anos\",\n \"quem é\",\n \"quando\",\n // Korean\n \"무엇\",\n \"정의\",\n \"번역\",\n \"안녕하세요\",\n \"예 또는 아니오\",\n \"수도\",\n \"누구\",\n \"언제\",\n // Arabic\n \"ما هو\",\n \"تعريف\",\n \"ترجم\",\n \"مرحبا\",\n \"نعم أو لا\",\n \"عاصمة\",\n \"من هو\",\n \"متى\",\n ],\n technicalKeywords: [\n // English\n \"algorithm\",\n \"optimize\",\n \"architecture\",\n \"distributed\",\n \"kubernetes\",\n \"microservice\",\n \"database\",\n \"infrastructure\",\n // Chinese\n \"算法\",\n \"优化\",\n \"架构\",\n \"分布式\",\n \"微服务\",\n \"数据库\",\n \"基础设施\",\n // Japanese\n \"アルゴリズム\",\n \"最適化\",\n \"アーキテクチャ\",\n \"分散\",\n \"マイクロサービス\",\n \"データベース\",\n // Russian\n \"алгоритм\",\n \"оптимизировать\",\n \"оптимизаци\",\n \"оптимизируй\",\n \"архитектура\",\n \"распределённый\",\n \"микросервис\",\n \"база данных\",\n \"инфраструктура\",\n // German\n \"algorithmus\",\n \"optimieren\",\n \"architektur\",\n \"verteilt\",\n \"kubernetes\",\n \"mikroservice\",\n \"datenbank\",\n \"infrastruktur\",\n // Spanish\n \"algoritmo\",\n \"optimizar\",\n \"arquitectura\",\n \"distribuido\",\n \"microservicio\",\n \"base de datos\",\n \"infraestructura\",\n // Portuguese\n \"algoritmo\",\n \"otimizar\",\n \"arquitetura\",\n \"distribuído\",\n \"microsserviço\",\n \"banco de dados\",\n \"infraestrutura\",\n // Korean\n \"알고리즘\",\n \"최적화\",\n \"아키텍처\",\n \"분산\",\n \"마이크로서비스\",\n \"데이터베이스\",\n \"인프라\",\n // Arabic\n \"خوارزمية\",\n \"تحسين\",\n \"بنية\",\n \"موزع\",\n \"خدمة مصغرة\",\n \"قاعدة بيانات\",\n \"بنية تحتية\",\n ],\n creativeKeywords: [\n // English\n \"story\",\n \"poem\",\n \"compose\",\n \"brainstorm\",\n \"creative\",\n \"imagine\",\n \"write a\",\n // Chinese\n \"故事\",\n \"诗\",\n \"创作\",\n \"头脑风暴\",\n \"创意\",\n \"想象\",\n \"写一个\",\n // Japanese\n \"物語\",\n \"詩\",\n \"作曲\",\n \"ブレインストーム\",\n \"創造的\",\n \"想像\",\n // Russian\n \"история\",\n \"рассказ\",\n \"стихотворение\",\n \"сочинить\",\n \"сочини\",\n \"мозговой штурм\",\n \"творческий\",\n \"представить\",\n \"придумай\",\n \"напиши\",\n // German\n \"geschichte\",\n \"gedicht\",\n \"komponieren\",\n \"brainstorming\",\n \"kreativ\",\n \"vorstellen\",\n \"schreibe\",\n \"erzählung\",\n // Spanish\n \"historia\",\n \"poema\",\n \"componer\",\n \"lluvia de ideas\",\n \"creativo\",\n \"imaginar\",\n \"escribe\",\n // Portuguese\n \"história\",\n \"poema\",\n \"compor\",\n \"criativo\",\n \"imaginar\",\n \"escreva\",\n // Korean\n \"이야기\",\n \"시\",\n \"작곡\",\n \"브레인스토밍\",\n \"창의적\",\n \"상상\",\n \"작성\",\n // Arabic\n \"قصة\",\n \"قصيدة\",\n \"تأليف\",\n \"عصف ذهني\",\n \"إبداعي\",\n \"تخيل\",\n \"اكتب\",\n ],\n\n // New dimension keyword lists (multilingual)\n imperativeVerbs: [\n // English\n \"build\",\n \"create\",\n \"implement\",\n \"design\",\n \"develop\",\n \"construct\",\n \"generate\",\n \"deploy\",\n \"configure\",\n \"set up\",\n // Chinese\n \"构建\",\n \"创建\",\n \"实现\",\n \"设计\",\n \"开发\",\n \"生成\",\n \"部署\",\n \"配置\",\n \"设置\",\n // Japanese\n \"構築\",\n \"作成\",\n \"実装\",\n \"設計\",\n \"開発\",\n \"生成\",\n \"デプロイ\",\n \"設定\",\n // Russian\n \"построить\",\n \"построй\",\n \"создать\",\n \"создай\",\n \"реализовать\",\n \"реализуй\",\n \"спроектировать\",\n \"разработать\",\n \"разработай\",\n \"сконструировать\",\n \"сгенерировать\",\n \"сгенерируй\",\n \"развернуть\",\n \"разверни\",\n \"настроить\",\n \"настрой\",\n // German\n \"erstellen\",\n \"bauen\",\n \"implementieren\",\n \"entwerfen\",\n \"entwickeln\",\n \"konstruieren\",\n \"generieren\",\n \"bereitstellen\",\n \"konfigurieren\",\n \"einrichten\",\n // Spanish\n \"construir\",\n \"crear\",\n \"implementar\",\n \"diseñar\",\n \"desarrollar\",\n \"generar\",\n \"desplegar\",\n \"configurar\",\n // Portuguese\n \"construir\",\n \"criar\",\n \"implementar\",\n \"projetar\",\n \"desenvolver\",\n \"gerar\",\n \"implantar\",\n \"configurar\",\n // Korean\n \"구축\",\n \"생성\",\n \"구현\",\n \"설계\",\n \"개발\",\n \"배포\",\n \"설정\",\n // Arabic\n \"بناء\",\n \"إنشاء\",\n \"تنفيذ\",\n \"تصميم\",\n \"تطوير\",\n \"توليد\",\n \"نشر\",\n \"إعداد\",\n ],\n constraintIndicators: [\n // English\n \"under\",\n \"at most\",\n \"at least\",\n \"within\",\n \"no more than\",\n \"o(\",\n \"maximum\",\n \"minimum\",\n \"limit\",\n \"budget\",\n // Chinese\n \"不超过\",\n \"至少\",\n \"最多\",\n \"在内\",\n \"最大\",\n \"最小\",\n \"限制\",\n \"预算\",\n // Japanese\n \"以下\",\n \"最大\",\n \"最小\",\n \"制限\",\n \"予算\",\n // Russian\n \"не более\",\n \"не менее\",\n \"как минимум\",\n \"в пределах\",\n \"максимум\",\n \"минимум\",\n \"ограничение\",\n \"бюджет\",\n // German\n \"höchstens\",\n \"mindestens\",\n \"innerhalb\",\n \"nicht mehr als\",\n \"maximal\",\n \"minimal\",\n \"grenze\",\n \"budget\",\n // Spanish\n \"como máximo\",\n \"al menos\",\n \"dentro de\",\n \"no más de\",\n \"máximo\",\n \"mínimo\",\n \"límite\",\n \"presupuesto\",\n // Portuguese\n \"no máximo\",\n \"pelo menos\",\n \"dentro de\",\n \"não mais que\",\n \"máximo\",\n \"mínimo\",\n \"limite\",\n \"orçamento\",\n // Korean\n \"이하\",\n \"이상\",\n \"최대\",\n \"최소\",\n \"제한\",\n \"예산\",\n // Arabic\n \"على الأكثر\",\n \"على الأقل\",\n \"ضمن\",\n \"لا يزيد عن\",\n \"أقصى\",\n \"أدنى\",\n \"حد\",\n \"ميزانية\",\n ],\n outputFormatKeywords: [\n // English\n \"json\",\n \"yaml\",\n \"xml\",\n \"table\",\n \"csv\",\n \"markdown\",\n \"schema\",\n \"format as\",\n \"structured\",\n // Chinese\n \"表格\",\n \"格式化为\",\n \"结构化\",\n // Japanese\n \"テーブル\",\n \"フォーマット\",\n \"構造化\",\n // Russian\n \"таблица\",\n \"форматировать как\",\n \"структурированный\",\n // German\n \"tabelle\",\n \"formatieren als\",\n \"strukturiert\",\n // Spanish\n \"tabla\",\n \"formatear como\",\n \"estructurado\",\n // Portuguese\n \"tabela\",\n \"formatar como\",\n \"estruturado\",\n // Korean\n \"테이블\",\n \"형식\",\n \"구조화\",\n // Arabic\n \"جدول\",\n \"تنسيق\",\n \"منظم\",\n ],\n referenceKeywords: [\n // English\n \"above\",\n \"below\",\n \"previous\",\n \"following\",\n \"the docs\",\n \"the api\",\n \"the code\",\n \"earlier\",\n \"attached\",\n // Chinese\n \"上面\",\n \"下面\",\n \"之前\",\n \"接下来\",\n \"文档\",\n \"代码\",\n \"附件\",\n // Japanese\n \"上記\",\n \"下記\",\n \"前の\",\n \"次の\",\n \"ドキュメント\",\n \"コード\",\n // Russian\n \"выше\",\n \"ниже\",\n \"предыдущий\",\n \"следующий\",\n \"документация\",\n \"код\",\n \"ранее\",\n \"вложение\",\n // German\n \"oben\",\n \"unten\",\n \"vorherige\",\n \"folgende\",\n \"dokumentation\",\n \"der code\",\n \"früher\",\n \"anhang\",\n // Spanish\n \"arriba\",\n \"abajo\",\n \"anterior\",\n \"siguiente\",\n \"documentación\",\n \"el código\",\n \"adjunto\",\n // Portuguese\n \"acima\",\n \"abaixo\",\n \"anterior\",\n \"seguinte\",\n \"documentação\",\n \"o código\",\n \"anexo\",\n // Korean\n \"위\",\n \"아래\",\n \"이전\",\n \"다음\",\n \"문서\",\n \"코드\",\n \"첨부\",\n // Arabic\n \"أعلاه\",\n \"أدناه\",\n \"السابق\",\n \"التالي\",\n \"الوثائق\",\n \"الكود\",\n \"مرفق\",\n ],\n negationKeywords: [\n // English\n \"don't\",\n \"do not\",\n \"avoid\",\n \"never\",\n \"without\",\n \"except\",\n \"exclude\",\n \"no longer\",\n // Chinese\n \"不要\",\n \"避免\",\n \"从不\",\n \"没有\",\n \"除了\",\n \"排除\",\n // Japanese\n \"しないで\",\n \"避ける\",\n \"決して\",\n \"なしで\",\n \"除く\",\n // Russian\n \"не делай\",\n \"не надо\",\n \"нельзя\",\n \"избегать\",\n \"никогда\",\n \"без\",\n \"кроме\",\n \"исключить\",\n \"больше не\",\n // German\n \"nicht\",\n \"vermeide\",\n \"niemals\",\n \"ohne\",\n \"außer\",\n \"ausschließen\",\n \"nicht mehr\",\n // Spanish\n \"no hagas\",\n \"evitar\",\n \"nunca\",\n \"sin\",\n \"excepto\",\n \"excluir\",\n // Portuguese\n \"não faça\",\n \"evitar\",\n \"nunca\",\n \"sem\",\n \"exceto\",\n \"excluir\",\n // Korean\n \"하지 마\",\n \"피하다\",\n \"절대\",\n \"없이\",\n \"제외\",\n // Arabic\n \"لا تفعل\",\n \"تجنب\",\n \"أبداً\",\n \"بدون\",\n \"باستثناء\",\n \"استبعاد\",\n ],\n domainSpecificKeywords: [\n // English\n \"quantum\",\n \"fpga\",\n \"vlsi\",\n \"risc-v\",\n \"asic\",\n \"photonics\",\n \"genomics\",\n \"proteomics\",\n \"topological\",\n \"homomorphic\",\n \"zero-knowledge\",\n \"lattice-based\",\n // Chinese\n \"量子\",\n \"光子学\",\n \"基因组学\",\n \"蛋白质组学\",\n \"拓扑\",\n \"同态\",\n \"零知识\",\n \"格密码\",\n // Japanese\n \"量子\",\n \"フォトニクス\",\n \"ゲノミクス\",\n \"トポロジカル\",\n // Russian\n \"квантовый\",\n \"фотоника\",\n \"геномика\",\n \"протеомика\",\n \"топологический\",\n \"гомоморфный\",\n \"с нулевым разглашением\",\n \"на основе решёток\",\n // German\n \"quanten\",\n \"photonik\",\n \"genomik\",\n \"proteomik\",\n \"topologisch\",\n \"homomorph\",\n \"zero-knowledge\",\n \"gitterbasiert\",\n // Spanish\n \"cuántico\",\n \"fotónica\",\n \"genómica\",\n \"proteómica\",\n \"topológico\",\n \"homomórfico\",\n // Portuguese\n \"quântico\",\n \"fotônica\",\n \"genômica\",\n \"proteômica\",\n \"topológico\",\n \"homomórfico\",\n // Korean\n \"양자\",\n \"포토닉스\",\n \"유전체학\",\n \"위상\",\n \"동형\",\n // Arabic\n \"كمي\",\n \"ضوئيات\",\n \"جينوميات\",\n \"طوبولوجي\",\n \"تماثلي\",\n ],\n\n // Agentic task keywords - file ops, execution, multi-step, iterative work\n // Pruned: removed overly common words like \"then\", \"first\", \"run\", \"test\", \"build\"\n agenticTaskKeywords: [\n // English - File operations (clearly agentic)\n \"read file\",\n \"read the file\",\n \"look at\",\n \"check the\",\n \"open the\",\n \"edit\",\n \"modify\",\n \"update the\",\n \"change the\",\n \"write to\",\n \"create file\",\n // English - Execution (specific commands only)\n \"execute\",\n \"deploy\",\n \"install\",\n \"npm\",\n \"pip\",\n \"compile\",\n // English - Multi-step patterns (specific only)\n \"after that\",\n \"and also\",\n \"once done\",\n \"step 1\",\n \"step 2\",\n // English - Iterative work\n \"fix\",\n \"debug\",\n \"until it works\",\n \"keep trying\",\n \"iterate\",\n \"make sure\",\n \"verify\",\n \"confirm\",\n // Chinese (keep specific ones)\n \"读取文件\",\n \"查看\",\n \"打开\",\n \"编辑\",\n \"修改\",\n \"更新\",\n \"创建\",\n \"执行\",\n \"部署\",\n \"安装\",\n \"第一步\",\n \"第二步\",\n \"修复\",\n \"调试\",\n \"直到\",\n \"确认\",\n \"验证\",\n // Spanish\n \"leer archivo\",\n \"editar\",\n \"modificar\",\n \"actualizar\",\n \"ejecutar\",\n \"desplegar\",\n \"instalar\",\n \"paso 1\",\n \"paso 2\",\n \"arreglar\",\n \"depurar\",\n \"verificar\",\n // Portuguese\n \"ler arquivo\",\n \"editar\",\n \"modificar\",\n \"atualizar\",\n \"executar\",\n \"implantar\",\n \"instalar\",\n \"passo 1\",\n \"passo 2\",\n \"corrigir\",\n \"depurar\",\n \"verificar\",\n // Korean\n \"파일 읽기\",\n \"편집\",\n \"수정\",\n \"업데이트\",\n \"실행\",\n \"배포\",\n \"설치\",\n \"단계 1\",\n \"단계 2\",\n \"디버그\",\n \"확인\",\n // Arabic\n \"قراءة ملف\",\n \"تحرير\",\n \"تعديل\",\n \"تحديث\",\n \"تنفيذ\",\n \"نشر\",\n \"تثبيت\",\n \"الخطوة 1\",\n \"الخطوة 2\",\n \"إصلاح\",\n \"تصحيح\",\n \"تحقق\",\n ],\n\n // Dimension weights (sum to 1.0)\n dimensionWeights: {\n tokenCount: 0.08,\n codePresence: 0.15,\n reasoningMarkers: 0.18,\n technicalTerms: 0.1,\n creativeMarkers: 0.05,\n simpleIndicators: 0.02, // Reduced from 0.12 to make room for agenticTask\n multiStepPatterns: 0.12,\n questionComplexity: 0.05,\n imperativeVerbs: 0.03,\n constraintCount: 0.04,\n outputFormat: 0.03,\n referenceComplexity: 0.02,\n negationComplexity: 0.01,\n domainSpecificity: 0.02,\n agenticTask: 0.04, // Reduced - agentic signals influence tier selection, not dominate it\n },\n\n // Tier boundaries on weighted score axis\n tierBoundaries: {\n simpleMedium: 0.0,\n mediumComplex: 0.3, // Raised from 0.18 - prevent simple tasks from reaching expensive COMPLEX tier\n complexReasoning: 0.5, // Raised from 0.4 - reserve for true reasoning tasks\n },\n\n // Sigmoid steepness for confidence calibration\n confidenceSteepness: 12,\n // Below this confidence → ambiguous (null tier)\n confidenceThreshold: 0.7,\n },\n\n // ─── Tier chains ───\n //\n // Catalog refresh 2026-08-29 (V3.5). Every chain below names only models\n // the public catalog lists (GET https://blockrun.ai/api/v1/models). Ids the\n // gateway withholds (`hidden: true`) — kimi-k2.5/k2.6/k2.7, the grok-4-fast\n // and grok-4-1-fast pairs, grok-4-0709, claude-opus-4.6, gemini-3-pro-preview,\n // the whole `free/*` namespace — were removed everywhere, including fallback\n // rungs, so a routed model is always one a user can find on blockrun.ai/models.\n //\n // Primaries moved only where portfolio.ts already carries calibration\n // evidence for the successor (Sonnet 5 over Sonnet 4.6, GPT-5 Mini for\n // agentic MEDIUM, Gemini 3.5 Flash where Kimi K2.7 was). Newcomers with no\n // trajectory evidence yet (gemini-3.6-flash, glm-5.3, glm-5.3-flash,\n // gpt-5.6-luna, grok-4.3, minimax-m3, qwen3.7-plus) enter as fallback rungs;\n // promotion waits for a calibration run, because version recency is not a\n // quality signal.\n //\n // Latency figures in comments are the 2026-08-29 gateway probe\n // (model-profiles.generated.json); prices are the catalog list.\n\n // Auto (balanced) tier configs - current default smart routing\n tiers: {\n SIMPLE: {\n primary: \"google/gemini-2.5-flash\", // $0.30/$2.50 — 60% retention (best) in the 2026-03 run; still the fastest quality answer\n fallback: [\n \"google/gemini-3-flash-preview\", // $0.50/$3 — GPQA 5/6 in the 2026-07 calibration\n \"google/gemini-3.5-flash-lite\", // $0.30/$2.50, 1M ctx, thinking mode — same price as 2.5 Flash, newer generation\n \"deepseek/deepseek-chat\", // $0.14/$0.28, 1M ctx\n \"google/gemini-3.1-flash-lite\", // $0.25/$1.50, 1M ctx\n \"openai/gpt-5.6-luna\", // $0.20/$1.20, 1M ctx — GPT-5.6 cost tier (cut 2026-07-30)\n \"openai/gpt-5.4-nano\", // $0.20/$1.25, 1M ctx\n \"google/gemini-2.5-flash-lite\", // $0.10/$0.40\n \"nvidia/nemotron-3.5-lightning\", // FREE backstop — NVIDIA free tier (probed 2026-08-30)\n ],\n },\n MEDIUM: {\n // Was moonshot/kimi-k2.7 (hidden 2026-08). Gemini 3.5 Flash is the\n // calibrated successor: MGSM 5/5, GPQA 4/6, extraction band (portfolio.ts).\n primary: \"google/gemini-3.5-flash\", // $1.50/$9, 1M ctx, vision + tools\n fallback: [\n \"google/gemini-3.6-flash\", // $1.50/$7.50 — newest Flash, output 17% cheaper than 3.5; awaiting calibration\n \"zai/glm-5.3-flash\", // $0.15/$0.50, 1M ctx, vision + tools verified live 2026-08-27\n \"openai/gpt-5.6-terra\", // $2/$12, 1M ctx — GPT-5.6 balanced tier\n \"google/gemini-3-flash-preview\", // $0.50/$3\n \"deepseek/deepseek-chat\", // $0.14/$0.28\n \"google/gemini-2.5-flash\", // $0.30/$2.50\n \"minimax/minimax-m3\", // $0.30/$1.20, 1M ctx\n \"google/gemini-3.1-flash-lite\", // $0.25/$1.50\n \"openai/gpt-5.6-luna\", // $0.20/$1.20\n \"google/gemini-2.5-flash-lite\", // $0.10/$0.40\n ],\n },\n COMPLEX: {\n primary: \"google/gemini-3.1-pro\", // $2/$12 — proven long-context flagship (portfolio.ts long_context lead)\n fallback: [\n \"google/gemini-3.6-flash\", // $1.50/$7.50 — Pro-level quality at Flash price (Google's claim; uncalibrated here)\n \"google/gemini-3.5-flash\", // $1.50/$9 — calibrated\n \"anthropic/claude-sonnet-5\", // $3/$15 — near-Opus quality, tau2 + Terminal-Bench calibrated\n \"xai/grok-4.5\", // $2.50/$9 — 503-resistant, independent infra (was grok-4-0709, now hidden)\n \"google/gemini-2.5-pro\", // $1.25/$10\n \"anthropic/claude-sonnet-4.6\", // $3/$15\n \"openai/gpt-5.6-terra\", // $2/$12 — GPT-5.6 balanced tier (Sol excluded: #202)\n \"openai/gpt-5.5\", // $5/$30 — prior OpenAI flagship\n \"openai/gpt-5.4\", // $2.50/$15 — previous flagship, benchmarked\n \"zai/glm-5.3\", // $1.40/$4.40, 1M ctx, always-on thinking — verified live 2026-08-19\n \"moonshot/kimi-k3\", // $3/$15, 1M ctx — Moonshot flagship (K2.7 successor)\n \"deepseek/deepseek-v4-pro\", // $0.435/$0.87 — strongest open-weight reasoner\n \"deepseek/deepseek-chat\", // $0.14/$0.28 — cheap last resort\n \"google/gemini-2.5-flash\", // $0.30/$2.50\n ],\n },\n REASONING: {\n // Was xai/grok-4-1-fast-reasoning ($0.20/$0.50, hidden 2026-08). DeepSeek\n // Reasoner is the cheapest listed reasoner at the same 1M context.\n primary: \"deepseek/deepseek-reasoner\", // $0.14/$0.28, 1M ctx\n fallback: [\n \"deepseek/deepseek-v4-pro\", // $0.435/$0.87 — calibrated reasoning band 0.95\n \"xai/grok-4.3\", // $1.50/$4, 1M ctx — xAI reasoning model, vision\n \"qwen/qwen3.7-plus\", // $0.32/$1.28, 1M ctx — reasoning; needs a generous max_tokens (thinking is billed)\n \"google/gemini-3.5-flash\", // $1.50/$9 — MGSM 5/5\n \"openai/o4-mini\", // $1.10/$4.40\n \"openai/o3\", // $2/$8\n ],\n },\n },\n\n // Eco tier configs - absolute cheapest (blockrun/eco)\n ecoTiers: {\n SIMPLE: {\n primary: \"nvidia/nemotron-3.5-lightning\", // FREE — NVIDIA free tier flagship, 1M ctx\n fallback: [\n // Was nvidia/nemotron-3-nano-30b until blockrun delisted it on 2026-09-08\n // (NVIDIA deprovisioned it for the account — a structured per-account\n // 404). nano-omni is blockrun's own redirect target for that id, so this\n // follows the same rule as the head: the router and the gateway name the\n // same model.\n \"nvidia/nemotron-3-nano-omni-30b-a3b-reasoning\", // FREE — nano-30b's successor, 256K ctx\n // The free head keeps rotting with NVIDIA's hosting (deepseek-v4-flash\n // 410 2026-08-12, seed-oss-36b 410 2026-08-03, gpt-oss-120b/20b 400\n // 2026-08-21, and on 2026-08-30 FOUR of the five visible free models at\n // once — step-3.7-flash, nemotron-nano-9b-v2 and nemotron-nano-12b-v2-vl\n // all 410, mistral-nemotron hung). Each retirement retargets the two\n // free rungs to the current free tier; the paid rungs below never move.\n // The head follows blockrun's own redirect of the model it replaces, so\n // the router and the gateway never name different models.\n \"google/gemini-2.5-flash-lite\", // $0.10/$0.40 — cheapest paid rung\n \"zai/glm-5.3-flash\", // $0.15/$0.50, 1M ctx, vision + tools\n \"openai/gpt-5.6-luna\", // $0.20/$1.20, 1M ctx\n \"openai/gpt-5.4-nano\", // $0.20/$1.25\n \"google/gemini-3.1-flash-lite\", // $0.25/$1.50\n ],\n },\n MEDIUM: {\n primary: \"zai/glm-5.3-flash\", // $0.15/$0.50, 1M ctx, vision + tools verified live — cheapest full-capability model\n fallback: [\n \"deepseek/deepseek-chat\", // $0.14/$0.28\n \"google/gemini-3.1-flash-lite\", // $0.25/$1.50\n \"openai/gpt-5.6-luna\", // $0.20/$1.20\n \"openai/gpt-5.4-nano\", // $0.20/$1.25\n \"google/gemini-2.5-flash-lite\", // $0.10/$0.40\n \"google/gemini-2.5-flash\", // $0.30/$2.50\n ],\n },\n COMPLEX: {\n primary: \"zai/glm-5.3-flash\", // $0.15/$0.50, 1M ctx\n fallback: [\n \"deepseek/deepseek-chat\", // $0.14/$0.28, 1M ctx\n \"minimax/minimax-m3\", // $0.30/$1.20, 1M ctx\n \"deepseek/deepseek-v4-pro\", // $0.435/$0.87\n \"google/gemini-3.1-flash-lite\", // $0.25/$1.50\n \"google/gemini-2.5-flash\", // $0.30/$2.50\n ],\n },\n REASONING: {\n primary: \"deepseek/deepseek-reasoner\", // $0.14/$0.28, 1M ctx — cheapest listed reasoner\n fallback: [\n \"deepseek/deepseek-v4-pro\", // $0.435/$0.87\n \"qwen/qwen3.7-plus\", // $0.32/$1.28 — reasoning\n \"minimax/minimax-m3\", // $0.30/$1.20 — reasoning + coding\n \"zai/glm-5.3-flash\", // $0.15/$0.50 — reasoning tokens alongside content\n ],\n },\n },\n\n // Premium tier configs - best quality (blockrun/premium)\n // codex=complex coding, flash=simple coding, sonnet=reasoning/instructions, fable/opus=architecture/PM/audits\n premiumTiers: {\n SIMPLE: {\n // Was moonshot/kimi-k2.7 (hidden 2026-08).\n primary: \"google/gemini-3.5-flash\", // $1.50/$9, 1M ctx, vision + tools — calibrated\n fallback: [\n \"google/gemini-3.6-flash\", // $1.50/$7.50 — newest Flash\n \"anthropic/claude-haiku-4.5\", // $1/$5\n \"zai/glm-5.3\", // $1.40/$4.40, 1M ctx\n \"google/gemini-2.5-flash\", // $0.30/$2.50\n \"google/gemini-3.5-flash-lite\", // $0.30/$2.50\n \"deepseek/deepseek-chat\", // $0.14/$0.28\n ],\n },\n MEDIUM: {\n primary: \"openai/gpt-5.3-codex\", // $1.75/$14 - 400K context, 128K output — code_edit/debug lead (portfolio.ts)\n fallback: [\n \"anthropic/claude-sonnet-5\", // $3/$15 — code_agent band 0.98\n \"moonshot/kimi-k3\", // $3/$15, 1M ctx — Moonshot flagship\n \"zai/glm-5.3\", // $1.40/$4.40 — long-horizon coding\n \"google/gemini-3.6-flash\", // $1.50/$7.50\n \"google/gemini-3.5-flash\", // $1.50/$9\n \"google/gemini-2.5-pro\", // $1.25/$10\n \"xai/grok-4.5\", // $2.50/$9\n \"anthropic/claude-sonnet-4.6\", // $3/$15\n \"openai/gpt-5.6-terra\", // $2/$12\n ],\n },\n COMPLEX: {\n // fable-5 was promoted here 2026-06-11, force-reverted 2026-06-13 when Anthropic\n // withdrew the offer, and restored 2026-07-14 now that BlockRun has relisted it.\n primary: \"anthropic/claude-fable-5\", // Best quality for complex tasks — Mythos-class flagship above Opus ($10/$50, 1M ctx, always-on thinking)\n // Fallback chain de-Gemini'd 2026-04-22: when Anthropic 503s, Gemini is\n // also prone to \"high demand\" 503s (correlated failure — everyone falls\n // back to Google at the same time). Prefer in-family → xAI → Moonshot →\n // OpenAI flagship → Z.AI → DeepSeek → NVIDIA free instead.\n fallback: [\n \"anthropic/claude-opus-5\", // in-family hot swap first (half the price, 1M ctx + adaptive thinking)\n \"anthropic/claude-opus-4.8\", // in-family hot swap (identical cost to 5)\n \"anthropic/claude-opus-4.7\", // in-family hot swap (identical cost to 4.8)\n \"anthropic/claude-sonnet-5\", // Sonnet-tier drop-down, near-Opus quality\n \"anthropic/claude-sonnet-4.6\",\n \"xai/grok-4.5\", // xAI flagship — 503-resistant, direct-xAI SKU\n \"moonshot/kimi-k3\", // Moonshot flagship, independent infra\n \"openai/gpt-5.6-terra\", // GPT-5.6 balanced tier — stable (Sol excluded: #202)\n \"openai/gpt-5.5\", // Prior OpenAI flagship — 1M+ ctx, native agent + computer use\n \"openai/gpt-5.4\", // Previous flagship (slow but stable, benchmarked at 6,213ms)\n \"openai/gpt-5.3-codex\",\n \"zai/glm-5.3\", // Z.AI flagship, 1M ctx\n \"deepseek/deepseek-v4-pro\", // strongest open-weight reasoner\n \"deepseek/deepseek-chat\", // Cheap, reliable\n \"nvidia/nemotron-3.5-lightning\", // NVIDIA free ultimate backstop\n ],\n },\n REASONING: {\n // Sonnet 5 promoted over Sonnet 4.6 (same price; reasoning band 0.98 for both,\n // plus Sonnet 5's tau2/BrowseComp trajectory evidence).\n primary: \"anthropic/claude-sonnet-5\", // $3/$15, 1M ctx, adaptive thinking\n fallback: [\n \"anthropic/claude-sonnet-4.6\", // in-family hot swap — same cost\n \"anthropic/claude-opus-5\", // Newest flagship Opus w/ adaptive thinking\n \"anthropic/claude-opus-4.8\", // Prior flagship Opus — identical cost to 5\n \"anthropic/claude-opus-4.7\", // Flagship Opus w/ adaptive thinking\n \"xai/grok-4.5\", // reasoning band 0.94\n \"deepseek/deepseek-v4-pro\", // reasoning band 0.95\n \"xai/grok-4.3\", // $1.50/$4 — xAI reasoning model\n \"openai/o4-mini\", // $1.10/$4.40\n \"openai/o3\", // $2/$8\n ],\n },\n },\n\n // Agentic tier configs - models that excel at multi-step autonomous tasks\n agenticTiers: {\n SIMPLE: {\n primary: \"openai/gpt-4o-mini\", // $0.15/$0.60 - best tool compliance at lowest cost\n fallback: [\n \"openai/gpt-5.6-luna\", // $0.20/$1.20 — lightweight agentic tier of GPT-5.6\n \"zai/glm-5.3-flash\", // $0.15/$0.50 — tool calls verified live 2026-08-27\n \"anthropic/claude-haiku-4.5\", // $1/$5\n \"google/gemini-2.5-flash\", // $0.30/$2.50\n ],\n },\n MEDIUM: {\n // Was moonshot/kimi-k2.7 (hidden 2026-08). GPT-5 Mini carries the\n // Terminal-Bench and tau2 trajectory evidence in portfolio.ts.\n primary: \"openai/gpt-5-mini\", // $0.25/$2 — 4/7 Terminal-Bench, 5/6 tau2 airline\n fallback: [\n \"google/gemini-3.5-flash\", // $1.50/$9 — tool_agent band 0.88\n \"zai/glm-5.3-flash\", // $0.15/$0.50 — tools verified\n \"openai/gpt-5.6-terra\", // $2/$12\n \"openai/gpt-4o-mini\", // $0.15/$0.60 — reliable tool calling\n \"anthropic/claude-haiku-4.5\", // $1/$5\n \"deepseek/deepseek-chat\", // $0.14/$0.28\n \"moonshot/kimi-k3\", // $3/$15 — tool_agent band 0.85\n ],\n },\n COMPLEX: {\n // Sonnet 5 promoted over Sonnet 4.6: tau2 airline + retail reward 1.0,\n // Terminal-Bench safety band lead (portfolio.ts).\n primary: \"anthropic/claude-sonnet-5\", // $3/$15 — best agentic quality per trajectory evidence\n // Fallback chain de-Gemini'd 2026-04-22: Gemini's \"high demand\" 503s\n // correlate with Anthropic outages (everyone falls back together).\n // Prefer 503-resistant providers first.\n fallback: [\n \"anthropic/claude-sonnet-4.6\", // in-family hot swap — same cost\n \"anthropic/claude-opus-5\", // Newest flagship Opus — in-family hot swap\n \"anthropic/claude-opus-4.8\", // Prior flagship Opus — identical cost to 5\n \"anthropic/claude-opus-4.7\", // Flagship Opus — in-family hot swap\n \"xai/grok-4.5\", // xAI flagship — strong tool use, independent infra\n \"moonshot/kimi-k3\", // Moonshot flagship — independent infra\n \"openai/gpt-5.6-terra\", // GPT-5.6 balanced tier — stable (Sol excluded: #202)\n \"openai/gpt-5.5\", // Prior flagship — native agent + computer use (exactly the agentic-tier use case)\n \"openai/gpt-5.4\", // Previous flagship — reliable\n \"openai/gpt-5.3-codex\", // code_agent lead\n \"zai/glm-5.3\", // long-horizon coding\n \"deepseek/deepseek-v4-pro\", // retail high-risk 3/3\n \"deepseek/deepseek-chat\", // cheap, reliable\n \"nvidia/nemotron-3.5-lightning\", // NVIDIA free ultimate backstop\n ],\n },\n REASONING: {\n primary: \"anthropic/claude-sonnet-5\", // $3/$15 — strong tool use + adaptive thinking\n fallback: [\n \"anthropic/claude-sonnet-4.6\", // in-family hot swap — same cost\n \"anthropic/claude-opus-5\", // Newest flagship Opus w/ adaptive thinking\n \"anthropic/claude-opus-4.8\", // Prior flagship Opus — identical cost to 5\n \"anthropic/claude-opus-4.7\", // Flagship Opus w/ adaptive thinking\n \"xai/grok-4.5\", // reasoning band 0.94\n \"deepseek/deepseek-v4-pro\", // reasoning band 0.95\n \"deepseek/deepseek-reasoner\", // $0.14/$0.28\n ],\n },\n },\n\n // Time-windowed promotions — auto-applied when active, ignored when expired.\n // The GLM-5.1 launch promo (2026-04-01 → 2026-05-01) was the last entry and\n // has expired; the list is kept empty so the mechanism stays wired.\n promotions: [],\n\n overrides: {\n maxTokensForceComplex: 100_000,\n structuredOutputMinTier: \"MEDIUM\",\n ambiguousDefaultTier: \"MEDIUM\",\n // agenticMode left undefined → auto-detect via tools/agenticScore.\n // Set to `true` to force agentic tiers; `false` to disable them entirely.\n },\n};\n","/**\n * Smart Router Entry Point\n *\n * Classifies requests and routes to the cheapest capable model.\n * Delegates to pluggable RouterStrategy (default: RulesStrategy, <1ms).\n */\n\nimport type { RoutingDecision, RouterOptions } from \"./types.js\";\nimport { getStrategy, registerStrategy } from \"./strategy.js\";\nimport { PortfolioStrategy } from \"./portfolio.js\";\n\n// Register here instead of strategy.ts so PortfolioStrategy can reuse the\n// stable RulesStrategy without introducing a module cycle.\nregisterStrategy(new PortfolioStrategy());\n\n/**\n * Route a request to the cheapest capable model.\n * Delegates to the configured strategy (PortfolioStrategy by default).\n */\nexport function route(\n prompt: string,\n systemPrompt: string | undefined,\n maxOutputTokens: number,\n options: RouterOptions,\n): RoutingDecision {\n const strategy = getStrategy(options.config.strategy ?? \"portfolio\");\n return strategy.route(prompt, systemPrompt, maxOutputTokens, options);\n}\n\nexport { getStrategy, registerStrategy, applyUnavailableModels } from \"./strategy.js\";\nexport { RulesStrategy } from \"./strategy.js\";\nexport { PortfolioStrategy } from \"./portfolio.js\";\nexport { classifyByRules } from \"./rules.js\";\nexport { inferToolRequirement } from \"./tool-intent.js\";\nexport {\n getFallbackChain,\n getFallbackChainFiltered,\n filterByToolCalling,\n filterByVision,\n filterByExcludeList,\n filterCandidatesByCapacity,\n calculateModelCost,\n} from \"./selector.js\";\nexport { DEFAULT_ROUTING_CONFIG } from \"./config.js\";\nexport { DEFAULT_MODEL_CAPABILITIES } from \"./model-capabilities.js\";\nexport { LIVE_MODEL_PROFILES, HISTORICAL_MODEL_PROFILES } from \"./model-profiles.js\";\nexport type {\n RoutingDecision,\n Tier,\n TaskType,\n RoutingConfig,\n RouterOptions,\n RouterStrategy,\n} from \"./types.js\";\nexport type { ModelPricing } from \"./selector.js\";\nexport type { ModelCapabilities } from \"./model-capabilities.js\";\nexport type { ModelPerformanceProfile } from \"./model-profiles.js\";\n"],"mappings":"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,MACA;AAAA,IACF;AAAA,IACA,mBAAmB;AAAA;AAAA,MAEjB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA,gBAAgB;AAAA;AAAA,MAEd;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA,mBAAmB;AAAA;AAAA,MAEjB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA,kBAAkB;AAAA;AAAA,MAEhB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA;AAAA,IAGA,iBAAiB;AAAA;AAAA,MAEf;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA,sBAAsB;AAAA;AAAA,MAEpB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA,sBAAsB;AAAA;AAAA,MAEpB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA,mBAAmB;AAAA;AAAA,MAEjB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA,kBAAkB;AAAA;AAAA,MAEhB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA,wBAAwB;AAAA;AAAA,MAEtB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA;AAAA;AAAA,IAIA,qBAAqB;AAAA;AAAA,MAEnB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA;AAA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","names":["confidence","decision","model"]} \ No newline at end of file +{"version":3,"sources":["../rules.ts","../selector.ts","../strategy.ts","../model-capabilities.ts","../model-profiles.generated.json","../model-profiles.ts","../tool-intent.ts","../portfolio.ts","../config.ts","../index.ts"],"sourcesContent":["/**\n * Rule-Based Classifier (v2 — Weighted Scoring)\n *\n * Scores a request across 15 weighted dimensions and maps the aggregate\n * score to a tier using configurable boundaries. Confidence is calibrated\n * via sigmoid — low confidence triggers the fallback classifier.\n *\n * Handles 70-80% of requests in < 1ms with zero cost.\n */\n\nimport type { Tier, ScoringResult, ScoringConfig } from \"./types.js\";\n\ntype DimensionScore = { name: string; score: number; signal: string | null };\n\n// ─── Dimension Scorers ───\n// Each returns a score in [-1, 1] and an optional signal string.\n\nfunction scoreTokenCount(\n estimatedTokens: number,\n thresholds: { simple: number; complex: number },\n): DimensionScore {\n if (estimatedTokens < thresholds.simple) {\n return { name: \"tokenCount\", score: -1.0, signal: `short (${estimatedTokens} tokens)` };\n }\n if (estimatedTokens > thresholds.complex) {\n return { name: \"tokenCount\", score: 1.0, signal: `long (${estimatedTokens} tokens)` };\n }\n return { name: \"tokenCount\", score: 0, signal: null };\n}\n\nfunction scoreKeywordMatch(\n text: string,\n keywords: string[],\n name: string,\n signalLabel: string,\n thresholds: { low: number; high: number },\n scores: { none: number; low: number; high: number },\n): DimensionScore {\n const matches = keywords.filter((kw) => text.includes(kw.toLowerCase()));\n if (matches.length >= thresholds.high) {\n return {\n name,\n score: scores.high,\n signal: `${signalLabel} (${matches.slice(0, 3).join(\", \")})`,\n };\n }\n if (matches.length >= thresholds.low) {\n return {\n name,\n score: scores.low,\n signal: `${signalLabel} (${matches.slice(0, 3).join(\", \")})`,\n };\n }\n return { name, score: scores.none, signal: null };\n}\n\nfunction scoreMultiStep(text: string): DimensionScore {\n const patterns = [/first.*then/i, /step \\d/i, /\\d\\.\\s/];\n const hits = patterns.filter((p) => p.test(text));\n if (hits.length > 0) {\n return { name: \"multiStepPatterns\", score: 0.5, signal: \"multi-step\" };\n }\n return { name: \"multiStepPatterns\", score: 0, signal: null };\n}\n\nfunction scoreQuestionComplexity(prompt: string): DimensionScore {\n const count = (prompt.match(/\\?/g) || []).length;\n if (count > 3) {\n return { name: \"questionComplexity\", score: 0.5, signal: `${count} questions` };\n }\n return { name: \"questionComplexity\", score: 0, signal: null };\n}\n\n/**\n * Score agentic task indicators.\n * Returns agenticScore (0-1) based on keyword matches:\n * - 4+ matches = 1.0 (high agentic)\n * - 3 matches = 0.6 (moderate agentic, triggers auto-agentic mode)\n * - 1-2 matches = 0.2 (low agentic)\n *\n * Thresholds raised because common keywords were pruned from the list.\n */\nfunction scoreAgenticTask(\n text: string,\n keywords: string[],\n): { dimensionScore: DimensionScore; agenticScore: number } {\n let matchCount = 0;\n const signals: string[] = [];\n\n for (const keyword of keywords) {\n if (text.includes(keyword.toLowerCase())) {\n matchCount++;\n if (signals.length < 3) {\n signals.push(keyword);\n }\n }\n }\n\n // Threshold-based scoring (raised thresholds after keyword pruning)\n if (matchCount >= 4) {\n return {\n dimensionScore: {\n name: \"agenticTask\",\n score: 1.0,\n signal: `agentic (${signals.join(\", \")})`,\n },\n agenticScore: 1.0,\n };\n } else if (matchCount >= 3) {\n return {\n dimensionScore: {\n name: \"agenticTask\",\n score: 0.6,\n signal: `agentic (${signals.join(\", \")})`,\n },\n agenticScore: 0.6,\n };\n } else if (matchCount >= 1) {\n return {\n dimensionScore: {\n name: \"agenticTask\",\n score: 0.2,\n signal: `agentic-light (${signals.join(\", \")})`,\n },\n agenticScore: 0.2,\n };\n }\n\n return {\n dimensionScore: { name: \"agenticTask\", score: 0, signal: null },\n agenticScore: 0,\n };\n}\n\n// ─── Main Classifier ───\n\nexport function classifyByRules(\n prompt: string,\n systemPrompt: string | undefined,\n estimatedTokens: number,\n config: ScoringConfig,\n): ScoringResult {\n // Score against user prompt only — system prompts contain boilerplate keywords\n // (tool definitions, skill descriptions, behavioral rules) that dominate scoring\n // and make every request score identically. See GitHub issue #50.\n const userText = prompt.toLowerCase();\n\n // Score the base dimensions against user text only; the agentic dimension is\n // appended below, so the scored total is one more than this list.\n const dimensions: DimensionScore[] = [\n // Token count uses total estimated tokens (system + user) — context size matters for model selection\n scoreTokenCount(estimatedTokens, config.tokenCountThresholds),\n scoreKeywordMatch(\n userText,\n config.codeKeywords,\n \"codePresence\",\n \"code\",\n { low: 1, high: 2 },\n { none: 0, low: 0.5, high: 1.0 },\n ),\n scoreKeywordMatch(\n userText,\n config.reasoningKeywords,\n \"reasoningMarkers\",\n \"reasoning\",\n { low: 1, high: 2 },\n { none: 0, low: 0.7, high: 1.0 },\n ),\n scoreKeywordMatch(\n userText,\n config.technicalKeywords,\n \"technicalTerms\",\n \"technical\",\n { low: 2, high: 4 },\n { none: 0, low: 0.5, high: 1.0 },\n ),\n scoreKeywordMatch(\n userText,\n config.creativeKeywords,\n \"creativeMarkers\",\n \"creative\",\n { low: 1, high: 2 },\n { none: 0, low: 0.5, high: 0.7 },\n ),\n scoreKeywordMatch(\n userText,\n config.simpleKeywords,\n \"simpleIndicators\",\n \"simple\",\n { low: 1, high: 2 },\n { none: 0, low: -1.0, high: -1.0 },\n ),\n scoreMultiStep(userText),\n scoreQuestionComplexity(prompt),\n\n // 6 new dimensions\n scoreKeywordMatch(\n userText,\n config.imperativeVerbs,\n \"imperativeVerbs\",\n \"imperative\",\n { low: 1, high: 2 },\n { none: 0, low: 0.3, high: 0.5 },\n ),\n scoreKeywordMatch(\n userText,\n config.constraintIndicators,\n \"constraintCount\",\n \"constraints\",\n { low: 1, high: 3 },\n { none: 0, low: 0.3, high: 0.7 },\n ),\n scoreKeywordMatch(\n userText,\n config.outputFormatKeywords,\n \"outputFormat\",\n \"format\",\n { low: 1, high: 2 },\n { none: 0, low: 0.4, high: 0.7 },\n ),\n scoreKeywordMatch(\n userText,\n config.referenceKeywords,\n \"referenceComplexity\",\n \"references\",\n { low: 1, high: 2 },\n { none: 0, low: 0.3, high: 0.5 },\n ),\n scoreKeywordMatch(\n userText,\n config.negationKeywords,\n \"negationComplexity\",\n \"negation\",\n { low: 2, high: 3 },\n { none: 0, low: 0.3, high: 0.5 },\n ),\n scoreKeywordMatch(\n userText,\n config.domainSpecificKeywords,\n \"domainSpecificity\",\n \"domain-specific\",\n { low: 1, high: 2 },\n { none: 0, low: 0.5, high: 0.8 },\n ),\n ];\n\n // Score agentic task indicators — user prompt only\n // System prompt describes assistant behavior, not user's intent.\n // e.g. a coding assistant system prompt with \"edit files\" / \"fix bugs\" should NOT\n // force every request into agentic mode.\n const agenticResult = scoreAgenticTask(userText, config.agenticTaskKeywords);\n dimensions.push(agenticResult.dimensionScore);\n const agenticScore = agenticResult.agenticScore;\n\n // Collect signals\n const signals = dimensions.filter((d) => d.signal !== null).map((d) => d.signal!);\n\n // Compute weighted score\n const weights = config.dimensionWeights;\n let weightedScore = 0;\n for (const d of dimensions) {\n const w = weights[d.name] ?? 0;\n weightedScore += d.score * w;\n }\n\n // Count reasoning markers for override — only check USER prompt, not system prompt\n // This prevents system prompts with \"step by step\" from triggering REASONING for simple queries\n const reasoningMatches = config.reasoningKeywords.filter((kw) =>\n userText.includes(kw.toLowerCase()),\n );\n\n // Direct reasoning override: 2+ reasoning markers = high confidence REASONING\n if (reasoningMatches.length >= 2) {\n const confidence = calibrateConfidence(\n Math.max(weightedScore, 0.3), // ensure positive for confidence calc\n config.confidenceSteepness,\n );\n return {\n score: weightedScore,\n tier: \"REASONING\",\n confidence: Math.max(confidence, 0.85),\n signals,\n agenticScore,\n dimensions,\n };\n }\n\n // Map weighted score to tier using boundaries\n const { simpleMedium, mediumComplex, complexReasoning } = config.tierBoundaries;\n let tier: Tier;\n let distanceFromBoundary: number;\n\n if (weightedScore < simpleMedium) {\n tier = \"SIMPLE\";\n distanceFromBoundary = simpleMedium - weightedScore;\n } else if (weightedScore < mediumComplex) {\n tier = \"MEDIUM\";\n distanceFromBoundary = Math.min(weightedScore - simpleMedium, mediumComplex - weightedScore);\n } else if (weightedScore < complexReasoning) {\n tier = \"COMPLEX\";\n distanceFromBoundary = Math.min(\n weightedScore - mediumComplex,\n complexReasoning - weightedScore,\n );\n } else {\n tier = \"REASONING\";\n distanceFromBoundary = weightedScore - complexReasoning;\n }\n\n // Calibrate confidence via sigmoid of distance from nearest boundary\n const confidence = calibrateConfidence(distanceFromBoundary, config.confidenceSteepness);\n\n // If confidence is below threshold → ambiguous\n if (confidence < config.confidenceThreshold) {\n return { score: weightedScore, tier: null, confidence, signals, agenticScore, dimensions };\n }\n\n return { score: weightedScore, tier, confidence, signals, agenticScore, dimensions };\n}\n\n/**\n * Sigmoid confidence calibration.\n * Maps distance from tier boundary to [0.5, 1.0] confidence range.\n */\nfunction calibrateConfidence(distance: number, steepness: number): number {\n return 1 / (1 + Math.exp(-steepness * distance));\n}\n","/**\n * Tier → Model Selection\n *\n * Maps a classification tier to the cheapest capable model.\n * Builds RoutingDecision metadata with cost estimates and savings.\n */\n\nimport type { Tier, TierConfig, RoutingDecision } from \"./types.js\";\n\nexport type ModelPricing = {\n inputPrice: number; // per 1M tokens\n outputPrice: number; // per 1M tokens\n /** Active promo flat price per request (overrides token-based pricing when set) */\n flatPrice?: number;\n};\n\n// The savings baseline is a price anchor, not \"the current flagship\" — it is\n// deliberately NOT bumped every time a new Opus ships. Opus 4.7, 4.8 and 5 all\n// bill $5/$25, so moving it would change no reported number while breaking\n// comparability with historical journal entries. Only move it if the Opus tier\n// itself is repriced.\nconst BASELINE_MODEL_ID = \"anthropic/claude-opus-4.7\";\n\n// Hardcoded fallback: Claude Opus 4.7 pricing (per 1M tokens)\n// Used when baseline model not found in dynamic pricing map\nconst BASELINE_INPUT_PRICE = 5.0;\nconst BASELINE_OUTPUT_PRICE = 25.0;\n\n/**\n * Select the primary model for a tier and build the RoutingDecision.\n *\n * Cost contract: the estimates here are raw token economics — no server\n * margin, no minimum-payment floor. `calculateModelCost` below applies both\n * to match the actual x402 charge, and hosts that display money (ClawRouter's\n * proxy does) recompute through it rather than reading these fields. Folding\n * the margin in here would double-apply it in every such host.\n */\nexport function selectModel(\n tier: Tier,\n confidence: number,\n method: \"rules\" | \"llm\" | \"portfolio\",\n reasoning: string,\n tierConfigs: Record,\n modelPricing: Map,\n estimatedInputTokens: number,\n maxOutputTokens: number,\n routingProfile?: \"free\" | \"eco\" | \"auto\" | \"premium\",\n agenticScore?: number,\n): RoutingDecision {\n const tierConfig = tierConfigs[tier];\n const model = tierConfig.primary;\n const pricing = modelPricing.get(model);\n\n let costEstimate: number;\n if (pricing?.flatPrice !== undefined) {\n costEstimate = pricing.flatPrice;\n } else {\n const inputPrice = pricing?.inputPrice ?? 0;\n const outputPrice = pricing?.outputPrice ?? 0;\n costEstimate =\n (estimatedInputTokens / 1_000_000) * inputPrice + (maxOutputTokens / 1_000_000) * outputPrice;\n }\n\n // Baseline: what the anchor Opus tier would cost (see BASELINE_MODEL_ID)\n const opusPricing = modelPricing.get(BASELINE_MODEL_ID);\n const opusInputPrice = opusPricing?.inputPrice ?? BASELINE_INPUT_PRICE;\n const opusOutputPrice = opusPricing?.outputPrice ?? BASELINE_OUTPUT_PRICE;\n const baselineInput = (estimatedInputTokens / 1_000_000) * opusInputPrice;\n const baselineOutput = (maxOutputTokens / 1_000_000) * opusOutputPrice;\n const baselineCost = baselineInput + baselineOutput;\n\n // Premium profile doesn't calculate savings (it's about quality, not cost)\n const savings =\n routingProfile === \"premium\"\n ? 0\n : baselineCost > 0\n ? Math.max(0, (baselineCost - costEstimate) / baselineCost)\n : 0;\n\n return {\n model,\n tier,\n confidence,\n method,\n reasoning,\n costEstimate,\n baselineCost,\n savings,\n ...(agenticScore !== undefined && { agenticScore }),\n };\n}\n\n/**\n * Get the ordered fallback chain for a tier: [primary, ...fallbacks].\n */\nexport function getFallbackChain(tier: Tier, tierConfigs: Record): string[] {\n const config = tierConfigs[tier];\n return [config.primary, ...config.fallback];\n}\n\n/**\n * Calculate charge-accurate cost fields for a specific model (server margin\n * and minimum-payment floor included — see the cost contract on selectModel).\n * Hosts call this to display money and to recost a decision after a fallback.\n */\n// Server-side margin applied to all x402 payments (must match blockrun server's MARGIN_PERCENT)\nconst SERVER_MARGIN_PERCENT = 5;\n// Minimum payment enforced by CDP Facilitator (must match blockrun server's MIN_PAYMENT_USD)\nconst MIN_PAYMENT_USD = 0.001;\n\nexport function calculateModelCost(\n model: string,\n modelPricing: Map,\n estimatedInputTokens: number,\n maxOutputTokens: number,\n routingProfile?: \"free\" | \"eco\" | \"auto\" | \"premium\",\n): { costEstimate: number; baselineCost: number; savings: number } {\n const pricing = modelPricing.get(model);\n\n let costEstimate: number;\n if (pricing?.flatPrice !== undefined) {\n // Active promo: fixed cost per request\n costEstimate = Math.max(pricing.flatPrice * (1 + SERVER_MARGIN_PERCENT / 100), MIN_PAYMENT_USD);\n } else {\n // Defensive: guard against undefined price fields (not just undefined pricing)\n const inputPrice = pricing?.inputPrice ?? 0;\n const outputPrice = pricing?.outputPrice ?? 0;\n const inputCost = (estimatedInputTokens / 1_000_000) * inputPrice;\n const outputCost = (maxOutputTokens / 1_000_000) * outputPrice;\n // Include server margin + minimum payment to match actual x402 charge\n costEstimate = Math.max(\n (inputCost + outputCost) * (1 + SERVER_MARGIN_PERCENT / 100),\n MIN_PAYMENT_USD,\n );\n }\n\n // Baseline: what the anchor Opus tier would cost (see BASELINE_MODEL_ID)\n const opusPricing = modelPricing.get(BASELINE_MODEL_ID);\n const opusInputPrice = opusPricing?.inputPrice ?? BASELINE_INPUT_PRICE;\n const opusOutputPrice = opusPricing?.outputPrice ?? BASELINE_OUTPUT_PRICE;\n const baselineInput = (estimatedInputTokens / 1_000_000) * opusInputPrice;\n const baselineOutput = (maxOutputTokens / 1_000_000) * opusOutputPrice;\n const baselineCost = baselineInput + baselineOutput;\n\n // Premium profile doesn't calculate savings (it's about quality, not cost)\n const savings =\n routingProfile === \"premium\"\n ? 0\n : baselineCost > 0\n ? Math.max(0, (baselineCost - costEstimate) / baselineCost)\n : 0;\n\n return { costEstimate, baselineCost, savings };\n}\n\n/**\n * Filter a model list to only those that support tool calling.\n * When hasTools is false, returns the list unchanged.\n * When all models lack tool calling support, returns the full list as a fallback\n * (better to let the API error than produce an empty chain).\n */\nexport function filterByToolCalling(\n models: string[],\n hasTools: boolean,\n supportsToolCalling: (modelId: string) => boolean,\n): string[] {\n if (!hasTools) return models;\n const filtered = models.filter(supportsToolCalling);\n return filtered.length > 0 ? filtered : models;\n}\n\n/**\n * Filter a model list to only those that support vision (image inputs).\n * When hasVision is false, returns the list unchanged.\n * When all models lack vision support, returns the full list as a fallback\n * (better to let the API error than produce an empty chain).\n */\nexport function filterByVision(\n models: string[],\n hasVision: boolean,\n supportsVision: (modelId: string) => boolean,\n): string[] {\n if (!hasVision) return models;\n const filtered = models.filter(supportsVision);\n return filtered.length > 0 ? filtered : models;\n}\n\n/**\n * Filter a model list to remove user-excluded models.\n * When all models are excluded, returns the full list as a fallback\n * (same safety pattern as filterByToolCalling/filterByVision).\n */\nexport function filterByExcludeList(models: string[], excludeList: Set): string[] {\n if (excludeList.size === 0) return models;\n const filtered = models.filter((m) => !excludeList.has(m));\n return filtered.length > 0 ? filtered : models;\n}\n\n/**\n * Get the fallback chain filtered by context length.\n * Only returns models that can handle the estimated total context.\n *\n * @param tier - The tier to get fallback chain for\n * @param tierConfigs - Tier configurations\n * @param estimatedTotalTokens - Estimated total context (input + output)\n * @param getContextWindow - Function to get context window for a model ID\n * @returns Filtered list of models that can handle the context\n */\nexport function getFallbackChainFiltered(\n tier: Tier,\n tierConfigs: Record,\n estimatedTotalTokens: number,\n getContextWindow: (modelId: string) => number | undefined,\n): string[] {\n const fullChain = getFallbackChain(tier, tierConfigs);\n\n // Filter to models that can handle the context\n const filtered = fullChain.filter((modelId) => {\n const contextWindow = getContextWindow(modelId);\n if (contextWindow === undefined) {\n // Unknown model - include it (let API reject if needed)\n return true;\n }\n // Add 10% buffer for safety\n return contextWindow >= estimatedTotalTokens * 1.1;\n });\n\n // If all models filtered out, return the original chain\n // (let the API error out - better than no options)\n if (filtered.length === 0) {\n return fullChain;\n }\n\n return filtered;\n}\n\n/**\n * Filter an already-ranked candidate list by total context and requested output.\n * Unlike the legacy tier helper, this supports the V3 portfolio order.\n */\nexport function filterCandidatesByCapacity(\n models: string[],\n estimatedInputTokens: number,\n requestedOutputTokens: number,\n getCapabilities: (modelId: string) => { contextWindow: number; maxOutput: number } | undefined,\n): string[] {\n const filtered = models.filter((modelId) => {\n const capabilities = getCapabilities(modelId);\n if (!capabilities) return true;\n return (\n capabilities.contextWindow >= (estimatedInputTokens + requestedOutputTokens) * 1.1 &&\n capabilities.maxOutput >= requestedOutputTokens\n );\n });\n return filtered;\n}\n","/**\n * Router Strategy Registry\n *\n * Pluggable strategy system for request routing.\n * Default: RulesStrategy — identical to the original inline route() logic, <1ms.\n */\n\nimport type {\n Tier,\n TierConfig,\n Promotion,\n RoutingDecision,\n RouterStrategy,\n RouterOptions,\n} from \"./types.js\";\nimport { classifyByRules } from \"./rules.js\";\nimport { selectModel } from \"./selector.js\";\n\n/**\n * Apply active time-windowed promotions to tier configs.\n * Returns a new tierConfigs object with promotion overrides merged in.\n * Expired or not-yet-active promotions are ignored.\n */\nfunction applyPromotions(\n tierConfigs: Record,\n promotions: Promotion[] | undefined,\n profile: \"auto\" | \"eco\" | \"premium\" | \"agentic\",\n now: Date = new Date(),\n): Record {\n if (!promotions || promotions.length === 0) return tierConfigs;\n\n let result = tierConfigs;\n for (const promo of promotions) {\n // Check time window\n const start = new Date(promo.startDate);\n const end = new Date(promo.endDate);\n if (now < start || now >= end) continue;\n\n // Check profile filter\n if (promo.profiles && !promo.profiles.includes(profile)) continue;\n\n // Shallow-clone on first mutation\n if (result === tierConfigs) {\n result = { ...tierConfigs };\n for (const t of Object.keys(result) as Tier[]) {\n result[t] = { ...result[t] };\n }\n }\n\n // Merge overrides\n for (const [tier, override] of Object.entries(promo.tierOverrides) as [\n Tier,\n Partial,\n ][]) {\n if (!result[tier]) continue;\n if (override.primary) result[tier].primary = override.primary;\n if (override.fallback) result[tier].fallback = override.fallback;\n }\n }\n\n return result;\n}\n\n/**\n * Remove host-declared-dead models from every tier chain, promoting the first\n * surviving rung to primary. A tier whose chain is entirely dead keeps its\n * original config — the router has nothing live to offer there, and inventing\n * a model would hide the outage from the host that reported it.\n */\nexport function applyUnavailableModels(\n tierConfigs: Record,\n unavailableModels: readonly string[] | undefined,\n): Record {\n if (!unavailableModels || unavailableModels.length === 0) return tierConfigs;\n const dead = new Set(unavailableModels);\n let result = tierConfigs;\n for (const tier of Object.keys(tierConfigs) as Tier[]) {\n const config = tierConfigs[tier];\n const alive = [config.primary, ...config.fallback].filter((model) => !dead.has(model));\n if (alive.length === 0 || (alive[0] === config.primary && alive.length === config.fallback.length + 1)) {\n continue;\n }\n if (result === tierConfigs) result = { ...tierConfigs };\n result[tier] = { primary: alive[0], fallback: alive.slice(1) };\n }\n return result;\n}\n\n/**\n * Rules-based routing strategy.\n * Extracted from the original route() in index.ts — logic is identical.\n * Attaches tierConfigs and profile to the decision for downstream use.\n */\nexport class RulesStrategy implements RouterStrategy {\n readonly name = \"rules\";\n\n route(\n prompt: string,\n systemPrompt: string | undefined,\n maxOutputTokens: number,\n options: RouterOptions,\n ): RoutingDecision {\n const { config, modelPricing } = options;\n\n // Estimate input tokens (~4 chars per token)\n const fullText = `${systemPrompt ?? \"\"} ${prompt}`;\n const estimatedTokens = Math.ceil(fullText.length / 4);\n const scanLimit = Math.max(1, Math.min(8_000, config.classifier.promptTruncationChars));\n const sample = (value: string): string => {\n if (value.length <= scanLimit) return value;\n const prefixLength = Math.ceil(scanLimit / 2);\n return `${value.slice(0, prefixLength)}\\n${value.slice(-(scanLimit - prefixLength))}`;\n };\n const scannedPrompt = sample(prompt);\n const scannedSystemPrompt = systemPrompt ? sample(systemPrompt) : undefined;\n\n // --- Rule-based classification (runs first to get agenticScore) ---\n const ruleResult = classifyByRules(\n scannedPrompt,\n scannedSystemPrompt,\n estimatedTokens,\n config.scoring,\n );\n\n // --- Select tier configs based on routing profile ---\n const { routingProfile } = options;\n let tierConfigs: Record;\n let profileSuffix: string;\n let profile: RoutingDecision[\"profile\"];\n\n if (routingProfile === \"eco\") {\n // `ecoTiers: null` explicitly disables the special eco tier set while\n // keeping eco routing semantics. Fall back to regular tiers instead of\n // dropping into auto routing (which could select agentic tiers).\n tierConfigs = config.ecoTiers ?? config.tiers;\n profileSuffix = config.ecoTiers ? \" | eco\" : \" | eco (default tiers)\";\n profile = \"eco\";\n } else if (routingProfile === \"premium\") {\n // `premiumTiers: null` disables the premium-specific tier set but the\n // request is still a premium-profile request, so use regular tiers while\n // preserving premium metadata/cost semantics.\n tierConfigs = config.premiumTiers ?? config.tiers;\n profileSuffix = config.premiumTiers ? \" | premium\" : \" | premium (default tiers)\";\n profile = \"premium\";\n } else {\n // Auto profile (or undefined): intelligent routing with agentic detection.\n //\n // `agenticMode` semantics:\n // - `true` → force agentic tiers (ignore heuristics)\n // - `false` → disable agentic tiers entirely (even if tools are present)\n // - `undefined` → auto-detect via heuristics (tools present OR high agenticScore)\n const agenticScore = ruleResult.agenticScore ?? 0;\n const isAutoAgentic = agenticScore >= 0.5;\n const agenticModeSetting = config.overrides.agenticMode;\n const hasToolsInRequest = options.requiresTools ?? options.hasTools ?? false;\n let useAgenticTiers: boolean;\n if (agenticModeSetting === false) {\n // Explicitly disabled — never use agentic tiers\n useAgenticTiers = false;\n } else if (agenticModeSetting === true) {\n // Explicitly enabled — use agentic tiers if available\n useAgenticTiers = config.agenticTiers != null;\n } else {\n // Auto-detect\n useAgenticTiers = (hasToolsInRequest || isAutoAgentic) && config.agenticTiers != null;\n }\n tierConfigs = useAgenticTiers ? config.agenticTiers! : config.tiers;\n profileSuffix = useAgenticTiers ? ` | agentic${hasToolsInRequest ? \" (tools)\" : \"\"}` : \"\";\n profile = useAgenticTiers ? \"agentic\" : \"auto\";\n }\n\n // Apply time-windowed promotions\n tierConfigs = applyPromotions(tierConfigs, config.promotions, profile!, options.now);\n\n // Hard-remove models the host has observed dead at the gateway. After\n // promotions, so a promo cannot resurrect a rung the host just killed.\n tierConfigs = applyUnavailableModels(tierConfigs, options.unavailableModels);\n\n const agenticScoreValue = ruleResult.agenticScore;\n\n // --- Override: large context → force COMPLEX ---\n if (estimatedTokens > config.overrides.maxTokensForceComplex) {\n const decision = selectModel(\n \"COMPLEX\",\n 0.95,\n \"rules\",\n `Input exceeds ${config.overrides.maxTokensForceComplex} tokens${profileSuffix}`,\n tierConfigs,\n modelPricing,\n estimatedTokens,\n maxOutputTokens,\n routingProfile,\n agenticScoreValue,\n );\n return { ...decision, tierConfigs, profile };\n }\n\n // Structured output detection\n const hasStructuredOutput =\n options.requiresStructuredOutput === true ||\n (scannedSystemPrompt ? /json|structured|schema/i.test(scannedSystemPrompt) : false);\n\n let tier: Tier;\n let confidence: number;\n const method: \"rules\" | \"llm\" = \"rules\";\n let reasoning = `score=${ruleResult.score.toFixed(2)} | ${ruleResult.signals.join(\", \")}`;\n\n if (ruleResult.tier !== null) {\n tier = ruleResult.tier;\n confidence = ruleResult.confidence;\n } else {\n // Ambiguous — default to configurable tier (no external API call)\n tier = config.overrides.ambiguousDefaultTier;\n confidence = 0.5;\n reasoning += ` | ambiguous -> default: ${tier}`;\n }\n\n // Apply structured output minimum tier\n if (hasStructuredOutput) {\n const tierRank: Record = { SIMPLE: 0, MEDIUM: 1, COMPLEX: 2, REASONING: 3 };\n const minTier = config.overrides.structuredOutputMinTier;\n if (tierRank[tier] < tierRank[minTier]) {\n reasoning += ` | upgraded to ${minTier} (structured output)`;\n tier = minTier;\n }\n }\n\n // Add routing profile suffix to reasoning\n reasoning += profileSuffix;\n\n const decision = selectModel(\n tier,\n confidence,\n method,\n reasoning,\n tierConfigs,\n modelPricing,\n estimatedTokens,\n maxOutputTokens,\n routingProfile,\n agenticScoreValue,\n );\n return { ...decision, tierConfigs, profile };\n }\n}\n\n// --- Strategy Registry ---\n\nconst registry = new Map();\nregistry.set(\"rules\", new RulesStrategy());\n\nexport function getStrategy(name: string): RouterStrategy {\n const strategy = registry.get(name);\n if (!strategy) {\n throw new Error(`Unknown routing strategy: ${name}`);\n }\n return strategy;\n}\n\nexport function registerStrategy(strategy: RouterStrategy): void {\n registry.set(strategy.name, strategy);\n}\n","/**\n * Model capabilities used for hard routing constraints.\n *\n * Hosts may inject fresher values through RouterOptions.modelCapabilities.\n * Keeping a small built-in snapshot makes the core safe and useful when a\n * product catalog is temporarily unavailable, without importing product code.\n *\n * GENERATED by scripts/sync-model-capabilities.mjs from the public catalog\n * (GET https://blockrun.ai/api/v1/models) on 2026-10-03; supportsTools comes\n * from a live function-calling probe (scripts/probe-tools.json). Regenerate\n * rather than editing by hand — a hand edit is overwritten on the next sync.\n */\nexport type ModelCapabilities = {\n contextWindow: number;\n maxOutputTokens: number;\n supportsTools: boolean;\n supportsVision: boolean;\n};\n\nexport const DEFAULT_MODEL_CAPABILITIES: Readonly> =\n Object.freeze({\n \"anthropic/claude-fable-5\": {\n contextWindow: 1_000_000,\n maxOutputTokens: 128_000,\n supportsTools: true,\n supportsVision: true,\n },\n \"anthropic/claude-fable-5.1\": {\n contextWindow: 1_000_000,\n maxOutputTokens: 128_000,\n supportsTools: true,\n supportsVision: true,\n },\n \"anthropic/claude-haiku-4.5\": { // override: The public catalog's `categories` omit \"vision\" for this Anthropic model even though the gateway accepts image input for it (the prior hand-maintained snapshot had it, and Anthropic's model card lists it). Without this the vision filter would silently drop it — reported against the catalog; remove once the categories carry vision.\n contextWindow: 200_000,\n maxOutputTokens: 64_000,\n supportsTools: true,\n supportsVision: true,\n },\n \"anthropic/claude-opus-4.5\": {\n contextWindow: 200_000,\n maxOutputTokens: 64_000,\n supportsTools: true,\n supportsVision: true,\n },\n \"anthropic/claude-opus-4.7\": {\n contextWindow: 1_000_000,\n maxOutputTokens: 128_000,\n supportsTools: true,\n supportsVision: true,\n },\n \"anthropic/claude-opus-4.8\": {\n contextWindow: 1_000_000,\n maxOutputTokens: 128_000,\n supportsTools: true,\n supportsVision: true,\n },\n \"anthropic/claude-opus-5\": {\n contextWindow: 1_000_000,\n maxOutputTokens: 128_000,\n supportsTools: true,\n supportsVision: true,\n },\n \"anthropic/claude-opus-5.5\": {\n contextWindow: 1_000_000,\n maxOutputTokens: 128_000,\n supportsTools: true,\n supportsVision: true,\n },\n \"anthropic/claude-sonnet-4.5\": {\n contextWindow: 200_000,\n maxOutputTokens: 64_000,\n supportsTools: true,\n supportsVision: true,\n },\n \"anthropic/claude-sonnet-4.6\": { // override: The public catalog's `categories` omit \"vision\" for this Anthropic model even though the gateway accepts image input for it (the prior hand-maintained snapshot had it, and Anthropic's model card lists it). Without this the vision filter would silently drop it — reported against the catalog; remove once the categories carry vision.\n contextWindow: 1_000_000,\n maxOutputTokens: 128_000,\n supportsTools: true,\n supportsVision: true,\n },\n \"anthropic/claude-sonnet-5\": {\n contextWindow: 1_000_000,\n maxOutputTokens: 128_000,\n supportsTools: true,\n supportsVision: true,\n },\n \"anthropic/claude-sonnet-5.5\": {\n contextWindow: 1_000_000,\n maxOutputTokens: 128_000,\n supportsTools: true,\n supportsVision: true,\n },\n \"cohere/north-mini-code\": { // supportsTools: not probed — fails closed\n contextWindow: 256_000,\n maxOutputTokens: 16_384,\n supportsTools: false,\n supportsVision: false,\n },\n \"deepseek/deepseek-chat\": {\n contextWindow: 1_048_576,\n maxOutputTokens: 65_536,\n supportsTools: true,\n supportsVision: false,\n },\n \"deepseek/deepseek-reasoner\": {\n contextWindow: 1_048_576,\n maxOutputTokens: 65_536,\n supportsTools: true,\n supportsVision: false,\n },\n \"deepseek/deepseek-v4-flash-vision-exp\": {\n contextWindow: 1_048_576,\n maxOutputTokens: 65_536,\n supportsTools: false,\n supportsVision: true,\n },\n \"deepseek/deepseek-v4-pro\": {\n contextWindow: 1_048_576,\n maxOutputTokens: 65_536,\n supportsTools: true,\n supportsVision: false,\n },\n \"google/gemini-2.5-flash\": {\n contextWindow: 1_048_576,\n maxOutputTokens: 65_536,\n supportsTools: true,\n supportsVision: true,\n },\n \"google/gemini-2.5-flash-lite\": {\n contextWindow: 1_048_576,\n maxOutputTokens: 65_536,\n supportsTools: true,\n supportsVision: false,\n },\n \"google/gemini-2.5-pro\": {\n contextWindow: 1_048_576,\n maxOutputTokens: 65_536,\n supportsTools: true,\n supportsVision: true,\n },\n \"google/gemini-3-flash-preview\": {\n contextWindow: 1_048_576,\n maxOutputTokens: 65_536,\n supportsTools: true,\n supportsVision: true,\n },\n \"google/gemini-3.1-flash-lite\": {\n contextWindow: 1_048_576,\n maxOutputTokens: 65_536,\n supportsTools: true,\n supportsVision: false,\n },\n \"google/gemini-3.1-pro\": {\n contextWindow: 1_048_576,\n maxOutputTokens: 65_536,\n supportsTools: true,\n supportsVision: true,\n },\n \"google/gemini-3.5-flash\": {\n contextWindow: 1_048_576,\n maxOutputTokens: 65_536,\n supportsTools: true,\n supportsVision: true,\n },\n \"google/gemini-3.5-flash-lite\": {\n contextWindow: 1_048_576,\n maxOutputTokens: 65_536,\n supportsTools: true,\n supportsVision: false,\n },\n \"google/gemini-3.6-flash\": {\n contextWindow: 1_048_576,\n maxOutputTokens: 65_536,\n supportsTools: true,\n supportsVision: true,\n },\n \"google/gemini-3.8-flash\": {\n contextWindow: 1_048_576,\n maxOutputTokens: 65_536,\n supportsTools: true,\n supportsVision: true,\n },\n \"minimax/minimax-m2.7\": {\n contextWindow: 204_800,\n maxOutputTokens: 16_384,\n supportsTools: true,\n supportsVision: false,\n },\n \"minimax/minimax-m3\": {\n contextWindow: 1_048_576,\n maxOutputTokens: 65_536,\n supportsTools: true,\n supportsVision: false,\n },\n \"moonshot/kimi-k3\": {\n contextWindow: 1_048_576,\n maxOutputTokens: 65_536,\n supportsTools: true,\n supportsVision: true,\n },\n \"nvidia/llama-3.2-11b-vision\": { // supportsTools: not probed — fails closed\n contextWindow: 128_000,\n maxOutputTokens: 16_384,\n supportsTools: false,\n supportsVision: true,\n },\n \"nvidia/muse-glimmer-30b\": { // supportsTools: not probed — fails closed\n contextWindow: 131_072,\n maxOutputTokens: 16_384,\n supportsTools: false,\n supportsVision: false,\n },\n \"nvidia/nemotron-3-nano-omni-30b-a3b-reasoning\": { // override: The catalog tags this model \"vision\", but a correctly sized probe does not hold up (ClawRouter, 2026-08-31): a 64x64 solid-red PNG was named correctly 1 of 4 times on Base, and on Solana the image was silently dropped and a text model answered \"white\". An HTTP 200 with a confident wrong answer gives the caller nothing to branch on, so image turns must not be routed here. It is ecoTiers.SIMPLE.fallback[0] since nemotron-3-nano-30b was delisted (2026-09-08); remove once a probe of this size comes back right on both chains.\n contextWindow: 256_000,\n maxOutputTokens: 16_384,\n supportsTools: false,\n supportsVision: false,\n },\n \"nvidia/nemotron-3-ultra-550b\": { // supportsTools: not probed — fails closed\n contextWindow: 1_000_000,\n maxOutputTokens: 16_384,\n supportsTools: false,\n supportsVision: false,\n },\n \"nvidia/nemotron-3.5-lightning\": { // supportsTools: not probed — fails closed\n contextWindow: 1_000_000,\n maxOutputTokens: 16_384,\n supportsTools: false,\n supportsVision: false,\n },\n \"openai/chat-latest\": {\n contextWindow: 128_000,\n maxOutputTokens: 128_000,\n supportsTools: true,\n supportsVision: true,\n },\n \"openai/gpt-4.1\": {\n contextWindow: 128_000,\n maxOutputTokens: 32_768,\n supportsTools: true,\n supportsVision: true,\n },\n \"openai/gpt-4.1-mini\": {\n contextWindow: 128_000,\n maxOutputTokens: 32_768,\n supportsTools: true,\n supportsVision: false,\n },\n \"openai/gpt-4.1-nano\": {\n contextWindow: 128_000,\n maxOutputTokens: 32_768,\n supportsTools: true,\n supportsVision: false,\n },\n \"openai/gpt-4o\": {\n contextWindow: 128_000,\n maxOutputTokens: 16_384,\n supportsTools: true,\n supportsVision: true,\n },\n \"openai/gpt-4o-mini\": {\n contextWindow: 128_000,\n maxOutputTokens: 16_384,\n supportsTools: true,\n supportsVision: false,\n },\n \"openai/gpt-5-mini\": {\n contextWindow: 200_000,\n maxOutputTokens: 128_000,\n supportsTools: true,\n supportsVision: false,\n },\n \"openai/gpt-5.1\": {\n contextWindow: 400_000,\n maxOutputTokens: 128_000,\n supportsTools: true,\n supportsVision: true,\n },\n \"openai/gpt-5.2\": {\n contextWindow: 400_000,\n maxOutputTokens: 128_000,\n supportsTools: true,\n supportsVision: true,\n },\n \"openai/gpt-5.2-pro\": { // supportsTools: not probed — fails closed\n contextWindow: 400_000,\n maxOutputTokens: 128_000,\n supportsTools: false,\n supportsVision: true,\n },\n \"openai/gpt-5.3-codex\": { // supportsTools: gateway unavailable at probe time — fails closed; override: 2026-08-29 probe: every request (6 plain + 3 tool attempts) returned a gateway 500, so the probe measured an incident, not the model. Codex's function calling is established by the 2026-07 Terminal-Bench / tau2 calibration trajectories in portfolio.ts. Hosts observing the 500s should drop it with RouterOptions.unavailableModels rather than this snapshot claiming the model cannot call tools.\n contextWindow: 400_000,\n maxOutputTokens: 128_000,\n supportsTools: true,\n supportsVision: false,\n },\n \"openai/gpt-5.4\": {\n contextWindow: 1_050_000,\n maxOutputTokens: 128_000,\n supportsTools: true,\n supportsVision: true,\n },\n \"openai/gpt-5.4-mini\": {\n contextWindow: 400_000,\n maxOutputTokens: 128_000,\n supportsTools: true,\n supportsVision: true,\n },\n \"openai/gpt-5.4-nano\": {\n contextWindow: 1_050_000,\n maxOutputTokens: 128_000,\n supportsTools: true,\n supportsVision: false,\n },\n \"openai/gpt-5.4-pro\": { // supportsTools: not probed — fails closed\n contextWindow: 1_050_000,\n maxOutputTokens: 128_000,\n supportsTools: false,\n supportsVision: true,\n },\n \"openai/gpt-5.5\": {\n contextWindow: 1_050_000,\n maxOutputTokens: 128_000,\n supportsTools: true,\n supportsVision: true,\n },\n \"openai/gpt-5.5-pro\": { // supportsTools: not probed — fails closed\n contextWindow: 1_050_000,\n maxOutputTokens: 128_000,\n supportsTools: false,\n supportsVision: true,\n },\n \"openai/gpt-5.6-luna\": {\n contextWindow: 1_050_000,\n maxOutputTokens: 128_000,\n supportsTools: true,\n supportsVision: true,\n },\n \"openai/gpt-5.6-luna-pro\": {\n contextWindow: 1_050_000,\n maxOutputTokens: 128_000,\n supportsTools: false,\n supportsVision: true,\n },\n \"openai/gpt-5.6-sol\": {\n contextWindow: 1_050_000,\n maxOutputTokens: 128_000,\n supportsTools: true,\n supportsVision: true,\n },\n \"openai/gpt-5.6-sol-pro\": {\n contextWindow: 1_050_000,\n maxOutputTokens: 128_000,\n supportsTools: true,\n supportsVision: true,\n },\n \"openai/gpt-5.6-terra\": {\n contextWindow: 1_050_000,\n maxOutputTokens: 128_000,\n supportsTools: true,\n supportsVision: true,\n },\n \"openai/gpt-5.6-terra-pro\": {\n contextWindow: 1_050_000,\n maxOutputTokens: 128_000,\n supportsTools: true,\n supportsVision: true,\n },\n \"openai/gpt-6-astra\": {\n contextWindow: 1_050_000,\n maxOutputTokens: 128_000,\n supportsTools: true,\n supportsVision: true,\n },\n \"openai/gpt-6-luna\": {\n contextWindow: 1_050_000,\n maxOutputTokens: 128_000,\n supportsTools: true,\n supportsVision: true,\n },\n \"openai/gpt-6-sol\": {\n contextWindow: 1_050_000,\n maxOutputTokens: 128_000,\n supportsTools: true,\n supportsVision: true,\n },\n \"openai/o1\": {\n contextWindow: 200_000,\n maxOutputTokens: 100_000,\n supportsTools: true,\n supportsVision: false,\n },\n \"openai/o3\": {\n contextWindow: 200_000,\n maxOutputTokens: 100_000,\n supportsTools: true,\n supportsVision: false,\n },\n \"openai/o3-mini\": {\n contextWindow: 128_000,\n maxOutputTokens: 100_000,\n supportsTools: true,\n supportsVision: false,\n },\n \"openai/o4-mini\": {\n contextWindow: 128_000,\n maxOutputTokens: 100_000,\n supportsTools: true,\n supportsVision: false,\n },\n \"poolside/laguna-s-2.1\": { // supportsTools: not probed — fails closed\n contextWindow: 1_048_576,\n maxOutputTokens: 131_072,\n supportsTools: false,\n supportsVision: false,\n },\n \"poolside/laguna-xs-2.1\": { // supportsTools: not probed — fails closed\n contextWindow: 131_072,\n maxOutputTokens: 16_384,\n supportsTools: false,\n supportsVision: false,\n },\n \"qwen/qwen3.7-flash\": {\n contextWindow: 1_000_000,\n maxOutputTokens: 65_536,\n supportsTools: true,\n supportsVision: false,\n },\n \"qwen/qwen3.7-max\": {\n contextWindow: 1_000_000,\n maxOutputTokens: 65_536,\n supportsTools: true,\n supportsVision: false,\n },\n \"qwen/qwen3.7-plus\": {\n contextWindow: 1_000_000,\n maxOutputTokens: 131_072,\n supportsTools: true,\n supportsVision: false,\n },\n \"qwen/qwen3.8-flash\": {\n contextWindow: 1_000_000,\n maxOutputTokens: 131_072,\n supportsTools: false,\n supportsVision: true,\n },\n \"qwen/qwen3.8-max\": { // supportsTools: not probed — fails closed\n contextWindow: 1_000_000,\n maxOutputTokens: 131_072,\n supportsTools: false,\n supportsVision: false,\n },\n \"tencent/hy4-preview\": { // supportsTools: not probed — fails closed\n contextWindow: 1_048_576,\n maxOutputTokens: 64_000,\n supportsTools: false,\n supportsVision: false,\n },\n \"xai/grok-4.3\": {\n contextWindow: 1_000_000,\n maxOutputTokens: 16_384,\n supportsTools: true,\n supportsVision: true,\n },\n \"xai/grok-4.5\": {\n contextWindow: 500_000,\n maxOutputTokens: 16_384,\n supportsTools: true,\n supportsVision: true,\n },\n \"xai/grok-4.6\": {\n contextWindow: 500_000,\n maxOutputTokens: 16_384,\n supportsTools: true,\n supportsVision: true,\n },\n \"xai/grok-4.7\": {\n contextWindow: 500_000,\n maxOutputTokens: 16_384,\n supportsTools: true,\n supportsVision: true,\n },\n \"xai/grok-build-0.1\": {\n contextWindow: 256_000,\n maxOutputTokens: 16_384,\n supportsTools: true,\n supportsVision: false,\n },\n \"xiaomi/mimo-v2.5\": {\n contextWindow: 1_048_576,\n maxOutputTokens: 131_072,\n supportsTools: true,\n supportsVision: true,\n },\n \"xiaomi/mimo-v2.5-pro\": {\n contextWindow: 1_048_576,\n maxOutputTokens: 131_072,\n supportsTools: true,\n supportsVision: false,\n },\n \"zai/glm-5\": {\n contextWindow: 200_000,\n maxOutputTokens: 128_000,\n supportsTools: true,\n supportsVision: false,\n },\n \"zai/glm-5-turbo\": {\n contextWindow: 200_000,\n maxOutputTokens: 128_000,\n supportsTools: true,\n supportsVision: false,\n },\n \"zai/glm-5.1\": {\n contextWindow: 200_000,\n maxOutputTokens: 128_000,\n supportsTools: true,\n supportsVision: false,\n },\n \"zai/glm-5.2\": {\n contextWindow: 1_000_000,\n maxOutputTokens: 131_072,\n supportsTools: true,\n supportsVision: false,\n },\n \"zai/glm-5.3\": {\n contextWindow: 1_000_000,\n maxOutputTokens: 131_072,\n supportsTools: true,\n supportsVision: false,\n },\n \"zai/glm-5.3-flash\": {\n contextWindow: 1_000_000,\n maxOutputTokens: 131_072,\n supportsTools: true,\n supportsVision: true,\n },\n });\n","{\n \"anthropic/claude-fable-5\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 9298.5,\n \"p95LatencyMs\": 9873.4,\n \"outputTokensPerSecond\": 55.17,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"anthropic/claude-haiku-4.5\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 3157.4,\n \"p95LatencyMs\": 3170.7,\n \"outputTokensPerSecond\": 162.16,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"anthropic/claude-opus-4.5\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 6497.7,\n \"p95LatencyMs\": 6953.7,\n \"outputTokensPerSecond\": 78.99,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"anthropic/claude-opus-4.7\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 5316.5,\n \"p95LatencyMs\": 6121.5,\n \"outputTokensPerSecond\": 97.34,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"anthropic/claude-opus-4.8\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 6216.1,\n \"p95LatencyMs\": 6847.7,\n \"outputTokensPerSecond\": 82.81,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"anthropic/claude-opus-5\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 7309,\n \"p95LatencyMs\": 7745.2,\n \"outputTokensPerSecond\": 70.17,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"anthropic/claude-sonnet-4.5\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 6330.4,\n \"p95LatencyMs\": 6631.6,\n \"outputTokensPerSecond\": 81.03,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"anthropic/claude-sonnet-4.6\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 6508,\n \"p95LatencyMs\": 6698.3,\n \"outputTokensPerSecond\": 78.6,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"anthropic/claude-sonnet-5\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 6165.4,\n \"p95LatencyMs\": 6582.9,\n \"outputTokensPerSecond\": 83.62,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"deepseek/deepseek-chat\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 4351.4,\n \"p95LatencyMs\": 4543.7,\n \"outputTokensPerSecond\": 117.78,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"deepseek/deepseek-reasoner\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 5201.2,\n \"p95LatencyMs\": 6079.6,\n \"outputTokensPerSecond\": 99.77,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"deepseek/deepseek-v4-pro\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 8781.2,\n \"p95LatencyMs\": 9881.1,\n \"outputTokensPerSecond\": 58.98,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"google/gemini-2.5-flash\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 5416.4,\n \"p95LatencyMs\": 6442.8,\n \"outputTokensPerSecond\": 213.07,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"google/gemini-2.5-flash-lite\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 5002.6,\n \"p95LatencyMs\": 5780.3,\n \"outputTokensPerSecond\": 408.43,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"google/gemini-2.5-pro\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 28169.5,\n \"p95LatencyMs\": 29491.4,\n \"outputTokensPerSecond\": 147.3,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"google/gemini-3-flash-preview\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 4717.1,\n \"p95LatencyMs\": 5037.1,\n \"outputTokensPerSecond\": 198.71,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"google/gemini-3.1-flash-lite\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 2855.8,\n \"p95LatencyMs\": 3172.7,\n \"outputTokensPerSecond\": 286.91,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"google/gemini-3.1-pro\": {\n \"measuredAt\": \"2026-08-29T16:59:54Z\",\n \"latencyMs\": 24194.1,\n \"p95LatencyMs\": 27269.6,\n \"outputTokensPerSecond\": 109.47,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"google/gemini-3.5-flash\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 5320.6,\n \"p95LatencyMs\": 5429.8,\n \"outputTokensPerSecond\": 226.21,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"google/gemini-3.5-flash-lite\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 3515.8,\n \"p95LatencyMs\": 4363.4,\n \"outputTokensPerSecond\": 248.9,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"google/gemini-3.6-flash\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 13020,\n \"p95LatencyMs\": 15383.1,\n \"outputTokensPerSecond\": 187.87,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"minimax/minimax-m2.7\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 8761.1,\n \"p95LatencyMs\": 10199.3,\n \"outputTokensPerSecond\": 59.18,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"minimax/minimax-m3\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 11101.9,\n \"p95LatencyMs\": 26087.1,\n \"outputTokensPerSecond\": 101.12,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"moonshot/kimi-k3\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 24498.9,\n \"p95LatencyMs\": 40365.3,\n \"outputTokensPerSecond\": 25.11,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"nvidia/mistral-nemotron\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 7349.6,\n \"p95LatencyMs\": 9932.3,\n \"outputTokensPerSecond\": 79.48,\n \"errorRate\": 0.3333,\n \"samples\": 3\n },\n \"nvidia/nemotron-3-nano-omni-30b-a3b-reasoning\": {\n \"measuredAt\": \"2026-08-29T16:59:54Z\",\n \"latencyMs\": 9324.6,\n \"p95LatencyMs\": 12992,\n \"outputTokensPerSecond\": 64.96,\n \"errorRate\": 0.3333,\n \"samples\": 3\n },\n \"nvidia/nemotron-nano-12b-v2-vl\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 5846.9,\n \"p95LatencyMs\": 5846.9,\n \"outputTokensPerSecond\": 87.57,\n \"errorRate\": 0.6667,\n \"samples\": 3\n },\n \"nvidia/nemotron-nano-9b-v2\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 5282.5,\n \"p95LatencyMs\": 5282.5,\n \"outputTokensPerSecond\": 96.92,\n \"errorRate\": 0.6667,\n \"samples\": 3\n },\n \"nvidia/step-3.7-flash\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 4617.4,\n \"p95LatencyMs\": 5237.4,\n \"outputTokensPerSecond\": 112.92,\n \"errorRate\": 0.3333,\n \"samples\": 3\n },\n \"openai/chat-latest\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 3690.9,\n \"p95LatencyMs\": 4344,\n \"outputTokensPerSecond\": 111.85,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"openai/gpt-4.1\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 3527.9,\n \"p95LatencyMs\": 3831.7,\n \"outputTokensPerSecond\": 141.27,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"openai/gpt-4.1-mini\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 4268.2,\n \"p95LatencyMs\": 5101.5,\n \"outputTokensPerSecond\": 103.42,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"openai/gpt-4.1-nano\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 3088.3,\n \"p95LatencyMs\": 3369.2,\n \"outputTokensPerSecond\": 150.31,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"openai/gpt-4o\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 2995.2,\n \"p95LatencyMs\": 3174.2,\n \"outputTokensPerSecond\": 171.32,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"openai/gpt-4o-mini\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 4751.5,\n \"p95LatencyMs\": 4930.4,\n \"outputTokensPerSecond\": 107.84,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"openai/gpt-5-mini\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 4558.1,\n \"p95LatencyMs\": 5081.9,\n \"outputTokensPerSecond\": 113.25,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"openai/gpt-5.2\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 5436.6,\n \"p95LatencyMs\": 5928.8,\n \"outputTokensPerSecond\": 95.47,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"openai/gpt-5.3-codex\": {\n \"measuredAt\": \"2026-08-29T16:59:54Z\",\n \"latencyMs\": 15290.4,\n \"p95LatencyMs\": 15290.4,\n \"outputTokensPerSecond\": 33.49,\n \"errorRate\": 0.6667,\n \"samples\": 3\n },\n \"openai/gpt-5.4\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 5596,\n \"p95LatencyMs\": 5919.4,\n \"outputTokensPerSecond\": 91.67,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"openai/gpt-5.4-mini\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 3377.8,\n \"p95LatencyMs\": 3646.8,\n \"outputTokensPerSecond\": 138.08,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"openai/gpt-5.4-nano\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 4040.4,\n \"p95LatencyMs\": 4205.9,\n \"outputTokensPerSecond\": 118.52,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"openai/gpt-5.5\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 6367.8,\n \"p95LatencyMs\": 7330.7,\n \"outputTokensPerSecond\": 81.29,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"openai/gpt-5.6-luna\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 6064.5,\n \"p95LatencyMs\": 7347.3,\n \"outputTokensPerSecond\": 87.93,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"openai/gpt-5.6-luna-pro\": {\n \"measuredAt\": \"2026-08-29T16:59:54Z\",\n \"latencyMs\": 13914.9,\n \"p95LatencyMs\": 13914.9,\n \"outputTokensPerSecond\": 36.79,\n \"errorRate\": 0.6667,\n \"samples\": 3\n },\n \"openai/gpt-5.6-sol\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 7720.2,\n \"p95LatencyMs\": 9108.2,\n \"outputTokensPerSecond\": 67.47,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"openai/gpt-5.6-sol-pro\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 11442.7,\n \"p95LatencyMs\": 13363.1,\n \"outputTokensPerSecond\": 148.75,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"openai/gpt-5.6-terra\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 4941,\n \"p95LatencyMs\": 5095.3,\n \"outputTokensPerSecond\": 103.69,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"openai/gpt-5.6-terra-pro\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 3574.1,\n \"p95LatencyMs\": 4126.3,\n \"outputTokensPerSecond\": 133.59,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"openai/o1\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 4324.9,\n \"p95LatencyMs\": 5838.1,\n \"outputTokensPerSecond\": 125.86,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"openai/o3\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 5463.4,\n \"p95LatencyMs\": 5613.1,\n \"outputTokensPerSecond\": 93.8,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"openai/o3-mini\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 2912.7,\n \"p95LatencyMs\": 3092.1,\n \"outputTokensPerSecond\": 176.49,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"openai/o4-mini\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 4958.7,\n \"p95LatencyMs\": 5313,\n \"outputTokensPerSecond\": 103.81,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"qwen/qwen3.7-flash\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 3385.5,\n \"p95LatencyMs\": 4042.7,\n \"outputTokensPerSecond\": 153.94,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"qwen/qwen3.7-max\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 9387.1,\n \"p95LatencyMs\": 10490.2,\n \"outputTokensPerSecond\": 54.92,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"qwen/qwen3.7-plus\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 9766.6,\n \"p95LatencyMs\": 9798.2,\n \"outputTokensPerSecond\": 52.42,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"tencent/hy3\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 6062.3,\n \"p95LatencyMs\": 7070.2,\n \"outputTokensPerSecond\": 87.3,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"xai/grok-4.3\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 9467.7,\n \"p95LatencyMs\": 10087.9,\n \"outputTokensPerSecond\": 48.36,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"xai/grok-4.5\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 13564.8,\n \"p95LatencyMs\": 17351.9,\n \"outputTokensPerSecond\": 60.71,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"xai/grok-build-0.1\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 16394.8,\n \"p95LatencyMs\": 18035.4,\n \"outputTokensPerSecond\": 96.86,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"xiaomi/mimo-v2.5-pro\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 12070.7,\n \"p95LatencyMs\": 12386.8,\n \"outputTokensPerSecond\": 42.44,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"zai/glm-5\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 6839.7,\n \"p95LatencyMs\": 7261.4,\n \"outputTokensPerSecond\": 75.16,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"zai/glm-5-turbo\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 55348.5,\n \"p95LatencyMs\": 114086.6,\n \"outputTokensPerSecond\": 14.64,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"zai/glm-5.1\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 15658.4,\n \"p95LatencyMs\": 17307.1,\n \"outputTokensPerSecond\": 32.9,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"zai/glm-5.2\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 10308.5,\n \"p95LatencyMs\": 15127.6,\n \"outputTokensPerSecond\": 54.87,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"zai/glm-5.3\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 7272.4,\n \"p95LatencyMs\": 7998.1,\n \"outputTokensPerSecond\": 71.09,\n \"errorRate\": 0,\n \"samples\": 3\n },\n \"zai/glm-5.3-flash\": {\n \"measuredAt\": \"2026-08-29T16:51:33Z\",\n \"latencyMs\": 10545.3,\n \"p95LatencyMs\": 11672.4,\n \"outputTokensPerSecond\": 49.01,\n \"errorRate\": 0,\n \"samples\": 3\n }\n}\n","/**\n * Model-performance priors consumed by the portfolio router.\n *\n * The entries below are a small, auditable seed extracted from the 2026-03-16\n * BlockRun performance run. They are deliberately weak priors: live data\n * injected by the host should replace them through configuration before a\n * release. Historical numbers must never be presented as a current\n * provider SLA or as task-quality measurements.\n */\n\nimport liveProfiles from \"./model-profiles.generated.json\";\n\nexport type ModelPerformanceProfile = {\n measuredAt: string;\n /** Gateway end-to-end latency for the benchmark workload. */\n latencyMs: number;\n /** Tail latency is more relevant than mean latency for urgent requests. */\n p95LatencyMs?: number;\n outputTokensPerSecond: number;\n /** External intelligence index when one was available; not task success. */\n intelligenceIndex?: number;\n /** Failure fraction observed in the same benchmark run. */\n errorRate?: number;\n /** Number of sampled calls behind the observation. */\n samples?: number;\n};\n\n// Generated from benchmark files that satisfy the uncached-inference\n// invariant. These are weak performance priors (speed/reliability), never\n// task-quality labels.\nexport const LIVE_MODEL_PROFILES: Readonly> = Object.freeze(\n liveProfiles as Record,\n);\n\nexport const HISTORICAL_MODEL_PROFILES: Readonly> =\n Object.freeze({\n \"anthropic/claude-haiku-4.5\": {\n measuredAt: \"2026-03-16T13:50:48Z\",\n latencyMs: 2305,\n outputTokensPerSecond: 140.6,\n },\n \"anthropic/claude-sonnet-4.6\": {\n measuredAt: \"2026-03-16T13:50:48Z\",\n latencyMs: 2110,\n outputTokensPerSecond: 121.3,\n },\n \"deepseek/deepseek-chat\": {\n measuredAt: \"2026-03-16T13:50:48Z\",\n latencyMs: 1431,\n outputTokensPerSecond: 179.2,\n intelligenceIndex: 32,\n },\n \"google/gemini-2.5-flash\": {\n measuredAt: \"2026-03-16T13:50:48Z\",\n latencyMs: 1238,\n outputTokensPerSecond: 207.6,\n intelligenceIndex: 20,\n },\n \"google/gemini-2.5-flash-lite\": {\n measuredAt: \"2026-03-16T13:50:48Z\",\n latencyMs: 1353,\n outputTokensPerSecond: 192.5,\n intelligenceIndex: 20,\n },\n \"google/gemini-2.5-pro\": {\n measuredAt: \"2026-03-16T13:50:48Z\",\n latencyMs: 1294,\n outputTokensPerSecond: 197.8,\n },\n \"google/gemini-3.1-pro\": {\n measuredAt: \"2026-03-16T13:50:48Z\",\n latencyMs: 1609,\n outputTokensPerSecond: 167.2,\n },\n \"openai/gpt-4o-mini\": {\n measuredAt: \"2026-03-16T13:50:48Z\",\n latencyMs: 2764,\n outputTokensPerSecond: 92.8,\n },\n \"openai/gpt-5.3-codex\": {\n measuredAt: \"2026-03-16T13:50:48Z\",\n latencyMs: 7935,\n outputTokensPerSecond: 32.3,\n },\n });\n","/**\n * Whether the request actually requires an external action/tool, as distinct\n * from merely being sent by a host that exposes tools on every turn.\n *\n * The detector intentionally looks for action+target pairs. A generic factual\n * or multiple-choice question must stay false even when the host attaches a\n * large tool schema; otherwise every tool-enabled host turn is over-routed as\n * an agent task and models may browse or mutate state unnecessarily.\n */\nexport function inferToolRequirement(\n prompt: string,\n _systemPrompt?: string,\n toolChoice?: unknown,\n): boolean {\n // OpenAI-compatible clients can state this requirement directly. Treat that\n // protocol signal as authoritative instead of trying to infer it from prose.\n if (toolChoice === \"none\") return false;\n if (toolChoice === \"required\") return true;\n if (\n typeof toolChoice === \"object\" &&\n toolChoice !== null &&\n (toolChoice as { type?: unknown }).type === \"function\"\n ) {\n return true;\n }\n\n // System prompts commonly describe every tool a host exposes. They are not\n // evidence that the user asked to perform an action on this turn. Explicit\n // host requirements should use tool_choice/requiresTools instead.\n const text = prompt;\n const explicitTool =\n /\\b(?:use|call|invoke)\\s+(?:the\\s+)?[\\w.-]+\\s+(?:tool|function|api)\\b|\\btool[_ -]?call\\b|使用.{0,20}(?:工具|函数|接口)|调用.{0,20}(?:工具|函数|接口)/i;\n const codeEnvironment =\n /\\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;\n const webAction =\n /\\b(?:browse|search|look up|fetch|open)\\b.{0,80}\\b(?:web|website|url|online|documentation|docs|news|weather|price)\\b|(?:浏览|搜索|查询|打开).{0,30}(?:网页|网站|链接|文档|新闻|天气|价格)/i;\n const statefulAction =\n /\\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;\n return (\n explicitTool.test(text) ||\n codeEnvironment.test(text) ||\n webAction.test(text) ||\n statefulAction.test(text)\n );\n}\n","/**\n * V3 portfolio router.\n *\n * This is deliberately local and deterministic: feature extraction, eligibility\n * checks and scoring read only request data plus the in-process model registry.\n * It is therefore safe for the hot path and provides a stable baseline for the\n * RouterBench evaluation before health telemetry / an optional judge are added.\n */\n\nimport { DEFAULT_MODEL_CAPABILITIES } from \"./model-capabilities.js\";\nimport { getFallbackChain, selectModel } from \"./selector.js\";\nimport { RulesStrategy } from \"./strategy.js\";\nimport {\n HISTORICAL_MODEL_PROFILES,\n LIVE_MODEL_PROFILES,\n type ModelPerformanceProfile,\n} from \"./model-profiles.js\";\nimport type { RouterOptions, RouterStrategy, TaskType, Tier, TierConfig } from \"./types.js\";\nimport { inferToolRequirement } from \"./tool-intent.js\";\n\ntype TaskFeatures = {\n taskType: TaskType;\n estimatedInputTokens: number;\n hasCode: boolean;\n needsTools: boolean;\n toolsAvailable: boolean;\n needsVision: boolean;\n needsStructuredOutput: boolean;\n latencySensitive: boolean;\n highStakes: boolean;\n language: \"zh\" | \"other\";\n likelyParallelToolCalls: boolean;\n complexMultiToolPlan: boolean;\n agentDomain: \"airline\" | \"retail\" | \"web_research\" | \"other\";\n deepWebResearch: boolean;\n agentRisk: \"standard\" | \"high\" | \"complex_high\" | \"policy_exception_simple\" | \"policy_exception\";\n terminalToolSignal: boolean;\n terminalSafetySensitive: boolean;\n implicitTerminalCode: boolean;\n};\n\nconst DEFAULT_PORTFOLIO_WEIGHTS = {\n auto: {\n quality: 0.47,\n capability: 0.2,\n cost: 0.18,\n speed: 0.07,\n reliability: 0.03,\n legacy: 0.05,\n },\n eco: { quality: 0.36, capability: 0.2, cost: 0.28, speed: 0.1, reliability: 0.04, legacy: 0.02 },\n premium: {\n quality: 0.58,\n capability: 0.2,\n cost: 0.08,\n speed: 0.06,\n reliability: 0.06,\n legacy: 0.02,\n },\n highStakesBoost: { quality: 0.08, reliability: 0.05 },\n latencySensitiveSpeedBoost: 0.08,\n affinityFloorGap: { auto: 0.1, eco: 0.22, premium: 0.05 },\n} as const;\n\n/**\n * Detect turns that probably need several tool calls. This is a\n * deliberately conservative request-side feature: it uses only the prompt\n * and visible tool count, never benchmark categories or expected answers.\n */\nfunction likelyNeedsParallelToolCalls(\n prompt: string,\n needsTools: boolean,\n toolCount: number | undefined,\n toolNames: readonly string[] | undefined,\n): boolean {\n if (!needsTools || toolCount === undefined || toolCount < 1) return false;\n const text = prompt.trim();\n const explicitRepeat =\n /\\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(\n text,\n );\n if (explicitRepeat) return true;\n\n const sentenceClauses = text\n .split(/[.!?。!?]+/)\n .map((part) => part.trim())\n .filter((part) => part.length >= 8);\n if (\n (/\\b(?:also|additionally|furthermore)\\b|另外|此外|그리고/i.test(text) &&\n sentenceClauses.length >= 2) ||\n /\\band\\s+(?:also|for the)\\b/i.test(text)\n )\n return true;\n\n const pairedQuantity =\n /\\b\\d+(?:\\.\\d+)?\\s+(?:and|or)\\s+\\d+(?:\\.\\d+)?\\s*(?:gb|mb|tb|kg|g|ml|oz|cups?|cores?|cpus?)\\b/i.test(\n text,\n );\n if (pairedQuantity) return true;\n\n // Distinctive tokens from two visible tool names are a strong local signal\n // for a multi-operation turn (for example add_task + delete_task).\n const operationTokens = new Set([\n \"add\",\n \"delete\",\n \"remove\",\n \"cancel\",\n \"return\",\n \"exchange\",\n \"modify\",\n \"book\",\n \"transfer\",\n \"send\",\n \"upload\",\n \"download\",\n \"create\",\n \"close\",\n ]);\n const lowered = text.toLowerCase();\n const matchedOperationTokens = new Set(\n (toolNames ?? [])\n .flatMap((name) => name.toLowerCase().split(/[^a-z0-9\\u3400-\\u9fff]+/))\n .filter((token) => operationTokens.has(token) && lowered.includes(token)),\n );\n // A single workflow naturally mentions domain nouns like order/item plus\n // one action. Upgrade only when two different visible operation verbs are\n // requested (for example cancel + book or add + delete).\n if (matchedOperationTokens.size >= 2) return true;\n\n // Repeated food/logging entries are commonly expressed as several lines,\n // each with its own quantity rather than an explicit \"for each\" phrase.\n const nonEmptyLines = text\n .split(/\\r?\\n/)\n .map((line) => line.trim())\n .filter(Boolean);\n const quantityMentions =\n text.match(\n /\\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,\n ) ?? [];\n if (nonEmptyLines.length >= 2 && quantityMentions.length >= 2) return true;\n\n // Weather prompts provide a useful language-independent high-confidence\n // pattern: a single lookup tool plus multiple locations joined in one turn.\n const repeatedLookup =\n /\\b(?:weather|climate|clima|tiempo|temperature|snow|news|report)\\b|天气|气象|温度|降雪|新闻|报告/i.test(\n text,\n );\n const multiLocationConnector = /\\b(?:and also|both|y|e)\\b|还有|以及|和|、/i.test(text);\n const commaSeparatedLocations = (text.match(/[,,]/g) ?? []).length >= 2;\n if (repeatedLookup && (multiLocationConnector || commaSeparatedLocations)) return true;\n\n const distinctOrderParts =\n /\\b(?:food|meal)\\b[\\s\\S]*\\bdrink\\b|\\bdrink\\b[\\s\\S]*\\b(?:food|meal)\\b/i.test(text);\n const koreanParallelClauses = (text.match(/,/g) ?? []).length >= 3 && /하고|그리고/.test(text);\n return distinctOrderParts || koreanParallelClauses;\n}\n\nfunction classifyTask(\n prompt: string,\n systemPrompt: string | undefined,\n options: RouterOptions,\n): TaskFeatures {\n const fullText = `${systemPrompt ?? \"\"} ${prompt}`;\n const estimatedInputTokens = Math.ceil(fullText.length / 4);\n // Feature regexes need request shape and intent, not the entire document.\n // Sample both ends so a long pasted artifact keeps the task instruction at\n // either boundary, while the full length still drives capacity decisions.\n const scanLimit = Math.max(1, Math.min(8_000, options.config.classifier.promptTruncationChars));\n const sample = (value: string): string => {\n if (value.length <= scanLimit) return value;\n const prefixLength = Math.ceil(scanLimit / 2);\n return `${value.slice(0, prefixLength)}\\n${value.slice(-(scanLimit - prefixLength))}`;\n };\n const scannedPrompt = sample(prompt);\n const scannedSystemPrompt = sample(systemPrompt ?? \"\");\n const scannedFullText = `${scannedSystemPrompt} ${scannedPrompt}`;\n const text = scannedPrompt.toLowerCase();\n const explicitCodeSignal =\n /```|\\b(?:typescript|javascript|python|rust|java|sql|stack trace|traceback|exception)\\b|\\.(?:ts|tsx|js|py|go|rs)\\b/i.test(\n scannedPrompt,\n );\n // `class` is common in non-code Agent domains (for example airline cabin\n // class). Treat code constructs as code only when the prompt also contains\n // an implementation/editing cue, instead of letting a single ambiguous\n // noun redirect an entire tool session to the code-agent portfolio.\n const codeConstructSignal =\n /\\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(\n scannedPrompt,\n );\n const nativeCodeSignal =\n /\\b(?:programmed|written|implemented?|code)\\s+(?:in|using)\\s+(?:c\\+\\+|c|rust|go)\\b/i.test(\n scannedPrompt,\n );\n const hasCode = explicitCodeSignal || codeConstructSignal || nativeCodeSignal;\n const toolsAvailable = options.hasTools ?? false;\n const needsTools =\n options.requiresTools ??\n (toolsAvailable && inferToolRequirement(scannedPrompt, scannedSystemPrompt));\n const likelyParallelToolCalls = likelyNeedsParallelToolCalls(\n scannedPrompt,\n needsTools,\n options.toolCount,\n options.toolNames,\n );\n const normalizedToolNames = (options.toolNames ?? []).map((name) => name.toLowerCase());\n const airlineToolSignal = normalizedToolNames.some((name) =>\n /(?:flight|reservation|airport|baggage|passenger)/.test(name),\n );\n const retailToolSignal = normalizedToolNames.some((name) =>\n /(?:order|product|item|return|exchange|address)/.test(name),\n );\n const webResearchToolSignal = normalizedToolNames.some((name) =>\n /^(?:web_?search|web_?fetch)$/.test(name),\n );\n const agentDomain =\n airlineToolSignal && !retailToolSignal\n ? \"airline\"\n : retailToolSignal && !airlineToolSignal\n ? \"retail\"\n : webResearchToolSignal\n ? \"web_research\"\n : \"other\";\n // Distinguish a cheap lookup from a BrowseComp-like investigation. These\n // prompts require joining several clues, resolving an entity, and ending in\n // one exact answer; complete agent trajectories show that treating them as\n // ordinary search causes long, costly loops. This is request/tool-surface\n // evidence only and does not depend on a benchmark id or hidden answer.\n const clueConnectors =\n scannedFullText.match(\n /\\b(?:after|before|while|where|whose|which|in \\d{4}|as of|over \\d+|another|also|furthermore)\\b|(?:之后|之前|其中|截至|超过|另一个|此外)/gi,\n ) ?? [];\n const entityResolutionSignal =\n /\\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(\n scannedFullText,\n );\n const exactAnswerSignal =\n /\\b(?:exact answer|single best-supported answer|following clues|multiple public sources)\\b|(?:精确答案|根据.*线索|多个公开来源)/i.test(\n scannedFullText,\n );\n const deepWebResearch =\n agentDomain === \"web_research\" &&\n (exactAnswerSignal ||\n (entityResolutionSignal && (clueConnectors.length >= 3 || prompt.length >= 320)));\n const globalOptimizationSignal =\n /\\b(?:cheapest|lowest[- ]price|least expensive|most expensive|highest(?:[- ]priced)?|largest|smallest|maximum|minimum|best available|closest|not (?:cost|exceed))\\b|最便宜|最低价|最贵|最高价|最大|最小/i.test(\n scannedPrompt,\n );\n const globalScopeSignal =\n /\\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(\n scannedPrompt,\n );\n const globalChoiceSignal = globalOptimizationSignal || globalScopeSignal;\n const crossRecordSignal =\n /\\b(?:another|other|different|previous)\\s+(?:order|reservation|booking|account|address)\\b|另一(?:个)?(?:订单|预订|账户|地址)|其他(?:订单|预订|账户|地址)/i.test(\n scannedPrompt,\n );\n const reservationIds = scannedPrompt.match(/\\b[A-Z0-9]{6}\\b/g) ?? [];\n const crossReservationBatchSignal =\n agentDomain === \"airline\" &&\n (/\\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(\n scannedPrompt,\n ) ||\n new Set(reservationIds).size >= 2);\n const conditionalGlobalWorkflowSignal =\n agentDomain === \"airline\" &&\n globalScopeSignal &&\n /\\b(?:if|that (?:contain|have)|longer than|shorter than|under|over|at (?:most|least)|wherever possible)\\b|如果|超过|少于|不超过|尽可能/i.test(\n scannedPrompt,\n ) &&\n /\\b(?:cancel|change|upgrade|move|book)\\b[\\s\\S]*\\b(?:cancel|change|upgrade|move|book)\\b|取消[\\s\\S]*(?:升级|更改)|升级[\\s\\S]*(?:取消|更改)/i.test(\n scannedPrompt,\n );\n // A refund explicitly targeted at a named/non-original card can conflict\n // with account state and require escalation rather than a substitute action.\n // This narrow feature is visible on the first turn and avoids sending every\n // ordinary return workflow to the expensive policy specialist.\n const policyExceptionSignal =\n agentDomain === \"retail\" &&\n /\\b(?:return|refund|send back|get (?:my |the )?money back)\\b|退货|退款|退回/i.test(\n scannedPrompt,\n ) &&\n /\\b(?:amex|american express|visa|mastercard|credit card|debit card|different card|another card|other card)\\b|信用卡|借记卡|其他卡|另一张卡/i.test(\n scannedPrompt,\n );\n // A comparative selector can mention two products while requesting only\n // one write (for example \"send back the pricier one\"). Three-repeat tau2\n // calibration found no quality gain from the policy specialist on these\n // single-write cases, so keep them in a distinct, lower-cost risk band.\n const singleSelectedPolicyException =\n policyExceptionSignal &&\n /\\b(?:return|refund|send back)\\b[^.!?。!?]{0,96}\\b(?:the )?(?:pricier|cheaper|more expensive|less expensive|costlier|one)\\b/i.test(\n scannedPrompt,\n );\n // Returns and exchanges often pivot after confirmation (return -> rethink\n // -> exchange -> choose a variant). That future state is not visible to a\n // task-start router, so treat the observable workflow verb as the risk cue.\n // Simpler cancellation and one-field order edits stay on the standard path.\n const negotiatedWorkflowSignal =\n agentDomain === \"retail\" && /\\b(?:return|exchange)\\b|退货|退回|换货|交换/i.test(scannedPrompt);\n const numberedSteps = (scannedPrompt.match(/(?:^|\\s)\\d+(?:\\.\\d+)*[.)]\\s+/g) ?? []).length;\n const complexMultiToolPlan =\n likelyParallelToolCalls &&\n ((options.toolCount ?? 0) >= 6 || numberedSteps >= 3 || prompt.length > 1_200);\n let agentRisk: TaskFeatures[\"agentRisk\"] =\n needsTools && singleSelectedPolicyException\n ? \"policy_exception_simple\"\n : needsTools && policyExceptionSignal\n ? \"policy_exception\"\n : // Airline prompts that require a global optimum (for example the\n // cheapest itinerary across several candidates) are materially harder\n // than applying one change to every passenger in a known reservation.\n // Full-session evidence supports Sonnet for the former, while upgrading\n // the latter merely because it says \"all passengers\" caused a large cost\n // increase without a quality gain.\n needsTools &&\n agentDomain === \"airline\" &&\n (globalOptimizationSignal || conditionalGlobalWorkflowSignal)\n ? \"complex_high\"\n : needsTools &&\n (likelyParallelToolCalls ||\n globalChoiceSignal ||\n crossRecordSignal ||\n crossReservationBatchSignal ||\n negotiatedWorkflowSignal)\n ? \"high\"\n : \"standard\";\n const needsVision = options.hasVision ?? false;\n const needsStructuredOutput = options.requiresStructuredOutput ?? false;\n const latencySensitive =\n /\\b(?:urgent|asap|fast|quick|low latency|real[- ]time)\\b|尽快|马上|快速|低延迟/i.test(\n scannedFullText,\n );\n const highStakes =\n /\\b(?:production|security|payment|legal|medical|financial|audit)\\b|生产|安全|支付|法律|医疗|财务|审计/i.test(\n scannedFullText,\n );\n // Terminal tasks often describe the desired artifact rather than naming a\n // programming language. Treat only small, deterministic local build/file\n // work as implicit code. Operational deployment, credentials, destructive\n // work, evaluation, vision, and broad search stay on the stronger generic\n // tool-agent path. This is a request-side feature, not a benchmark ID list.\n const terminalToolSignal = normalizedToolNames.some((name) =>\n /^(?:terminalexec|terminalinspect|terminalsendkeys)$/.test(name),\n );\n const simpleTerminalArtifact =\n /\\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(\n scannedPrompt,\n );\n // Multi-file repair is qualitatively different from fixing one known local\n // script. The agent must preserve state across inspections, infer ordering\n // and dependencies, edit several artifacts, and close the loop with tests.\n // A frozen Terminal-Bench trajectory showed the economy model spending 27\n // turns repeatedly rereading files without making an edit, while Opus solved\n // the same task in eight turns. Promote this request-visible pattern before\n // model scoring; no benchmark ID or expected answer is consulted.\n const terminalComplexRepair =\n terminalToolSignal &&\n /\\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(\n scannedPrompt,\n );\n // One artifact that must be accepted by multiple compilers/runtimes is not\n // a routine file-writing task. It requires reasoning across incompatible\n // grammars and validating every execution path; cheap code models can\n // produce plausible-looking source that satisfies neither toolchain.\n const mentionedTerminalRuntimes = new Set(\n (scannedPrompt.match(/\\b(?:gcc|clang|rustc|javac|go\\s+build|node|python)\\b/gi) ?? []).map(\n (name) => name.toLowerCase().replace(/\\s+/g, \" \"),\n ),\n );\n const terminalCrossRuntimeArtifact =\n terminalToolSignal &&\n (/\\bpolyglot\\b/i.test(scannedPrompt) ||\n /\\b(?:both|each)\\b[\\s\\S]{0,120}\\b(?:compilers?|runtimes?|toolchains?)\\b/i.test(\n scannedPrompt,\n ) ||\n (mentionedTerminalRuntimes.size >= 2 &&\n /\\b(?:compile|build|run|execute)\\b/i.test(scannedPrompt)));\n // Framework-to-native ports combine binary checkpoint inspection, weight\n // export, tensor-layout reasoning, image/data decoding, and a separately\n // compiled runtime. A task-start router can see this boundary directly in\n // the request (for example PyTorch state_dict -> a pure C CLI); treating it\n // like routine single-file C work caused a 30-turn read/retry loop in a\n // frozen official Terminal-Bench trajectory.\n const terminalFrameworkToNativeArtifact =\n terminalToolSignal &&\n /\\b(?:pytorch|tensorflow|jax|onnx|state[_ -]?dict|checkpoint|safetensors?)\\b|\\.(?:pth|pt|onnx)\\b/i.test(\n scannedPrompt,\n ) &&\n /\\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(\n scannedPrompt,\n ) &&\n /\\b(?:inference|model|weights?|tensor|export|convert|load)\\b/i.test(scannedPrompt);\n if (\n needsTools &&\n (terminalComplexRepair || terminalCrossRuntimeArtifact || terminalFrameworkToNativeArtifact) &&\n (agentRisk === \"standard\" || agentRisk === \"high\")\n )\n agentRisk = \"complex_high\";\n const complexTerminalOperation =\n /\\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(\n scannedPrompt,\n );\n // A bare \"token\" is not a credential signal: blockchain, tokenizer, and\n // LLM tasks use that word routinely (for example \"token transfers\"). Only\n // treat it as sensitive when the prompt gives it an authentication/secret\n // qualifier. API keys remain an unambiguous high-risk signal on their own.\n const terminalCredentialSignal =\n /\\b(?:ssh|nginx|certificate|authentication|credentials?|passwords?|api keys?|deploy|production|encrypt|gpg|shred|securely delete|decommission)\\b/i.test(\n scannedPrompt,\n ) ||\n /\\b(?:access|auth|authentication|bearer|secret|api)\\s+tokens?\\b|\\btokens?\\s+(?:secret|credential|authentication)\\b/i.test(\n scannedPrompt,\n );\n const terminalSafetySensitive = terminalToolSignal && (highStakes || terminalCredentialSignal);\n const implicitTerminalCode =\n needsTools &&\n terminalToolSignal &&\n agentRisk === \"standard\" &&\n !highStakes &&\n !complexTerminalOperation &&\n numberedSteps < 3 &&\n prompt.length <= 1_000 &&\n simpleTerminalArtifact;\n const language = /[\\u3400-\\u9fff]/.test(scannedFullText) ? \"zh\" : \"other\";\n const multipleChoiceSignals = (scannedPrompt.match(/(?:^|\\n)\\s*[A-D][.)]\\s+/gim) ?? []).length;\n const numericSignals = (scannedPrompt.match(/-?\\d+(?:[.,]\\d+)?/g) ?? []).length;\n const compactMathProblem =\n !hasCode &&\n prompt.length < 2_500 &&\n numericSignals >= 2 &&\n (/[+×÷=%$€£¥]|\\b(?:total|each|per|times|half|twice|percent|how many|how much|calculate)\\b/i.test(\n scannedPrompt,\n ) ||\n /[??]\\s*$/.test(scannedPrompt.trim()) ||\n numericSignals >= 3);\n\n let taskType: TaskType = \"chat\";\n if (needsVision) taskType = \"vision\";\n else if (estimatedInputTokens > 80_000) taskType = \"long_context\";\n else if (needsTools && (hasCode || implicitTerminalCode)) taskType = \"code_agent\";\n else if (needsTools && likelyParallelToolCalls && !complexMultiToolPlan)\n taskType = \"tool_agent_parallel\";\n else if (needsTools) taskType = \"tool_agent\";\n else if (multipleChoiceSignals >= 3) taskType = \"reasoning_mcq\";\n else if (compactMathProblem) taskType = \"reasoning_math\";\n else if (\n /\\b(?:bug|debug|error|failure|failing|regression|crash|修复|报错|错误|调试)\\b/i.test(text)\n )\n taskType = \"debug\";\n else if (hasCode || /\\b(?:refactor|implement|patch|edit|rewrite|重构|实现|修改)\\b/i.test(text))\n taskType = \"code_edit\";\n else if (needsStructuredOutput || /\\b(?:extract|json|schema|csv|字段|提取)\\b/i.test(text))\n taskType = \"extraction\";\n else if (\n /\\b(?:prove|derive|theorem|formal|mathematical|reasoning|证明|推导|定理|数学)\\b/i.test(text)\n )\n taskType = \"reasoning\";\n\n return {\n taskType,\n estimatedInputTokens,\n hasCode,\n needsTools,\n toolsAvailable,\n needsVision,\n needsStructuredOutput,\n latencySensitive,\n highStakes,\n language,\n likelyParallelToolCalls,\n complexMultiToolPlan,\n agentDomain,\n deepWebResearch,\n agentRisk,\n terminalToolSignal,\n terminalSafetySensitive,\n implicitTerminalCode,\n };\n}\n\nfunction affinity(\n modelId: string,\n task: TaskType,\n language: TaskFeatures[\"language\"] = \"other\",\n agentDomain: TaskFeatures[\"agentDomain\"] = \"other\",\n deepWebResearch = false,\n agentRisk: TaskFeatures[\"agentRisk\"] = \"standard\",\n terminalToolSignal = false,\n terminalSafetySensitive = false,\n): number {\n const id = modelId.toLowerCase();\n // Model family names are intentionally similar (for example\n // `gemini-2.5-flash` vs `gemini-2.5-flash-lite`). A substring match lets a\n // smaller sibling inherit a capability claim that was measured only for the\n // flagship. Keep these assignments model-exact; a sibling can be added only\n // with its own evidence.\n const modelName = id.slice(id.indexOf(\"/\") + 1);\n const match = (values: string[], score: number) =>\n values.some((value) => modelName === value) ? score : 0;\n const base = 0.68;\n\n switch (task) {\n case \"code_agent\":\n if (terminalToolSignal && agentRisk === \"complex_high\") {\n // Strong native tool loop until the Responses function-output fix is\n // deployed on both gateways; keep Codex available below the floor.\n return Math.max(\n base,\n match([\"claude-sonnet-5\"], 1),\n match([\"gpt-5.3-codex\"], 0.87),\n match([\"gpt-5-mini\"], 0.78),\n match([\"gemini-3.5-flash\"], 0.76),\n );\n }\n // Seven valid full agent + official Terminal-Bench trajectories\n // (2026-07-28) gave GPT-5 Mini 4/7 resolved tasks versus 1/7 for the\n // prior dynamic code-agent choice. Its token-normalized total cost was\n // higher in this small calibration, so keep Codex and Sonnet's quality\n // priors above it; admitting Mini to the scoring band lets the normal\n // quality/cost profile choose it without erasing stronger fallbacks.\n // DeepSeek V4 Pro is kept below the primary band after two consecutive\n // mid-trajectory provider timeouts contaminated its calibration runs.\n return Math.max(\n base,\n match([\"gpt-5.3-codex\"], 1),\n match([\"claude-sonnet-5\"], 0.98),\n match([\"gpt-5-mini\"], 0.96),\n match([\"gemini-3.5-flash\"], 0.92),\n match([\"kimi-k3\"], 0.9),\n match([\"deepseek-v4-pro\", \"glm-5.2\"], 0.88),\n );\n case \"tool_agent\":\n if (terminalToolSignal && agentRisk === \"complex_high\") {\n // Keep the Responses-API Codex path outside auto's affinity floor\n // until the gateway fix that preserves function_call_output is live\n // on both chains. Sonnet has a verified native multi-turn tool loop\n // and is the safe strong default for this band today.\n return Math.max(\n base,\n match([\"claude-sonnet-5\"], 1),\n match([\"gpt-5.3-codex\"], 0.87),\n match([\"gpt-5-mini\"], 0.78),\n match([\"gemini-3.5-flash\"], 0.76),\n );\n }\n if (terminalToolSignal && !terminalSafetySensitive) {\n // Seven official Terminal-Bench calibration trajectories favoured\n // GPT-5 Mini over the prior dynamic choice. Admit Codex/Sonnet as\n // close fallbacks, but let actual request cost break the tie.\n return Math.max(\n base,\n match([\"gpt-5-mini\"], 1),\n match([\"gpt-5.3-codex\"], 0.98),\n match([\"claude-sonnet-5\"], 0.9),\n match([\"gemini-3.5-flash\"], 0.89),\n );\n }\n if (terminalToolSignal && terminalSafetySensitive) {\n // Two complete agent observations on the public\n // Terminal-Bench new-encrypt-command task ended in Codex repeating\n // the same TerminalExec input until the loop guard fired. Keep Codex\n // as an availability fallback, but below the safety-band affinity\n // floor until its Responses function-output path is verified on both\n // gateways. This does not change explicit code-agent routing.\n return Math.max(\n base,\n match([\"claude-sonnet-5\"], 1),\n match([\"claude-opus-4.8\"], 0.9),\n match([\"gpt-5.3-codex\"], 0.84),\n );\n }\n if (agentDomain === \"web_research\") {\n // Complete-session BrowseComp calibration supersedes the earlier\n // single-case Opus promotion: strict deduplicated evidence has Sonnet\n // 5 at 2/9 versus Opus 5 at 0/3, while Opus also costs more and has a\n // much longer tail. Keep Opus as an availability fallback until a\n // larger stable-provider sample supports promotion.\n return deepWebResearch\n ? Math.max(\n base,\n match([\"claude-sonnet-5\"], 1),\n match([\"gpt-5-mini\"], 0.88),\n match([\"gemini-3.5-flash\"], 0.84),\n match([\"claude-opus-5\"], 0.8),\n match([\"claude-opus-4.8\"], 0.78),\n )\n : Math.max(\n base,\n match([\"claude-sonnet-5\"], 1),\n match([\"gpt-5-mini\"], 0.88),\n match([\"gemini-3.5-flash\"], 0.86),\n match([\"claude-opus-5\"], 0.84),\n match([\"claude-opus-4.8\"], 0.82),\n );\n }\n // Full-trajectory tau2 calibration (2026-07-28, official gpt-4.1\n // simulator): Sonnet 5 completed both an airline policy task and a\n // retail multi-write task with reward 1.0. Gemini 3.5 Flash emitted\n // function calls as plain text after the first structured calls and\n // looped to the 100-step ceiling on the airline task. Keep only the\n // trajectory-validated primary inside the scoring band; the remaining\n // eligible models are retained below as availability fallbacks.\n if (agentDomain === \"retail\") {\n // Full-session calibration: GPT-5 Mini completed two local/single\n // retail workflows at a fraction of Sonnet's token cost. It remains\n // ineligible for promotion when the prompt asks for multiple actions,\n // cross-record discovery, or a global optimum; those trajectories\n // exposed unstable write arguments in prior calibration. DeepSeek V4\n // Pro completed all three high-risk retail calibration trajectories\n // that included global-choice, cross-record, and multi-write behavior;\n // Sonnet completed one of the same three.\n if (agentRisk === \"standard\") {\n return Math.max(\n base,\n match([\"gpt-5-mini\"], 1),\n match([\"claude-sonnet-5\"], 0.88),\n match([\"gemini-3.5-flash\"], 0.82),\n match([\"gpt-5.3-codex\"], 0.81),\n match([\"kimi-k3\"], 0.78),\n match([\"deepseek-v4-pro\"], 0.76),\n );\n }\n if (agentRisk === \"policy_exception\") {\n return Math.max(\n base,\n match([\"gpt-4.1\"], 1),\n match([\"claude-sonnet-5\"], 0.9),\n match([\"deepseek-v4-pro\"], 0.82),\n match([\"gpt-5-mini\"], 0.8),\n match([\"gpt-4o-mini\"], 0.76),\n );\n }\n if (agentRisk === \"policy_exception_simple\") {\n return Math.max(\n base,\n match([\"gpt-5-mini\"], 1),\n match([\"gpt-4.1\"], 0.86),\n match([\"deepseek-v4-pro\"], 0.82),\n match([\"gpt-4o-mini\"], 0.8),\n );\n }\n return Math.max(\n base,\n match([\"deepseek-v4-pro\"], 1),\n match([\"claude-sonnet-5\"], 0.88),\n match([\"gemini-3.5-flash\"], 0.82),\n match([\"gpt-5.3-codex\"], 0.81),\n match([\"kimi-k3\"], 0.78),\n match([\"gpt-5-mini\"], 0.76),\n );\n }\n // Standard airline workflows stay on GPT-5 Mini: six full-session\n // development trajectories gave it the same 5/6 success as Sonnet at\n // roughly one order of magnitude lower normalized token cost. A held-out\n // high-risk cabin/date negotiation then produced a persistent empty\n // assistant turn on Mini even after a semantic retry, while Sonnet 5\n // completed the identical official tau2 trajectory with reward 1.0.\n // Promote only global optimization / conditional-global work. A known\n // batch of reservations is operationally high-risk but still a\n // structured tool workflow: current Tau evidence has Mini and Sonnet at\n // equal task reward there, while Sonnet costs roughly two orders of\n // magnitude more on the long-tail case.\n if (agentDomain === \"airline\") {\n if (agentRisk === \"complex_high\") {\n return Math.max(\n base,\n match([\"claude-sonnet-5\"], 1),\n match([\"gpt-5-mini\"], 0.78),\n match([\"gemini-3.5-flash\"], 0.76),\n match([\"deepseek-v4-pro\"], 0.74),\n );\n }\n return Math.max(\n base,\n match([\"gpt-5-mini\"], 1),\n match([\"claude-sonnet-5\"], 0.9),\n match([\"gemini-3.5-flash\"], 0.8),\n match([\"deepseek-v4-pro\"], 0.76),\n );\n }\n return Math.max(\n base,\n match([\"claude-sonnet-5\"], 1),\n match([\"gemini-3.5-flash\"], 0.88),\n match([\"gpt-5.3-codex\"], 0.87),\n match([\"gpt-5-mini\"], 0.84),\n match([\"kimi-k3\"], 0.85),\n match([\"deepseek-v4-pro\"], 0.82),\n );\n case \"tool_agent_parallel\":\n if (terminalToolSignal) {\n // Multi-file Terminal work is not equivalent to a one-turn parallel\n // function-call benchmark. Sonnet is the strongest trajectory-tested\n // cost-controlled default; Opus remains a close safety fallback.\n return terminalSafetySensitive\n ? Math.max(\n base,\n match([\"claude-sonnet-5\"], 1),\n match([\"claude-opus-4.8\"], 0.9),\n match([\"gpt-5.3-codex\"], 0.86),\n )\n : Math.max(\n base,\n match([\"gpt-5-mini\"], 1),\n match([\"gpt-5.3-codex\"], 0.98),\n match([\"claude-sonnet-5\"], 0.92),\n match([\"gemini-3.5-flash\"], 0.88),\n );\n }\n if (agentDomain === \"web_research\") {\n return deepWebResearch\n ? Math.max(\n base,\n match([\"claude-sonnet-5\"], 1),\n match([\"gpt-5-mini\"], 0.88),\n match([\"gemini-3.5-flash\"], 0.84),\n match([\"claude-opus-5\"], 0.8),\n match([\"claude-opus-4.8\"], 0.78),\n )\n : Math.max(\n base,\n match([\"claude-sonnet-5\"], 1),\n match([\"gpt-5-mini\"], 0.88),\n match([\"gemini-3.5-flash\"], 0.86),\n match([\"claude-opus-5\"], 0.84),\n match([\"claude-opus-4.8\"], 0.82),\n );\n }\n if (agentDomain === \"retail\") {\n if (agentRisk === \"policy_exception\") {\n return Math.max(\n base,\n match([\"gpt-4.1\"], 1),\n match([\"claude-sonnet-5\"], 0.9),\n match([\"deepseek-v4-pro\"], 0.82),\n match([\"gpt-5-mini\"], 0.8),\n match([\"gpt-4o-mini\"], 0.76),\n );\n }\n if (agentRisk === \"policy_exception_simple\") {\n return Math.max(\n base,\n match([\"gpt-5-mini\"], 1),\n match([\"gpt-4.1\"], 0.86),\n match([\"deepseek-v4-pro\"], 0.82),\n match([\"gpt-4o-mini\"], 0.8),\n );\n }\n return Math.max(\n base,\n match([\"deepseek-v4-pro\"], 1),\n match([\"claude-sonnet-5\"], 0.88),\n match([\"claude-opus-4.8\"], 0.84),\n match([\"gpt-5-mini\"], 0.78),\n match([\"gemini-3.5-flash\"], 0.76),\n );\n }\n if (agentDomain === \"airline\") {\n return agentRisk === \"complex_high\"\n ? Math.max(\n base,\n match([\"claude-sonnet-5\"], 1),\n match([\"gpt-5-mini\"], 0.78),\n match([\"claude-opus-4.8\"], 0.76),\n match([\"gemini-3.5-flash\"], 0.74),\n )\n : Math.max(\n base,\n match([\"gpt-5-mini\"], 1),\n match([\"claude-sonnet-5\"], 0.9),\n match([\"gemini-3.5-flash\"], 0.8),\n );\n }\n // RouterBench calibration, 2026-07-26: Opus 4.8 produced complete\n // multi-call payloads on 2/3 multilingual BFCL parallel cases. Gemini\n // 3.5 Flash, Sonnet 5, DeepSeek V4 Pro, and Grok 4.5 were 0/3. This\n // narrow prior only applies after the conservative prompt feature above.\n return Math.max(\n base,\n match([\"claude-opus-4.8\"], 1),\n match([\"claude-sonnet-5\"], 0.84),\n match([\"grok-4.5\"], 0.82),\n match([\"gemini-3.5-flash\"], 0.8),\n match([\"deepseek-v4-pro\"], 0.78),\n );\n case \"code_edit\":\n case \"debug\":\n return Math.max(\n base,\n match([\"gpt-5.3-codex\"], 1),\n match([\"claude-sonnet-4.6\"], 0.94),\n match([\"glm-5.2\"], 0.9),\n match([\"deepseek-v4-pro\"], 0.86),\n );\n case \"reasoning\":\n return Math.max(\n base,\n match([\"claude-sonnet-5\", \"claude-sonnet-4.6\"], 0.98),\n match([\"deepseek-v4-pro\"], 0.95),\n match([\"grok-4.5\"], 0.94),\n match([\"gemini-3.1-pro\", \"gemini-3.5-flash\"], 0.92),\n );\n case \"reasoning_mcq\":\n // RouterBench calibration (2026-07-28, six stratified GPQA Diamond\n // tasks, identical agent adapter and 512-token budget): Gemini 3\n // Flash Preview scored 5/6, Gemini 3.5 Flash 4/6, and Gemini 3.1 Pro\n // 3/6 while costing ~170x more than Flash. Keep the measured winner as\n // the narrow default; version recency alone is not a quality signal.\n // Unused host tools must not change this reasoning-only model choice.\n return Math.max(\n base,\n match([\"gemini-3-flash-preview\"], 1),\n match([\"gemini-3.5-flash\"], 0.91),\n match([\"grok-4.5\"], 0.9),\n match([\"claude-sonnet-5\"], 0.88),\n match([\"deepseek-v4-pro\"], 0.84),\n );\n case \"reasoning_math\":\n // Same calibration, five multilingual MGSM tasks: Gemini 3.5 Flash was\n // 5/5 with the lowest cost and latency; four current flagships were 4/5\n // and Kimi K2.7 was 3/5.\n return Math.max(\n base,\n match([\"gemini-3.5-flash\"], 1),\n match([\"grok-4.5\"], 0.93),\n match([\"claude-sonnet-5\", \"deepseek-v4-pro\", \"kimi-k3\"], 0.9),\n );\n case \"vision\":\n return Math.max(\n base,\n match([\"gemini-3.1-pro\"], 0.96),\n match([\"qwen3.7-max\", \"claude-sonnet-4.6\", \"kimi-k3\", \"grok-4.3\"], 0.9),\n );\n case \"long_context\":\n // Long-context eligibility is necessary but not sufficient: a provider\n // can advertise a 1M window yet return an empty completion near that\n // boundary. Keep the proven long-context flagship in the lead and put\n // less-established alternatives in a separate affinity band so price\n // alone cannot displace it.\n return Math.max(\n base,\n match([\"gemini-3.1-pro\"], 1),\n match([\"qwen3.7-max\", \"glm-5.2\"], 0.89),\n match([\"gemini-3.5-flash\"], 0.88),\n match([\"deepseek-v4-pro\"], 0.85),\n );\n case \"extraction\": {\n // A structured extraction must preserve both the output contract and the\n // source-language fields. For Mandarin input, keep the language-native\n // Kimi candidate in a distinct affinity band. This is deliberately a\n // candidate-pool decision (rather than a brittle post-hoc override): it\n // still falls back normally if that model is unavailable or ineligible.\n // Kimi K3 costs ~5x its retired sibling K2.7, so the band must be wider\n // than the auto affinityFloorGap (0.10) or price alone re-selects a\n // non-native model for Mandarin input; 0.12 keeps K3 alone in the\n // primary band for zh and leaves every other language untouched.\n const kimiExtractionAffinity = language === \"zh\" ? 1 : 0.9;\n const otherExtractionAffinity = language === \"zh\" ? 0.88 : 0.9;\n return Math.max(\n base,\n match([\"gemini-3.5-flash\", \"gemini-2.5-flash\", \"gpt-4o-mini\"], otherExtractionAffinity),\n match([\"claude-sonnet-5\", \"claude-sonnet-4.6\"], otherExtractionAffinity),\n match([\"kimi-k3\"], kimiExtractionAffinity),\n );\n }\n default:\n return Math.max(\n base,\n match([\"gemini-3.5-flash\", \"gemini-2.5-flash\", \"kimi-k3\"], 0.86),\n );\n }\n}\n\nfunction evidenceCandidates(task: TaskType): string[] {\n if (task === \"code_agent\") {\n return [\n \"openai/gpt-5.3-codex\",\n \"anthropic/claude-sonnet-5\",\n \"openai/gpt-5-mini\",\n \"google/gemini-3.5-flash\",\n \"moonshot/kimi-k3\",\n \"deepseek/deepseek-v4-pro\",\n ];\n }\n if (task === \"tool_agent\") {\n return [\n \"anthropic/claude-sonnet-5\",\n \"anthropic/claude-opus-5\",\n \"openai/gpt-5-mini\",\n \"openai/gpt-4.1\",\n \"openai/gpt-4o-mini\",\n \"google/gemini-3.5-flash\",\n \"openai/gpt-5.3-codex\",\n \"moonshot/kimi-k3\",\n \"deepseek/deepseek-v4-pro\",\n ];\n }\n if (task === \"tool_agent_parallel\") {\n return [\n \"anthropic/claude-opus-5\",\n \"anthropic/claude-opus-4.8\",\n \"anthropic/claude-sonnet-5\",\n \"openai/gpt-5-mini\",\n \"openai/gpt-4.1\",\n \"openai/gpt-4o-mini\",\n \"xai/grok-4.5\",\n \"google/gemini-3.5-flash\",\n \"deepseek/deepseek-v4-pro\",\n ];\n }\n if (task === \"long_context\") {\n return [\n \"google/gemini-3.1-pro\",\n \"deepseek/deepseek-v4-pro\",\n \"qwen/qwen3.7-max\",\n \"zai/glm-5.2\",\n \"google/gemini-3.5-flash\",\n ];\n }\n if (task === \"reasoning_mcq\") {\n return [\n \"google/gemini-3-flash-preview\",\n \"google/gemini-3.5-flash\",\n \"xai/grok-4.5\",\n \"anthropic/claude-sonnet-5\",\n \"deepseek/deepseek-v4-pro\",\n ];\n }\n if (task === \"extraction\") {\n // Kimi K3 is no longer on the auto MEDIUM chain (K2.7 was); the\n // language-native extraction band in affinity() needs it in the pool.\n return [\"moonshot/kimi-k3\", \"google/gemini-3.5-flash\", \"anthropic/claude-sonnet-5\"];\n }\n if (task === \"reasoning_math\") {\n return [\n \"google/gemini-3.5-flash\",\n \"xai/grok-4.5\",\n \"anthropic/claude-sonnet-5\",\n \"deepseek/deepseek-v4-pro\",\n \"moonshot/kimi-k3\",\n ];\n }\n return [];\n}\n\n/**\n * Recently added catalog models with a verified structured function call.\n *\n * Tool compliance is enough to make these models safe availability fallbacks,\n * but it is not evidence that they should displace a trajectory-benchmarked\n * primary. Keep them after the configured and benchmark-backed chains until a\n * full agent evaluation earns a task-specific affinity above the neutral 0.68\n * floor. `isEligible` still applies every host capability override, context\n * limit, vision constraint, and unavailable-model guard before they are used.\n */\nconst VERIFIED_TOOL_FALLBACKS = [\n \"anthropic/claude-fable-5.1\",\n \"anthropic/claude-opus-5.5\",\n \"anthropic/claude-sonnet-5.5\",\n \"google/gemini-3.8-flash\",\n \"openai/gpt-5.1\",\n \"openai/gpt-6-astra\",\n \"openai/gpt-6-luna\",\n \"openai/gpt-6-sol\",\n \"xai/grok-4.6\",\n \"xai/grok-4.7\",\n \"xiaomi/mimo-v2.5\",\n] as const;\n\nfunction isEligible(\n modelId: string,\n features: TaskFeatures,\n maxOutputTokens: number,\n options: RouterOptions,\n): boolean {\n const model = options.modelCapabilities?.[modelId] ?? DEFAULT_MODEL_CAPABILITIES[modelId];\n // Preserve compatibility for temporarily catalog-less fallback IDs. They are\n // kept behind known-model candidates but are not silently dropped.\n if (!model) return true;\n if (features.needsTools && !model.supportsTools) return false;\n if (features.needsVision && !model.supportsVision) return false;\n if (features.needsStructuredOutput && !model.supportsTools) return false;\n if (model.maxOutputTokens < maxOutputTokens) return false;\n return model.contextWindow >= (features.estimatedInputTokens + maxOutputTokens) * 1.1;\n}\n\nfunction estimatedCost(\n modelId: string,\n options: RouterOptions,\n inputTokens: number,\n outputTokens: number,\n): number {\n const price = options.modelPricing.get(modelId);\n if (!price) return Number.POSITIVE_INFINITY;\n if (price.flatPrice !== undefined) return price.flatPrice;\n return (inputTokens * price.inputPrice + outputTokens * price.outputPrice) / 1_000_000;\n}\n\nfunction profileScore(\n modelId: string,\n options: RouterOptions,\n now: Date,\n):\n | { quality?: number; speed: number; tailSpeed: number; reliability: number; freshness: number }\n | undefined {\n const profile: ModelPerformanceProfile | undefined =\n options.modelPerformance?.[modelId] ??\n LIVE_MODEL_PROFILES[modelId] ??\n HISTORICAL_MODEL_PROFILES[modelId];\n if (!profile) return undefined;\n const measuredAt = Date.parse(profile.measuredAt);\n if (!Number.isFinite(measuredAt)) return undefined;\n const ageDays = Math.max(0, (now.getTime() - measuredAt) / 86_400_000);\n // A 30-day half-life makes old data a tie-breaker only. Small probe runs are\n // also weak evidence: three quick samples should not overturn a curated\n // tier ordering merely because of a transient provider tail. Callers that\n // inject an observation without a sample count retain the legacy full\n // confidence behaviour for compatibility.\n const sampleConfidence =\n profile.samples === undefined ? 1 : Math.min(1, Math.max(0, profile.samples) / 10);\n const freshness = Math.pow(0.5, ageDays / 30) * sampleConfidence;\n const quality =\n profile.intelligenceIndex === undefined\n ? undefined\n : Math.min(1, profile.intelligenceIndex / 50);\n const speed = Math.min(\n 1,\n (2_000 / Math.max(500, profile.latencyMs) + profile.outputTokensPerSecond / 250) / 2,\n );\n const tailSpeed = Math.min(1, 3_000 / Math.max(750, profile.p95LatencyMs ?? profile.latencyMs));\n const reliability = Math.max(0, 1 - (profile.errorRate ?? 0));\n return { quality, speed, tailSpeed, reliability, freshness };\n}\n\n/** Candidate router used for Auto. Rules still set the capability tier; V3 ranks within it. */\nexport class PortfolioStrategy implements RouterStrategy {\n readonly name = \"portfolio\";\n\n route(\n prompt: string,\n systemPrompt: string | undefined,\n maxOutputTokens: number,\n options: RouterOptions,\n ) {\n const features = classifyTask(prompt, systemPrompt, options);\n const base = new RulesStrategy().route(prompt, systemPrompt, maxOutputTokens, {\n ...options,\n requiresTools: features.needsTools,\n });\n const tierConfigs = base.tierConfigs;\n if (!tierConfigs) return base;\n const targetTier: Tier =\n (features.taskType === \"reasoning_mcq\" || features.taskType === \"reasoning_math\") &&\n (base.tier === \"SIMPLE\" || base.tier === \"MEDIUM\")\n ? \"REASONING\"\n : base.tier;\n const tierConfig = tierConfigs[targetTier];\n const configuredCandidates = tierConfig ? getFallbackChain(targetTier, tierConfigs) : [];\n // Evidence candidates join the configured chain, but the host's\n // unavailable set applies to both: the configured side arrives filtered\n // through RulesStrategy, and a dead evidence model must not re-enter here.\n const unavailable = new Set(options.unavailableModels ?? []);\n // `modelPricing` is the host's live catalog view. Do not introduce a\n // built-in fallback that the current gateway does not advertise. These\n // models carry no task evidence, so outside Premium the cheapest one is\n // the first recovery hop; otherwise an outage of the curated chain would\n // jump an Eco turn straight to the most expensive model in the list.\n const verifiedToolFallbacks = features.needsTools\n ? VERIFIED_TOOL_FALLBACKS.filter((model) => options.modelPricing.has(model))\n : [];\n if (options.routingProfile !== \"premium\") {\n const fallbackCost = (model: string) =>\n estimatedCost(model, options, features.estimatedInputTokens, maxOutputTokens);\n verifiedToolFallbacks.sort((a, b) => fallbackCost(a) - fallbackCost(b));\n }\n const chain = [\n ...new Set([\n ...configuredCandidates,\n ...evidenceCandidates(features.taskType),\n ...verifiedToolFallbacks,\n ]),\n ].filter(\n (model): model is string =>\n typeof model === \"string\" && model.length > 0 && !unavailable.has(model),\n );\n const eligible = chain.filter((model) =>\n isEligible(model, features, maxOutputTokens, options),\n );\n const eligibleCandidates = eligible.length > 0 ? eligible : chain;\n if (eligibleCandidates.length === 0) return base;\n const profileName =\n options.routingProfile === \"eco\"\n ? \"eco\"\n : options.routingProfile === \"premium\"\n ? \"premium\"\n : \"auto\";\n const portfolio = options.config.portfolio ?? DEFAULT_PORTFOLIO_WEIGHTS;\n const getAffinity = (model: string) =>\n affinity(\n model,\n features.taskType,\n features.language,\n features.agentDomain,\n features.deepWebResearch,\n features.agentRisk,\n features.terminalToolSignal,\n features.terminalSafetySensitive,\n );\n const bestAffinity = Math.max(...eligibleCandidates.map(getAffinity));\n const specificAffinity = eligibleCandidates.filter((model) => getAffinity(model) > 0.68);\n // A tier's fallback list is primarily an availability/recovery chain, not a\n // set of equally validated substitutes. Re-ranking every fallback lets a\n // cheap generic model displace the curated primary merely because it has a\n // favourable short performance probe. Only promote models with explicit\n // task affinity; otherwise retain the first capability-eligible tier model.\n const affinityPool = specificAffinity.length > 0 ? specificAffinity : [eligibleCandidates[0]];\n // Generic Terminal work has much wider trajectory variance than a BFCL-like\n // one-turn parallel call. Keep the strong-model safety band, but admit the\n // next capable tier so Auto's cost/reliability score can reject an Opus\n // primary that is materially more expensive without measured benefit.\n const affinityFloorGap = features.terminalToolSignal\n ? Math.max(\n portfolio.affinityFloorGap[profileName],\n features.terminalSafetySensitive ? 0.15 : 0.12,\n )\n : portfolio.affinityFloorGap[profileName];\n const candidates = affinityPool.filter(\n (model) => getAffinity(model) >= bestAffinity - affinityFloorGap,\n );\n const costs = candidates.map((model) =>\n estimatedCost(model, options, features.estimatedInputTokens, maxOutputTokens),\n );\n const finiteCosts = costs.filter(Number.isFinite);\n const minCost = finiteCosts.length > 0 ? Math.min(...finiteCosts) : 0;\n const maxCost = finiteCosts.length > 0 ? Math.max(...finiteCosts) : 1;\n\n const now = options.now ?? new Date();\n const profileWeights = portfolio[profileName];\n const rankedEntries = candidates\n .map((model, index) => {\n const cost = estimatedCost(model, options, features.estimatedInputTokens, maxOutputTokens);\n const costScore =\n Number.isFinite(cost) && maxCost > minCost\n ? 1 - (cost - minCost) / (maxCost - minCost)\n : 0.5;\n const capabilityScore = isEligible(model, features, maxOutputTokens, options) ? 1 : 0;\n const profile = profileScore(model, options, now);\n // Fresh observations can refine affinity. Historical observations fade\n // quickly and never replace task-level RouterBench evidence.\n const observedQuality =\n profile?.quality === undefined\n ? getAffinity(model)\n : getAffinity(model) * (1 - profile.freshness) + profile.quality * profile.freshness;\n const observedSpeed = profile ? profile.speed * profile.freshness : 0.5;\n const observedTailSpeed = profile ? profile.tailSpeed * profile.freshness : 0.5;\n const observedReliability = profile\n ? profile.reliability * profile.freshness + (1 - profile.freshness)\n : 1;\n // Preserve a small amount of the hand-curated fallback order while V3's\n // task affinity and real request constraints do the primary work.\n const legacyScore = 1 - index / Math.max(1, candidates.length - 1);\n const qualityWeight =\n profileWeights.quality + (features.highStakes ? portfolio.highStakesBoost.quality : 0);\n const speedScore = features.latencySensitive ? observedTailSpeed : observedSpeed;\n const speedWeight =\n profileWeights.speed +\n (features.latencySensitive ? portfolio.latencySensitiveSpeedBoost : 0);\n const reliabilityWeight =\n profileWeights.reliability +\n (features.highStakes ? portfolio.highStakesBoost.reliability : 0);\n const score =\n observedQuality * qualityWeight +\n capabilityScore * profileWeights.capability +\n costScore * profileWeights.cost +\n speedScore * speedWeight +\n observedReliability * reliabilityWeight +\n legacyScore * profileWeights.legacy;\n return {\n model,\n score,\n quality: observedQuality,\n cost: costScore,\n speed: speedScore,\n reliability: observedReliability,\n };\n })\n .sort((a, b) => b.score - a.score);\n const scoredModels = rankedEntries.map((item) => item.model);\n // The affinity floor controls which models may compete for the primary;\n // it must not erase availability fallbacks. Append all remaining eligible\n // models in their curated chain order after the scored primary pool.\n const webResearchFallbackOrder = [\n \"anthropic/claude-sonnet-5\",\n \"openai/gpt-5-mini\",\n \"google/gemini-3.5-flash\",\n \"anthropic/claude-opus-5\",\n \"anthropic/claude-opus-4.8\",\n \"openai/gpt-5.3-codex\",\n ];\n const ranked =\n features.agentDomain === \"web_research\"\n ? [\n ...scoredModels,\n ...webResearchFallbackOrder.filter(\n (model) => eligibleCandidates.includes(model) && !scoredModels.includes(model),\n ),\n ...eligibleCandidates.filter(\n (model) => !scoredModels.includes(model) && !webResearchFallbackOrder.includes(model),\n ),\n ]\n : [...scoredModels, ...eligibleCandidates.filter((model) => !scoredModels.includes(model))];\n\n const model = ranked[0] ?? base.model;\n const selectedTierConfigs: Record = {\n ...tierConfigs,\n [targetTier]: { primary: model, fallback: ranked.slice(1) },\n };\n // selectModel only reads the selected tier; retain the complete tier map for host fallback.\n const decision = selectModel(\n targetTier,\n base.confidence,\n \"portfolio\",\n `${base.reasoning} | v3 task=${features.taskType} agentRisk=${features.agentRisk} deepWebResearch=${features.deepWebResearch} terminalCode=${features.implicitTerminalCode} terminalSafety=${features.terminalSafetySensitive} candidates=${ranked.length}`,\n selectedTierConfigs,\n options.modelPricing,\n features.estimatedInputTokens,\n maxOutputTokens,\n options.routingProfile,\n base.agenticScore,\n );\n return {\n ...decision,\n tierConfigs: selectedTierConfigs,\n profile: base.profile,\n candidates: ranked,\n candidateScores: rankedEntries.map(({ model, score, quality, cost, speed, reliability }) => ({\n model,\n score,\n quality,\n cost,\n speed,\n reliability,\n })),\n taskType: features.taskType,\n routerVersion: \"v3-portfolio\" as const,\n };\n }\n}\n","/**\n * Default Routing Config\n *\n * All routing parameters as a TypeScript constant.\n * Operators override via openclaw.yaml plugin config.\n *\n * Scoring uses 15 weighted dimensions with sigmoid confidence calibration.\n */\n\nimport type { RoutingConfig } from \"./types.js\";\n\nexport const DEFAULT_ROUTING_CONFIG: RoutingConfig = {\n version: \"3.5\",\n strategy: \"portfolio\",\n portfolio: {\n auto: {\n quality: 0.47,\n capability: 0.2,\n cost: 0.18,\n speed: 0.07,\n reliability: 0.03,\n legacy: 0.05,\n },\n eco: {\n quality: 0.36,\n capability: 0.2,\n cost: 0.28,\n speed: 0.1,\n reliability: 0.04,\n legacy: 0.02,\n },\n premium: {\n quality: 0.58,\n capability: 0.2,\n cost: 0.08,\n speed: 0.06,\n reliability: 0.06,\n legacy: 0.02,\n },\n highStakesBoost: { quality: 0.08, reliability: 0.05 },\n latencySensitiveSpeedBoost: 0.08,\n affinityFloorGap: { auto: 0.1, eco: 0.22, premium: 0.05 },\n },\n\n classifier: {\n llmModel: \"google/gemini-2.5-flash\",\n llmMaxTokens: 10,\n llmTemperature: 0,\n promptTruncationChars: 500,\n cacheTtlMs: 3_600_000, // 1 hour\n },\n\n scoring: {\n tokenCountThresholds: { simple: 50, complex: 500 },\n\n // Multilingual keywords: EN + ZH + JA + RU + DE + ES + PT + KO + AR\n codeKeywords: [\n // English\n \"function\",\n \"class\",\n \"import\",\n \"def\",\n \"SELECT\",\n \"async\",\n \"await\",\n \"const\",\n \"let\",\n \"var\",\n \"return\",\n \"```\",\n // Chinese\n \"函数\",\n \"类\",\n \"导入\",\n \"定义\",\n \"查询\",\n \"异步\",\n \"等待\",\n \"常量\",\n \"变量\",\n \"返回\",\n // Japanese\n \"関数\",\n \"クラス\",\n \"インポート\",\n \"非同期\",\n \"定数\",\n \"変数\",\n // Russian\n \"функция\",\n \"класс\",\n \"импорт\",\n \"определ\",\n \"запрос\",\n \"асинхронный\",\n \"ожидать\",\n \"константа\",\n \"переменная\",\n \"вернуть\",\n // German\n \"funktion\",\n \"klasse\",\n \"importieren\",\n \"definieren\",\n \"abfrage\",\n \"asynchron\",\n \"erwarten\",\n \"konstante\",\n \"variable\",\n \"zurückgeben\",\n // Spanish\n \"función\",\n \"clase\",\n \"importar\",\n \"definir\",\n \"consulta\",\n \"asíncrono\",\n \"esperar\",\n \"constante\",\n \"variable\",\n \"retornar\",\n // Portuguese\n \"função\",\n \"classe\",\n \"importar\",\n \"definir\",\n \"consulta\",\n \"assíncrono\",\n \"aguardar\",\n \"constante\",\n \"variável\",\n \"retornar\",\n // Korean\n \"함수\",\n \"클래스\",\n \"가져오기\",\n \"정의\",\n \"쿼리\",\n \"비동기\",\n \"대기\",\n \"상수\",\n \"변수\",\n \"반환\",\n // Arabic\n \"دالة\",\n \"فئة\",\n \"استيراد\",\n \"تعريف\",\n \"استعلام\",\n \"غير متزامن\",\n \"انتظار\",\n \"ثابت\",\n \"متغير\",\n \"إرجاع\",\n ],\n reasoningKeywords: [\n // English\n \"prove\",\n \"theorem\",\n \"derive\",\n \"step by step\",\n \"chain of thought\",\n \"formally\",\n \"mathematical\",\n \"proof\",\n \"logically\",\n // Chinese\n \"证明\",\n \"定理\",\n \"推导\",\n \"逐步\",\n \"思维链\",\n \"形式化\",\n \"数学\",\n \"逻辑\",\n // Japanese\n \"証明\",\n \"定理\",\n \"導出\",\n \"ステップバイステップ\",\n \"論理的\",\n // Russian\n \"доказать\",\n \"докажи\",\n \"доказательств\",\n \"теорема\",\n \"вывести\",\n \"шаг за шагом\",\n \"пошагово\",\n \"поэтапно\",\n \"цепочка рассуждений\",\n \"рассуждени\",\n \"формально\",\n \"математически\",\n \"логически\",\n // German\n \"beweisen\",\n \"beweis\",\n \"theorem\",\n \"ableiten\",\n \"schritt für schritt\",\n \"gedankenkette\",\n \"formal\",\n \"mathematisch\",\n \"logisch\",\n // Spanish\n \"demostrar\",\n \"teorema\",\n \"derivar\",\n \"paso a paso\",\n \"cadena de pensamiento\",\n \"formalmente\",\n \"matemático\",\n \"prueba\",\n \"lógicamente\",\n // Portuguese\n \"provar\",\n \"teorema\",\n \"derivar\",\n \"passo a passo\",\n \"cadeia de pensamento\",\n \"formalmente\",\n \"matemático\",\n \"prova\",\n \"logicamente\",\n // Korean\n \"증명\",\n \"정리\",\n \"도출\",\n \"단계별\",\n \"사고의 연쇄\",\n \"형식적\",\n \"수학적\",\n \"논리적\",\n // Arabic\n \"إثبات\",\n \"نظرية\",\n \"اشتقاق\",\n \"خطوة بخطوة\",\n \"سلسلة التفكير\",\n \"رسمياً\",\n \"رياضي\",\n \"برهان\",\n \"منطقياً\",\n ],\n simpleKeywords: [\n // English\n \"what is\",\n \"define\",\n \"translate\",\n \"hello\",\n \"yes or no\",\n \"capital of\",\n \"how old\",\n \"who is\",\n \"when was\",\n // Chinese\n \"什么是\",\n \"定义\",\n \"翻译\",\n \"你好\",\n \"是否\",\n \"首都\",\n \"多大\",\n \"谁是\",\n \"何时\",\n // Japanese\n \"とは\",\n \"定義\",\n \"翻訳\",\n \"こんにちは\",\n \"はいかいいえ\",\n \"首都\",\n \"誰\",\n // Russian\n \"что такое\",\n \"определение\",\n \"перевести\",\n \"переведи\",\n \"привет\",\n \"да или нет\",\n \"столица\",\n \"сколько лет\",\n \"кто такой\",\n \"когда\",\n \"объясни\",\n // German\n \"was ist\",\n \"definiere\",\n \"übersetze\",\n \"hallo\",\n \"ja oder nein\",\n \"hauptstadt\",\n \"wie alt\",\n \"wer ist\",\n \"wann\",\n \"erkläre\",\n // Spanish\n \"qué es\",\n \"definir\",\n \"traducir\",\n \"hola\",\n \"sí o no\",\n \"capital de\",\n \"cuántos años\",\n \"quién es\",\n \"cuándo\",\n // Portuguese\n \"o que é\",\n \"definir\",\n \"traduzir\",\n \"olá\",\n \"sim ou não\",\n \"capital de\",\n \"quantos anos\",\n \"quem é\",\n \"quando\",\n // Korean\n \"무엇\",\n \"정의\",\n \"번역\",\n \"안녕하세요\",\n \"예 또는 아니오\",\n \"수도\",\n \"누구\",\n \"언제\",\n // Arabic\n \"ما هو\",\n \"تعريف\",\n \"ترجم\",\n \"مرحبا\",\n \"نعم أو لا\",\n \"عاصمة\",\n \"من هو\",\n \"متى\",\n ],\n technicalKeywords: [\n // English\n \"algorithm\",\n \"optimize\",\n \"architecture\",\n \"distributed\",\n \"kubernetes\",\n \"microservice\",\n \"database\",\n \"infrastructure\",\n // Chinese\n \"算法\",\n \"优化\",\n \"架构\",\n \"分布式\",\n \"微服务\",\n \"数据库\",\n \"基础设施\",\n // Japanese\n \"アルゴリズム\",\n \"最適化\",\n \"アーキテクチャ\",\n \"分散\",\n \"マイクロサービス\",\n \"データベース\",\n // Russian\n \"алгоритм\",\n \"оптимизировать\",\n \"оптимизаци\",\n \"оптимизируй\",\n \"архитектура\",\n \"распределённый\",\n \"микросервис\",\n \"база данных\",\n \"инфраструктура\",\n // German\n \"algorithmus\",\n \"optimieren\",\n \"architektur\",\n \"verteilt\",\n \"kubernetes\",\n \"mikroservice\",\n \"datenbank\",\n \"infrastruktur\",\n // Spanish\n \"algoritmo\",\n \"optimizar\",\n \"arquitectura\",\n \"distribuido\",\n \"microservicio\",\n \"base de datos\",\n \"infraestructura\",\n // Portuguese\n \"algoritmo\",\n \"otimizar\",\n \"arquitetura\",\n \"distribuído\",\n \"microsserviço\",\n \"banco de dados\",\n \"infraestrutura\",\n // Korean\n \"알고리즘\",\n \"최적화\",\n \"아키텍처\",\n \"분산\",\n \"마이크로서비스\",\n \"데이터베이스\",\n \"인프라\",\n // Arabic\n \"خوارزمية\",\n \"تحسين\",\n \"بنية\",\n \"موزع\",\n \"خدمة مصغرة\",\n \"قاعدة بيانات\",\n \"بنية تحتية\",\n ],\n creativeKeywords: [\n // English\n \"story\",\n \"poem\",\n \"compose\",\n \"brainstorm\",\n \"creative\",\n \"imagine\",\n \"write a\",\n // Chinese\n \"故事\",\n \"诗\",\n \"创作\",\n \"头脑风暴\",\n \"创意\",\n \"想象\",\n \"写一个\",\n // Japanese\n \"物語\",\n \"詩\",\n \"作曲\",\n \"ブレインストーム\",\n \"創造的\",\n \"想像\",\n // Russian\n \"история\",\n \"рассказ\",\n \"стихотворение\",\n \"сочинить\",\n \"сочини\",\n \"мозговой штурм\",\n \"творческий\",\n \"представить\",\n \"придумай\",\n \"напиши\",\n // German\n \"geschichte\",\n \"gedicht\",\n \"komponieren\",\n \"brainstorming\",\n \"kreativ\",\n \"vorstellen\",\n \"schreibe\",\n \"erzählung\",\n // Spanish\n \"historia\",\n \"poema\",\n \"componer\",\n \"lluvia de ideas\",\n \"creativo\",\n \"imaginar\",\n \"escribe\",\n // Portuguese\n \"história\",\n \"poema\",\n \"compor\",\n \"criativo\",\n \"imaginar\",\n \"escreva\",\n // Korean\n \"이야기\",\n \"시\",\n \"작곡\",\n \"브레인스토밍\",\n \"창의적\",\n \"상상\",\n \"작성\",\n // Arabic\n \"قصة\",\n \"قصيدة\",\n \"تأليف\",\n \"عصف ذهني\",\n \"إبداعي\",\n \"تخيل\",\n \"اكتب\",\n ],\n\n // New dimension keyword lists (multilingual)\n imperativeVerbs: [\n // English\n \"build\",\n \"create\",\n \"implement\",\n \"design\",\n \"develop\",\n \"construct\",\n \"generate\",\n \"deploy\",\n \"configure\",\n \"set up\",\n // Chinese\n \"构建\",\n \"创建\",\n \"实现\",\n \"设计\",\n \"开发\",\n \"生成\",\n \"部署\",\n \"配置\",\n \"设置\",\n // Japanese\n \"構築\",\n \"作成\",\n \"実装\",\n \"設計\",\n \"開発\",\n \"生成\",\n \"デプロイ\",\n \"設定\",\n // Russian\n \"построить\",\n \"построй\",\n \"создать\",\n \"создай\",\n \"реализовать\",\n \"реализуй\",\n \"спроектировать\",\n \"разработать\",\n \"разработай\",\n \"сконструировать\",\n \"сгенерировать\",\n \"сгенерируй\",\n \"развернуть\",\n \"разверни\",\n \"настроить\",\n \"настрой\",\n // German\n \"erstellen\",\n \"bauen\",\n \"implementieren\",\n \"entwerfen\",\n \"entwickeln\",\n \"konstruieren\",\n \"generieren\",\n \"bereitstellen\",\n \"konfigurieren\",\n \"einrichten\",\n // Spanish\n \"construir\",\n \"crear\",\n \"implementar\",\n \"diseñar\",\n \"desarrollar\",\n \"generar\",\n \"desplegar\",\n \"configurar\",\n // Portuguese\n \"construir\",\n \"criar\",\n \"implementar\",\n \"projetar\",\n \"desenvolver\",\n \"gerar\",\n \"implantar\",\n \"configurar\",\n // Korean\n \"구축\",\n \"생성\",\n \"구현\",\n \"설계\",\n \"개발\",\n \"배포\",\n \"설정\",\n // Arabic\n \"بناء\",\n \"إنشاء\",\n \"تنفيذ\",\n \"تصميم\",\n \"تطوير\",\n \"توليد\",\n \"نشر\",\n \"إعداد\",\n ],\n constraintIndicators: [\n // English\n \"under\",\n \"at most\",\n \"at least\",\n \"within\",\n \"no more than\",\n \"o(\",\n \"maximum\",\n \"minimum\",\n \"limit\",\n \"budget\",\n // Chinese\n \"不超过\",\n \"至少\",\n \"最多\",\n \"在内\",\n \"最大\",\n \"最小\",\n \"限制\",\n \"预算\",\n // Japanese\n \"以下\",\n \"最大\",\n \"最小\",\n \"制限\",\n \"予算\",\n // Russian\n \"не более\",\n \"не менее\",\n \"как минимум\",\n \"в пределах\",\n \"максимум\",\n \"минимум\",\n \"ограничение\",\n \"бюджет\",\n // German\n \"höchstens\",\n \"mindestens\",\n \"innerhalb\",\n \"nicht mehr als\",\n \"maximal\",\n \"minimal\",\n \"grenze\",\n \"budget\",\n // Spanish\n \"como máximo\",\n \"al menos\",\n \"dentro de\",\n \"no más de\",\n \"máximo\",\n \"mínimo\",\n \"límite\",\n \"presupuesto\",\n // Portuguese\n \"no máximo\",\n \"pelo menos\",\n \"dentro de\",\n \"não mais que\",\n \"máximo\",\n \"mínimo\",\n \"limite\",\n \"orçamento\",\n // Korean\n \"이하\",\n \"이상\",\n \"최대\",\n \"최소\",\n \"제한\",\n \"예산\",\n // Arabic\n \"على الأكثر\",\n \"على الأقل\",\n \"ضمن\",\n \"لا يزيد عن\",\n \"أقصى\",\n \"أدنى\",\n \"حد\",\n \"ميزانية\",\n ],\n outputFormatKeywords: [\n // English\n \"json\",\n \"yaml\",\n \"xml\",\n \"table\",\n \"csv\",\n \"markdown\",\n \"schema\",\n \"format as\",\n \"structured\",\n // Chinese\n \"表格\",\n \"格式化为\",\n \"结构化\",\n // Japanese\n \"テーブル\",\n \"フォーマット\",\n \"構造化\",\n // Russian\n \"таблица\",\n \"форматировать как\",\n \"структурированный\",\n // German\n \"tabelle\",\n \"formatieren als\",\n \"strukturiert\",\n // Spanish\n \"tabla\",\n \"formatear como\",\n \"estructurado\",\n // Portuguese\n \"tabela\",\n \"formatar como\",\n \"estruturado\",\n // Korean\n \"테이블\",\n \"형식\",\n \"구조화\",\n // Arabic\n \"جدول\",\n \"تنسيق\",\n \"منظم\",\n ],\n referenceKeywords: [\n // English\n \"above\",\n \"below\",\n \"previous\",\n \"following\",\n \"the docs\",\n \"the api\",\n \"the code\",\n \"earlier\",\n \"attached\",\n // Chinese\n \"上面\",\n \"下面\",\n \"之前\",\n \"接下来\",\n \"文档\",\n \"代码\",\n \"附件\",\n // Japanese\n \"上記\",\n \"下記\",\n \"前の\",\n \"次の\",\n \"ドキュメント\",\n \"コード\",\n // Russian\n \"выше\",\n \"ниже\",\n \"предыдущий\",\n \"следующий\",\n \"документация\",\n \"код\",\n \"ранее\",\n \"вложение\",\n // German\n \"oben\",\n \"unten\",\n \"vorherige\",\n \"folgende\",\n \"dokumentation\",\n \"der code\",\n \"früher\",\n \"anhang\",\n // Spanish\n \"arriba\",\n \"abajo\",\n \"anterior\",\n \"siguiente\",\n \"documentación\",\n \"el código\",\n \"adjunto\",\n // Portuguese\n \"acima\",\n \"abaixo\",\n \"anterior\",\n \"seguinte\",\n \"documentação\",\n \"o código\",\n \"anexo\",\n // Korean\n \"위\",\n \"아래\",\n \"이전\",\n \"다음\",\n \"문서\",\n \"코드\",\n \"첨부\",\n // Arabic\n \"أعلاه\",\n \"أدناه\",\n \"السابق\",\n \"التالي\",\n \"الوثائق\",\n \"الكود\",\n \"مرفق\",\n ],\n negationKeywords: [\n // English\n \"don't\",\n \"do not\",\n \"avoid\",\n \"never\",\n \"without\",\n \"except\",\n \"exclude\",\n \"no longer\",\n // Chinese\n \"不要\",\n \"避免\",\n \"从不\",\n \"没有\",\n \"除了\",\n \"排除\",\n // Japanese\n \"しないで\",\n \"避ける\",\n \"決して\",\n \"なしで\",\n \"除く\",\n // Russian\n \"не делай\",\n \"не надо\",\n \"нельзя\",\n \"избегать\",\n \"никогда\",\n \"без\",\n \"кроме\",\n \"исключить\",\n \"больше не\",\n // German\n \"nicht\",\n \"vermeide\",\n \"niemals\",\n \"ohne\",\n \"außer\",\n \"ausschließen\",\n \"nicht mehr\",\n // Spanish\n \"no hagas\",\n \"evitar\",\n \"nunca\",\n \"sin\",\n \"excepto\",\n \"excluir\",\n // Portuguese\n \"não faça\",\n \"evitar\",\n \"nunca\",\n \"sem\",\n \"exceto\",\n \"excluir\",\n // Korean\n \"하지 마\",\n \"피하다\",\n \"절대\",\n \"없이\",\n \"제외\",\n // Arabic\n \"لا تفعل\",\n \"تجنب\",\n \"أبداً\",\n \"بدون\",\n \"باستثناء\",\n \"استبعاد\",\n ],\n domainSpecificKeywords: [\n // English\n \"quantum\",\n \"fpga\",\n \"vlsi\",\n \"risc-v\",\n \"asic\",\n \"photonics\",\n \"genomics\",\n \"proteomics\",\n \"topological\",\n \"homomorphic\",\n \"zero-knowledge\",\n \"lattice-based\",\n // Chinese\n \"量子\",\n \"光子学\",\n \"基因组学\",\n \"蛋白质组学\",\n \"拓扑\",\n \"同态\",\n \"零知识\",\n \"格密码\",\n // Japanese\n \"量子\",\n \"フォトニクス\",\n \"ゲノミクス\",\n \"トポロジカル\",\n // Russian\n \"квантовый\",\n \"фотоника\",\n \"геномика\",\n \"протеомика\",\n \"топологический\",\n \"гомоморфный\",\n \"с нулевым разглашением\",\n \"на основе решёток\",\n // German\n \"quanten\",\n \"photonik\",\n \"genomik\",\n \"proteomik\",\n \"topologisch\",\n \"homomorph\",\n \"zero-knowledge\",\n \"gitterbasiert\",\n // Spanish\n \"cuántico\",\n \"fotónica\",\n \"genómica\",\n \"proteómica\",\n \"topológico\",\n \"homomórfico\",\n // Portuguese\n \"quântico\",\n \"fotônica\",\n \"genômica\",\n \"proteômica\",\n \"topológico\",\n \"homomórfico\",\n // Korean\n \"양자\",\n \"포토닉스\",\n \"유전체학\",\n \"위상\",\n \"동형\",\n // Arabic\n \"كمي\",\n \"ضوئيات\",\n \"جينوميات\",\n \"طوبولوجي\",\n \"تماثلي\",\n ],\n\n // Agentic task keywords - file ops, execution, multi-step, iterative work\n // Pruned: removed overly common words like \"then\", \"first\", \"run\", \"test\", \"build\"\n agenticTaskKeywords: [\n // English - File operations (clearly agentic)\n \"read file\",\n \"read the file\",\n \"look at\",\n \"check the\",\n \"open the\",\n \"edit\",\n \"modify\",\n \"update the\",\n \"change the\",\n \"write to\",\n \"create file\",\n // English - Execution (specific commands only)\n \"execute\",\n \"deploy\",\n \"install\",\n \"npm\",\n \"pip\",\n \"compile\",\n // English - Multi-step patterns (specific only)\n \"after that\",\n \"and also\",\n \"once done\",\n \"step 1\",\n \"step 2\",\n // English - Iterative work\n \"fix\",\n \"debug\",\n \"until it works\",\n \"keep trying\",\n \"iterate\",\n \"make sure\",\n \"verify\",\n \"confirm\",\n // Chinese (keep specific ones)\n \"读取文件\",\n \"查看\",\n \"打开\",\n \"编辑\",\n \"修改\",\n \"更新\",\n \"创建\",\n \"执行\",\n \"部署\",\n \"安装\",\n \"第一步\",\n \"第二步\",\n \"修复\",\n \"调试\",\n \"直到\",\n \"确认\",\n \"验证\",\n // Spanish\n \"leer archivo\",\n \"editar\",\n \"modificar\",\n \"actualizar\",\n \"ejecutar\",\n \"desplegar\",\n \"instalar\",\n \"paso 1\",\n \"paso 2\",\n \"arreglar\",\n \"depurar\",\n \"verificar\",\n // Portuguese\n \"ler arquivo\",\n \"editar\",\n \"modificar\",\n \"atualizar\",\n \"executar\",\n \"implantar\",\n \"instalar\",\n \"passo 1\",\n \"passo 2\",\n \"corrigir\",\n \"depurar\",\n \"verificar\",\n // Korean\n \"파일 읽기\",\n \"편집\",\n \"수정\",\n \"업데이트\",\n \"실행\",\n \"배포\",\n \"설치\",\n \"단계 1\",\n \"단계 2\",\n \"디버그\",\n \"확인\",\n // Arabic\n \"قراءة ملف\",\n \"تحرير\",\n \"تعديل\",\n \"تحديث\",\n \"تنفيذ\",\n \"نشر\",\n \"تثبيت\",\n \"الخطوة 1\",\n \"الخطوة 2\",\n \"إصلاح\",\n \"تصحيح\",\n \"تحقق\",\n ],\n\n // Dimension weights (sum to 1.0)\n dimensionWeights: {\n tokenCount: 0.08,\n codePresence: 0.15,\n reasoningMarkers: 0.18,\n technicalTerms: 0.1,\n creativeMarkers: 0.05,\n simpleIndicators: 0.02, // Reduced from 0.12 to make room for agenticTask\n multiStepPatterns: 0.12,\n questionComplexity: 0.05,\n imperativeVerbs: 0.03,\n constraintCount: 0.04,\n outputFormat: 0.03,\n referenceComplexity: 0.02,\n negationComplexity: 0.01,\n domainSpecificity: 0.02,\n agenticTask: 0.04, // Reduced - agentic signals influence tier selection, not dominate it\n },\n\n // Tier boundaries on weighted score axis\n tierBoundaries: {\n simpleMedium: 0.0,\n mediumComplex: 0.3, // Raised from 0.18 - prevent simple tasks from reaching expensive COMPLEX tier\n complexReasoning: 0.5, // Raised from 0.4 - reserve for true reasoning tasks\n },\n\n // Sigmoid steepness for confidence calibration\n confidenceSteepness: 12,\n // Below this confidence → ambiguous (null tier)\n confidenceThreshold: 0.7,\n },\n\n // ─── Tier chains ───\n //\n // Catalog refresh 2026-08-29 (V3.5). Every chain below names only models\n // the public catalog lists (GET https://blockrun.ai/api/v1/models). Ids the\n // gateway withholds (`hidden: true`) — kimi-k2.5/k2.6/k2.7, the grok-4-fast\n // and grok-4-1-fast pairs, grok-4-0709, claude-opus-4.6, gemini-3-pro-preview,\n // the whole `free/*` namespace — were removed everywhere, including fallback\n // rungs, so a routed model is always one a user can find on blockrun.ai/models.\n //\n // Primaries moved only where portfolio.ts already carries calibration\n // evidence for the successor (Sonnet 5 over Sonnet 4.6, GPT-5 Mini for\n // agentic MEDIUM, Gemini 3.5 Flash where Kimi K2.7 was). Newcomers with no\n // trajectory evidence yet (gemini-3.6-flash, glm-5.3, glm-5.3-flash,\n // gpt-5.6-luna, grok-4.3, minimax-m3, qwen3.7-plus) enter as fallback rungs;\n // promotion waits for a calibration run, because version recency is not a\n // quality signal.\n //\n // Latency figures in comments are the 2026-08-29 gateway probe\n // (model-profiles.generated.json); prices are the catalog list.\n\n // Auto (balanced) tier configs - current default smart routing\n tiers: {\n SIMPLE: {\n primary: \"google/gemini-2.5-flash\", // $0.30/$2.50 — 60% retention (best) in the 2026-03 run; still the fastest quality answer\n fallback: [\n \"google/gemini-3-flash-preview\", // $0.50/$3 — GPQA 5/6 in the 2026-07 calibration\n \"google/gemini-3.5-flash-lite\", // $0.30/$2.50, 1M ctx, thinking mode — same price as 2.5 Flash, newer generation\n \"deepseek/deepseek-chat\", // $0.14/$0.28, 1M ctx\n \"google/gemini-3.1-flash-lite\", // $0.25/$1.50, 1M ctx\n \"openai/gpt-5.6-luna\", // $0.20/$1.20, 1M ctx — GPT-5.6 cost tier (cut 2026-07-30)\n \"openai/gpt-5.4-nano\", // $0.20/$1.25, 1M ctx\n \"google/gemini-2.5-flash-lite\", // $0.10/$0.40\n \"nvidia/nemotron-3.5-lightning\", // FREE backstop — NVIDIA free tier (probed 2026-08-30)\n ],\n },\n MEDIUM: {\n // Was moonshot/kimi-k2.7 (hidden 2026-08). Gemini 3.5 Flash is the\n // calibrated successor: MGSM 5/5, GPQA 4/6, extraction band (portfolio.ts).\n primary: \"google/gemini-3.5-flash\", // $1.50/$9, 1M ctx, vision + tools\n fallback: [\n \"google/gemini-3.6-flash\", // $1.50/$7.50 — newest Flash, output 17% cheaper than 3.5; awaiting calibration\n \"zai/glm-5.3-flash\", // $0.15/$0.50, 1M ctx, vision + tools verified live 2026-08-27\n \"openai/gpt-5.6-terra\", // $2/$12, 1M ctx — GPT-5.6 balanced tier\n \"google/gemini-3-flash-preview\", // $0.50/$3\n \"deepseek/deepseek-chat\", // $0.14/$0.28\n \"google/gemini-2.5-flash\", // $0.30/$2.50\n \"minimax/minimax-m3\", // $0.30/$1.20, 1M ctx\n \"google/gemini-3.1-flash-lite\", // $0.25/$1.50\n \"openai/gpt-5.6-luna\", // $0.20/$1.20\n \"google/gemini-2.5-flash-lite\", // $0.10/$0.40\n ],\n },\n COMPLEX: {\n primary: \"google/gemini-3.1-pro\", // $2/$12 — proven long-context flagship (portfolio.ts long_context lead)\n fallback: [\n \"google/gemini-3.6-flash\", // $1.50/$7.50 — Pro-level quality at Flash price (Google's claim; uncalibrated here)\n \"google/gemini-3.5-flash\", // $1.50/$9 — calibrated\n \"anthropic/claude-sonnet-5\", // $3/$15 — near-Opus quality, tau2 + Terminal-Bench calibrated\n \"xai/grok-4.5\", // $2.50/$9 — 503-resistant, independent infra (was grok-4-0709, now hidden)\n \"google/gemini-2.5-pro\", // $1.25/$10\n \"anthropic/claude-sonnet-4.6\", // $3/$15\n \"openai/gpt-5.6-terra\", // $2/$12 — GPT-5.6 balanced tier (Sol excluded: #202)\n \"openai/gpt-5.5\", // $5/$30 — prior OpenAI flagship\n \"openai/gpt-5.4\", // $2.50/$15 — previous flagship, benchmarked\n \"zai/glm-5.3\", // $1.40/$4.40, 1M ctx, always-on thinking — verified live 2026-08-19\n \"moonshot/kimi-k3\", // $3/$15, 1M ctx — Moonshot flagship (K2.7 successor)\n \"deepseek/deepseek-v4-pro\", // $0.435/$0.87 — strongest open-weight reasoner\n \"deepseek/deepseek-chat\", // $0.14/$0.28 — cheap last resort\n \"google/gemini-2.5-flash\", // $0.30/$2.50\n ],\n },\n REASONING: {\n // Was xai/grok-4-1-fast-reasoning ($0.20/$0.50, hidden 2026-08). DeepSeek\n // Reasoner is the cheapest listed reasoner at the same 1M context.\n primary: \"deepseek/deepseek-reasoner\", // $0.14/$0.28, 1M ctx\n fallback: [\n \"deepseek/deepseek-v4-pro\", // $0.435/$0.87 — calibrated reasoning band 0.95\n \"xai/grok-4.3\", // $1.50/$4, 1M ctx — xAI reasoning model, vision\n \"qwen/qwen3.7-plus\", // $0.32/$1.28, 1M ctx — reasoning; needs a generous max_tokens (thinking is billed)\n \"google/gemini-3.5-flash\", // $1.50/$9 — MGSM 5/5\n \"openai/o4-mini\", // $1.10/$4.40\n \"openai/o3\", // $2/$8\n ],\n },\n },\n\n // Eco tier configs - absolute cheapest (blockrun/eco)\n ecoTiers: {\n SIMPLE: {\n primary: \"nvidia/nemotron-3.5-lightning\", // FREE — NVIDIA free tier flagship, 1M ctx\n fallback: [\n // Was nvidia/nemotron-3-nano-30b until blockrun delisted it on 2026-09-08\n // (NVIDIA deprovisioned it for the account — a structured per-account\n // 404). nano-omni is blockrun's own redirect target for that id, so this\n // follows the same rule as the head: the router and the gateway name the\n // same model.\n \"nvidia/nemotron-3-nano-omni-30b-a3b-reasoning\", // FREE — nano-30b's successor, 256K ctx\n // The free head keeps rotting with NVIDIA's hosting (deepseek-v4-flash\n // 410 2026-08-12, seed-oss-36b 410 2026-08-03, gpt-oss-120b/20b 400\n // 2026-08-21, and on 2026-08-30 FOUR of the five visible free models at\n // once — step-3.7-flash, nemotron-nano-9b-v2 and nemotron-nano-12b-v2-vl\n // all 410, mistral-nemotron hung). Each retirement retargets the two\n // free rungs to the current free tier; the paid rungs below never move.\n // The head follows blockrun's own redirect of the model it replaces, so\n // the router and the gateway never name different models.\n \"google/gemini-2.5-flash-lite\", // $0.10/$0.40 — cheapest paid rung\n \"zai/glm-5.3-flash\", // $0.15/$0.50, 1M ctx, vision + tools\n \"openai/gpt-5.6-luna\", // $0.20/$1.20, 1M ctx\n \"openai/gpt-5.4-nano\", // $0.20/$1.25\n \"google/gemini-3.1-flash-lite\", // $0.25/$1.50\n ],\n },\n MEDIUM: {\n primary: \"zai/glm-5.3-flash\", // $0.15/$0.50, 1M ctx, vision + tools verified live — cheapest full-capability model\n fallback: [\n \"deepseek/deepseek-chat\", // $0.14/$0.28\n \"google/gemini-3.1-flash-lite\", // $0.25/$1.50\n \"openai/gpt-5.6-luna\", // $0.20/$1.20\n \"openai/gpt-5.4-nano\", // $0.20/$1.25\n \"google/gemini-2.5-flash-lite\", // $0.10/$0.40\n \"google/gemini-2.5-flash\", // $0.30/$2.50\n ],\n },\n COMPLEX: {\n primary: \"zai/glm-5.3-flash\", // $0.15/$0.50, 1M ctx\n fallback: [\n \"deepseek/deepseek-chat\", // $0.14/$0.28, 1M ctx\n \"minimax/minimax-m3\", // $0.30/$1.20, 1M ctx\n \"deepseek/deepseek-v4-pro\", // $0.435/$0.87\n \"google/gemini-3.1-flash-lite\", // $0.25/$1.50\n \"google/gemini-2.5-flash\", // $0.30/$2.50\n ],\n },\n REASONING: {\n primary: \"deepseek/deepseek-reasoner\", // $0.14/$0.28, 1M ctx — cheapest listed reasoner\n fallback: [\n \"deepseek/deepseek-v4-pro\", // $0.435/$0.87\n \"qwen/qwen3.7-plus\", // $0.32/$1.28 — reasoning\n \"minimax/minimax-m3\", // $0.30/$1.20 — reasoning + coding\n \"zai/glm-5.3-flash\", // $0.15/$0.50 — reasoning tokens alongside content\n ],\n },\n },\n\n // Premium tier configs - best quality (blockrun/premium)\n // codex=complex coding, flash=simple coding, sonnet=reasoning/instructions, fable/opus=architecture/PM/audits\n premiumTiers: {\n SIMPLE: {\n // Was moonshot/kimi-k2.7 (hidden 2026-08).\n primary: \"google/gemini-3.5-flash\", // $1.50/$9, 1M ctx, vision + tools — calibrated\n fallback: [\n \"google/gemini-3.6-flash\", // $1.50/$7.50 — newest Flash\n \"anthropic/claude-haiku-4.5\", // $1/$5\n \"zai/glm-5.3\", // $1.40/$4.40, 1M ctx\n \"google/gemini-2.5-flash\", // $0.30/$2.50\n \"google/gemini-3.5-flash-lite\", // $0.30/$2.50\n \"deepseek/deepseek-chat\", // $0.14/$0.28\n ],\n },\n MEDIUM: {\n primary: \"openai/gpt-5.3-codex\", // $1.75/$14 - 400K context, 128K output — code_edit/debug lead (portfolio.ts)\n fallback: [\n \"anthropic/claude-sonnet-5\", // $3/$15 — code_agent band 0.98\n \"moonshot/kimi-k3\", // $3/$15, 1M ctx — Moonshot flagship\n \"zai/glm-5.3\", // $1.40/$4.40 — long-horizon coding\n \"google/gemini-3.6-flash\", // $1.50/$7.50\n \"google/gemini-3.5-flash\", // $1.50/$9\n \"google/gemini-2.5-pro\", // $1.25/$10\n \"xai/grok-4.5\", // $2.50/$9\n \"anthropic/claude-sonnet-4.6\", // $3/$15\n \"openai/gpt-5.6-terra\", // $2/$12\n ],\n },\n COMPLEX: {\n // fable-5 was promoted here 2026-06-11, force-reverted 2026-06-13 when Anthropic\n // withdrew the offer, and restored 2026-07-14 now that BlockRun has relisted it.\n primary: \"anthropic/claude-fable-5\", // Best quality for complex tasks — Mythos-class flagship above Opus ($10/$50, 1M ctx, always-on thinking)\n // Fallback chain de-Gemini'd 2026-04-22: when Anthropic 503s, Gemini is\n // also prone to \"high demand\" 503s (correlated failure — everyone falls\n // back to Google at the same time). Prefer in-family → xAI → Moonshot →\n // OpenAI flagship → Z.AI → DeepSeek → NVIDIA free instead.\n fallback: [\n \"anthropic/claude-opus-5\", // in-family hot swap first (half the price, 1M ctx + adaptive thinking)\n \"anthropic/claude-opus-4.8\", // in-family hot swap (identical cost to 5)\n \"anthropic/claude-opus-4.7\", // in-family hot swap (identical cost to 4.8)\n \"anthropic/claude-sonnet-5\", // Sonnet-tier drop-down, near-Opus quality\n \"anthropic/claude-sonnet-4.6\",\n \"xai/grok-4.5\", // xAI flagship — 503-resistant, direct-xAI SKU\n \"moonshot/kimi-k3\", // Moonshot flagship, independent infra\n \"openai/gpt-5.6-terra\", // GPT-5.6 balanced tier — stable (Sol excluded: #202)\n \"openai/gpt-5.5\", // Prior OpenAI flagship — 1M+ ctx, native agent + computer use\n \"openai/gpt-5.4\", // Previous flagship (slow but stable, benchmarked at 6,213ms)\n \"openai/gpt-5.3-codex\",\n \"zai/glm-5.3\", // Z.AI flagship, 1M ctx\n \"deepseek/deepseek-v4-pro\", // strongest open-weight reasoner\n \"deepseek/deepseek-chat\", // Cheap, reliable\n \"nvidia/nemotron-3.5-lightning\", // NVIDIA free ultimate backstop\n ],\n },\n REASONING: {\n // Sonnet 5 promoted over Sonnet 4.6 (same price; reasoning band 0.98 for both,\n // plus Sonnet 5's tau2/BrowseComp trajectory evidence).\n primary: \"anthropic/claude-sonnet-5\", // $3/$15, 1M ctx, adaptive thinking\n fallback: [\n \"anthropic/claude-sonnet-4.6\", // in-family hot swap — same cost\n \"anthropic/claude-opus-5\", // Newest flagship Opus w/ adaptive thinking\n \"anthropic/claude-opus-4.8\", // Prior flagship Opus — identical cost to 5\n \"anthropic/claude-opus-4.7\", // Flagship Opus w/ adaptive thinking\n \"xai/grok-4.5\", // reasoning band 0.94\n \"deepseek/deepseek-v4-pro\", // reasoning band 0.95\n \"xai/grok-4.3\", // $1.50/$4 — xAI reasoning model\n \"openai/o4-mini\", // $1.10/$4.40\n \"openai/o3\", // $2/$8\n ],\n },\n },\n\n // Agentic tier configs - models that excel at multi-step autonomous tasks\n agenticTiers: {\n SIMPLE: {\n primary: \"openai/gpt-4o-mini\", // $0.15/$0.60 - best tool compliance at lowest cost\n fallback: [\n \"openai/gpt-5.6-luna\", // $0.20/$1.20 — lightweight agentic tier of GPT-5.6\n \"zai/glm-5.3-flash\", // $0.15/$0.50 — tool calls verified live 2026-08-27\n \"anthropic/claude-haiku-4.5\", // $1/$5\n \"google/gemini-2.5-flash\", // $0.30/$2.50\n ],\n },\n MEDIUM: {\n // Was moonshot/kimi-k2.7 (hidden 2026-08). GPT-5 Mini carries the\n // Terminal-Bench and tau2 trajectory evidence in portfolio.ts.\n primary: \"openai/gpt-5-mini\", // $0.25/$2 — 4/7 Terminal-Bench, 5/6 tau2 airline\n fallback: [\n \"google/gemini-3.5-flash\", // $1.50/$9 — tool_agent band 0.88\n \"zai/glm-5.3-flash\", // $0.15/$0.50 — tools verified\n \"openai/gpt-5.6-terra\", // $2/$12\n \"openai/gpt-4o-mini\", // $0.15/$0.60 — reliable tool calling\n \"anthropic/claude-haiku-4.5\", // $1/$5\n \"deepseek/deepseek-chat\", // $0.14/$0.28\n \"moonshot/kimi-k3\", // $3/$15 — tool_agent band 0.85\n ],\n },\n COMPLEX: {\n // Sonnet 5 promoted over Sonnet 4.6: tau2 airline + retail reward 1.0,\n // Terminal-Bench safety band lead (portfolio.ts).\n primary: \"anthropic/claude-sonnet-5\", // $3/$15 — best agentic quality per trajectory evidence\n // Fallback chain de-Gemini'd 2026-04-22: Gemini's \"high demand\" 503s\n // correlate with Anthropic outages (everyone falls back together).\n // Prefer 503-resistant providers first.\n fallback: [\n \"anthropic/claude-sonnet-4.6\", // in-family hot swap — same cost\n \"anthropic/claude-opus-5\", // Newest flagship Opus — in-family hot swap\n \"anthropic/claude-opus-4.8\", // Prior flagship Opus — identical cost to 5\n \"anthropic/claude-opus-4.7\", // Flagship Opus — in-family hot swap\n \"xai/grok-4.5\", // xAI flagship — strong tool use, independent infra\n \"moonshot/kimi-k3\", // Moonshot flagship — independent infra\n \"openai/gpt-5.6-terra\", // GPT-5.6 balanced tier — stable (Sol excluded: #202)\n \"openai/gpt-5.5\", // Prior flagship — native agent + computer use (exactly the agentic-tier use case)\n \"openai/gpt-5.4\", // Previous flagship — reliable\n \"openai/gpt-5.3-codex\", // code_agent lead\n \"zai/glm-5.3\", // long-horizon coding\n \"deepseek/deepseek-v4-pro\", // retail high-risk 3/3\n \"deepseek/deepseek-chat\", // cheap, reliable\n \"nvidia/nemotron-3.5-lightning\", // NVIDIA free ultimate backstop\n ],\n },\n REASONING: {\n primary: \"anthropic/claude-sonnet-5\", // $3/$15 — strong tool use + adaptive thinking\n fallback: [\n \"anthropic/claude-sonnet-4.6\", // in-family hot swap — same cost\n \"anthropic/claude-opus-5\", // Newest flagship Opus w/ adaptive thinking\n \"anthropic/claude-opus-4.8\", // Prior flagship Opus — identical cost to 5\n \"anthropic/claude-opus-4.7\", // Flagship Opus w/ adaptive thinking\n \"xai/grok-4.5\", // reasoning band 0.94\n \"deepseek/deepseek-v4-pro\", // reasoning band 0.95\n \"deepseek/deepseek-reasoner\", // $0.14/$0.28\n ],\n },\n },\n\n // Time-windowed promotions — auto-applied when active, ignored when expired.\n // The GLM-5.1 launch promo (2026-04-01 → 2026-05-01) was the last entry and\n // has expired; the list is kept empty so the mechanism stays wired.\n promotions: [],\n\n overrides: {\n maxTokensForceComplex: 100_000,\n structuredOutputMinTier: \"MEDIUM\",\n ambiguousDefaultTier: \"MEDIUM\",\n // agenticMode left undefined → auto-detect via tools/agenticScore.\n // Set to `true` to force agentic tiers; `false` to disable them entirely.\n },\n};\n","/**\n * Smart Router Entry Point\n *\n * Classifies requests and routes to the cheapest capable model.\n * Delegates to pluggable RouterStrategy (default: RulesStrategy, <1ms).\n */\n\nimport type { RoutingDecision, RouterOptions } from \"./types.js\";\nimport { getStrategy, registerStrategy } from \"./strategy.js\";\nimport { PortfolioStrategy } from \"./portfolio.js\";\n\n// Register here instead of strategy.ts so PortfolioStrategy can reuse the\n// stable RulesStrategy without introducing a module cycle.\nregisterStrategy(new PortfolioStrategy());\n\n/**\n * Route a request to the cheapest capable model.\n * Delegates to the configured strategy (PortfolioStrategy by default).\n */\nexport function route(\n prompt: string,\n systemPrompt: string | undefined,\n maxOutputTokens: number,\n options: RouterOptions,\n): RoutingDecision {\n const strategy = getStrategy(options.config.strategy ?? \"portfolio\");\n return strategy.route(prompt, systemPrompt, maxOutputTokens, options);\n}\n\nexport { getStrategy, registerStrategy, applyUnavailableModels } from \"./strategy.js\";\nexport { RulesStrategy } from \"./strategy.js\";\nexport { PortfolioStrategy } from \"./portfolio.js\";\nexport { classifyByRules } from \"./rules.js\";\nexport { inferToolRequirement } from \"./tool-intent.js\";\nexport {\n getFallbackChain,\n getFallbackChainFiltered,\n filterByToolCalling,\n filterByVision,\n filterByExcludeList,\n filterCandidatesByCapacity,\n calculateModelCost,\n} from \"./selector.js\";\nexport { DEFAULT_ROUTING_CONFIG } from \"./config.js\";\nexport { DEFAULT_MODEL_CAPABILITIES } from \"./model-capabilities.js\";\nexport { LIVE_MODEL_PROFILES, HISTORICAL_MODEL_PROFILES } from \"./model-profiles.js\";\nexport type {\n RoutingDecision,\n Tier,\n TaskType,\n RoutingConfig,\n RouterOptions,\n RouterStrategy,\n} from \"./types.js\";\nexport type { ModelPricing } from \"./selector.js\";\nexport type { ModelCapabilities } from \"./model-capabilities.js\";\nexport type { ModelPerformanceProfile } from \"./model-profiles.js\";\n"],"mappings":"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CA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA,mBAAmB;AAAA;AAAA,MAEjB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA,gBAAgB;AAAA;AAAA,MAEd;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA,mBAAmB;AAAA;AAAA,MAEjB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA,kBAAkB;AAAA;AAAA,MAEhB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA;AAAA,IAGA,iBAAiB;AAAA;AAAA,MAEf;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA,sBAAsB;AAAA;AAAA,MAEpB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA,sBAAsB;AAAA;AAAA,MAEpB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA,mBAAmB;AAAA;AAAA,MAEjB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA,kBAAkB;AAAA;AAAA,MAEhB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA;AAAA,MACA;AAAA,MACA;AAAA,MA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","names":["confidence","decision","model"]} \ No newline at end of file diff --git a/model-capabilities.test.ts b/model-capabilities.test.ts new file mode 100644 index 0000000..860164c --- /dev/null +++ b/model-capabilities.test.ts @@ -0,0 +1,28 @@ +import { describe, expect, it } from "vitest"; + +import { DEFAULT_MODEL_CAPABILITIES } from "./model-capabilities.js"; + +describe("generated model capability snapshot", () => { + it.each([ + "anthropic/claude-fable-5.1", + "anthropic/claude-opus-5.5", + "anthropic/claude-sonnet-5.5", + "google/gemini-3.8-flash", + "openai/gpt-5.1", + "openai/gpt-6-astra", + "openai/gpt-6-luna", + "openai/gpt-6-sol", + "xai/grok-4.6", + "xai/grok-4.7", + "xiaomi/mimo-v2.5", + ])("accepts a live-probed tool call from %s", (model) => { + expect(DEFAULT_MODEL_CAPABILITIES[model]?.supportsTools).toBe(true); + }); + + it.each([ + "deepseek/deepseek-v4-flash-vision-exp", + "qwen/qwen3.8-flash", + ])("keeps %s out of tool-required routes after an invalid tool response", (model) => { + expect(DEFAULT_MODEL_CAPABILITIES[model]?.supportsTools).toBe(false); + }); +}); diff --git a/model-capabilities.ts b/model-capabilities.ts index c815265..eec99e0 100644 --- a/model-capabilities.ts +++ b/model-capabilities.ts @@ -6,7 +6,7 @@ * product catalog is temporarily unavailable, without importing product code. * * GENERATED by scripts/sync-model-capabilities.mjs from the public catalog - * (GET https://blockrun.ai/api/v1/models) on 2026-10-02; supportsTools comes + * (GET https://blockrun.ai/api/v1/models) on 2026-10-03; supportsTools comes * from a live function-calling probe (scripts/probe-tools.json). Regenerate * rather than editing by hand — a hand edit is overwritten on the next sync. */ @@ -25,10 +25,10 @@ export const DEFAULT_MODEL_CAPABILITIES: Readonly([ ["openai/gpt-4o-mini", { inputPrice: 0.15, outputPrice: 0.6 }], ["deepseek/deepseek-chat", { inputPrice: 0.2, outputPrice: 0.4 }], ["free/seed-oss-36b", { inputPrice: 0, outputPrice: 0 }], + ["anthropic/claude-fable-5.1", { inputPrice: 10, outputPrice: 50 }], + ["anthropic/claude-opus-5.5", { inputPrice: 5, outputPrice: 25 }], + ["anthropic/claude-sonnet-5.5", { inputPrice: 3, outputPrice: 15 }], + ["google/gemini-3.8-flash", { inputPrice: 1, outputPrice: 5 }], + ["openai/gpt-5.1", { inputPrice: 1, outputPrice: 8 }], + ["openai/gpt-6-astra", { inputPrice: 5, outputPrice: 25 }], + ["openai/gpt-6-luna", { inputPrice: 0.2, outputPrice: 1.2 }], + ["openai/gpt-6-sol", { inputPrice: 1.75, outputPrice: 14 }], + ["xai/grok-4.6", { inputPrice: 2, outputPrice: 10 }], + ["xai/grok-4.7", { inputPrice: 2.5, outputPrice: 12 }], + ["xiaomi/mimo-v2.5", { inputPrice: 0.5, outputPrice: 2 }], ]); describe("PortfolioStrategy", () => { @@ -107,6 +118,75 @@ describe("PortfolioStrategy", () => { expect(decision.candidates).toContain("google/gemini-3.5-flash"); }); + it("keeps newly tool-verified catalog models as safe fallbacks without promoting them", () => { + const decision = route("Use lookup_order for order B-42.", undefined, 256, { + config: DEFAULT_ROUTING_CONFIG, + modelPricing: pricing, + routingProfile: "auto", + hasTools: true, + requiresTools: true, + toolCount: 1, + unavailableModels: ["openai/gpt-6-astra"], + }); + + expect(decision.taskType).toBe("tool_agent"); + expect(decision.model).toBe("anthropic/claude-sonnet-5"); + expect(decision.candidates).toEqual( + expect.arrayContaining([ + "anthropic/claude-fable-5.1", + "anthropic/claude-opus-5.5", + "anthropic/claude-sonnet-5.5", + "google/gemini-3.8-flash", + "openai/gpt-5.1", + "openai/gpt-6-luna", + "openai/gpt-6-sol", + "xai/grok-4.6", + "xai/grok-4.7", + "xiaomi/mimo-v2.5", + ]), + ); + expect(decision.candidates).not.toContain("openai/gpt-6-astra"); + }); + + it("does not add tool-only availability fallbacks to an ordinary chat request", () => { + const decision = route("What is the capital of France?", undefined, 256, { + config: DEFAULT_ROUTING_CONFIG, + modelPricing: pricing, + }); + + expect(decision.taskType).toBe("chat"); + expect(decision.candidates).not.toContain("openai/gpt-6-luna"); + expect(decision.candidates).not.toContain("anthropic/claude-sonnet-5.5"); + }); + + it.each([ + ["eco", "openai/gpt-6-luna"], + ["auto", "openai/gpt-6-luna"], + ["premium", "anthropic/claude-fable-5.1"], + ] as const)( + "recovers a %s tool turn on %s when the established tool chain is unavailable", + (routingProfile, firstNewModel) => { + const input = { + config: DEFAULT_ROUTING_CONFIG, + modelPricing: pricing, + routingProfile, + hasTools: true, + requiresTools: true, + toolCount: 1, + }; + const initial = route("Use lookup_order for order B-42.", undefined, 256, input); + const firstNewIndex = initial.candidates?.indexOf(firstNewModel) ?? -1; + + expect(firstNewIndex).toBeGreaterThan(0); + const decision = route("Use lookup_order for order B-42.", undefined, 256, { + ...input, + unavailableModels: initial.candidates?.slice(0, firstNewIndex), + }); + + expect(decision.model).toBe(firstNewModel); + }, + ); + it("keeps deep multi-clue web research on the empirically steadier Sonnet 5", () => { const decision = route( "Research the following clues across multiple public sources and identify the country.", diff --git a/portfolio.ts b/portfolio.ts index a96066c..fdcf09d 100644 --- a/portfolio.ts +++ b/portfolio.ts @@ -943,6 +943,30 @@ function evidenceCandidates(task: TaskType): string[] { return []; } +/** + * Recently added catalog models with a verified structured function call. + * + * Tool compliance is enough to make these models safe availability fallbacks, + * but it is not evidence that they should displace a trajectory-benchmarked + * primary. Keep them after the configured and benchmark-backed chains until a + * full agent evaluation earns a task-specific affinity above the neutral 0.68 + * floor. `isEligible` still applies every host capability override, context + * limit, vision constraint, and unavailable-model guard before they are used. + */ +const VERIFIED_TOOL_FALLBACKS = [ + "anthropic/claude-fable-5.1", + "anthropic/claude-opus-5.5", + "anthropic/claude-sonnet-5.5", + "google/gemini-3.8-flash", + "openai/gpt-5.1", + "openai/gpt-6-astra", + "openai/gpt-6-luna", + "openai/gpt-6-sol", + "xai/grok-4.6", + "xai/grok-4.7", + "xiaomi/mimo-v2.5", +] as const; + function isEligible( modelId: string, features: TaskFeatures, @@ -1036,8 +1060,25 @@ export class PortfolioStrategy implements RouterStrategy { // unavailable set applies to both: the configured side arrives filtered // through RulesStrategy, and a dead evidence model must not re-enter here. const unavailable = new Set(options.unavailableModels ?? []); + // `modelPricing` is the host's live catalog view. Do not introduce a + // built-in fallback that the current gateway does not advertise. These + // models carry no task evidence, so outside Premium the cheapest one is + // the first recovery hop; otherwise an outage of the curated chain would + // jump an Eco turn straight to the most expensive model in the list. + const verifiedToolFallbacks = features.needsTools + ? VERIFIED_TOOL_FALLBACKS.filter((model) => options.modelPricing.has(model)) + : []; + if (options.routingProfile !== "premium") { + const fallbackCost = (model: string) => + estimatedCost(model, options, features.estimatedInputTokens, maxOutputTokens); + verifiedToolFallbacks.sort((a, b) => fallbackCost(a) - fallbackCost(b)); + } const chain = [ - ...new Set([...configuredCandidates, ...evidenceCandidates(features.taskType)]), + ...new Set([ + ...configuredCandidates, + ...evidenceCandidates(features.taskType), + ...verifiedToolFallbacks, + ]), ].filter( (model): model is string => typeof model === "string" && model.length > 0 && !unavailable.has(model), diff --git a/scripts/probe-tools.json b/scripts/probe-tools.json index 1b60154..90322ae 100644 --- a/scripts/probe-tools.json +++ b/scripts/probe-tools.json @@ -3,6 +3,10 @@ "supportsTools": true, "probedAt": "2026-08-29T16:51:33Z" }, + "anthropic/claude-fable-5.1": { + "supportsTools": true, + "probedAt": "2026-10-03T04:27:03Z" + }, "anthropic/claude-haiku-4.5": { "supportsTools": true, "probedAt": "2026-08-29T16:51:33Z" @@ -24,6 +28,10 @@ "probedAt": "2026-08-29T16:51:33Z", "emptyCompletionSeen": true }, + "anthropic/claude-opus-5.5": { + "supportsTools": true, + "probedAt": "2026-10-03T04:27:06Z" + }, "anthropic/claude-sonnet-4.5": { "supportsTools": true, "probedAt": "2026-08-29T16:51:33Z" @@ -36,6 +44,10 @@ "supportsTools": true, "probedAt": "2026-08-29T16:51:33Z" }, + "anthropic/claude-sonnet-5.5": { + "supportsTools": true, + "probedAt": "2026-10-03T04:27:07Z" + }, "deepseek/deepseek-chat": { "supportsTools": true, "probedAt": "2026-08-29T16:51:33Z" @@ -44,6 +56,10 @@ "supportsTools": true, "probedAt": "2026-08-29T16:51:33Z" }, + "deepseek/deepseek-v4-flash-vision-exp": { + "supportsTools": false, + "probedAt": "2026-10-03T04:27:09Z" + }, "deepseek/deepseek-v4-pro": { "supportsTools": true, "probedAt": "2026-08-29T16:51:33Z" @@ -84,6 +100,10 @@ "supportsTools": true, "probedAt": "2026-08-29T16:51:33Z" }, + "google/gemini-3.8-flash": { + "supportsTools": true, + "probedAt": "2026-10-03T04:27:11Z" + }, "minimax/minimax-m2.7": { "supportsTools": true, "probedAt": "2026-08-29T16:51:33Z" @@ -154,6 +174,10 @@ "probedAt": "2026-08-29T16:51:33Z", "emptyCompletionSeen": true }, + "openai/gpt-5.1": { + "supportsTools": true, + "probedAt": "2026-10-03T04:27:13Z" + }, "openai/gpt-5.2": { "supportsTools": true, "probedAt": "2026-08-29T16:51:33Z", @@ -217,6 +241,18 @@ "probedAt": "2026-08-29T16:51:33Z", "emptyCompletionSeen": true }, + "openai/gpt-6-astra": { + "supportsTools": true, + "probedAt": "2026-10-03T04:27:17Z" + }, + "openai/gpt-6-luna": { + "supportsTools": true, + "probedAt": "2026-10-03T04:27:19Z" + }, + "openai/gpt-6-sol": { + "supportsTools": true, + "probedAt": "2026-10-03T04:27:21Z" + }, "openai/o1": { "supportsTools": true, "probedAt": "2026-08-29T16:51:33Z", @@ -249,6 +285,10 @@ "supportsTools": true, "probedAt": "2026-08-29T16:51:33Z" }, + "qwen/qwen3.8-flash": { + "supportsTools": false, + "probedAt": "2026-10-03T04:27:22Z" + }, "tencent/hy3": { "supportsTools": true, "probedAt": "2026-08-29T16:51:33Z" @@ -261,10 +301,22 @@ "supportsTools": true, "probedAt": "2026-08-29T16:51:33Z" }, + "xai/grok-4.6": { + "supportsTools": true, + "probedAt": "2026-10-03T04:27:28Z" + }, + "xai/grok-4.7": { + "supportsTools": true, + "probedAt": "2026-10-03T04:27:31Z" + }, "xai/grok-build-0.1": { "supportsTools": true, "probedAt": "2026-08-29T16:51:33Z" }, + "xiaomi/mimo-v2.5": { + "supportsTools": true, + "probedAt": "2026-10-03T04:27:34Z" + }, "xiaomi/mimo-v2.5-pro": { "supportsTools": true, "probedAt": "2026-08-29T16:51:33Z"