diff --git a/README.md b/README.md index b1a7df2..f67f686 100644 --- a/README.md +++ b/README.md @@ -263,12 +263,75 @@ 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 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 90 text models in the public catalog (2026-10-20 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. GPT-6.1 Sol, Mistral Large 4, DeepSeek V4.1 Flash and Gemini 4 Argon, listed since the last probe, have no probe evidence yet. A model with no probe evidence 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 90 text models in the public catalog (2026-10-20 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. GPT-6.1 Sol and DeepSeek V4.1 Flash also passed a structured tool-call probe in the subsequent capability refresh. Mistral Large 4 and Gemini 4 Argon have no probe evidence yet. 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. --- +## One catalog for chat, image, video and music + +`parseModelCatalog()` normalizes the same public gateway catalog for every +consumer. A new model ID is discovered from its categories and valid prices; +there is no model-ID allowlist or product-specific picker order in Core. +GPT-6.1 Sol, image generators, video generators and music generators all appear +in one result, grouped by `chat`, `image`, `video` and `music`. + +```ts +import { + parseModelCatalog, toRoutingCatalog, route, DEFAULT_ROUTING_CONFIG, +} from "@blockrun/router-core"; + +// The host selects the gateway (Base or Solana), performs I/O and keeps its +// last successful catalog on refresh errors. Core never fetches or caches it. +const response = await fetch("https://blockrun.ai/api/v1/models"); +if (!response.ok) throw new Error(`Catalog unavailable: ${response.status}`); +const catalog = parseModelCatalog(await response.json()); + +catalog.chat; // GPT-6.1 Sol and the other currently available chat models +catalog.image; // GPT Image, Nano Banana, Grok Imagine, CogView, Seedream, ... +catalog.video; // Seedance, Grok Imagine Video, Sora (where available), ... +catalog.music; // MiniMax Music and subsequent music listings + +// Optional adapter: only chat entries enter the LLM router. +const routing = toRoutingCatalog(catalog); +const decision = route(prompt, undefined, 4096, { config: DEFAULT_ROUTING_CONFIG, ...routing }); +// route() keeps a tier's configured chain when every rung is unavailable. +// Hidden IDs absent from the listing are still served, so check only the +// gateway's explicit unavailable list, not catalog.chat membership. +if (catalog.unavailable.includes(decision.model)) { + throw new Error("Every configured model for this request is unavailable"); +} +``` + +- `models` is the deduplicated full list; the four category arrays preserve + gateway order. A model can belong to more than one category. Products own + display names, grouping, preferred order and default selections. +- Hidden/unavailable entries and rows with invalid per-kind prices are omitted. + IDs explicitly marked `available: false` are listed in `catalog.unavailable` + (the gateway substitutes another model for them rather than returning 4xx). + Speech and sound-effect rows are outside the four kinds and omitted. + Last duplicate wins, including a final retirement. Malformed envelopes throw; + an explicit `data: []` produces an empty catalog. Hosts decide how to handle + an empty or stale response and keep Base/Solana caches separate. +- Prices retain gateway units (chat per 1M tokens; media per image/second/track). + The parser carries base prices and known cache, surcharge and duration fields; + it is not a billing quote engine or a media parameter schema. It does not add + margins, infer image sizes, or assume reference-image support. +- The routing adapter uses live context/output limits and vision categories. + Tool support comes from the bundled verified table or explicit host evidence + via `verifiedCapabilities`; a newly listed model is not automatically declared + tool-capable; host evidence is merged over the bundled table per ID. Missing + capacities fall back to verified limits, then zero. +- `unavailableModels` contains only explicitly unavailable IDs. A configured ID + that is merely absent from `/v1/models` stays routable: the gateway serves + hidden IDs, so listing absence is never treated as an outage. +- Discovering a model makes it available to a picker. It does not promote it to + an Auto primary or add media generation to the LLM router. Existing routing + chains, scoring and decision snapshots are unchanged. + +--- + ## Feeding the router live data The engine never makes a network call. Everything current is **injected** by the host, which keeps routing on the hot path while still tracking a catalog that moves faster than this package releases. @@ -333,6 +396,9 @@ Omitted entries fall back to a weak historical prior rather than disqualifying a | Export | Purpose | |---|---| | `route(prompt, systemPrompt, maxOutputTokens, options)` | The entry point. Returns a `RoutingDecision`. | +| `parseModelCatalog(payload)` | Pure normalization of the public chat/image/video/music catalog. | +| `toRoutingCatalog(catalog, options?)` | Chat-only pricing/capability/availability adapter for `route()`. | +| `MODEL_KINDS` | The four supported catalog kinds. | | `DEFAULT_ROUTING_CONFIG` | Router Core V3.5 config: tiers, profiles, weights, promotions. | | `DEFAULT_MODEL_CAPABILITIES` | Built-in capability snapshot (context, max output, tools, vision). | | `LIVE_MODEL_PROFILES` / `HISTORICAL_MODEL_PROFILES` | Performance priors. | @@ -371,7 +437,7 @@ npm run sync:capabilities # → model-capabilities.ts fro UPDATE_DECISION_SNAPSHOT=1 npm test # then review the snapshot diff ``` -The two scripts are the only place the catalog enters this repository. `probe:profiles` pays for real, uncached completions (three samples plus one function-calling request per model, ≈$1 for the whole catalog) and writes the speed/reliability priors; `sync:capabilities` rebuilds the built-in capability snapshot from the public model list, taking `supportsTools` **only** from that probe. Hidden gateway ids are never written — the router should only name a model a user can see on [blockrun.ai/models](https://blockrun.ai/models). +These two scripts update the committed capability and performance snapshots. Runtime catalogs enter through the pure `parseModelCatalog` API described above. `probe:profiles` pays for real, uncached completions (three samples plus one function-calling request per model, ≈$1 for the whole catalog) and writes the speed/reliability priors; `sync:capabilities` rebuilds the built-in capability snapshot from the public model list, taking `supportsTools` **only** from that probe. Hidden gateway ids are never written — the router should only name a model a user can see on [blockrun.ai/models](https://blockrun.ai/models). Three rules keep consumers safe: diff --git a/catalog.test.ts b/catalog.test.ts new file mode 100644 index 0000000..c58e665 --- /dev/null +++ b/catalog.test.ts @@ -0,0 +1,169 @@ +import { describe, expect, it, vi } from "vitest"; +import { + DEFAULT_MODEL_CAPABILITIES, DEFAULT_ROUTING_CONFIG, MODEL_KINDS, parseModelCatalog, route, toRoutingCatalog, +} from "./index.js"; +import type { ModelCapabilities } from "./index.js"; + +const chat = (id = "openai/gpt-6.1-sol", extra: Record = {}) => ({ + id, name: "GPT-6.1 Sol", categories: ["chat", "vision", "reasoning"], + context_window: 1_050_000, max_output: 128_000, billing_mode: "paid", + pricing: { input: 2, output: 10 }, ...extra, +}); +const media = (kind: "image" | "video" | "music", id = `future/${kind}-next`) => ({ + id, name: `New ${kind}`, categories: [kind], + pricing: { [kind === "image" ? "per_image" : kind === "video" ? "per_second" : "per_track"]: 0.12 }, +}); + +describe("unified model catalog", () => { + it("discovers current chat and media models and keeps gateway prices in their original units", () => { + const catalog = parseModelCatalog({ data: [chat(), ...[media("image"), media("video"), media("music")]] }); + expect(MODEL_KINDS.map(kind => catalog[kind].length)).toEqual([1, 1, 1, 1]); + expect(catalog.models).toHaveLength(4); + expect(catalog.chat[0]).toMatchObject({ + id: "openai/gpt-6.1-sol", name: "GPT-6.1 Sol", free: false, + contextWindow: 1_050_000, maxOutputTokens: 128_000, pricing: { input: 2, output: 10 }, + }); + expect(catalog.image[0].pricing).toEqual({ per_image: 0.12 }); + expect(catalog.video[0].pricing).toEqual({ per_second: 0.12 }); + expect(catalog.music[0].pricing).toEqual({ per_track: 0.12 }); + }); + + it("accepts newly listed and multi-category IDs, including version and colon suffixes", () => { + const catalog = parseModelCatalog({ data: [ + chat("new-provider/model-7.2:free", { name: "Next Model", categories: ["chat", "image", "vision"], pricing: { input: 1, output: 3, per_image: 0.4 } }), + media("image", "xai/grok-imagine-image-pro"), media("image", "zai/cogview-4"), + media("video", "bytedance/seedance-1.5-pro"), + ] }); + expect(catalog.chat[0].name).toBe("Next Model"); + expect(catalog.chat[0].kinds).toEqual(["chat", "image"]); + expect(catalog.image).toHaveLength(3); + expect(catalog.video[0].id).toBe("bytedance/seedance-1.5-pro"); + }); + + it("requires an explicit free billing mode as well as zero token prices", () => { + const catalog = parseModelCatalog({ data: [ + chat("acme/zero", { pricing: { input: 0, output: 0 } }), + chat("acme/free", { billing_mode: "free", pricing: { input: 0, output: 0 } }), + chat("acme/not-free", { billing_mode: "free", pricing: { input: 0, output: 1 } }), + ] }); + expect(catalog.chat.map(m => m.free)).toEqual([false, true, false]); + }); + + it.each([null, {}, { data: null }, { data: {} }, [], { error: "offline" }])("rejects malformed envelopes rather than clearing a host cache: %j", value => { + expect(() => parseModelCatalog(value)).toThrow(TypeError); + }); + + it("allows an explicitly empty catalog and does not borrow models from another network", () => { + const base = parseModelCatalog({ data: [chat(), media("video", "azure/sora-2")] }); + const solana = parseModelCatalog({ data: [chat()] }); + expect(base.video).toHaveLength(1); + expect(solana.video).toEqual([]); + expect(parseModelCatalog({ data: [] }).models).toEqual([]); + }); + + it("drops hidden, unavailable, malformed and incorrectly priced rows", () => { + const catalog = parseModelCatalog({ data: [ + null, 42, chat("../escape"), chat("acme/missing", { categories: null }), + chat("acme/hidden", { hidden: true }), chat("acme/off", { available: false }), + chat("acme/ambiguous", { available: "true" }), chat("acme/bad", { pricing: { input: -1, output: 1 } }), + chat("acme/infinite", { pricing: { input: Infinity, output: 1 } }), + { ...media("image"), pricing: { per_image: NaN } }, + { ...media("video"), pricing: { per_image: 0.1 } }, + { ...media("music"), pricing: { per_track: "0.1" } }, + chat(), + ] }); + expect(catalog.models.map(m => m.id)).toEqual(["openai/gpt-6.1-sol"]); + }); + + it("treats the last duplicate as authoritative, including a retirement or invalid replacement", () => { + const catalog = parseModelCatalog({ data: [ + chat("acme/update"), chat("acme/remove"), chat("acme/invalid"), + chat("acme/update", { name: "Updated" }), chat("acme/remove", { available: false }), + chat("acme/invalid", { pricing: null }), + ] }); + expect(catalog.models.map(m => [m.id, m.name])).toEqual([["acme/update", "Updated"]]); + }); + + it("does not truncate a growing catalog or modify the caller's payload", () => { + const input = { data: Array.from({ length: 600 }, (_, i) => chat(`acme/model-${i}`)) }; + const original = structuredClone(input); + const catalog = parseModelCatalog(input); + expect(catalog.chat).toHaveLength(600); + input.data[0].categories.push("music"); + expect(catalog.chat[0].categories).not.toContain("music"); + expect(input.data.slice(1)).toEqual(original.data.slice(1)); + }); +}); + +describe("chat routing catalog adapter", () => { + it("feeds GPT-6.1 Sol's verified tools and live limits into the existing router without retiring absent IDs", () => { + const catalog = parseModelCatalog({ data: [chat(), media("image")] }); + const routing = toRoutingCatalog(catalog); + expect(routing.modelPricing.size).toBe(1); + expect(routing.modelCapabilities["openai/gpt-6.1-sol"]).toEqual({ + contextWindow: 1_050_000, maxOutputTokens: 128_000, supportsTools: true, supportsVision: true, + }); + const decision = route("Search the latest news using web_search", undefined, 256, { + config: DEFAULT_ROUTING_CONFIG, ...routing, hasTools: true, requiresTools: true, toolNames: ["web_search"], + }); + expect(DEFAULT_MODEL_CAPABILITIES[decision.model]?.supportsTools).toBe(true); + expect(routing.unavailableModels).toEqual([]); + }); + + it("does not infer tool support from a new model's name or categories", () => { + const catalog = parseModelCatalog({ data: [chat("future/tool-agent", { categories: ["chat", "tools"] })] }); + expect(toRoutingCatalog(catalog).modelCapabilities["future/tool-agent"].supportsTools).toBe(false); + const capabilities: ModelCapabilities = { contextWindow: 500_000, maxOutputTokens: 32_000, supportsTools: true, supportsVision: false }; + const routing = toRoutingCatalog(catalog, { verifiedCapabilities: { "future/tool-agent": capabilities } }); + expect(routing.modelCapabilities["future/tool-agent"].supportsTools).toBe(true); + expect(routing.modelCapabilities["future/tool-agent"].contextWindow).toBe(1_050_000); + }); + + it("merges host evidence over the bundled table instead of replacing it", () => { + const catalog = parseModelCatalog({ data: [chat(), chat("future/tool-agent")] }); + const capabilities: ModelCapabilities = { contextWindow: 500_000, maxOutputTokens: 32_000, supportsTools: true, supportsVision: false }; + const routing = toRoutingCatalog(catalog, { verifiedCapabilities: { "future/tool-agent": capabilities } }); + expect(routing.modelCapabilities["openai/gpt-6.1-sol"].supportsTools).toBe(true); + expect(routing.modelCapabilities["future/tool-agent"].supportsTools).toBe(true); + }); + + it("uses verified fallback limits only when the live catalog lacks valid limits", () => { + const routing = toRoutingCatalog(parseModelCatalog({ data: [ + chat("openai/gpt-6.1-sol", { context_window: -1, max_output: 0 }), + chat("future/unknown", { context_window: Infinity, max_output: "large" }), + ] })); + expect(routing.modelCapabilities["openai/gpt-6.1-sol"].contextWindow).toBe(1_050_000); + expect(routing.modelCapabilities["future/unknown"]).toMatchObject({ contextWindow: 0, maxOutputTokens: 0, supportsTools: false }); + }); + + it("retires only explicitly unavailable IDs, never hidden or uncategorized ones", () => { + const catalog = parseModelCatalog({ data: [ + chat(), media("image"), media("video"), media("music"), + chat("nvidia/offline", { available: false, billing_mode: "free", pricing: { input: 0, output: 0 } }), + chat("openai/o4-mini", { categories: ["reasoning", "coding"] }), + chat("acme/hidden", { hidden: true }), + chat("acme/retired"), chat("acme/retired", { available: false }), + ] }); + expect(catalog.unavailable).toEqual(["nvidia/offline", "acme/retired"]); + const routing = toRoutingCatalog(catalog); + expect(routing.unavailableModels).toEqual(["nvidia/offline", "acme/retired"]); + expect([...routing.modelPricing.keys()]).toEqual(["openai/gpt-6.1-sol"]); + }); + + it("keeps configured IDs absent from the listing routable", () => { + const routing = toRoutingCatalog(parseModelCatalog({ data: [chat()] })); + const decision = route("hello", undefined, 256, { config: DEFAULT_ROUTING_CONFIG, ...routing }); + const plain = route("hello", undefined, 256, { config: DEFAULT_ROUTING_CONFIG, modelPricing: routing.modelPricing }); + expect(decision.model).toBe(plain.model); + expect(decision.model).not.toBe("openai/gpt-6.1-sol"); + }); + + it("performs no network requests during parsing, adaptation or routing", () => { + const fetch = vi.spyOn(globalThis, "fetch").mockImplementation(() => { throw new Error("unexpected network"); }); + try { + const routing = toRoutingCatalog(parseModelCatalog({ data: [chat()] })); + route("hello", undefined, 256, { config: DEFAULT_ROUTING_CONFIG, ...routing }); + expect(fetch).not.toHaveBeenCalled(); + } finally { fetch.mockRestore(); } + }); +}); diff --git a/catalog.ts b/catalog.ts new file mode 100644 index 0000000..d828649 --- /dev/null +++ b/catalog.ts @@ -0,0 +1,153 @@ +/** Pure public-catalog parsing. Fetching, caching and UI ordering belong to hosts. */ +import { DEFAULT_MODEL_CAPABILITIES, type ModelCapabilities } from "./model-capabilities.js"; +import type { ModelPricing } from "./selector.js"; + +export const MODEL_KINDS = ["chat", "image", "video", "music"] as const; +export type ModelKind = (typeof MODEL_KINDS)[number]; + +/** Gateway units are preserved: token prices per 1M tokens; media per unit. */ +export interface CatalogPricing { + input?: number; + output?: number; + per_image?: number; + per_second?: number; + per_track?: number; + cache_read?: number; + cache_write?: number; + transaction_fee?: number; + per_call_surcharge?: number; + default_duration_seconds?: number; + max_duration_seconds?: number; +} + +export interface CatalogModel { + id: string; + name: string; + categories: readonly string[]; + kinds: readonly ModelKind[]; + billingMode?: string; + /** Zero pricing alone does not imply a free model. */ + free: boolean; + pricing: CatalogPricing; + contextWindow?: number; + maxOutputTokens?: number; +} + +export interface ModelCatalog { + models: readonly CatalogModel[]; + chat: readonly CatalogModel[]; + image: readonly CatalogModel[]; + video: readonly CatalogModel[]; + music: readonly CatalogModel[]; + /** + * IDs whose authoritative row says `available: false`. The gateway does not + * reject these; it substitutes another model. Absence from the listing is + * not unavailability: hidden IDs are still served. + */ + unavailable: readonly string[]; +} + +const PRICE_KEYS = [ + "input", "output", "per_image", "per_second", "per_track", "cache_read", "cache_write", + "transaction_fee", "per_call_surcharge", "default_duration_seconds", "max_duration_seconds", +] as const; +const UNIT_PRICE = { image: "per_image", video: "per_second", music: "per_track" } as const; +const MODEL_ID = /^[a-z0-9][a-z0-9._-]*\/[a-zA-Z0-9][a-zA-Z0-9._:+-]*$/; +const record = (value: unknown): value is Record => + value !== null && typeof value === "object" && !Array.isArray(value); +const price = (value: unknown): value is number => + typeof value === "number" && Number.isFinite(value) && value >= 0; +const capacity = (value: unknown): number | undefined => + typeof value === "number" && Number.isSafeInteger(value) && value > 0 ? value : undefined; + +/** + * Normalize GET /api/v1/models without a model-ID allowlist. New provider IDs + * appear immediately. Hidden/unavailable rows and invalid per-kind prices are + * omitted. A malformed envelope throws so a host can retain its last good list; + * an explicitly empty `data` array is a valid empty catalog. + * + * IDs explicitly marked `available: false` are also listed in `unavailable`. + * Rows outside MODEL_KINDS (speech, sound effects) are omitted. + * + * Last duplicate wins, including a final unavailable/invalid row. No sorting, + * price markup, network request, capability probe or media routing is performed. + */ +export function parseModelCatalog(value: unknown): ModelCatalog { + if (!record(value) || !Array.isArray(value.data)) { + throw new TypeError("Model catalog must contain a data array"); + } + const entries = new Map>(); + for (const entry of value.data) { + if (record(entry) && typeof entry.id === "string" && entry.id.length <= 200 && MODEL_ID.test(entry.id)) { + entries.set(entry.id, entry); + } + } + const result: ModelCatalog = { models: [], chat: [], image: [], video: [], music: [], unavailable: [] }; + const models: CatalogModel[] = []; + const unavailable: string[] = []; + for (const [id, entry] of entries) { + if (entry.available === false) unavailable.push(id); + if ((entry.available !== undefined && entry.available !== true) || + (entry.hidden !== undefined && entry.hidden !== false) || + !Array.isArray(entry.categories) || !record(entry.pricing)) continue; + const categories = [...new Set(entry.categories.filter((c): c is string => typeof c === "string"))]; + const rawPricing = entry.pricing; + const pricing: CatalogPricing = {}; + for (const key of PRICE_KEYS) if (price(rawPricing[key])) pricing[key] = rawPricing[key]; + const kinds = MODEL_KINDS.filter(kind => categories.includes(kind) && (kind === "chat" + ? price(rawPricing.input) && price(rawPricing.output) + : price(rawPricing[UNIT_PRICE[kind]]))); + if (!kinds.length) continue; + const model: CatalogModel = { + id, name: typeof entry.name === "string" && entry.name.trim() ? entry.name : id, + categories, kinds, pricing, + free: kinds.includes("chat") && entry.billing_mode === "free" && pricing.input === 0 && pricing.output === 0, + ...(typeof entry.billing_mode === "string" ? { billingMode: entry.billing_mode } : {}), + ...(capacity(entry.context_window) !== undefined ? { contextWindow: capacity(entry.context_window) } : {}), + ...(capacity(entry.max_output) !== undefined ? { maxOutputTokens: capacity(entry.max_output) } : {}), + }; + models.push(model); + } + result.models = models; + result.unavailable = unavailable; + for (const kind of MODEL_KINDS) result[kind] = models.filter(model => model.kinds.includes(kind)); + return result; +} + +export interface CatalogRoutingOptions { + /** Host evidence, merged over (and overriding per ID) the bundled verified table. */ + verifiedCapabilities?: Readonly>; +} + +export interface RoutingCatalog { + modelPricing: Map; + modelCapabilities: Record; + unavailableModels: string[]; +} + +/** + * Adapt only the chat catalog for route(). Media never enters LLM candidate + * chains. Tool support comes from verified evidence, never a name or category. + * Unknown capacities are zero, rather than invented defaults. + * + * Only rows the gateway explicitly marks `available: false` become + * unavailableModels. Configured IDs that are merely absent from the listing + * stay routable: the gateway serves hidden IDs, and only the configured chain + * knows about them. + */ +export function toRoutingCatalog(catalog: ModelCatalog, options: CatalogRoutingOptions = {}): RoutingCatalog { + const verified = { ...DEFAULT_MODEL_CAPABILITIES, ...options.verifiedCapabilities }; + const modelPricing = new Map(); + const modelCapabilities: Record = {}; + for (const model of catalog.chat) { + modelPricing.set(model.id, { inputPrice: model.pricing.input!, outputPrice: model.pricing.output! }); + const evidence = verified[model.id]; + modelCapabilities[model.id] = { + contextWindow: model.contextWindow ?? evidence?.contextWindow ?? 0, + maxOutputTokens: model.maxOutputTokens ?? evidence?.maxOutputTokens ?? 0, + supportsTools: evidence?.supportsTools === true, + supportsVision: model.categories.includes("vision"), + }; + } + return { modelPricing, modelCapabilities, unavailableModels: [...catalog.unavailable] }; +} diff --git a/dist/index.d.ts b/dist/index.d.ts index 1317813..ab40969 100644 --- a/dist/index.d.ts +++ b/dist/index.d.ts @@ -400,6 +400,83 @@ declare function inferToolRequirement(prompt: string, _systemPrompt?: string, to /** Approximate token count: one per CJK character, one per four of anything else. */ declare function estimateTokens(text: string): number; +/** Pure public-catalog parsing. Fetching, caching and UI ordering belong to hosts. */ + +declare const MODEL_KINDS: readonly ["chat", "image", "video", "music"]; +type ModelKind = (typeof MODEL_KINDS)[number]; +/** Gateway units are preserved: token prices per 1M tokens; media per unit. */ +interface CatalogPricing { + input?: number; + output?: number; + per_image?: number; + per_second?: number; + per_track?: number; + cache_read?: number; + cache_write?: number; + transaction_fee?: number; + per_call_surcharge?: number; + default_duration_seconds?: number; + max_duration_seconds?: number; +} +interface CatalogModel { + id: string; + name: string; + categories: readonly string[]; + kinds: readonly ModelKind[]; + billingMode?: string; + /** Zero pricing alone does not imply a free model. */ + free: boolean; + pricing: CatalogPricing; + contextWindow?: number; + maxOutputTokens?: number; +} +interface ModelCatalog { + models: readonly CatalogModel[]; + chat: readonly CatalogModel[]; + image: readonly CatalogModel[]; + video: readonly CatalogModel[]; + music: readonly CatalogModel[]; + /** + * IDs whose authoritative row says `available: false`. The gateway does not + * reject these; it substitutes another model. Absence from the listing is + * not unavailability: hidden IDs are still served. + */ + unavailable: readonly string[]; +} +/** + * Normalize GET /api/v1/models without a model-ID allowlist. New provider IDs + * appear immediately. Hidden/unavailable rows and invalid per-kind prices are + * omitted. A malformed envelope throws so a host can retain its last good list; + * an explicitly empty `data` array is a valid empty catalog. + * + * IDs explicitly marked `available: false` are also listed in `unavailable`. + * Rows outside MODEL_KINDS (speech, sound effects) are omitted. + * + * Last duplicate wins, including a final unavailable/invalid row. No sorting, + * price markup, network request, capability probe or media routing is performed. + */ +declare function parseModelCatalog(value: unknown): ModelCatalog; +interface CatalogRoutingOptions { + /** Host evidence, merged over (and overriding per ID) the bundled verified table. */ + verifiedCapabilities?: Readonly>; +} +interface RoutingCatalog { + modelPricing: Map; + modelCapabilities: Record; + unavailableModels: string[]; +} +/** + * Adapt only the chat catalog for route(). Media never enters LLM candidate + * chains. Tool support comes from verified evidence, never a name or category. + * Unknown capacities are zero, rather than invented defaults. + * + * Only rows the gateway explicitly marks `available: false` become + * unavailableModels. Configured IDs that are merely absent from the listing + * stay routable: the gateway serves hidden IDs, and only the configured chain + * knows about them. + */ +declare function toRoutingCatalog(catalog: ModelCatalog, options?: CatalogRoutingOptions): RoutingCatalog; + /** * Default Routing Config * @@ -424,4 +501,4 @@ declare const DEFAULT_ROUTING_CONFIG: RoutingConfig; */ declare function route(prompt: string, systemPrompt: string | undefined, maxOutputTokens: number, options: RouterOptions): RoutingDecision; -export { DEFAULT_MODEL_CAPABILITIES, DEFAULT_ROUTING_CONFIG, HISTORICAL_MODEL_PROFILES, LIVE_MODEL_PROFILES, type ModelCapabilities, type ModelPerformanceProfile, type ModelPricing, PortfolioStrategy, type RouterOptions, type RouterStrategy, type RoutingConfig, type RoutingDecision, RulesStrategy, type TaskType, type Tier, applyUnavailableModels, calculateModelCost, classifyByRules, estimateTokens, filterByExcludeList, filterByToolCalling, filterByVision, filterCandidatesByCapacity, getFallbackChain, getFallbackChainFiltered, getStrategy, inferToolRequirement, registerStrategy, route }; +export { type CatalogModel, type CatalogPricing, type CatalogRoutingOptions, DEFAULT_MODEL_CAPABILITIES, DEFAULT_ROUTING_CONFIG, HISTORICAL_MODEL_PROFILES, LIVE_MODEL_PROFILES, MODEL_KINDS, type ModelCapabilities, type ModelCatalog, type ModelKind, type ModelPerformanceProfile, type ModelPricing, PortfolioStrategy, type RouterOptions, type RouterStrategy, type RoutingCatalog, type RoutingConfig, type RoutingDecision, RulesStrategy, type TaskType, type Tier, applyUnavailableModels, calculateModelCost, classifyByRules, estimateTokens, filterByExcludeList, filterByToolCalling, filterByVision, filterCandidatesByCapacity, getFallbackChain, getFallbackChainFiltered, getStrategy, inferToolRequirement, parseModelCatalog, registerStrategy, route, toRoutingCatalog }; diff --git a/dist/index.js b/dist/index.js index ba40c31..2a6d002 100644 --- a/dist/index.js +++ b/dist/index.js @@ -2375,10 +2375,10 @@ function isEligible(modelId, features, maxOutputTokens, options) { return model.contextWindow >= (features.estimatedInputTokens + maxOutputTokens) * 1.1; } function estimatedCost(modelId, options, inputTokens, outputTokens) { - const price = options.modelPricing.get(modelId); - if (!price) return Number.POSITIVE_INFINITY; - if (price.flatPrice !== void 0) return price.flatPrice; - return (inputTokens * price.inputPrice + outputTokens * price.outputPrice) / 1e6; + const price2 = options.modelPricing.get(modelId); + if (!price2) return Number.POSITIVE_INFINITY; + if (price2.flatPrice !== void 0) return price2.flatPrice; + return (inputTokens * price2.inputPrice + outputTokens * price2.outputPrice) / 1e6; } function profileScore(modelId, options, now) { const profile = options.modelPerformance?.[modelId] ?? LIVE_MODEL_PROFILES[modelId] ?? HISTORICAL_MODEL_PROFILES[modelId]; @@ -2540,6 +2540,83 @@ var PortfolioStrategy = class { } }; +// catalog.ts +var MODEL_KINDS = ["chat", "image", "video", "music"]; +var PRICE_KEYS = [ + "input", + "output", + "per_image", + "per_second", + "per_track", + "cache_read", + "cache_write", + "transaction_fee", + "per_call_surcharge", + "default_duration_seconds", + "max_duration_seconds" +]; +var UNIT_PRICE = { image: "per_image", video: "per_second", music: "per_track" }; +var MODEL_ID = /^[a-z0-9][a-z0-9._-]*\/[a-zA-Z0-9][a-zA-Z0-9._:+-]*$/; +var record = (value) => value !== null && typeof value === "object" && !Array.isArray(value); +var price = (value) => typeof value === "number" && Number.isFinite(value) && value >= 0; +var capacity = (value) => typeof value === "number" && Number.isSafeInteger(value) && value > 0 ? value : void 0; +function parseModelCatalog(value) { + if (!record(value) || !Array.isArray(value.data)) { + throw new TypeError("Model catalog must contain a data array"); + } + const entries = /* @__PURE__ */ new Map(); + for (const entry of value.data) { + if (record(entry) && typeof entry.id === "string" && entry.id.length <= 200 && MODEL_ID.test(entry.id)) { + entries.set(entry.id, entry); + } + } + const result = { models: [], chat: [], image: [], video: [], music: [], unavailable: [] }; + const models = []; + const unavailable = []; + for (const [id, entry] of entries) { + if (entry.available === false) unavailable.push(id); + if (entry.available !== void 0 && entry.available !== true || entry.hidden !== void 0 && entry.hidden !== false || !Array.isArray(entry.categories) || !record(entry.pricing)) continue; + const categories = [...new Set(entry.categories.filter((c) => typeof c === "string"))]; + const rawPricing = entry.pricing; + const pricing = {}; + for (const key of PRICE_KEYS) if (price(rawPricing[key])) pricing[key] = rawPricing[key]; + const kinds = MODEL_KINDS.filter((kind) => categories.includes(kind) && (kind === "chat" ? price(rawPricing.input) && price(rawPricing.output) : price(rawPricing[UNIT_PRICE[kind]]))); + if (!kinds.length) continue; + const model = { + id, + name: typeof entry.name === "string" && entry.name.trim() ? entry.name : id, + categories, + kinds, + pricing, + free: kinds.includes("chat") && entry.billing_mode === "free" && pricing.input === 0 && pricing.output === 0, + ...typeof entry.billing_mode === "string" ? { billingMode: entry.billing_mode } : {}, + ...capacity(entry.context_window) !== void 0 ? { contextWindow: capacity(entry.context_window) } : {}, + ...capacity(entry.max_output) !== void 0 ? { maxOutputTokens: capacity(entry.max_output) } : {} + }; + models.push(model); + } + result.models = models; + result.unavailable = unavailable; + for (const kind of MODEL_KINDS) result[kind] = models.filter((model) => model.kinds.includes(kind)); + return result; +} +function toRoutingCatalog(catalog, options = {}) { + const verified = { ...DEFAULT_MODEL_CAPABILITIES, ...options.verifiedCapabilities }; + const modelPricing = /* @__PURE__ */ new Map(); + const modelCapabilities = {}; + for (const model of catalog.chat) { + modelPricing.set(model.id, { inputPrice: model.pricing.input, outputPrice: model.pricing.output }); + const evidence = verified[model.id]; + modelCapabilities[model.id] = { + contextWindow: model.contextWindow ?? evidence?.contextWindow ?? 0, + maxOutputTokens: model.maxOutputTokens ?? evidence?.maxOutputTokens ?? 0, + supportsTools: evidence?.supportsTools === true, + supportsVision: model.categories.includes("vision") + }; + } + return { modelPricing, modelCapabilities, unavailableModels: [...catalog.unavailable] }; +} + // config.ts var DEFAULT_ROUTING_CONFIG = { version: "3.5", @@ -4039,6 +4116,7 @@ export { DEFAULT_ROUTING_CONFIG, HISTORICAL_MODEL_PROFILES, LIVE_MODEL_PROFILES, + MODEL_KINDS, PortfolioStrategy, RulesStrategy, applyUnavailableModels, @@ -4053,7 +4131,9 @@ export { getFallbackChainFiltered, getStrategy, inferToolRequirement, + parseModelCatalog, registerStrategy, - route + route, + toRoutingCatalog }; //# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dist/index.js.map b/dist/index.js.map index 60a3cd0..5d62399 100644 --- a/dist/index.js.map +++ b/dist/index.js.map @@ -1 +1 @@ -{"version":3,"sources":["../rules.ts","../selector.ts","../tokens.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// ─── Keyword Matching ───\n//\n// A plain substring test counted `class` in \"classic\", `story` in \"history\",\n// `edit` in \"credit\" and `fix` in \"prefix\", so everyday prose picked up code,\n// creative and agentic signals it did not carry. Alphabetic keywords now have\n// to start at a word boundary. Short ASCII keywords additionally have to end\n// at one, after an optional inflection, graded by how much a stray suffix can\n// change the word: a three-letter keyword takes only the English endings that\n// cannot spell another word (fix → fixes, never pip → pipe or def → defer); a\n// four-to-six-letter keyword also takes the common German and Romance endings,\n// because the lists spell those languages in ASCII too (beweis → beweise,\n// klasse → klassen); anything longer stays trailing-open like the substring\n// test it replaces, since its false-positive surface is small and its\n// inflection surface is large. Non-ASCII alphabetic keywords keep a\n// trailing-open match because several are deliberate stems (`оптимизаци`,\n// `рассуждени`). CJK, Hangul and Arabic keywords keep the substring test:\n// those scripts have no word boundaries, or attach particles and articles\n// directly to the word.\n\nconst UNSEGMENTED_SCRIPT =\n /[؀-ۿ -ヿ㐀-䶿一-鿿가-힯豈-﫿＀-￯]/;\nconst WORD_CHAR = /[\\p{L}\\p{N}]/u;\nconst ASCII_PHRASE = /^[a-z0-9' -]+$/;\n// A word boundary is a transition out of the segmented scripts. A CJK\n// character next to a Latin keyword (\"请step by step证明\") is a boundary, not\n// part of the word: mixed-script prompts carry no spaces between scripts.\nconst SEGMENTED_WORD_CHAR = \"\\\\p{Script=Latin}\\\\p{Script=Cyrillic}\\\\p{Script=Greek}\\\\p{N}\";\nconst BOUNDARY_BEFORE = `(?();\n\nfunction escapeRegExp(value: string): string {\n return value.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\n\nfunction keywordMatcher(keyword: string): KeywordMatcher {\n const cached = matcherCache.get(keyword);\n if (cached) return cached;\n\n const kw = keyword.toLowerCase();\n let matcher: KeywordMatcher;\n if (UNSEGMENTED_SCRIPT.test(kw) || kw.length === 0) {\n matcher = { needle: kw, pattern: null };\n } else {\n const lead = WORD_CHAR.test(kw[0]) ? BOUNDARY_BEFORE : \"\";\n const escaped = escapeRegExp(kw);\n let body = escaped;\n let trail = \"\";\n let needle = kw;\n const lastWord = kw.slice(kw.lastIndexOf(\" \") + 1);\n if (\n WORD_CHAR.test(kw[kw.length - 1]) &&\n ASCII_PHRASE.test(kw) &&\n lastWord.length <= BOUNDED_LAST_WORD_LENGTH\n ) {\n // ASCII phrases contain no regex metacharacters, so `escaped` slices\n // align with `kw` slices below.\n const forms: string[] = [];\n if (/\\d$/.test(kw)) {\n // \"step 1\" must not absorb \"step 10\".\n forms.push(escaped);\n } else if (lastWord.length <= 3) {\n forms.push(`${escaped}${SHORT_SUFFIXES}`);\n if (/(?:x|s|z|ch|sh)$/.test(kw)) forms.push(`${escaped}${SIBILANT_PLURAL}`);\n } else {\n forms.push(`${escaped}${MID_SUFFIXES}`);\n if (kw.endsWith(\"e\")) {\n forms.push(`${escaped.slice(0, -1)}${DROPPED_E_SUFFIXES}`);\n needle = kw.slice(0, -1);\n } else if (kw.endsWith(\"y\")) {\n forms.push(`${escaped.slice(0, -1)}(?:ies|ied)`);\n needle = kw.slice(0, -1);\n } else if (/[aeiou][bdgmnprt]$/.test(kw)) {\n // debug → debugging, plan → planned\n forms.push(`${escaped}${kw[kw.length - 1]}${DOUBLED_CONSONANT_SUFFIXES}`);\n }\n }\n body = `(?:${forms.join(\"|\")})`;\n trail = BOUNDARY_AFTER;\n }\n matcher = { needle, pattern: new RegExp(`${lead}${body}${trail}`, \"u\") };\n }\n matcherCache.set(keyword, matcher);\n return matcher;\n}\n\n/** Whether lower-cased `text` contains `keyword` as a word (or as a substring for CJK). */\nfunction matchesKeyword(text: string, keyword: string): boolean {\n const { needle, pattern } = keywordMatcher(keyword);\n if (!text.includes(needle)) return false;\n return pattern === null ? true : pattern.test(text);\n}\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) => matchesKeyword(text, kw));\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 (matchesKeyword(text, keyword)) {\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) => matchesKeyword(userText, kw));\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 // A model the host has no price for costs an unknown amount, not nothing;\n // reporting its savings as 100% would be a fabricated figure.\n const savings =\n routingProfile === \"premium\" || pricing === undefined\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 * Request-size helpers shared by the rules and portfolio strategies.\n *\n * The router never tokenizes — it is on the hot path and model-agnostic — so\n * sizes are estimates. The estimate only has to be honest enough for the\n * decisions that consume it: the long-context task type, the COMPLEX\n * override and the per-model capacity filter.\n */\n\n// Han, kana, Hangul, CJK punctuation and fullwidth forms. Every production\n// tokenizer spends roughly one token per character here, so the Latin\n// four-characters-per-token rule under-counts these scripts about fourfold:\n// a 200k-character Chinese contract would read as 50k tokens, slip under the\n// 80k long-context boundary and pass the capacity filter for models that\n// cannot hold it.\nconst CJK_CHARS = /[ -ヿ㐀-䶿一-鿿가-힯豈-﫿＀-￯]/g;\n\n/** Approximate token count: one per CJK character, one per four of anything else. */\nexport function estimateTokens(text: string): number {\n if (text.length === 0) return 0;\n const cjk = text.match(CJK_CHARS)?.length ?? 0;\n return cjk + Math.ceil((text.length - cjk) / 4);\n}\n\n/** The scan window the feature regexes read, bounded so a pasted document cannot stall routing. */\nexport function scanLimit(promptTruncationChars: number): number {\n return Math.max(1, Math.min(8_000, promptTruncationChars));\n}\n\n/**\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 */\nexport function sampleForScan(value: string, limit: number): string {\n if (value.length <= limit) return value;\n const prefixLength = Math.ceil(limit / 2);\n return `${value.slice(0, prefixLength)}\\n${value.slice(-(limit - prefixLength))}`;\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\";\nimport { estimateTokens, sampleForScan, scanLimit } from \"./tokens.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 const fullText = `${systemPrompt ?? \"\"} ${prompt}`;\n const estimatedTokens = estimateTokens(fullText);\n const limit = scanLimit(config.classifier.promptTruncationChars);\n const scannedPrompt = sampleForScan(prompt, limit);\n const scannedSystemPrompt = systemPrompt ? sampleForScan(systemPrompt, limit) : 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 is a protocol fact the host states (`response_format`\n // → requiresStructuredOutput). It used to be inferred from the system\n // prompt as well, but agent hosts describe their tool schemas there on\n // every turn, which upgraded every one of their requests off SIMPLE.\n const hasStructuredOutput = options.requiresStructuredOutput === true;\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-20; 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 \"deepseek/deepseek-v4.1-flash\": {\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 \"google/gemini-4-argon\": { // 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 \"mistral/mistral-large-4\": { // supportsTools: not probed — fails closed\n contextWindow: 524_288,\n maxOutputTokens: 262_144,\n supportsTools: false,\n supportsVision: true,\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/gpt-6.1-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 \"deepseek/deepseek-v4.1-flash\": {\n \"measuredAt\": \"2026-10-20T18:12:51Z\",\n \"latencyMs\": 2383.5,\n \"p95LatencyMs\": 2547.8,\n \"outputTokensPerSecond\": 216.53,\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/gpt-6.1-sol\": {\n \"measuredAt\": \"2026-10-20T18:12:51Z\",\n \"latencyMs\": 11324,\n \"p95LatencyMs\": 12747.6,\n \"outputTokensPerSecond\": 45.11,\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\";\nimport { estimateTokens, sampleForScan, scanLimit } from \"./tokens.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 /** A code artifact or coding action is present, not merely a language name. */\n codeArtifact: 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 = estimateTokens(fullText);\n const limit = scanLimit(options.config.classifier.promptTruncationChars);\n const scannedPrompt = sampleForScan(prompt, limit);\n const scannedSystemPrompt = sampleForScan(systemPrompt ?? \"\", limit);\n // Only the deep-web-research clue detectors below read the system prompt,\n // and they are gated on a web-research tool surface. Every other feature\n // reads the user turn: a host's standing instructions (\"be quick\", \"follow\n // security best practices\", a Mandarin persona) describe the assistant, not\n // this request, and must not move its scoring or language band.\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 // A CamelCase error class (TypeError, NullPointerException) is a runtime\n // artifact, not prose about errors; case-sensitive on purpose.\n const errorClassSignal = /\\b[A-Z][A-Za-z]*(?:Error|Exception)\\b/.test(scannedPrompt);\n const hasCode = explicitCodeSignal || codeConstructSignal || nativeCodeSignal || errorClassSignal;\n // Stronger than hasCode: an actual code artifact or coding action, never a\n // bare language name (\"What is Python?\" is trivia, not a code task) and\n // never the English word \"exception\" on its own (\"please make an\n // exception\"); a thrown exception shows up as a CamelCase class above.\n const codeArtifact =\n /```|\\b(?:stack trace|traceback)\\b|\\.(?:ts|tsx|js|py|go|rs)\\b/i.test(scannedPrompt) ||\n codeConstructSignal ||\n nativeCodeSignal ||\n errorClassSignal;\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 scannedPrompt,\n );\n const highStakes =\n /\\b(?:production|security|payment|legal|medical|financial|audit)\\b|生产|安全|支付|法律|医疗|财务|审计/i.test(\n scannedPrompt,\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(scannedPrompt) ? \"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 errorClassSignal ||\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 codeArtifact,\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 \"deepseek/deepseek-v4.1-flash\",\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 \"openai/gpt-6.1-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 // Rules set the capability tier; the strategy is stateless, so one instance serves every request.\n private readonly rules = new RulesStrategy();\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 = this.rules.route(prompt, systemPrompt, maxOutputTokens, {\n ...options,\n requiresTools: features.needsTools,\n });\n const tierConfigs = base.tierConfigs;\n if (!tierConfigs) return base;\n // The rules score sets the capability tier, but two task types carry a\n // floor of their own: a compact reasoning problem belongs on the\n // reasoning chain however short it is, and a code edit or stack trace\n // belongs at least on the MEDIUM chain — the SIMPLE chain is curated for\n // trivia and translation and has no model with code affinity. The code\n // floor requires a code artifact or coding action: `debug` and `code_edit`\n // are also assigned from bare verbs (\"rewrite this sentence\", \"margin of\n // error\") and bare language names (\"What is Python?\"), and that prose\n // must stay on the cheap chain.\n const targetTier: Tier =\n (features.taskType === \"reasoning_mcq\" || features.taskType === \"reasoning_math\") &&\n (base.tier === \"SIMPLE\" || base.tier === \"MEDIUM\")\n ? \"REASONING\"\n : (features.taskType === \"debug\" || features.taskType === \"code_edit\") &&\n features.codeArtifact &&\n base.tier === \"SIMPLE\"\n ? \"MEDIUM\"\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 = new Set(\n chain.filter((model) => isEligible(model, features, maxOutputTokens, options)),\n );\n // When nothing is eligible the whole chain competes, scored as incapable.\n const eligibleCandidates = eligible.size > 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 = eligible.has(model) ? 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 // Every observed dimension fades toward its neutral prior as the\n // observation ages, exactly like reliability below. Fading speed\n // toward zero instead ranked any model with a stale probe below a\n // model nobody had measured, which the latter's 0.5 silently won.\n const observedSpeed = profile\n ? profile.speed * profile.freshness + 0.5 * (1 - profile.freshness)\n : 0.5;\n const observedTailSpeed = profile\n ? profile.tailSpeed * profile.freshness + 0.5 * (1 - profile.freshness)\n : 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 { estimateTokens } from \"./tokens.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":";AAiCA,IAAM,qBACJ;AACF,IAAM,YAAY;AAClB,IAAM,eAAe;AAIrB,IAAM,sBAAsB;AAC5B,IAAM,kBAAkB,QAAQ,mBAAmB;AACnD,IAAM,iBAAiB,OAAO,mBAAmB;AACjD,IAAM,2BAA2B;AACjC,IAAM,iBAAiB;AACvB,IAAM,kBAAkB;AACxB,IAAM,eACJ;AACF,IAAM,qBAAqB;AAC3B,IAAM,6BAA6B;AAQnC,IAAM,eAAe,oBAAI,IAA4B;AAErD,SAAS,aAAa,OAAuB;AAC3C,SAAO,MAAM,QAAQ,uBAAuB,MAAM;AACpD;AAEA,SAAS,eAAe,SAAiC;AACvD,QAAM,SAAS,aAAa,IAAI,OAAO;AACvC,MAAI,OAAQ,QAAO;AAEnB,QAAM,KAAK,QAAQ,YAAY;AAC/B,MAAI;AACJ,MAAI,mBAAmB,KAAK,EAAE,KAAK,GAAG,WAAW,GAAG;AAClD,cAAU,EAAE,QAAQ,IAAI,SAAS,KAAK;AAAA,EACxC,OAAO;AACL,UAAM,OAAO,UAAU,KAAK,GAAG,CAAC,CAAC,IAAI,kBAAkB;AACvD,UAAM,UAAU,aAAa,EAAE;AAC/B,QAAI,OAAO;AACX,QAAI,QAAQ;AACZ,QAAI,SAAS;AACb,UAAM,WAAW,GAAG,MAAM,GAAG,YAAY,GAAG,IAAI,CAAC;AACjD,QACE,UAAU,KAAK,GAAG,GAAG,SAAS,CAAC,CAAC,KAChC,aAAa,KAAK,EAAE,KACpB,SAAS,UAAU,0BACnB;AAGA,YAAM,QAAkB,CAAC;AACzB,UAAI,MAAM,KAAK,EAAE,GAAG;AAElB,cAAM,KAAK,OAAO;AAAA,MACpB,WAAW,SAAS,UAAU,GAAG;AAC/B,cAAM,KAAK,GAAG,OAAO,GAAG,cAAc,EAAE;AACxC,YAAI,mBAAmB,KAAK,EAAE,EAAG,OAAM,KAAK,GAAG,OAAO,GAAG,eAAe,EAAE;AAAA,MAC5E,OAAO;AACL,cAAM,KAAK,GAAG,OAAO,GAAG,YAAY,EAAE;AACtC,YAAI,GAAG,SAAS,GAAG,GAAG;AACpB,gBAAM,KAAK,GAAG,QAAQ,MAAM,GAAG,EAAE,CAAC,GAAG,kBAAkB,EAAE;AACzD,mBAAS,GAAG,MAAM,GAAG,EAAE;AAAA,QACzB,WAAW,GAAG,SAAS,GAAG,GAAG;AAC3B,gBAAM,KAAK,GAAG,QAAQ,MAAM,GAAG,EAAE,CAAC,aAAa;AAC/C,mBAAS,GAAG,MAAM,GAAG,EAAE;AAAA,QACzB,WAAW,qBAAqB,KAAK,EAAE,GAAG;AAExC,gBAAM,KAAK,GAAG,OAAO,GAAG,GAAG,GAAG,SAAS,CAAC,CAAC,GAAG,0BAA0B,EAAE;AAAA,QAC1E;AAAA,MACF;AACA,aAAO,MAAM,MAAM,KAAK,GAAG,CAAC;AAC5B,cAAQ;AAAA,IACV;AACA,cAAU,EAAE,QAAQ,SAAS,IAAI,OAAO,GAAG,IAAI,GAAG,IAAI,GAAG,KAAK,IAAI,GAAG,EAAE;AAAA,EACzE;AACA,eAAa,IAAI,SAAS,OAAO;AACjC,SAAO;AACT;AAGA,SAAS,eAAe,MAAc,SAA0B;AAC9D,QAAM,EAAE,QAAQ,QAAQ,IAAI,eAAe,OAAO;AAClD,MAAI,CAAC,KAAK,SAAS,MAAM,EAAG,QAAO;AACnC,SAAO,YAAY,OAAO,OAAO,QAAQ,KAAK,IAAI;AACpD;AAKA,SAAS,gBACP,iBACA,YACgB;AAChB,MAAI,kBAAkB,WAAW,QAAQ;AACvC,WAAO,EAAE,MAAM,cAAc,OAAO,IAAM,QAAQ,UAAU,eAAe,WAAW;AAAA,EACxF;AACA,MAAI,kBAAkB,WAAW,SAAS;AACxC,WAAO,EAAE,MAAM,cAAc,OAAO,GAAK,QAAQ,SAAS,eAAe,WAAW;AAAA,EACtF;AACA,SAAO,EAAE,MAAM,cAAc,OAAO,GAAG,QAAQ,KAAK;AACtD;AAEA,SAAS,kBACP,MACA,UACA,MACA,aACA,YACA,QACgB;AAChB,QAAM,UAAU,SAAS,OAAO,CAAC,OAAO,eAAe,MAAM,EAAE,CAAC;AAChE,MAAI,QAAQ,UAAU,WAAW,MAAM;AACrC,WAAO;AAAA,MACL;AAAA,MACA,OAAO,OAAO;AAAA,MACd,QAAQ,GAAG,WAAW,KAAK,QAAQ,MAAM,GAAG,CAAC,EAAE,KAAK,IAAI,CAAC;AAAA,IAC3D;AAAA,EACF;AACA,MAAI,QAAQ,UAAU,WAAW,KAAK;AACpC,WAAO;AAAA,MACL;AAAA,MACA,OAAO,OAAO;AAAA,MACd,QAAQ,GAAG,WAAW,KAAK,QAAQ,MAAM,GAAG,CAAC,EAAE,KAAK,IAAI,CAAC;AAAA,IAC3D;AAAA,EACF;AACA,SAAO,EAAE,MAAM,OAAO,OAAO,MAAM,QAAQ,KAAK;AAClD;AAEA,SAAS,eAAe,MAA8B;AACpD,QAAM,WAAW,CAAC,gBAAgB,YAAY,QAAQ;AACtD,QAAM,OAAO,SAAS,OAAO,CAAC,MAAM,EAAE,KAAK,IAAI,CAAC;AAChD,MAAI,KAAK,SAAS,GAAG;AACnB,WAAO,EAAE,MAAM,qBAAqB,OAAO,KAAK,QAAQ,aAAa;AAAA,EACvE;AACA,SAAO,EAAE,MAAM,qBAAqB,OAAO,GAAG,QAAQ,KAAK;AAC7D;AAEA,SAAS,wBAAwB,QAAgC;AAC/D,QAAM,SAAS,OAAO,MAAM,KAAK,KAAK,CAAC,GAAG;AAC1C,MAAI,QAAQ,GAAG;AACb,WAAO,EAAE,MAAM,sBAAsB,OAAO,KAAK,QAAQ,GAAG,KAAK,aAAa;AAAA,EAChF;AACA,SAAO,EAAE,MAAM,sBAAsB,OAAO,GAAG,QAAQ,KAAK;AAC9D;AAWA,SAAS,iBACP,MACA,UAC0D;AAC1D,MAAI,aAAa;AACjB,QAAM,UAAoB,CAAC;AAE3B,aAAW,WAAW,UAAU;AAC9B,QAAI,eAAe,MAAM,OAAO,GAAG;AACjC;AACA,UAAI,QAAQ,SAAS,GAAG;AACtB,gBAAQ,KAAK,OAAO;AAAA,MACtB;AAAA,IACF;AAAA,EACF;AAGA,MAAI,cAAc,GAAG;AACnB,WAAO;AAAA,MACL,gBAAgB;AAAA,QACd,MAAM;AAAA,QACN,OAAO;AAAA,QACP,QAAQ,YAAY,QAAQ,KAAK,IAAI,CAAC;AAAA,MACxC;AAAA,MACA,cAAc;AAAA,IAChB;AAAA,EACF,WAAW,cAAc,GAAG;AAC1B,WAAO;AAAA,MACL,gBAAgB;AAAA,QACd,MAAM;AAAA,QACN,OAAO;AAAA,QACP,QAAQ,YAAY,QAAQ,KAAK,IAAI,CAAC;AAAA,MACxC;AAAA,MACA,cAAc;AAAA,IAChB;AAAA,EACF,WAAW,cAAc,GAAG;AAC1B,WAAO;AAAA,MACL,gBAAgB;AAAA,QACd,MAAM;AAAA,QACN,OAAO;AAAA,QACP,QAAQ,kBAAkB,QAAQ,KAAK,IAAI,CAAC;AAAA,MAC9C;AAAA,MACA,cAAc;AAAA,IAChB;AAAA,EACF;AAEA,SAAO;AAAA,IACL,gBAAgB,EAAE,MAAM,eAAe,OAAO,GAAG,QAAQ,KAAK;AAAA,IAC9D,cAAc;AAAA,EAChB;AACF;AAIO,SAAS,gBACd,QACA,cACA,iBACA,QACe;AAIf,QAAM,WAAW,OAAO,YAAY;AAIpC,QAAM,aAA+B;AAAA;AAAA,IAEnC,gBAAgB,iBAAiB,OAAO,oBAAoB;AAAA,IAC5D;AAAA,MACE;AAAA,MACA,OAAO;AAAA,MACP;AAAA,MACA;AAAA,MACA,EAAE,KAAK,GAAG,MAAM,EAAE;AAAA,MAClB,EAAE,MAAM,GAAG,KAAK,KAAK,MAAM,EAAI;AAAA,IACjC;AAAA,IACA;AAAA,MACE;AAAA,MACA,OAAO;AAAA,MACP;AAAA,MACA;AAAA,MACA,EAAE,KAAK,GAAG,MAAM,EAAE;AAAA,MAClB,EAAE,MAAM,GAAG,KAAK,KAAK,MAAM,EAAI;AAAA,IACjC;AAAA,IACA;AAAA,MACE;AAAA,MACA,OAAO;AAAA,MACP;AAAA,MACA;AAAA,MACA,EAAE,KAAK,GAAG,MAAM,EAAE;AAAA,MAClB,EAAE,MAAM,GAAG,KAAK,KAAK,MAAM,EAAI;AAAA,IACjC;AAAA,IACA;AAAA,MACE;AAAA,MACA,OAAO;AAAA,MACP;AAAA,MACA;AAAA,MACA,EAAE,KAAK,GAAG,MAAM,EAAE;AAAA,MAClB,EAAE,MAAM,GAAG,KAAK,KAAK,MAAM,IAAI;AAAA,IACjC;AAAA,IACA;AAAA,MACE;AAAA,MACA,OAAO;AAAA,MACP;AAAA,MACA;AAAA,MACA,EAAE,KAAK,GAAG,MAAM,EAAE;AAAA,MAClB,EAAE,MAAM,GAAG,KAAK,IAAM,MAAM,GAAK;AAAA,IACnC;AAAA,IACA,eAAe,QAAQ;AAAA,IACvB,wBAAwB,MAAM;AAAA;AAAA,IAG9B;AAAA,MACE;AAAA,MACA,OAAO;AAAA,MACP;AAAA,MACA;AAAA,MACA,EAAE,KAAK,GAAG,MAAM,EAAE;AAAA,MAClB,EAAE,MAAM,GAAG,KAAK,KAAK,MAAM,IAAI;AAAA,IACjC;AAAA,IACA;AAAA,MACE;AAAA,MACA,OAAO;AAAA,MACP;AAAA,MACA;AAAA,MACA,EAAE,KAAK,GAAG,MAAM,EAAE;AAAA,MAClB,EAAE,MAAM,GAAG,KAAK,KAAK,MAAM,IAAI;AAAA,IACjC;AAAA,IACA;AAAA,MACE;AAAA,MACA,OAAO;AAAA,MACP;AAAA,MACA;AAAA,MACA,EAAE,KAAK,GAAG,MAAM,EAAE;AAAA,MAClB,EAAE,MAAM,GAAG,KAAK,KAAK,MAAM,IAAI;AAAA,IACjC;AAAA,IACA;AAAA,MACE;AAAA,MACA,OAAO;AAAA,MACP;AAAA,MACA;AAAA,MACA,EAAE,KAAK,GAAG,MAAM,EAAE;AAAA,MAClB,EAAE,MAAM,GAAG,KAAK,KAAK,MAAM,IAAI;AAAA,IACjC;AAAA,IACA;AAAA,MACE;AAAA,MACA,OAAO;AAAA,MACP;AAAA,MACA;AAAA,MACA,EAAE,KAAK,GAAG,MAAM,EAAE;AAAA,MAClB,EAAE,MAAM,GAAG,KAAK,KAAK,MAAM,IAAI;AAAA,IACjC;AAAA,IACA;AAAA,MACE;AAAA,MACA,OAAO;AAAA,MACP;AAAA,MACA;AAAA,MACA,EAAE,KAAK,GAAG,MAAM,EAAE;AAAA,MAClB,EAAE,MAAM,GAAG,KAAK,KAAK,MAAM,IAAI;AAAA,IACjC;AAAA,EACF;AAMA,QAAM,gBAAgB,iBAAiB,UAAU,OAAO,mBAAmB;AAC3E,aAAW,KAAK,cAAc,cAAc;AAC5C,QAAM,eAAe,cAAc;AAGnC,QAAM,UAAU,WAAW,OAAO,CAAC,MAAM,EAAE,WAAW,IAAI,EAAE,IAAI,CAAC,MAAM,EAAE,MAAO;AAGhF,QAAM,UAAU,OAAO;AACvB,MAAI,gBAAgB;AACpB,aAAW,KAAK,YAAY;AAC1B,UAAM,IAAI,QAAQ,EAAE,IAAI,KAAK;AAC7B,qBAAiB,EAAE,QAAQ;AAAA,EAC7B;AAIA,QAAM,mBAAmB,OAAO,kBAAkB,OAAO,CAAC,OAAO,eAAe,UAAU,EAAE,CAAC;AAG7F,MAAI,iBAAiB,UAAU,GAAG;AAChC,UAAMA,cAAa;AAAA,MACjB,KAAK,IAAI,eAAe,GAAG;AAAA;AAAA,MAC3B,OAAO;AAAA,IACT;AACA,WAAO;AAAA,MACL,OAAO;AAAA,MACP,MAAM;AAAA,MACN,YAAY,KAAK,IAAIA,aAAY,IAAI;AAAA,MACrC;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAGA,QAAM,EAAE,cAAc,eAAe,iBAAiB,IAAI,OAAO;AACjE,MAAI;AACJ,MAAI;AAEJ,MAAI,gBAAgB,cAAc;AAChC,WAAO;AACP,2BAAuB,eAAe;AAAA,EACxC,WAAW,gBAAgB,eAAe;AACxC,WAAO;AACP,2BAAuB,KAAK,IAAI,gBAAgB,cAAc,gBAAgB,aAAa;AAAA,EAC7F,WAAW,gBAAgB,kBAAkB;AAC3C,WAAO;AACP,2BAAuB,KAAK;AAAA,MAC1B,gBAAgB;AAAA,MAChB,mBAAmB;AAAA,IACrB;AAAA,EACF,OAAO;AACL,WAAO;AACP,2BAAuB,gBAAgB;AAAA,EACzC;AAGA,QAAM,aAAa,oBAAoB,sBAAsB,OAAO,mBAAmB;AAGvF,MAAI,aAAa,OAAO,qBAAqB;AAC3C,WAAO,EAAE,OAAO,eAAe,MAAM,MAAM,YAAY,SAAS,cAAc,WAAW;AAAA,EAC3F;AAEA,SAAO,EAAE,OAAO,eAAe,MAAM,YAAY,SAAS,cAAc,WAAW;AACrF;AAMA,SAAS,oBAAoB,UAAkB,WAA2B;AACxE,SAAO,KAAK,IAAI,KAAK,IAAI,CAAC,YAAY,QAAQ;AAChD;;;AC1ZA,IAAM,oBAAoB;AAI1B,IAAM,uBAAuB;AAC7B,IAAM,wBAAwB;AAWvB,SAAS,YACd,MACA,YACA,QACA,WACA,aACA,cACA,sBACA,iBACA,gBACA,cACiB;AACjB,QAAM,aAAa,YAAY,IAAI;AACnC,QAAM,QAAQ,WAAW;AACzB,QAAM,UAAU,aAAa,IAAI,KAAK;AAEtC,MAAI;AACJ,MAAI,SAAS,cAAc,QAAW;AACpC,mBAAe,QAAQ;AAAA,EACzB,OAAO;AACL,UAAM,aAAa,SAAS,cAAc;AAC1C,UAAM,cAAc,SAAS,eAAe;AAC5C,mBACG,uBAAuB,MAAa,aAAc,kBAAkB,MAAa;AAAA,EACtF;AAGA,QAAM,cAAc,aAAa,IAAI,iBAAiB;AACtD,QAAM,iBAAiB,aAAa,cAAc;AAClD,QAAM,kBAAkB,aAAa,eAAe;AACpD,QAAM,gBAAiB,uBAAuB,MAAa;AAC3D,QAAM,iBAAkB,kBAAkB,MAAa;AACvD,QAAM,eAAe,gBAAgB;AAKrC,QAAM,UACJ,mBAAmB,aAAa,YAAY,SACxC,IACA,eAAe,IACb,KAAK,IAAI,IAAI,eAAe,gBAAgB,YAAY,IACxD;AAER,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,GAAI,iBAAiB,UAAa,EAAE,aAAa;AAAA,EACnD;AACF;AAKO,SAAS,iBAAiB,MAAY,aAAiD;AAC5F,QAAM,SAAS,YAAY,IAAI;AAC/B,SAAO,CAAC,OAAO,SAAS,GAAG,OAAO,QAAQ;AAC5C;AAQA,IAAM,wBAAwB;AAE9B,IAAM,kBAAkB;AAEjB,SAAS,mBACd,OACA,cACA,sBACA,iBACA,gBACiE;AACjE,QAAM,UAAU,aAAa,IAAI,KAAK;AAEtC,MAAI;AACJ,MAAI,SAAS,cAAc,QAAW;AAEpC,mBAAe,KAAK,IAAI,QAAQ,aAAa,IAAI,wBAAwB,MAAM,eAAe;AAAA,EAChG,OAAO;AAEL,UAAM,aAAa,SAAS,cAAc;AAC1C,UAAM,cAAc,SAAS,eAAe;AAC5C,UAAM,YAAa,uBAAuB,MAAa;AACvD,UAAM,aAAc,kBAAkB,MAAa;AAEnD,mBAAe,KAAK;AAAA,OACjB,YAAY,eAAe,IAAI,wBAAwB;AAAA,MACxD;AAAA,IACF;AAAA,EACF;AAGA,QAAM,cAAc,aAAa,IAAI,iBAAiB;AACtD,QAAM,iBAAiB,aAAa,cAAc;AAClD,QAAM,kBAAkB,aAAa,eAAe;AACpD,QAAM,gBAAiB,uBAAuB,MAAa;AAC3D,QAAM,iBAAkB,kBAAkB,MAAa;AACvD,QAAM,eAAe,gBAAgB;AAGrC,QAAM,UACJ,mBAAmB,YACf,IACA,eAAe,IACb,KAAK,IAAI,IAAI,eAAe,gBAAgB,YAAY,IACxD;AAER,SAAO,EAAE,cAAc,cAAc,QAAQ;AAC/C;AAQO,SAAS,oBACd,QACA,UACA,qBACU;AACV,MAAI,CAAC,SAAU,QAAO;AACtB,QAAM,WAAW,OAAO,OAAO,mBAAmB;AAClD,SAAO,SAAS,SAAS,IAAI,WAAW;AAC1C;AAQO,SAAS,eACd,QACA,WACA,gBACU;AACV,MAAI,CAAC,UAAW,QAAO;AACvB,QAAM,WAAW,OAAO,OAAO,cAAc;AAC7C,SAAO,SAAS,SAAS,IAAI,WAAW;AAC1C;AAOO,SAAS,oBAAoB,QAAkB,aAAoC;AACxF,MAAI,YAAY,SAAS,EAAG,QAAO;AACnC,QAAM,WAAW,OAAO,OAAO,CAAC,MAAM,CAAC,YAAY,IAAI,CAAC,CAAC;AACzD,SAAO,SAAS,SAAS,IAAI,WAAW;AAC1C;AAYO,SAAS,yBACd,MACA,aACA,sBACA,kBACU;AACV,QAAM,YAAY,iBAAiB,MAAM,WAAW;AAGpD,QAAM,WAAW,UAAU,OAAO,CAAC,YAAY;AAC7C,UAAM,gBAAgB,iBAAiB,OAAO;AAC9C,QAAI,kBAAkB,QAAW;AAE/B,aAAO;AAAA,IACT;AAEA,WAAO,iBAAiB,uBAAuB;AAAA,EACjD,CAAC;AAID,MAAI,SAAS,WAAW,GAAG;AACzB,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AAMO,SAAS,2BACd,QACA,sBACA,uBACA,iBACU;AACV,QAAM,WAAW,OAAO,OAAO,CAAC,YAAY;AAC1C,UAAM,eAAe,gBAAgB,OAAO;AAC5C,QAAI,CAAC,aAAc,QAAO;AAC1B,WACE,aAAa,kBAAkB,uBAAuB,yBAAyB,OAC/E,aAAa,aAAa;AAAA,EAE9B,CAAC;AACD,SAAO;AACT;;;AClPA,IAAM,YAAY;AAGX,SAAS,eAAe,MAAsB;AACnD,MAAI,KAAK,WAAW,EAAG,QAAO;AAC9B,QAAM,MAAM,KAAK,MAAM,SAAS,GAAG,UAAU;AAC7C,SAAO,MAAM,KAAK,MAAM,KAAK,SAAS,OAAO,CAAC;AAChD;AAGO,SAAS,UAAU,uBAAuC;AAC/D,SAAO,KAAK,IAAI,GAAG,KAAK,IAAI,KAAO,qBAAqB,CAAC;AAC3D;AAOO,SAAS,cAAc,OAAe,OAAuB;AAClE,MAAI,MAAM,UAAU,MAAO,QAAO;AAClC,QAAM,eAAe,KAAK,KAAK,QAAQ,CAAC;AACxC,SAAO,GAAG,MAAM,MAAM,GAAG,YAAY,CAAC;AAAA,EAAK,MAAM,MAAM,EAAE,QAAQ,aAAa,CAAC;AACjF;;;ACdA,SAAS,gBACP,aACA,YACA,SACA,MAAY,oBAAI,KAAK,GACK;AAC1B,MAAI,CAAC,cAAc,WAAW,WAAW,EAAG,QAAO;AAEnD,MAAI,SAAS;AACb,aAAW,SAAS,YAAY;AAE9B,UAAM,QAAQ,IAAI,KAAK,MAAM,SAAS;AACtC,UAAM,MAAM,IAAI,KAAK,MAAM,OAAO;AAClC,QAAI,MAAM,SAAS,OAAO,IAAK;AAG/B,QAAI,MAAM,YAAY,CAAC,MAAM,SAAS,SAAS,OAAO,EAAG;AAGzD,QAAI,WAAW,aAAa;AAC1B,eAAS,EAAE,GAAG,YAAY;AAC1B,iBAAW,KAAK,OAAO,KAAK,MAAM,GAAa;AAC7C,eAAO,CAAC,IAAI,EAAE,GAAG,OAAO,CAAC,EAAE;AAAA,MAC7B;AAAA,IACF;AAGA,eAAW,CAAC,MAAM,QAAQ,KAAK,OAAO,QAAQ,MAAM,aAAa,GAG5D;AACH,UAAI,CAAC,OAAO,IAAI,EAAG;AACnB,UAAI,SAAS,QAAS,QAAO,IAAI,EAAE,UAAU,SAAS;AACtD,UAAI,SAAS,SAAU,QAAO,IAAI,EAAE,WAAW,SAAS;AAAA,IAC1D;AAAA,EACF;AAEA,SAAO;AACT;AAQO,SAAS,uBACd,aACA,mBAC0B;AAC1B,MAAI,CAAC,qBAAqB,kBAAkB,WAAW,EAAG,QAAO;AACjE,QAAM,OAAO,IAAI,IAAI,iBAAiB;AACtC,MAAI,SAAS;AACb,aAAW,QAAQ,OAAO,KAAK,WAAW,GAAa;AACrD,UAAM,SAAS,YAAY,IAAI;AAC/B,UAAM,QAAQ,CAAC,OAAO,SAAS,GAAG,OAAO,QAAQ,EAAE,OAAO,CAAC,UAAU,CAAC,KAAK,IAAI,KAAK,CAAC;AACrF,QAAI,MAAM,WAAW,KAAM,MAAM,CAAC,MAAM,OAAO,WAAW,MAAM,WAAW,OAAO,SAAS,SAAS,GAAI;AACtG;AAAA,IACF;AACA,QAAI,WAAW,YAAa,UAAS,EAAE,GAAG,YAAY;AACtD,WAAO,IAAI,IAAI,EAAE,SAAS,MAAM,CAAC,GAAG,UAAU,MAAM,MAAM,CAAC,EAAE;AAAA,EAC/D;AACA,SAAO;AACT;AAOO,IAAM,gBAAN,MAA8C;AAAA,EAC1C,OAAO;AAAA,EAEhB,MACE,QACA,cACA,iBACA,SACiB;AACjB,UAAM,EAAE,QAAQ,aAAa,IAAI;AAEjC,UAAM,WAAW,GAAG,gBAAgB,EAAE,IAAI,MAAM;AAChD,UAAM,kBAAkB,eAAe,QAAQ;AAC/C,UAAM,QAAQ,UAAU,OAAO,WAAW,qBAAqB;AAC/D,UAAM,gBAAgB,cAAc,QAAQ,KAAK;AACjD,UAAM,sBAAsB,eAAe,cAAc,cAAc,KAAK,IAAI;AAGhF,UAAM,aAAa;AAAA,MACjB;AAAA,MACA;AAAA,MACA;AAAA,MACA,OAAO;AAAA,IACT;AAGA,UAAM,EAAE,eAAe,IAAI;AAC3B,QAAI;AACJ,QAAI;AACJ,QAAI;AAEJ,QAAI,mBAAmB,OAAO;AAI5B,oBAAc,OAAO,YAAY,OAAO;AACxC,sBAAgB,OAAO,WAAW,WAAW;AAC7C,gBAAU;AAAA,IACZ,WAAW,mBAAmB,WAAW;AAIvC,oBAAc,OAAO,gBAAgB,OAAO;AAC5C,sBAAgB,OAAO,eAAe,eAAe;AACrD,gBAAU;AAAA,IACZ,OAAO;AAOL,YAAM,eAAe,WAAW,gBAAgB;AAChD,YAAM,gBAAgB,gBAAgB;AACtC,YAAM,qBAAqB,OAAO,UAAU;AAC5C,YAAM,oBAAoB,QAAQ,iBAAiB,QAAQ,YAAY;AACvE,UAAI;AACJ,UAAI,uBAAuB,OAAO;AAEhC,0BAAkB;AAAA,MACpB,WAAW,uBAAuB,MAAM;AAEtC,0BAAkB,OAAO,gBAAgB;AAAA,MAC3C,OAAO;AAEL,2BAAmB,qBAAqB,kBAAkB,OAAO,gBAAgB;AAAA,MACnF;AACA,oBAAc,kBAAkB,OAAO,eAAgB,OAAO;AAC9D,sBAAgB,kBAAkB,aAAa,oBAAoB,aAAa,EAAE,KAAK;AACvF,gBAAU,kBAAkB,YAAY;AAAA,IAC1C;AAGA,kBAAc,gBAAgB,aAAa,OAAO,YAAY,SAAU,QAAQ,GAAG;AAInF,kBAAc,uBAAuB,aAAa,QAAQ,iBAAiB;AAE3E,UAAM,oBAAoB,WAAW;AAGrC,QAAI,kBAAkB,OAAO,UAAU,uBAAuB;AAC5D,YAAMC,YAAW;AAAA,QACf;AAAA,QACA;AAAA,QACA;AAAA,QACA,iBAAiB,OAAO,UAAU,qBAAqB,UAAU,aAAa;AAAA,QAC9E;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AACA,aAAO,EAAE,GAAGA,WAAU,aAAa,QAAQ;AAAA,IAC7C;AAMA,UAAM,sBAAsB,QAAQ,6BAA6B;AAEjE,QAAI;AACJ,QAAI;AACJ,UAAM,SAA0B;AAChC,QAAI,YAAY,SAAS,WAAW,MAAM,QAAQ,CAAC,CAAC,MAAM,WAAW,QAAQ,KAAK,IAAI,CAAC;AAEvF,QAAI,WAAW,SAAS,MAAM;AAC5B,aAAO,WAAW;AAClB,mBAAa,WAAW;AAAA,IAC1B,OAAO;AAEL,aAAO,OAAO,UAAU;AACxB,mBAAa;AACb,mBAAa,4BAA4B,IAAI;AAAA,IAC/C;AAGA,QAAI,qBAAqB;AACvB,YAAM,WAAiC,EAAE,QAAQ,GAAG,QAAQ,GAAG,SAAS,GAAG,WAAW,EAAE;AACxF,YAAM,UAAU,OAAO,UAAU;AACjC,UAAI,SAAS,IAAI,IAAI,SAAS,OAAO,GAAG;AACtC,qBAAa,kBAAkB,OAAO;AACtC,eAAO;AAAA,MACT;AAAA,IACF;AAGA,iBAAa;AAEb,UAAM,WAAW;AAAA,MACf;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AACA,WAAO,EAAE,GAAG,UAAU,aAAa,QAAQ;AAAA,EAC7C;AACF;AAIA,IAAM,WAAW,oBAAI,IAA4B;AACjD,SAAS,IAAI,SAAS,IAAI,cAAc,CAAC;AAElC,SAAS,YAAY,MAA8B;AACxD,QAAM,WAAW,SAAS,IAAI,IAAI;AAClC,MAAI,CAAC,UAAU;AACb,UAAM,IAAI,MAAM,6BAA6B,IAAI,EAAE;AAAA,EACrD;AACA,SAAO;AACT;AAEO,SAAS,iBAAiB,UAAgC;AAC/D,WAAS,IAAI,SAAS,MAAM,QAAQ;AACtC;;;AC9OO,IAAM,6BACX,OAAO,OAAO;AAAA,EACZ,4BAA4B;AAAA,IAC1B,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,gBAAgB;AAAA,EAClB;AAAA,EACA,8BAA8B;AAAA,IAC5B,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,gBAAgB;AAAA,EAClB;AAAA,EACA,8BAA8B;AAAA;AAAA,IAC5B,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,gBAAgB;AAAA,EAClB;AAAA,EACA,6BAA6B;AAAA,IAC3B,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,gBAAgB;AAAA,EAClB;AAAA,EACA,6BAA6B;AAAA,IAC3B,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,gBAAgB;AAAA,EAClB;AAAA,EACA,6BAA6B;AAAA,IAC3B,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,gBAAgB;AAAA,EAClB;AAAA,EACA,2BAA2B;AAAA,IACzB,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,gBAAgB;AAAA,EAClB;AAAA,EACA,6BAA6B;AAAA,IAC3B,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,gBAAgB;AAAA,EAClB;AAAA,EACA,+BAA+B;AAAA,IAC7B,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,gBAAgB;AAAA,EAClB;AAAA,EACA,+BAA+B;AAAA;AAAA,IAC7B,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,gBAAgB;AAAA,EAClB;AAAA,EACA,6BAA6B;AAAA,IAC3B,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,gBAAgB;AAAA,EAClB;AAAA,EACA,+BAA+B;AAAA,IAC7B,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,gBAAgB;AAAA,EAClB;AAAA,EACA,0BAA0B;AAAA;AAAA,IACxB,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,gBAAgB;AAAA,EAClB;AAAA,EACA,0BAA0B;AAAA,IACxB,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,gBAAgB;AAAA,EAClB;AAAA,EACA,8BAA8B;AAAA,IAC5B,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,gBAAgB;AAAA,EAClB;AAAA,EACA,yCAAyC;AAAA,IACvC,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,gBAAgB;AAAA,EAClB;AAAA,EACA,4BAA4B;AAAA,IAC1B,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,gBAAgB;AAAA,EAClB;AAAA,EACA,gCAAgC;AAAA,IAC9B,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,gBAAgB;AAAA,EAClB;AAAA,EACA,2BAA2B;AAAA,IACzB,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,gBAAgB;AAAA,EAClB;AAAA,EACA,gCAAgC;AAAA,IAC9B,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,gBAAgB;AAAA,EAClB;AAAA,EACA,yBAAyB;AAAA,IACvB,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,gBAAgB;AAAA,EAClB;AAAA,EACA,iCAAiC;AAAA,IAC/B,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,gBAAgB;AAAA,EAClB;AAAA,EACA,gCAAgC;AAAA,IAC9B,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,gBAAgB;AAAA,EAClB;AAAA,EACA,yBAAyB;AAAA,IACvB,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,gBAAgB;AAAA,EAClB;AAAA,EACA,2BAA2B;AAAA,IACzB,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,gBAAgB;AAAA,EAClB;AAAA,EACA,gCAAgC;AAAA,IAC9B,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,gBAAgB;AAAA,EAClB;AAAA,EACA,2BAA2B;AAAA,IACzB,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,gBAAgB;AAAA,EAClB;AAAA,EACA,2BAA2B;AAAA,IACzB,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,gBAAgB;AAAA,EAClB;AAAA,EACA,yBAAyB;AAAA;AAAA,IACvB,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,gBAAgB;AAAA,EAClB;AAAA,EACA,wBAAwB;AAAA,IACtB,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,gBAAgB;AAAA,EAClB;AAAA,EACA,sBAAsB;AAAA,IACpB,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,gBAAgB;AAAA,EAClB;AAAA,EACA,2BAA2B;AAAA;AAAA,IACzB,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,gBAAgB;AAAA,EAClB;AAAA,EACA,oBAAoB;AAAA,IAClB,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,gBAAgB;AAAA,EAClB;AAAA,EACA,+BAA+B;AAAA;AAAA,IAC7B,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,gBAAgB;AAAA,EAClB;AAAA,EACA,2BAA2B;AAAA;AAAA,IACzB,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,gBAAgB;AAAA,EAClB;AAAA,EACA,iDAAiD;AAAA;AAAA,IAC/C,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,gBAAgB;AAAA,EAClB;AAAA,EACA,gCAAgC;AAAA;AAAA,IAC9B,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,gBAAgB;AAAA,EAClB;AAAA,EACA,iCAAiC;AAAA;AAAA,IAC/B,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,gBAAgB;AAAA,EAClB;AAAA,EACA,sBAAsB;AAAA,IACpB,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,gBAAgB;AAAA,EAClB;AAAA,EACA,kBAAkB;AAAA,IAChB,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,gBAAgB;AAAA,EAClB;AAAA,EACA,uBAAuB;AAAA,IACrB,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,gBAAgB;AAAA,EAClB;AAAA,EACA,uBAAuB;AAAA,IACrB,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,gBAAgB;AAAA,EAClB;AAAA,EACA,iBAAiB;AAAA,IACf,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,gBAAgB;AAAA,EAClB;AAAA,EACA,sBAAsB;AAAA,IACpB,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,gBAAgB;AAAA,EAClB;AAAA,EACA,qBAAqB;AAAA,IACnB,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,gBAAgB;AAAA,EAClB;AAAA,EACA,kBAAkB;AAAA,IAChB,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,gBAAgB;AAAA,EAClB;AAAA,EACA,kBAAkB;AAAA,IAChB,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,gBAAgB;AAAA,EAClB;AAAA,EACA,sBAAsB;AAAA;AAAA,IACpB,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,gBAAgB;AAAA,EAClB;AAAA,EACA,wBAAwB;AAAA;AAAA,IACtB,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,gBAAgB;AAAA,EAClB;AAAA,EACA,kBAAkB;AAAA,IAChB,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,gBAAgB;AAAA,EAClB;AAAA,EACA,uBAAuB;AAAA,IACrB,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,gBAAgB;AAAA,EAClB;AAAA,EACA,uBAAuB;AAAA,IACrB,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,gBAAgB;AAAA,EAClB;AAAA,EACA,sBAAsB;AAAA;AAAA,IACpB,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,gBAAgB;AAAA,EAClB;AAAA,EACA,kBAAkB;AAAA,IAChB,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,gBAAgB;AAAA,EAClB;AAAA,EACA,sBAAsB;AAAA;AAAA,IACpB,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,gBAAgB;AAAA,EAClB;AAAA,EACA,uBAAuB;AAAA,IACrB,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,gBAAgB;AAAA,EAClB;AAAA,EACA,2BAA2B;AAAA,IACzB,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,gBAAgB;AAAA,EAClB;AAAA,EACA,sBAAsB;AAAA,IACpB,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,gBAAgB;AAAA,EAClB;AAAA,EACA,0BAA0B;AAAA,IACxB,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,gBAAgB;AAAA,EAClB;AAAA,EACA,wBAAwB;AAAA,IACtB,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,gBAAgB;AAAA,EAClB;AAAA,EACA,4BAA4B;AAAA,IAC1B,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,gBAAgB;AAAA,EAClB;AAAA,EACA,sBAAsB;AAAA,IACpB,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,gBAAgB;AAAA,EAClB;AAAA,EACA,qBAAqB;AAAA,IACnB,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,gBAAgB;AAAA,EAClB;AAAA,EACA,oBAAoB;AAAA,IAClB,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,gBAAgB;AAAA,EAClB;AAAA,EACA,sBAAsB;AAAA,IACpB,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,gBAAgB;AAAA,EAClB;AAAA,EACA,aAAa;AAAA,IACX,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,gBAAgB;AAAA,EAClB;AAAA,EACA,aAAa;AAAA,IACX,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,gBAAgB;AAAA,EAClB;AAAA,EACA,kBAAkB;AAAA,IAChB,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,gBAAgB;AAAA,EAClB;AAAA,EACA,kBAAkB;AAAA,IAChB,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,gBAAgB;AAAA,EAClB;AAAA,EACA,yBAAyB;AAAA;AAAA,IACvB,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,gBAAgB;AAAA,EAClB;AAAA,EACA,0BAA0B;AAAA;AAAA,IACxB,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,gBAAgB;AAAA,EAClB;AAAA,EACA,sBAAsB;AAAA,IACpB,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,gBAAgB;AAAA,EAClB;AAAA,EACA,oBAAoB;AAAA,IAClB,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,gBAAgB;AAAA,EAClB;AAAA,EACA,qBAAqB;AAAA,IACnB,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,gBAAgB;AAAA,EAClB;AAAA,EACA,sBAAsB;AAAA,IACpB,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,gBAAgB;AAAA,EAClB;AAAA,EACA,oBAAoB;AAAA;AAAA,IAClB,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,gBAAgB;AAAA,EAClB;AAAA,EACA,uBAAuB;AAAA;AAAA,IACrB,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,gBAAgB;AAAA,EAClB;AAAA,EACA,gBAAgB;AAAA,IACd,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,gBAAgB;AAAA,EAClB;AAAA,EACA,gBAAgB;AAAA,IACd,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,gBAAgB;AAAA,EAClB;AAAA,EACA,gBAAgB;AAAA,IACd,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,gBAAgB;AAAA,EAClB;AAAA,EACA,gBAAgB;AAAA,IACd,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,gBAAgB;AAAA,EAClB;AAAA,EACA,sBAAsB;AAAA,IACpB,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,gBAAgB;AAAA,EAClB;AAAA,EACA,oBAAoB;AAAA,IAClB,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,gBAAgB;AAAA,EAClB;AAAA,EACA,wBAAwB;AAAA,IACtB,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,gBAAgB;AAAA,EAClB;AAAA,EACA,aAAa;AAAA,IACX,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,gBAAgB;AAAA,EAClB;AAAA,EACA,mBAAmB;AAAA,IACjB,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,gBAAgB;AAAA,EAClB;AAAA,EACA,eAAe;AAAA,IACb,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,gBAAgB;AAAA,EAClB;AAAA,EACA,eAAe;AAAA,IACb,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,gBAAgB;AAAA,EAClB;AAAA,EACA,eAAe;AAAA,IACb,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,gBAAgB;AAAA,EAClB;AAAA,EACA,qBAAqB;AAAA,IACnB,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,gBAAgB;AAAA,EAClB;AACF,CAAC;;;ACjjBH;AAAA,EACE,4BAA4B;AAAA,IAC1B,YAAc;AAAA,IACd,WAAa;AAAA,IACb,cAAgB;AAAA,IAChB,uBAAyB;AAAA,IACzB,WAAa;AAAA,IACb,SAAW;AAAA,EACb;AAAA,EACA,8BAA8B;AAAA,IAC5B,YAAc;AAAA,IACd,WAAa;AAAA,IACb,cAAgB;AAAA,IAChB,uBAAyB;AAAA,IACzB,WAAa;AAAA,IACb,SAAW;AAAA,EACb;AAAA,EACA,6BAA6B;AAAA,IAC3B,YAAc;AAAA,IACd,WAAa;AAAA,IACb,cAAgB;AAAA,IAChB,uBAAyB;AAAA,IACzB,WAAa;AAAA,IACb,SAAW;AAAA,EACb;AAAA,EACA,6BAA6B;AAAA,IAC3B,YAAc;AAAA,IACd,WAAa;AAAA,IACb,cAAgB;AAAA,IAChB,uBAAyB;AAAA,IACzB,WAAa;AAAA,IACb,SAAW;AAAA,EACb;AAAA,EACA,6BAA6B;AAAA,IAC3B,YAAc;AAAA,IACd,WAAa;AAAA,IACb,cAAgB;AAAA,IAChB,uBAAyB;AAAA,IACzB,WAAa;AAAA,IACb,SAAW;AAAA,EACb;AAAA,EACA,2BAA2B;AAAA,IACzB,YAAc;AAAA,IACd,WAAa;AAAA,IACb,cAAgB;AAAA,IAChB,uBAAyB;AAAA,IACzB,WAAa;AAAA,IACb,SAAW;AAAA,EACb;AAAA,EACA,+BAA+B;AAAA,IAC7B,YAAc;AAAA,IACd,WAAa;AAAA,IACb,cAAgB;AAAA,IAChB,uBAAyB;AAAA,IACzB,WAAa;AAAA,IACb,SAAW;AAAA,EACb;AAAA,EACA,+BAA+B;AAAA,IAC7B,YAAc;AAAA,IACd,WAAa;AAAA,IACb,cAAgB;AAAA,IAChB,uBAAyB;AAAA,IACzB,WAAa;AAAA,IACb,SAAW;AAAA,EACb;AAAA,EACA,6BAA6B;AAAA,IAC3B,YAAc;AAAA,IACd,WAAa;AAAA,IACb,cAAgB;AAAA,IAChB,uBAAyB;AAAA,IACzB,WAAa;AAAA,IACb,SAAW;AAAA,EACb;AAAA,EACA,0BAA0B;AAAA,IACxB,YAAc;AAAA,IACd,WAAa;AAAA,IACb,cAAgB;AAAA,IAChB,uBAAyB;AAAA,IACzB,WAAa;AAAA,IACb,SAAW;AAAA,EACb;AAAA,EACA,8BAA8B;AAAA,IAC5B,YAAc;AAAA,IACd,WAAa;AAAA,IACb,cAAgB;AAAA,IAChB,uBAAyB;AAAA,IACzB,WAAa;AAAA,IACb,SAAW;AAAA,EACb;AAAA,EACA,4BAA4B;AAAA,IAC1B,YAAc;AAAA,IACd,WAAa;AAAA,IACb,cAAgB;AAAA,IAChB,uBAAyB;AAAA,IACzB,WAAa;AAAA,IACb,SAAW;AAAA,EACb;AAAA,EACA,gCAAgC;AAAA,IAC9B,YAAc;AAAA,IACd,WAAa;AAAA,IACb,cAAgB;AAAA,IAChB,uBAAyB;AAAA,IACzB,WAAa;AAAA,IACb,SAAW;AAAA,EACb;AAAA,EACA,2BAA2B;AAAA,IACzB,YAAc;AAAA,IACd,WAAa;AAAA,IACb,cAAgB;AAAA,IAChB,uBAAyB;AAAA,IACzB,WAAa;AAAA,IACb,SAAW;AAAA,EACb;AAAA,EACA,gCAAgC;AAAA,IAC9B,YAAc;AAAA,IACd,WAAa;AAAA,IACb,cAAgB;AAAA,IAChB,uBAAyB;AAAA,IACzB,WAAa;AAAA,IACb,SAAW;AAAA,EACb;AAAA,EACA,yBAAyB;AAAA,IACvB,YAAc;AAAA,IACd,WAAa;AAAA,IACb,cAAgB;AAAA,IAChB,uBAAyB;AAAA,IACzB,WAAa;AAAA,IACb,SAAW;AAAA,EACb;AAAA,EACA,iCAAiC;AAAA,IAC/B,YAAc;AAAA,IACd,WAAa;AAAA,IACb,cAAgB;AAAA,IAChB,uBAAyB;AAAA,IACzB,WAAa;AAAA,IACb,SAAW;AAAA,EACb;AAAA,EACA,gCAAgC;AAAA,IAC9B,YAAc;AAAA,IACd,WAAa;AAAA,IACb,cAAgB;AAAA,IAChB,uBAAyB;AAAA,IACzB,WAAa;AAAA,IACb,SAAW;AAAA,EACb;AAAA,EACA,yBAAyB;AAAA,IACvB,YAAc;AAAA,IACd,WAAa;AAAA,IACb,cAAgB;AAAA,IAChB,uBAAyB;AAAA,IACzB,WAAa;AAAA,IACb,SAAW;AAAA,EACb;AAAA,EACA,2BAA2B;AAAA,IACzB,YAAc;AAAA,IACd,WAAa;AAAA,IACb,cAAgB;AAAA,IAChB,uBAAyB;AAAA,IACzB,WAAa;AAAA,IACb,SAAW;AAAA,EACb;AAAA,EACA,gCAAgC;AAAA,IAC9B,YAAc;AAAA,IACd,WAAa;AAAA,IACb,cAAgB;AAAA,IAChB,uBAAyB;AAAA,IACzB,WAAa;AAAA,IACb,SAAW;AAAA,EACb;AAAA,EACA,2BAA2B;AAAA,IACzB,YAAc;AAAA,IACd,WAAa;AAAA,IACb,cAAgB;AAAA,IAChB,uBAAyB;AAAA,IACzB,WAAa;AAAA,IACb,SAAW;AAAA,EACb;AAAA,EACA,wBAAwB;AAAA,IACtB,YAAc;AAAA,IACd,WAAa;AAAA,IACb,cAAgB;AAAA,IAChB,uBAAyB;AAAA,IACzB,WAAa;AAAA,IACb,SAAW;AAAA,EACb;AAAA,EACA,sBAAsB;AAAA,IACpB,YAAc;AAAA,IACd,WAAa;AAAA,IACb,cAAgB;AAAA,IAChB,uBAAyB;AAAA,IACzB,WAAa;AAAA,IACb,SAAW;AAAA,EACb;AAAA,EACA,oBAAoB;AAAA,IAClB,YAAc;AAAA,IACd,WAAa;AAAA,IACb,cAAgB;AAAA,IAChB,uBAAyB;AAAA,IACzB,WAAa;AAAA,IACb,SAAW;AAAA,EACb;AAAA,EACA,2BAA2B;AAAA,IACzB,YAAc;AAAA,IACd,WAAa;AAAA,IACb,cAAgB;AAAA,IAChB,uBAAyB;AAAA,IACzB,WAAa;AAAA,IACb,SAAW;AAAA,EACb;AAAA,EACA,iDAAiD;AAAA,IAC/C,YAAc;AAAA,IACd,WAAa;AAAA,IACb,cAAgB;AAAA,IAChB,uBAAyB;AAAA,IACzB,WAAa;AAAA,IACb,SAAW;AAAA,EACb;AAAA,EACA,kCAAkC;AAAA,IAChC,YAAc;AAAA,IACd,WAAa;AAAA,IACb,cAAgB;AAAA,IAChB,uBAAyB;AAAA,IACzB,WAAa;AAAA,IACb,SAAW;AAAA,EACb;AAAA,EACA,8BAA8B;AAAA,IAC5B,YAAc;AAAA,IACd,WAAa;AAAA,IACb,cAAgB;AAAA,IAChB,uBAAyB;AAAA,IACzB,WAAa;AAAA,IACb,SAAW;AAAA,EACb;AAAA,EACA,yBAAyB;AAAA,IACvB,YAAc;AAAA,IACd,WAAa;AAAA,IACb,cAAgB;AAAA,IAChB,uBAAyB;AAAA,IACzB,WAAa;AAAA,IACb,SAAW;AAAA,EACb;AAAA,EACA,sBAAsB;AAAA,IACpB,YAAc;AAAA,IACd,WAAa;AAAA,IACb,cAAgB;AAAA,IAChB,uBAAyB;AAAA,IACzB,WAAa;AAAA,IACb,SAAW;AAAA,EACb;AAAA,EACA,kBAAkB;AAAA,IAChB,YAAc;AAAA,IACd,WAAa;AAAA,IACb,cAAgB;AAAA,IAChB,uBAAyB;AAAA,IACzB,WAAa;AAAA,IACb,SAAW;AAAA,EACb;AAAA,EACA,uBAAuB;AAAA,IACrB,YAAc;AAAA,IACd,WAAa;AAAA,IACb,cAAgB;AAAA,IAChB,uBAAyB;AAAA,IACzB,WAAa;AAAA,IACb,SAAW;AAAA,EACb;AAAA,EACA,uBAAuB;AAAA,IACrB,YAAc;AAAA,IACd,WAAa;AAAA,IACb,cAAgB;AAAA,IAChB,uBAAyB;AAAA,IACzB,WAAa;AAAA,IACb,SAAW;AAAA,EACb;AAAA,EACA,iBAAiB;AAAA,IACf,YAAc;AAAA,IACd,WAAa;AAAA,IACb,cAAgB;AAAA,IAChB,uBAAyB;AAAA,IACzB,WAAa;AAAA,IACb,SAAW;AAAA,EACb;AAAA,EACA,sBAAsB;AAAA,IACpB,YAAc;AAAA,IACd,WAAa;AAAA,IACb,cAAgB;AAAA,IAChB,uBAAyB;AAAA,IACzB,WAAa;AAAA,IACb,SAAW;AAAA,EACb;AAAA,EACA,qBAAqB;AAAA,IACnB,YAAc;AAAA,IACd,WAAa;AAAA,IACb,cAAgB;AAAA,IAChB,uBAAyB;AAAA,IACzB,WAAa;AAAA,IACb,SAAW;AAAA,EACb;AAAA,EACA,kBAAkB;AAAA,IAChB,YAAc;AAAA,IACd,WAAa;AAAA,IACb,cAAgB;AAAA,IAChB,uBAAyB;AAAA,IACzB,WAAa;AAAA,IACb,SAAW;AAAA,EACb;AAAA,EACA,wBAAwB;AAAA,IACtB,YAAc;AAAA,IACd,WAAa;AAAA,IACb,cAAgB;AAAA,IAChB,uBAAyB;AAAA,IACzB,WAAa;AAAA,IACb,SAAW;AAAA,EACb;AAAA,EACA,kBAAkB;AAAA,IAChB,YAAc;AAAA,IACd,WAAa;AAAA,IACb,cAAgB;AAAA,IAChB,uBAAyB;AAAA,IACzB,WAAa;AAAA,IACb,SAAW;AAAA,EACb;AAAA,EACA,uBAAuB;AAAA,IACrB,YAAc;AAAA,IACd,WAAa;AAAA,IACb,cAAgB;AAAA,IAChB,uBAAyB;AAAA,IACzB,WAAa;AAAA,IACb,SAAW;AAAA,EACb;AAAA,EACA,uBAAuB;AAAA,IACrB,YAAc;AAAA,IACd,WAAa;AAAA,IACb,cAAgB;AAAA,IAChB,uBAAyB;AAAA,IACzB,WAAa;AAAA,IACb,SAAW;AAAA,EACb;AAAA,EACA,kBAAkB;AAAA,IAChB,YAAc;AAAA,IACd,WAAa;AAAA,IACb,cAAgB;AAAA,IAChB,uBAAyB;AAAA,IACzB,WAAa;AAAA,IACb,SAAW;AAAA,EACb;AAAA,EACA,uBAAuB;AAAA,IACrB,YAAc;AAAA,IACd,WAAa;AAAA,IACb,cAAgB;AAAA,IAChB,uBAAyB;AAAA,IACzB,WAAa;AAAA,IACb,SAAW;AAAA,EACb;AAAA,EACA,2BAA2B;AAAA,IACzB,YAAc;AAAA,IACd,WAAa;AAAA,IACb,cAAgB;AAAA,IAChB,uBAAyB;AAAA,IACzB,WAAa;AAAA,IACb,SAAW;AAAA,EACb;AAAA,EACA,sBAAsB;AAAA,IACpB,YAAc;AAAA,IACd,WAAa;AAAA,IACb,cAAgB;AAAA,IAChB,uBAAyB;AAAA,IACzB,WAAa;AAAA,IACb,SAAW;AAAA,EACb;AAAA,EACA,0BAA0B;AAAA,IACxB,YAAc;AAAA,IACd,WAAa;AAAA,IACb,cAAgB;AAAA,IAChB,uBAAyB;AAAA,IACzB,WAAa;AAAA,IACb,SAAW;AAAA,EACb;AAAA,EACA,wBAAwB;AAAA,IACtB,YAAc;AAAA,IACd,WAAa;AAAA,IACb,cAAgB;AAAA,IAChB,uBAAyB;AAAA,IACzB,WAAa;AAAA,IACb,SAAW;AAAA,EACb;AAAA,EACA,4BAA4B;AAAA,IAC1B,YAAc;AAAA,IACd,WAAa;AAAA,IACb,cAAgB;AAAA,IAChB,uBAAyB;AAAA,IACzB,WAAa;AAAA,IACb,SAAW;AAAA,EACb;AAAA,EACA,sBAAsB;AAAA,IACpB,YAAc;AAAA,IACd,WAAa;AAAA,IACb,cAAgB;AAAA,IAChB,uBAAyB;AAAA,IACzB,WAAa;AAAA,IACb,SAAW;AAAA,EACb;AAAA,EACA,aAAa;AAAA,IACX,YAAc;AAAA,IACd,WAAa;AAAA,IACb,cAAgB;AAAA,IAChB,uBAAyB;AAAA,IACzB,WAAa;AAAA,IACb,SAAW;AAAA,EACb;AAAA,EACA,aAAa;AAAA,IACX,YAAc;AAAA,IACd,WAAa;AAAA,IACb,cAAgB;AAAA,IAChB,uBAAyB;AAAA,IACzB,WAAa;AAAA,IACb,SAAW;AAAA,EACb;AAAA,EACA,kBAAkB;AAAA,IAChB,YAAc;AAAA,IACd,WAAa;AAAA,IACb,cAAgB;AAAA,IAChB,uBAAyB;AAAA,IACzB,WAAa;AAAA,IACb,SAAW;AAAA,EACb;AAAA,EACA,kBAAkB;AAAA,IAChB,YAAc;AAAA,IACd,WAAa;AAAA,IACb,cAAgB;AAAA,IAChB,uBAAyB;AAAA,IACzB,WAAa;AAAA,IACb,SAAW;AAAA,EACb;AAAA,EACA,sBAAsB;AAAA,IACpB,YAAc;AAAA,IACd,WAAa;AAAA,IACb,cAAgB;AAAA,IAChB,uBAAyB;AAAA,IACzB,WAAa;AAAA,IACb,SAAW;AAAA,EACb;AAAA,EACA,oBAAoB;AAAA,IAClB,YAAc;AAAA,IACd,WAAa;AAAA,IACb,cAAgB;AAAA,IAChB,uBAAyB;AAAA,IACzB,WAAa;AAAA,IACb,SAAW;AAAA,EACb;AAAA,EACA,qBAAqB;AAAA,IACnB,YAAc;AAAA,IACd,WAAa;AAAA,IACb,cAAgB;AAAA,IAChB,uBAAyB;AAAA,IACzB,WAAa;AAAA,IACb,SAAW;AAAA,EACb;AAAA,EACA,eAAe;AAAA,IACb,YAAc;AAAA,IACd,WAAa;AAAA,IACb,cAAgB;AAAA,IAChB,uBAAyB;AAAA,IACzB,WAAa;AAAA,IACb,SAAW;AAAA,EACb;AAAA,EACA,gBAAgB;AAAA,IACd,YAAc;AAAA,IACd,WAAa;AAAA,IACb,cAAgB;AAAA,IAChB,uBAAyB;AAAA,IACzB,WAAa;AAAA,IACb,SAAW;AAAA,EACb;AAAA,EACA,gBAAgB;AAAA,IACd,YAAc;AAAA,IACd,WAAa;AAAA,IACb,cAAgB;AAAA,IAChB,uBAAyB;AAAA,IACzB,WAAa;AAAA,IACb,SAAW;AAAA,EACb;AAAA,EACA,sBAAsB;AAAA,IACpB,YAAc;AAAA,IACd,WAAa;AAAA,IACb,cAAgB;AAAA,IAChB,uBAAyB;AAAA,IACzB,WAAa;AAAA,IACb,SAAW;AAAA,EACb;AAAA,EACA,wBAAwB;AAAA,IACtB,YAAc;AAAA,IACd,WAAa;AAAA,IACb,cAAgB;AAAA,IAChB,uBAAyB;AAAA,IACzB,WAAa;AAAA,IACb,SAAW;AAAA,EACb;AAAA,EACA,aAAa;AAAA,IACX,YAAc;AAAA,IACd,WAAa;AAAA,IACb,cAAgB;AAAA,IAChB,uBAAyB;AAAA,IACzB,WAAa;AAAA,IACb,SAAW;AAAA,EACb;AAAA,EACA,mBAAmB;AAAA,IACjB,YAAc;AAAA,IACd,WAAa;AAAA,IACb,cAAgB;AAAA,IAChB,uBAAyB;AAAA,IACzB,WAAa;AAAA,IACb,SAAW;AAAA,EACb;AAAA,EACA,eAAe;AAAA,IACb,YAAc;AAAA,IACd,WAAa;AAAA,IACb,cAAgB;AAAA,IAChB,uBAAyB;AAAA,IACzB,WAAa;AAAA,IACb,SAAW;AAAA,EACb;AAAA,EACA,eAAe;AAAA,IACb,YAAc;AAAA,IACd,WAAa;AAAA,IACb,cAAgB;AAAA,IAChB,uBAAyB;AAAA,IACzB,WAAa;AAAA,IACb,SAAW;AAAA,EACb;AAAA,EACA,eAAe;AAAA,IACb,YAAc;AAAA,IACd,WAAa;AAAA,IACb,cAAgB;AAAA,IAChB,uBAAyB;AAAA,IACzB,WAAa;AAAA,IACb,SAAW;AAAA,EACb;AAAA,EACA,qBAAqB;AAAA,IACnB,YAAc;AAAA,IACd,WAAa;AAAA,IACb,cAAgB;AAAA,IAChB,uBAAyB;AAAA,IACzB,WAAa;AAAA,IACb,SAAW;AAAA,EACb;AACF;;;ACngBO,IAAM,sBAAyE,OAAO;AAAA,EAC3F;AACF;AAEO,IAAM,4BACX,OAAO,OAAO;AAAA,EACZ,8BAA8B;AAAA,IAC5B,YAAY;AAAA,IACZ,WAAW;AAAA,IACX,uBAAuB;AAAA,EACzB;AAAA,EACA,+BAA+B;AAAA,IAC7B,YAAY;AAAA,IACZ,WAAW;AAAA,IACX,uBAAuB;AAAA,EACzB;AAAA,EACA,0BAA0B;AAAA,IACxB,YAAY;AAAA,IACZ,WAAW;AAAA,IACX,uBAAuB;AAAA,IACvB,mBAAmB;AAAA,EACrB;AAAA,EACA,2BAA2B;AAAA,IACzB,YAAY;AAAA,IACZ,WAAW;AAAA,IACX,uBAAuB;AAAA,IACvB,mBAAmB;AAAA,EACrB;AAAA,EACA,gCAAgC;AAAA,IAC9B,YAAY;AAAA,IACZ,WAAW;AAAA,IACX,uBAAuB;AAAA,IACvB,mBAAmB;AAAA,EACrB;AAAA,EACA,yBAAyB;AAAA,IACvB,YAAY;AAAA,IACZ,WAAW;AAAA,IACX,uBAAuB;AAAA,EACzB;AAAA,EACA,yBAAyB;AAAA,IACvB,YAAY;AAAA,IACZ,WAAW;AAAA,IACX,uBAAuB;AAAA,EACzB;AAAA,EACA,sBAAsB;AAAA,IACpB,YAAY;AAAA,IACZ,WAAW;AAAA,IACX,uBAAuB;AAAA,EACzB;AAAA,EACA,wBAAwB;AAAA,IACtB,YAAY;AAAA,IACZ,WAAW;AAAA,IACX,uBAAuB;AAAA,EACzB;AACF,CAAC;;;AC3EI,SAAS,qBACd,QACA,eACA,YACS;AAGT,MAAI,eAAe,OAAQ,QAAO;AAClC,MAAI,eAAe,WAAY,QAAO;AACtC,MACE,OAAO,eAAe,YACtB,eAAe,QACd,WAAkC,SAAS,YAC5C;AACA,WAAO;AAAA,EACT;AAKA,QAAM,OAAO;AACb,QAAM,eACJ;AACF,QAAM,kBACJ;AACF,QAAM,YACJ;AACF,QAAM,iBACJ;AACF,SACE,aAAa,KAAK,IAAI,KACtB,gBAAgB,KAAK,IAAI,KACzB,UAAU,KAAK,IAAI,KACnB,eAAe,KAAK,IAAI;AAE5B;;;ACAA,IAAM,4BAA4B;AAAA,EAChC,MAAM;AAAA,IACJ,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,MAAM;AAAA,IACN,OAAO;AAAA,IACP,aAAa;AAAA,IACb,QAAQ;AAAA,EACV;AAAA,EACA,KAAK,EAAE,SAAS,MAAM,YAAY,KAAK,MAAM,MAAM,OAAO,KAAK,aAAa,MAAM,QAAQ,KAAK;AAAA,EAC/F,SAAS;AAAA,IACP,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,MAAM;AAAA,IACN,OAAO;AAAA,IACP,aAAa;AAAA,IACb,QAAQ;AAAA,EACV;AAAA,EACA,iBAAiB,EAAE,SAAS,MAAM,aAAa,KAAK;AAAA,EACpD,4BAA4B;AAAA,EAC5B,kBAAkB,EAAE,MAAM,KAAK,KAAK,MAAM,SAAS,KAAK;AAC1D;AAOA,SAAS,6BACP,QACA,YACA,WACA,WACS;AACT,MAAI,CAAC,cAAc,cAAc,UAAa,YAAY,EAAG,QAAO;AACpE,QAAM,OAAO,OAAO,KAAK;AACzB,QAAM,iBACJ,kQAAkQ;AAAA,IAChQ;AAAA,EACF;AACF,MAAI,eAAgB,QAAO;AAE3B,QAAM,kBAAkB,KACrB,MAAM,WAAW,EACjB,IAAI,CAAC,SAAS,KAAK,KAAK,CAAC,EACzB,OAAO,CAAC,SAAS,KAAK,UAAU,CAAC;AACpC,MACG,mDAAmD,KAAK,IAAI,KAC3D,gBAAgB,UAAU,KAC5B,8BAA8B,KAAK,IAAI;AAEvC,WAAO;AAET,QAAM,iBACJ,+FAA+F;AAAA,IAC7F;AAAA,EACF;AACF,MAAI,eAAgB,QAAO;AAI3B,QAAM,kBAAkB,oBAAI,IAAI;AAAA,IAC9B;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AACD,QAAM,UAAU,KAAK,YAAY;AACjC,QAAM,yBAAyB,IAAI;AAAA,KAChC,aAAa,CAAC,GACZ,QAAQ,CAAC,SAAS,KAAK,YAAY,EAAE,MAAM,yBAAyB,CAAC,EACrE,OAAO,CAAC,UAAU,gBAAgB,IAAI,KAAK,KAAK,QAAQ,SAAS,KAAK,CAAC;AAAA,EAC5E;AAIA,MAAI,uBAAuB,QAAQ,EAAG,QAAO;AAI7C,QAAM,gBAAgB,KACnB,MAAM,OAAO,EACb,IAAI,CAAC,SAAS,KAAK,KAAK,CAAC,EACzB,OAAO,OAAO;AACjB,QAAM,mBACJ,KAAK;AAAA,IACH;AAAA,EACF,KAAK,CAAC;AACR,MAAI,cAAc,UAAU,KAAK,iBAAiB,UAAU,EAAG,QAAO;AAItE,QAAM,iBACJ,uFAAuF;AAAA,IACrF;AAAA,EACF;AACF,QAAM,yBAAyB,uCAAuC,KAAK,IAAI;AAC/E,QAAM,2BAA2B,KAAK,MAAM,OAAO,KAAK,CAAC,GAAG,UAAU;AACtE,MAAI,mBAAmB,0BAA0B,yBAA0B,QAAO;AAElF,QAAM,qBACJ,uEAAuE,KAAK,IAAI;AAClF,QAAM,yBAAyB,KAAK,MAAM,IAAI,KAAK,CAAC,GAAG,UAAU,KAAK,SAAS,KAAK,IAAI;AACxF,SAAO,sBAAsB;AAC/B;AAEA,SAAS,aACP,QACA,cACA,SACc;AACd,QAAM,WAAW,GAAG,gBAAgB,EAAE,IAAI,MAAM;AAChD,QAAM,uBAAuB,eAAe,QAAQ;AACpD,QAAM,QAAQ,UAAU,QAAQ,OAAO,WAAW,qBAAqB;AACvE,QAAM,gBAAgB,cAAc,QAAQ,KAAK;AACjD,QAAM,sBAAsB,cAAc,gBAAgB,IAAI,KAAK;AAMnE,QAAM,kBAAkB,GAAG,mBAAmB,IAAI,aAAa;AAC/D,QAAM,OAAO,cAAc,YAAY;AACvC,QAAM,qBACJ,qHAAqH;AAAA,IACnH;AAAA,EACF;AAKF,QAAM,sBACJ,4OAA4O;AAAA,IAC1O;AAAA,EACF;AACF,QAAM,mBACJ,qFAAqF;AAAA,IACnF;AAAA,EACF;AAGF,QAAM,mBAAmB,wCAAwC,KAAK,aAAa;AACnF,QAAM,UAAU,sBAAsB,uBAAuB,oBAAoB;AAKjF,QAAM,eACJ,gEAAgE,KAAK,aAAa,KAClF,uBACA,oBACA;AACF,QAAM,iBAAiB,QAAQ,YAAY;AAC3C,QAAM,aACJ,QAAQ,kBACP,kBAAkB,qBAAqB,eAAe,mBAAmB;AAC5E,QAAM,0BAA0B;AAAA,IAC9B;AAAA,IACA;AAAA,IACA,QAAQ;AAAA,IACR,QAAQ;AAAA,EACV;AACA,QAAM,uBAAuB,QAAQ,aAAa,CAAC,GAAG,IAAI,CAAC,SAAS,KAAK,YAAY,CAAC;AACtF,QAAM,oBAAoB,oBAAoB;AAAA,IAAK,CAAC,SAClD,mDAAmD,KAAK,IAAI;AAAA,EAC9D;AACA,QAAM,mBAAmB,oBAAoB;AAAA,IAAK,CAAC,SACjD,iDAAiD,KAAK,IAAI;AAAA,EAC5D;AACA,QAAM,wBAAwB,oBAAoB;AAAA,IAAK,CAAC,SACtD,+BAA+B,KAAK,IAAI;AAAA,EAC1C;AACA,QAAM,cACJ,qBAAqB,CAAC,mBAClB,YACA,oBAAoB,CAAC,oBACnB,WACA,wBACE,iBACA;AAMV,QAAM,iBACJ,gBAAgB;AAAA,IACd;AAAA,EACF,KAAK,CAAC;AACR,QAAM,yBACJ,sKAAsK;AAAA,IACpK;AAAA,EACF;AACF,QAAM,oBACJ,oHAAoH;AAAA,IAClH;AAAA,EACF;AACF,QAAM,kBACJ,gBAAgB,mBACf,qBACE,2BAA2B,eAAe,UAAU,KAAK,OAAO,UAAU;AAC/E,QAAM,2BACJ,2LAA2L;AAAA,IACzL;AAAA,EACF;AACF,QAAM,oBACJ,wMAAwM;AAAA,IACtM;AAAA,EACF;AACF,QAAM,qBAAqB,4BAA4B;AACvD,QAAM,oBACJ,sIAAsI;AAAA,IACpI;AAAA,EACF;AACF,QAAM,iBAAiB,cAAc,MAAM,kBAAkB,KAAK,CAAC;AACnE,QAAM,8BACJ,gBAAgB,cACf,uKAAuK;AAAA,IACtK;AAAA,EACF,KACE,IAAI,IAAI,cAAc,EAAE,QAAQ;AACpC,QAAM,kCACJ,gBAAgB,aAChB,qBACA,6HAA6H;AAAA,IAC3H;AAAA,EACF,KACA,+HAA+H;AAAA,IAC7H;AAAA,EACF;AAKF,QAAM,wBACJ,gBAAgB,YAChB,wEAAwE;AAAA,IACtE;AAAA,EACF,KACA,gIAAgI;AAAA,IAC9H;AAAA,EACF;AAKF,QAAM,gCACJ,yBACA,6HAA6H;AAAA,IAC3H;AAAA,EACF;AAKF,QAAM,2BACJ,gBAAgB,YAAY,uCAAuC,KAAK,aAAa;AACvF,QAAM,iBAAiB,cAAc,MAAM,+BAA+B,KAAK,CAAC,GAAG;AACnF,QAAM,uBACJ,6BACE,QAAQ,aAAa,MAAM,KAAK,iBAAiB,KAAK,OAAO,SAAS;AAC1E,MAAI,YACF,cAAc,gCACV,4BACA,cAAc,wBACZ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAOA,cACE,gBAAgB,cACf,4BAA4B,mCAC7B,iBACA,eACG,2BACC,sBACA,qBACA,+BACA,4BACF,SACA;AAAA;AACZ,QAAM,cAAc,QAAQ,aAAa;AACzC,QAAM,wBAAwB,QAAQ,4BAA4B;AAClE,QAAM,mBACJ,wEAAwE;AAAA,IACtE;AAAA,EACF;AACF,QAAM,aACJ,0FAA0F;AAAA,IACxF;AAAA,EACF;AAMF,QAAM,qBAAqB,oBAAoB;AAAA,IAAK,CAAC,SACnD,sDAAsD,KAAK,IAAI;AAAA,EACjE;AACA,QAAM,yBACJ,wJAAwJ;AAAA,IACtJ;AAAA,EACF;AAQF,QAAM,wBACJ,sBACA,mOAAmO;AAAA,IACjO;AAAA,EACF;AAKF,QAAM,4BAA4B,IAAI;AAAA,KACnC,cAAc,MAAM,wDAAwD,KAAK,CAAC,GAAG;AAAA,MACpF,CAAC,SAAS,KAAK,YAAY,EAAE,QAAQ,QAAQ,GAAG;AAAA,IAClD;AAAA,EACF;AACA,QAAM,+BACJ,uBACC,gBAAgB,KAAK,aAAa,KACjC,0EAA0E;AAAA,IACxE;AAAA,EACF,KACC,0BAA0B,QAAQ,KACjC,qCAAqC,KAAK,aAAa;AAO7D,QAAM,oCACJ,sBACA,mGAAmG;AAAA,IACjG;AAAA,EACF,KACA,4KAA4K;AAAA,IAC1K;AAAA,EACF,KACA,+DAA+D,KAAK,aAAa;AACnF,MACE,eACC,yBAAyB,gCAAgC,uCACzD,cAAc,cAAc,cAAc;AAE3C,gBAAY;AACd,QAAM,2BACJ,4PAA4P;AAAA,IAC1P;AAAA,EACF;AAKF,QAAM,2BACJ,mJAAmJ;AAAA,IACjJ;AAAA,EACF,KACA,qHAAqH;AAAA,IACnH;AAAA,EACF;AACF,QAAM,0BAA0B,uBAAuB,cAAc;AACrE,QAAM,uBACJ,cACA,sBACA,cAAc,cACd,CAAC,cACD,CAAC,4BACD,gBAAgB,KAChB,OAAO,UAAU,OACjB;AACF,QAAM,WAAW,kBAAkB,KAAK,aAAa,IAAI,OAAO;AAChE,QAAM,yBAAyB,cAAc,MAAM,4BAA4B,KAAK,CAAC,GAAG;AACxF,QAAM,kBAAkB,cAAc,MAAM,oBAAoB,KAAK,CAAC,GAAG;AACzE,QAAM,qBACJ,CAAC,WACD,OAAO,SAAS,QAChB,kBAAkB,MACjB,2FAA2F;AAAA,IAC1F;AAAA,EACF,KACE,WAAW,KAAK,cAAc,KAAK,CAAC,KACpC,kBAAkB;AAEtB,MAAI,WAAqB;AACzB,MAAI,YAAa,YAAW;AAAA,WACnB,uBAAuB,IAAQ,YAAW;AAAA,WAC1C,eAAe,WAAW,sBAAuB,YAAW;AAAA,WAC5D,cAAc,2BAA2B,CAAC;AACjD,eAAW;AAAA,WACJ,WAAY,YAAW;AAAA,WACvB,yBAAyB,EAAG,YAAW;AAAA,WACvC,mBAAoB,YAAW;AAAA,WAEtC,oBACA,wEAAwE,KAAK,IAAI;AAEjF,eAAW;AAAA,WACJ,WAAW,0DAA0D,KAAK,IAAI;AACrF,eAAW;AAAA,WACJ,yBAAyB,yCAAyC,KAAK,IAAI;AAClF,eAAW;AAAA,WAEX,0EAA0E,KAAK,IAAI;AAEnF,eAAW;AAEb,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAEA,SAAS,SACP,SACA,MACA,WAAqC,SACrC,cAA2C,SAC3C,kBAAkB,OAClB,YAAuC,YACvC,qBAAqB,OACrB,0BAA0B,OAClB;AACR,QAAM,KAAK,QAAQ,YAAY;AAM/B,QAAM,YAAY,GAAG,MAAM,GAAG,QAAQ,GAAG,IAAI,CAAC;AAC9C,QAAM,QAAQ,CAAC,QAAkB,UAC/B,OAAO,KAAK,CAAC,UAAU,cAAc,KAAK,IAAI,QAAQ;AACxD,QAAM,OAAO;AAEb,UAAQ,MAAM;AAAA,IACZ,KAAK;AACH,UAAI,sBAAsB,cAAc,gBAAgB;AAGtD,eAAO,KAAK;AAAA,UACV;AAAA,UACA,MAAM,CAAC,iBAAiB,GAAG,CAAC;AAAA,UAC5B,MAAM,CAAC,eAAe,GAAG,IAAI;AAAA,UAC7B,MAAM,CAAC,YAAY,GAAG,IAAI;AAAA,UAC1B,MAAM,CAAC,kBAAkB,GAAG,IAAI;AAAA,QAClC;AAAA,MACF;AASA,aAAO,KAAK;AAAA,QACV;AAAA,QACA,MAAM,CAAC,eAAe,GAAG,CAAC;AAAA,QAC1B,MAAM,CAAC,iBAAiB,GAAG,IAAI;AAAA,QAC/B,MAAM,CAAC,YAAY,GAAG,IAAI;AAAA,QAC1B,MAAM,CAAC,kBAAkB,GAAG,IAAI;AAAA,QAChC,MAAM,CAAC,SAAS,GAAG,GAAG;AAAA,QACtB,MAAM,CAAC,mBAAmB,SAAS,GAAG,IAAI;AAAA,MAC5C;AAAA,IACF,KAAK;AACH,UAAI,sBAAsB,cAAc,gBAAgB;AAKtD,eAAO,KAAK;AAAA,UACV;AAAA,UACA,MAAM,CAAC,iBAAiB,GAAG,CAAC;AAAA,UAC5B,MAAM,CAAC,eAAe,GAAG,IAAI;AAAA,UAC7B,MAAM,CAAC,YAAY,GAAG,IAAI;AAAA,UAC1B,MAAM,CAAC,kBAAkB,GAAG,IAAI;AAAA,QAClC;AAAA,MACF;AACA,UAAI,sBAAsB,CAAC,yBAAyB;AAIlD,eAAO,KAAK;AAAA,UACV;AAAA,UACA,MAAM,CAAC,YAAY,GAAG,CAAC;AAAA,UACvB,MAAM,CAAC,eAAe,GAAG,IAAI;AAAA,UAC7B,MAAM,CAAC,iBAAiB,GAAG,GAAG;AAAA,UAC9B,MAAM,CAAC,kBAAkB,GAAG,IAAI;AAAA,QAClC;AAAA,MACF;AACA,UAAI,sBAAsB,yBAAyB;AAOjD,eAAO,KAAK;AAAA,UACV;AAAA,UACA,MAAM,CAAC,iBAAiB,GAAG,CAAC;AAAA,UAC5B,MAAM,CAAC,iBAAiB,GAAG,GAAG;AAAA,UAC9B,MAAM,CAAC,eAAe,GAAG,IAAI;AAAA,QAC/B;AAAA,MACF;AACA,UAAI,gBAAgB,gBAAgB;AAMlC,eAAO,kBACH,KAAK;AAAA,UACH;AAAA,UACA,MAAM,CAAC,iBAAiB,GAAG,CAAC;AAAA,UAC5B,MAAM,CAAC,YAAY,GAAG,IAAI;AAAA,UAC1B,MAAM,CAAC,kBAAkB,GAAG,IAAI;AAAA,UAChC,MAAM,CAAC,eAAe,GAAG,GAAG;AAAA,UAC5B,MAAM,CAAC,iBAAiB,GAAG,IAAI;AAAA,QACjC,IACA,KAAK;AAAA,UACH;AAAA,UACA,MAAM,CAAC,iBAAiB,GAAG,CAAC;AAAA,UAC5B,MAAM,CAAC,YAAY,GAAG,IAAI;AAAA,UAC1B,MAAM,CAAC,kBAAkB,GAAG,IAAI;AAAA,UAChC,MAAM,CAAC,eAAe,GAAG,IAAI;AAAA,UAC7B,MAAM,CAAC,iBAAiB,GAAG,IAAI;AAAA,QACjC;AAAA,MACN;AAQA,UAAI,gBAAgB,UAAU;AAS5B,YAAI,cAAc,YAAY;AAC5B,iBAAO,KAAK;AAAA,YACV;AAAA,YACA,MAAM,CAAC,YAAY,GAAG,CAAC;AAAA,YACvB,MAAM,CAAC,iBAAiB,GAAG,IAAI;AAAA,YAC/B,MAAM,CAAC,kBAAkB,GAAG,IAAI;AAAA,YAChC,MAAM,CAAC,eAAe,GAAG,IAAI;AAAA,YAC7B,MAAM,CAAC,SAAS,GAAG,IAAI;AAAA,YACvB,MAAM,CAAC,iBAAiB,GAAG,IAAI;AAAA,UACjC;AAAA,QACF;AACA,YAAI,cAAc,oBAAoB;AACpC,iBAAO,KAAK;AAAA,YACV;AAAA,YACA,MAAM,CAAC,SAAS,GAAG,CAAC;AAAA,YACpB,MAAM,CAAC,iBAAiB,GAAG,GAAG;AAAA,YAC9B,MAAM,CAAC,iBAAiB,GAAG,IAAI;AAAA,YAC/B,MAAM,CAAC,YAAY,GAAG,GAAG;AAAA,YACzB,MAAM,CAAC,aAAa,GAAG,IAAI;AAAA,UAC7B;AAAA,QACF;AACA,YAAI,cAAc,2BAA2B;AAC3C,iBAAO,KAAK;AAAA,YACV;AAAA,YACA,MAAM,CAAC,YAAY,GAAG,CAAC;AAAA,YACvB,MAAM,CAAC,SAAS,GAAG,IAAI;AAAA,YACvB,MAAM,CAAC,iBAAiB,GAAG,IAAI;AAAA,YAC/B,MAAM,CAAC,aAAa,GAAG,GAAG;AAAA,UAC5B;AAAA,QACF;AACA,eAAO,KAAK;AAAA,UACV;AAAA,UACA,MAAM,CAAC,iBAAiB,GAAG,CAAC;AAAA,UAC5B,MAAM,CAAC,iBAAiB,GAAG,IAAI;AAAA,UAC/B,MAAM,CAAC,kBAAkB,GAAG,IAAI;AAAA,UAChC,MAAM,CAAC,eAAe,GAAG,IAAI;AAAA,UAC7B,MAAM,CAAC,SAAS,GAAG,IAAI;AAAA,UACvB,MAAM,CAAC,YAAY,GAAG,IAAI;AAAA,QAC5B;AAAA,MACF;AAYA,UAAI,gBAAgB,WAAW;AAC7B,YAAI,cAAc,gBAAgB;AAChC,iBAAO,KAAK;AAAA,YACV;AAAA,YACA,MAAM,CAAC,iBAAiB,GAAG,CAAC;AAAA,YAC5B,MAAM,CAAC,YAAY,GAAG,IAAI;AAAA,YAC1B,MAAM,CAAC,kBAAkB,GAAG,IAAI;AAAA,YAChC,MAAM,CAAC,iBAAiB,GAAG,IAAI;AAAA,UACjC;AAAA,QACF;AACA,eAAO,KAAK;AAAA,UACV;AAAA,UACA,MAAM,CAAC,YAAY,GAAG,CAAC;AAAA,UACvB,MAAM,CAAC,iBAAiB,GAAG,GAAG;AAAA,UAC9B,MAAM,CAAC,kBAAkB,GAAG,GAAG;AAAA,UAC/B,MAAM,CAAC,iBAAiB,GAAG,IAAI;AAAA,QACjC;AAAA,MACF;AACA,aAAO,KAAK;AAAA,QACV;AAAA,QACA,MAAM,CAAC,iBAAiB,GAAG,CAAC;AAAA,QAC5B,MAAM,CAAC,kBAAkB,GAAG,IAAI;AAAA,QAChC,MAAM,CAAC,eAAe,GAAG,IAAI;AAAA,QAC7B,MAAM,CAAC,YAAY,GAAG,IAAI;AAAA,QAC1B,MAAM,CAAC,SAAS,GAAG,IAAI;AAAA,QACvB,MAAM,CAAC,iBAAiB,GAAG,IAAI;AAAA,MACjC;AAAA,IACF,KAAK;AACH,UAAI,oBAAoB;AAItB,eAAO,0BACH,KAAK;AAAA,UACH;AAAA,UACA,MAAM,CAAC,iBAAiB,GAAG,CAAC;AAAA,UAC5B,MAAM,CAAC,iBAAiB,GAAG,GAAG;AAAA,UAC9B,MAAM,CAAC,eAAe,GAAG,IAAI;AAAA,QAC/B,IACA,KAAK;AAAA,UACH;AAAA,UACA,MAAM,CAAC,YAAY,GAAG,CAAC;AAAA,UACvB,MAAM,CAAC,eAAe,GAAG,IAAI;AAAA,UAC7B,MAAM,CAAC,iBAAiB,GAAG,IAAI;AAAA,UAC/B,MAAM,CAAC,kBAAkB,GAAG,IAAI;AAAA,QAClC;AAAA,MACN;AACA,UAAI,gBAAgB,gBAAgB;AAClC,eAAO,kBACH,KAAK;AAAA,UACH;AAAA,UACA,MAAM,CAAC,iBAAiB,GAAG,CAAC;AAAA,UAC5B,MAAM,CAAC,YAAY,GAAG,IAAI;AAAA,UAC1B,MAAM,CAAC,kBAAkB,GAAG,IAAI;AAAA,UAChC,MAAM,CAAC,eAAe,GAAG,GAAG;AAAA,UAC5B,MAAM,CAAC,iBAAiB,GAAG,IAAI;AAAA,QACjC,IACA,KAAK;AAAA,UACH;AAAA,UACA,MAAM,CAAC,iBAAiB,GAAG,CAAC;AAAA,UAC5B,MAAM,CAAC,YAAY,GAAG,IAAI;AAAA,UAC1B,MAAM,CAAC,kBAAkB,GAAG,IAAI;AAAA,UAChC,MAAM,CAAC,eAAe,GAAG,IAAI;AAAA,UAC7B,MAAM,CAAC,iBAAiB,GAAG,IAAI;AAAA,QACjC;AAAA,MACN;AACA,UAAI,gBAAgB,UAAU;AAC5B,YAAI,cAAc,oBAAoB;AACpC,iBAAO,KAAK;AAAA,YACV;AAAA,YACA,MAAM,CAAC,SAAS,GAAG,CAAC;AAAA,YACpB,MAAM,CAAC,iBAAiB,GAAG,GAAG;AAAA,YAC9B,MAAM,CAAC,iBAAiB,GAAG,IAAI;AAAA,YAC/B,MAAM,CAAC,YAAY,GAAG,GAAG;AAAA,YACzB,MAAM,CAAC,aAAa,GAAG,IAAI;AAAA,UAC7B;AAAA,QACF;AACA,YAAI,cAAc,2BAA2B;AAC3C,iBAAO,KAAK;AAAA,YACV;AAAA,YACA,MAAM,CAAC,YAAY,GAAG,CAAC;AAAA,YACvB,MAAM,CAAC,SAAS,GAAG,IAAI;AAAA,YACvB,MAAM,CAAC,iBAAiB,GAAG,IAAI;AAAA,YAC/B,MAAM,CAAC,aAAa,GAAG,GAAG;AAAA,UAC5B;AAAA,QACF;AACA,eAAO,KAAK;AAAA,UACV;AAAA,UACA,MAAM,CAAC,iBAAiB,GAAG,CAAC;AAAA,UAC5B,MAAM,CAAC,iBAAiB,GAAG,IAAI;AAAA,UAC/B,MAAM,CAAC,iBAAiB,GAAG,IAAI;AAAA,UAC/B,MAAM,CAAC,YAAY,GAAG,IAAI;AAAA,UAC1B,MAAM,CAAC,kBAAkB,GAAG,IAAI;AAAA,QAClC;AAAA,MACF;AACA,UAAI,gBAAgB,WAAW;AAC7B,eAAO,cAAc,iBACjB,KAAK;AAAA,UACH;AAAA,UACA,MAAM,CAAC,iBAAiB,GAAG,CAAC;AAAA,UAC5B,MAAM,CAAC,YAAY,GAAG,IAAI;AAAA,UAC1B,MAAM,CAAC,iBAAiB,GAAG,IAAI;AAAA,UAC/B,MAAM,CAAC,kBAAkB,GAAG,IAAI;AAAA,QAClC,IACA,KAAK;AAAA,UACH;AAAA,UACA,MAAM,CAAC,YAAY,GAAG,CAAC;AAAA,UACvB,MAAM,CAAC,iBAAiB,GAAG,GAAG;AAAA,UAC9B,MAAM,CAAC,kBAAkB,GAAG,GAAG;AAAA,QACjC;AAAA,MACN;AAKA,aAAO,KAAK;AAAA,QACV;AAAA,QACA,MAAM,CAAC,iBAAiB,GAAG,CAAC;AAAA,QAC5B,MAAM,CAAC,iBAAiB,GAAG,IAAI;AAAA,QAC/B,MAAM,CAAC,UAAU,GAAG,IAAI;AAAA,QACxB,MAAM,CAAC,kBAAkB,GAAG,GAAG;AAAA,QAC/B,MAAM,CAAC,iBAAiB,GAAG,IAAI;AAAA,MACjC;AAAA,IACF,KAAK;AAAA,IACL,KAAK;AACH,aAAO,KAAK;AAAA,QACV;AAAA,QACA,MAAM,CAAC,eAAe,GAAG,CAAC;AAAA,QAC1B,MAAM,CAAC,mBAAmB,GAAG,IAAI;AAAA,QACjC,MAAM,CAAC,SAAS,GAAG,GAAG;AAAA,QACtB,MAAM,CAAC,iBAAiB,GAAG,IAAI;AAAA,MACjC;AAAA,IACF,KAAK;AACH,aAAO,KAAK;AAAA,QACV;AAAA,QACA,MAAM,CAAC,mBAAmB,mBAAmB,GAAG,IAAI;AAAA,QACpD,MAAM,CAAC,iBAAiB,GAAG,IAAI;AAAA,QAC/B,MAAM,CAAC,UAAU,GAAG,IAAI;AAAA,QACxB,MAAM,CAAC,kBAAkB,kBAAkB,GAAG,IAAI;AAAA,MACpD;AAAA,IACF,KAAK;AAOH,aAAO,KAAK;AAAA,QACV;AAAA,QACA,MAAM,CAAC,wBAAwB,GAAG,CAAC;AAAA,QACnC,MAAM,CAAC,kBAAkB,GAAG,IAAI;AAAA,QAChC,MAAM,CAAC,UAAU,GAAG,GAAG;AAAA,QACvB,MAAM,CAAC,iBAAiB,GAAG,IAAI;AAAA,QAC/B,MAAM,CAAC,iBAAiB,GAAG,IAAI;AAAA,MACjC;AAAA,IACF,KAAK;AAIH,aAAO,KAAK;AAAA,QACV;AAAA,QACA,MAAM,CAAC,kBAAkB,GAAG,CAAC;AAAA,QAC7B,MAAM,CAAC,UAAU,GAAG,IAAI;AAAA,QACxB,MAAM,CAAC,mBAAmB,mBAAmB,SAAS,GAAG,GAAG;AAAA,MAC9D;AAAA,IACF,KAAK;AACH,aAAO,KAAK;AAAA,QACV;AAAA,QACA,MAAM,CAAC,gBAAgB,GAAG,IAAI;AAAA,QAC9B,MAAM,CAAC,eAAe,qBAAqB,WAAW,UAAU,GAAG,GAAG;AAAA,MACxE;AAAA,IACF,KAAK;AAMH,aAAO,KAAK;AAAA,QACV;AAAA,QACA,MAAM,CAAC,gBAAgB,GAAG,CAAC;AAAA,QAC3B,MAAM,CAAC,eAAe,SAAS,GAAG,IAAI;AAAA,QACtC,MAAM,CAAC,kBAAkB,GAAG,IAAI;AAAA,QAChC,MAAM,CAAC,iBAAiB,GAAG,IAAI;AAAA,MACjC;AAAA,IACF,KAAK,cAAc;AAUjB,YAAM,yBAAyB,aAAa,OAAO,IAAI;AACvD,YAAM,0BAA0B,aAAa,OAAO,OAAO;AAC3D,aAAO,KAAK;AAAA,QACV;AAAA,QACA,MAAM,CAAC,oBAAoB,oBAAoB,aAAa,GAAG,uBAAuB;AAAA,QACtF,MAAM,CAAC,mBAAmB,mBAAmB,GAAG,uBAAuB;AAAA,QACvE,MAAM,CAAC,SAAS,GAAG,sBAAsB;AAAA,MAC3C;AAAA,IACF;AAAA,IACA;AACE,aAAO,KAAK;AAAA,QACV;AAAA,QACA,MAAM,CAAC,oBAAoB,oBAAoB,SAAS,GAAG,IAAI;AAAA,MACjE;AAAA,EACJ;AACF;AAEA,SAAS,mBAAmB,MAA0B;AACpD,MAAI,SAAS,cAAc;AACzB,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AACA,MAAI,SAAS,cAAc;AACzB,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AACA,MAAI,SAAS,uBAAuB;AAClC,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AACA,MAAI,SAAS,gBAAgB;AAC3B,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AACA,MAAI,SAAS,iBAAiB;AAC5B,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AACA,MAAI,SAAS,cAAc;AAGzB,WAAO,CAAC,oBAAoB,2BAA2B,2BAA2B;AAAA,EACpF;AACA,MAAI,SAAS,kBAAkB;AAC7B,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AACA,SAAO,CAAC;AACV;AAYA,IAAM,0BAA0B;AAAA,EAC9B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEA,SAAS,WACP,SACA,UACA,iBACA,SACS;AACT,QAAM,QAAQ,QAAQ,oBAAoB,OAAO,KAAK,2BAA2B,OAAO;AAGxF,MAAI,CAAC,MAAO,QAAO;AACnB,MAAI,SAAS,cAAc,CAAC,MAAM,cAAe,QAAO;AACxD,MAAI,SAAS,eAAe,CAAC,MAAM,eAAgB,QAAO;AAC1D,MAAI,SAAS,yBAAyB,CAAC,MAAM,cAAe,QAAO;AACnE,MAAI,MAAM,kBAAkB,gBAAiB,QAAO;AACpD,SAAO,MAAM,kBAAkB,SAAS,uBAAuB,mBAAmB;AACpF;AAEA,SAAS,cACP,SACA,SACA,aACA,cACQ;AACR,QAAM,QAAQ,QAAQ,aAAa,IAAI,OAAO;AAC9C,MAAI,CAAC,MAAO,QAAO,OAAO;AAC1B,MAAI,MAAM,cAAc,OAAW,QAAO,MAAM;AAChD,UAAQ,cAAc,MAAM,aAAa,eAAe,MAAM,eAAe;AAC/E;AAEA,SAAS,aACP,SACA,SACA,KAGY;AACZ,QAAM,UACJ,QAAQ,mBAAmB,OAAO,KAClC,oBAAoB,OAAO,KAC3B,0BAA0B,OAAO;AACnC,MAAI,CAAC,QAAS,QAAO;AACrB,QAAM,aAAa,KAAK,MAAM,QAAQ,UAAU;AAChD,MAAI,CAAC,OAAO,SAAS,UAAU,EAAG,QAAO;AACzC,QAAM,UAAU,KAAK,IAAI,IAAI,IAAI,QAAQ,IAAI,cAAc,KAAU;AAMrE,QAAM,mBACJ,QAAQ,YAAY,SAAY,IAAI,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,QAAQ,OAAO,IAAI,EAAE;AACnF,QAAM,YAAY,KAAK,IAAI,KAAK,UAAU,EAAE,IAAI;AAChD,QAAM,UACJ,QAAQ,sBAAsB,SAC1B,SACA,KAAK,IAAI,GAAG,QAAQ,oBAAoB,EAAE;AAChD,QAAM,QAAQ,KAAK;AAAA,IACjB;AAAA,KACC,MAAQ,KAAK,IAAI,KAAK,QAAQ,SAAS,IAAI,QAAQ,wBAAwB,OAAO;AAAA,EACrF;AACA,QAAM,YAAY,KAAK,IAAI,GAAG,MAAQ,KAAK,IAAI,KAAK,QAAQ,gBAAgB,QAAQ,SAAS,CAAC;AAC9F,QAAM,cAAc,KAAK,IAAI,GAAG,KAAK,QAAQ,aAAa,EAAE;AAC5D,SAAO,EAAE,SAAS,OAAO,WAAW,aAAa,UAAU;AAC7D;AAGO,IAAM,oBAAN,MAAkD;AAAA,EAC9C,OAAO;AAAA;AAAA,EAEC,QAAQ,IAAI,cAAc;AAAA,EAE3C,MACE,QACA,cACA,iBACA,SACA;AACA,UAAM,WAAW,aAAa,QAAQ,cAAc,OAAO;AAC3D,UAAM,OAAO,KAAK,MAAM,MAAM,QAAQ,cAAc,iBAAiB;AAAA,MACnE,GAAG;AAAA,MACH,eAAe,SAAS;AAAA,IAC1B,CAAC;AACD,UAAM,cAAc,KAAK;AACzB,QAAI,CAAC,YAAa,QAAO;AAUzB,UAAM,cACH,SAAS,aAAa,mBAAmB,SAAS,aAAa,sBAC/D,KAAK,SAAS,YAAY,KAAK,SAAS,YACrC,eACC,SAAS,aAAa,WAAW,SAAS,aAAa,gBACtD,SAAS,gBACT,KAAK,SAAS,WACd,WACA,KAAK;AACb,UAAM,aAAa,YAAY,UAAU;AACzC,UAAM,uBAAuB,aAAa,iBAAiB,YAAY,WAAW,IAAI,CAAC;AAIvF,UAAM,cAAc,IAAI,IAAI,QAAQ,qBAAqB,CAAC,CAAC;AAM3D,UAAM,wBAAwB,SAAS,aACnC,wBAAwB,OAAO,CAACC,WAAU,QAAQ,aAAa,IAAIA,MAAK,CAAC,IACzE,CAAC;AACL,QAAI,QAAQ,mBAAmB,WAAW;AACxC,YAAM,eAAe,CAACA,WACpB,cAAcA,QAAO,SAAS,SAAS,sBAAsB,eAAe;AAC9E,4BAAsB,KAAK,CAAC,GAAG,MAAM,aAAa,CAAC,IAAI,aAAa,CAAC,CAAC;AAAA,IACxE;AACA,UAAM,QAAQ;AAAA,MACZ,GAAG,oBAAI,IAAI;AAAA,QACT,GAAG;AAAA,QACH,GAAG,mBAAmB,SAAS,QAAQ;AAAA,QACvC,GAAG;AAAA,MACL,CAAC;AAAA,IACH,EAAE;AAAA,MACA,CAACA,WACC,OAAOA,WAAU,YAAYA,OAAM,SAAS,KAAK,CAAC,YAAY,IAAIA,MAAK;AAAA,IAC3E;AACA,UAAM,WAAW,IAAI;AAAA,MACnB,MAAM,OAAO,CAACA,WAAU,WAAWA,QAAO,UAAU,iBAAiB,OAAO,CAAC;AAAA,IAC/E;AAEA,UAAM,qBAAqB,SAAS,OAAO,IAAI,CAAC,GAAG,QAAQ,IAAI;AAC/D,QAAI,mBAAmB,WAAW,EAAG,QAAO;AAC5C,UAAM,cACJ,QAAQ,mBAAmB,QACvB,QACA,QAAQ,mBAAmB,YACzB,YACA;AACR,UAAM,YAAY,QAAQ,OAAO,aAAa;AAC9C,UAAM,cAAc,CAACA,WACnB;AAAA,MACEA;AAAA,MACA,SAAS;AAAA,MACT,SAAS;AAAA,MACT,SAAS;AAAA,MACT,SAAS;AAAA,MACT,SAAS;AAAA,MACT,SAAS;AAAA,MACT,SAAS;AAAA,IACX;AACF,UAAM,eAAe,KAAK,IAAI,GAAG,mBAAmB,IAAI,WAAW,CAAC;AACpE,UAAM,mBAAmB,mBAAmB,OAAO,CAACA,WAAU,YAAYA,MAAK,IAAI,IAAI;AAMvF,UAAM,eAAe,iBAAiB,SAAS,IAAI,mBAAmB,CAAC,mBAAmB,CAAC,CAAC;AAK5F,UAAM,mBAAmB,SAAS,qBAC9B,KAAK;AAAA,MACH,UAAU,iBAAiB,WAAW;AAAA,MACtC,SAAS,0BAA0B,OAAO;AAAA,IAC5C,IACA,UAAU,iBAAiB,WAAW;AAC1C,UAAM,aAAa,aAAa;AAAA,MAC9B,CAACA,WAAU,YAAYA,MAAK,KAAK,eAAe;AAAA,IAClD;AACA,UAAM,QAAQ,WAAW;AAAA,MAAI,CAACA,WAC5B,cAAcA,QAAO,SAAS,SAAS,sBAAsB,eAAe;AAAA,IAC9E;AACA,UAAM,cAAc,MAAM,OAAO,OAAO,QAAQ;AAChD,UAAM,UAAU,YAAY,SAAS,IAAI,KAAK,IAAI,GAAG,WAAW,IAAI;AACpE,UAAM,UAAU,YAAY,SAAS,IAAI,KAAK,IAAI,GAAG,WAAW,IAAI;AAEpE,UAAM,MAAM,QAAQ,OAAO,oBAAI,KAAK;AACpC,UAAM,iBAAiB,UAAU,WAAW;AAC5C,UAAM,gBAAgB,WACnB,IAAI,CAACA,QAAO,UAAU;AACrB,YAAM,OAAO,cAAcA,QAAO,SAAS,SAAS,sBAAsB,eAAe;AACzF,YAAM,YACJ,OAAO,SAAS,IAAI,KAAK,UAAU,UAC/B,KAAK,OAAO,YAAY,UAAU,WAClC;AACN,YAAM,kBAAkB,SAAS,IAAIA,MAAK,IAAI,IAAI;AAClD,YAAM,UAAU,aAAaA,QAAO,SAAS,GAAG;AAGhD,YAAM,kBACJ,SAAS,YAAY,SACjB,YAAYA,MAAK,IACjB,YAAYA,MAAK,KAAK,IAAI,QAAQ,aAAa,QAAQ,UAAU,QAAQ;AAK/E,YAAM,gBAAgB,UAClB,QAAQ,QAAQ,QAAQ,YAAY,OAAO,IAAI,QAAQ,aACvD;AACJ,YAAM,oBAAoB,UACtB,QAAQ,YAAY,QAAQ,YAAY,OAAO,IAAI,QAAQ,aAC3D;AACJ,YAAM,sBAAsB,UACxB,QAAQ,cAAc,QAAQ,aAAa,IAAI,QAAQ,aACvD;AAGJ,YAAM,cAAc,IAAI,QAAQ,KAAK,IAAI,GAAG,WAAW,SAAS,CAAC;AACjE,YAAM,gBACJ,eAAe,WAAW,SAAS,aAAa,UAAU,gBAAgB,UAAU;AACtF,YAAM,aAAa,SAAS,mBAAmB,oBAAoB;AACnE,YAAM,cACJ,eAAe,SACd,SAAS,mBAAmB,UAAU,6BAA6B;AACtE,YAAM,oBACJ,eAAe,eACd,SAAS,aAAa,UAAU,gBAAgB,cAAc;AACjE,YAAM,QACJ,kBAAkB,gBAClB,kBAAkB,eAAe,aACjC,YAAY,eAAe,OAC3B,aAAa,cACb,sBAAsB,oBACtB,cAAc,eAAe;AAC/B,aAAO;AAAA,QACL,OAAAA;AAAA,QACA;AAAA,QACA,SAAS;AAAA,QACT,MAAM;AAAA,QACN,OAAO;AAAA,QACP,aAAa;AAAA,MACf;AAAA,IACF,CAAC,EACA,KAAK,CAAC,GAAG,MAAM,EAAE,QAAQ,EAAE,KAAK;AACnC,UAAM,eAAe,cAAc,IAAI,CAAC,SAAS,KAAK,KAAK;AAI3D,UAAM,2BAA2B;AAAA,MAC/B;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AACA,UAAM,SACJ,SAAS,gBAAgB,iBACrB;AAAA,MACE,GAAG;AAAA,MACH,GAAG,yBAAyB;AAAA,QAC1B,CAACA,WAAU,mBAAmB,SAASA,MAAK,KAAK,CAAC,aAAa,SAASA,MAAK;AAAA,MAC/E;AAAA,MACA,GAAG,mBAAmB;AAAA,QACpB,CAACA,WAAU,CAAC,aAAa,SAASA,MAAK,KAAK,CAAC,yBAAyB,SAASA,MAAK;AAAA,MACtF;AAAA,IACF,IACA,CAAC,GAAG,cAAc,GAAG,mBAAmB,OAAO,CAACA,WAAU,CAAC,aAAa,SAASA,MAAK,CAAC,CAAC;AAE9F,UAAM,QAAQ,OAAO,CAAC,KAAK,KAAK;AAChC,UAAM,sBAAgD;AAAA,MACpD,GAAG;AAAA,MACH,CAAC,UAAU,GAAG,EAAE,SAAS,OAAO,UAAU,OAAO,MAAM,CAAC,EAAE;AAAA,IAC5D;AAEA,UAAM,WAAW;AAAA,MACf;AAAA,MACA,KAAK;AAAA,MACL;AAAA,MACA,GAAG,KAAK,SAAS,cAAc,SAAS,QAAQ,cAAc,SAAS,SAAS,oBAAoB,SAAS,eAAe,iBAAiB,SAAS,oBAAoB,mBAAmB,SAAS,uBAAuB,eAAe,OAAO,MAAM;AAAA,MACzP;AAAA,MACA,QAAQ;AAAA,MACR,SAAS;AAAA,MACT;AAAA,MACA,QAAQ;AAAA,MACR,KAAK;AAAA,IACP;AACA,WAAO;AAAA,MACL,GAAG;AAAA,MACH,aAAa;AAAA,MACb,SAAS,KAAK;AAAA,MACd,YAAY;AAAA,MACZ,iBAAiB,cAAc,IAAI,CAAC,EAAE,OAAAA,QAAO,OAAO,SAAS,MAAM,OAAO,YAAY,OAAO;AAAA,QAC3F,OAAAA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF,EAAE;AAAA,MACF,UAAU,SAAS;AAAA,MACnB,eAAe;AAAA,IACjB;AAAA,EACF;AACF;;;AC5vCO,IAAM,yBAAwC;AAAA,EACnD,SAAS;AAAA,EACT,UAAU;AAAA,EACV,WAAW;AAAA,IACT,MAAM;AAAA,MACJ,SAAS;AAAA,MACT,YAAY;AAAA,MACZ,MAAM;AAAA,MACN,OAAO;AAAA,MACP,aAAa;AAAA,MACb,QAAQ;AAAA,IACV;AAAA,IACA,KAAK;AAAA,MACH,SAAS;AAAA,MACT,YAAY;AAAA,MACZ,MAAM;AAAA,MACN,OAAO;AAAA,MACP,aAAa;AAAA,MACb,QAAQ;AAAA,IACV;AAAA,IACA,SAAS;AAAA,MACP,SAAS;AAAA,MACT,YAAY;AAAA,MACZ,MAAM;AAAA,MACN,OAAO;AAAA,MACP,aAAa;AAAA,MACb,QAAQ;AAAA,IACV;AAAA,IACA,iBAAiB,EAAE,SAAS,MAAM,aAAa,KAAK;AAAA,IACpD,4BAA4B;AAAA,IAC5B,kBAAkB,EAAE,MAAM,KAAK,KAAK,MAAM,SAAS,KAAK;AAAA,EAC1D;AAAA,EAEA,YAAY;AAAA,IACV,UAAU;AAAA,IACV,cAAc;AAAA,IACd,gBAAgB;AAAA,IAChB,uBAAuB;AAAA,IACvB,YAAY;AAAA;AAAA,EACd;AAAA,EAEA,SAAS;AAAA,IACP,sBAAsB,EAAE,QAAQ,IAAI,SAAS,IAAI;AAAA;AAAA,IAGjD,cAAc;AAAA;AAAA,MAEZ;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;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;AA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","names":["confidence","decision","model"]} \ No newline at end of file +{"version":3,"sources":["../rules.ts","../selector.ts","../tokens.ts","../strategy.ts","../model-capabilities.ts","../model-profiles.generated.json","../model-profiles.ts","../tool-intent.ts","../portfolio.ts","../catalog.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// ─── Keyword Matching ───\n//\n// A plain substring test counted `class` in \"classic\", `story` in \"history\",\n// `edit` in \"credit\" and `fix` in \"prefix\", so everyday prose picked up code,\n// creative and agentic signals it did not carry. Alphabetic keywords now have\n// to start at a word boundary. Short ASCII keywords additionally have to end\n// at one, after an optional inflection, graded by how much a stray suffix can\n// change the word: a three-letter keyword takes only the English endings that\n// cannot spell another word (fix → fixes, never pip → pipe or def → defer); a\n// four-to-six-letter keyword also takes the common German and Romance endings,\n// because the lists spell those languages in ASCII too (beweis → beweise,\n// klasse → klassen); anything longer stays trailing-open like the substring\n// test it replaces, since its false-positive surface is small and its\n// inflection surface is large. Non-ASCII alphabetic keywords keep a\n// trailing-open match because several are deliberate stems (`оптимизаци`,\n// `рассуждени`). CJK, Hangul and Arabic keywords keep the substring test:\n// those scripts have no word boundaries, or attach particles and articles\n// directly to the word.\n\nconst UNSEGMENTED_SCRIPT =\n /[؀-ۿ -ヿ㐀-䶿一-鿿가-힯豈-﫿＀-￯]/;\nconst WORD_CHAR = /[\\p{L}\\p{N}]/u;\nconst ASCII_PHRASE = /^[a-z0-9' -]+$/;\n// A word boundary is a transition out of the segmented scripts. A CJK\n// character next to a Latin keyword (\"请step by step证明\") is a boundary, not\n// part of the word: mixed-script prompts carry no spaces between scripts.\nconst SEGMENTED_WORD_CHAR = \"\\\\p{Script=Latin}\\\\p{Script=Cyrillic}\\\\p{Script=Greek}\\\\p{N}\";\nconst BOUNDARY_BEFORE = `(?();\n\nfunction escapeRegExp(value: string): string {\n return value.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\n\nfunction keywordMatcher(keyword: string): KeywordMatcher {\n const cached = matcherCache.get(keyword);\n if (cached) return cached;\n\n const kw = keyword.toLowerCase();\n let matcher: KeywordMatcher;\n if (UNSEGMENTED_SCRIPT.test(kw) || kw.length === 0) {\n matcher = { needle: kw, pattern: null };\n } else {\n const lead = WORD_CHAR.test(kw[0]) ? BOUNDARY_BEFORE : \"\";\n const escaped = escapeRegExp(kw);\n let body = escaped;\n let trail = \"\";\n let needle = kw;\n const lastWord = kw.slice(kw.lastIndexOf(\" \") + 1);\n if (\n WORD_CHAR.test(kw[kw.length - 1]) &&\n ASCII_PHRASE.test(kw) &&\n lastWord.length <= BOUNDED_LAST_WORD_LENGTH\n ) {\n // ASCII phrases contain no regex metacharacters, so `escaped` slices\n // align with `kw` slices below.\n const forms: string[] = [];\n if (/\\d$/.test(kw)) {\n // \"step 1\" must not absorb \"step 10\".\n forms.push(escaped);\n } else if (lastWord.length <= 3) {\n forms.push(`${escaped}${SHORT_SUFFIXES}`);\n if (/(?:x|s|z|ch|sh)$/.test(kw)) forms.push(`${escaped}${SIBILANT_PLURAL}`);\n } else {\n forms.push(`${escaped}${MID_SUFFIXES}`);\n if (kw.endsWith(\"e\")) {\n forms.push(`${escaped.slice(0, -1)}${DROPPED_E_SUFFIXES}`);\n needle = kw.slice(0, -1);\n } else if (kw.endsWith(\"y\")) {\n forms.push(`${escaped.slice(0, -1)}(?:ies|ied)`);\n needle = kw.slice(0, -1);\n } else if (/[aeiou][bdgmnprt]$/.test(kw)) {\n // debug → debugging, plan → planned\n forms.push(`${escaped}${kw[kw.length - 1]}${DOUBLED_CONSONANT_SUFFIXES}`);\n }\n }\n body = `(?:${forms.join(\"|\")})`;\n trail = BOUNDARY_AFTER;\n }\n matcher = { needle, pattern: new RegExp(`${lead}${body}${trail}`, \"u\") };\n }\n matcherCache.set(keyword, matcher);\n return matcher;\n}\n\n/** Whether lower-cased `text` contains `keyword` as a word (or as a substring for CJK). */\nfunction matchesKeyword(text: string, keyword: string): boolean {\n const { needle, pattern } = keywordMatcher(keyword);\n if (!text.includes(needle)) return false;\n return pattern === null ? true : pattern.test(text);\n}\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) => matchesKeyword(text, kw));\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 (matchesKeyword(text, keyword)) {\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) => matchesKeyword(userText, kw));\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 // A model the host has no price for costs an unknown amount, not nothing;\n // reporting its savings as 100% would be a fabricated figure.\n const savings =\n routingProfile === \"premium\" || pricing === undefined\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 * Request-size helpers shared by the rules and portfolio strategies.\n *\n * The router never tokenizes — it is on the hot path and model-agnostic — so\n * sizes are estimates. The estimate only has to be honest enough for the\n * decisions that consume it: the long-context task type, the COMPLEX\n * override and the per-model capacity filter.\n */\n\n// Han, kana, Hangul, CJK punctuation and fullwidth forms. Every production\n// tokenizer spends roughly one token per character here, so the Latin\n// four-characters-per-token rule under-counts these scripts about fourfold:\n// a 200k-character Chinese contract would read as 50k tokens, slip under the\n// 80k long-context boundary and pass the capacity filter for models that\n// cannot hold it.\nconst CJK_CHARS = /[ -ヿ㐀-䶿一-鿿가-힯豈-﫿＀-￯]/g;\n\n/** Approximate token count: one per CJK character, one per four of anything else. */\nexport function estimateTokens(text: string): number {\n if (text.length === 0) return 0;\n const cjk = text.match(CJK_CHARS)?.length ?? 0;\n return cjk + Math.ceil((text.length - cjk) / 4);\n}\n\n/** The scan window the feature regexes read, bounded so a pasted document cannot stall routing. */\nexport function scanLimit(promptTruncationChars: number): number {\n return Math.max(1, Math.min(8_000, promptTruncationChars));\n}\n\n/**\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 */\nexport function sampleForScan(value: string, limit: number): string {\n if (value.length <= limit) return value;\n const prefixLength = Math.ceil(limit / 2);\n return `${value.slice(0, prefixLength)}\\n${value.slice(-(limit - prefixLength))}`;\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\";\nimport { estimateTokens, sampleForScan, scanLimit } from \"./tokens.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 const fullText = `${systemPrompt ?? \"\"} ${prompt}`;\n const estimatedTokens = estimateTokens(fullText);\n const limit = scanLimit(config.classifier.promptTruncationChars);\n const scannedPrompt = sampleForScan(prompt, limit);\n const scannedSystemPrompt = systemPrompt ? sampleForScan(systemPrompt, limit) : 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 is a protocol fact the host states (`response_format`\n // → requiresStructuredOutput). It used to be inferred from the system\n // prompt as well, but agent hosts describe their tool schemas there on\n // every turn, which upgraded every one of their requests off SIMPLE.\n const hasStructuredOutput = options.requiresStructuredOutput === true;\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-20; 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 \"deepseek/deepseek-v4.1-flash\": {\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 \"google/gemini-4-argon\": { // 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 \"mistral/mistral-large-4\": { // supportsTools: not probed — fails closed\n contextWindow: 524_288,\n maxOutputTokens: 262_144,\n supportsTools: false,\n supportsVision: true,\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/gpt-6.1-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 \"deepseek/deepseek-v4.1-flash\": {\n \"measuredAt\": \"2026-10-20T18:12:51Z\",\n \"latencyMs\": 2383.5,\n \"p95LatencyMs\": 2547.8,\n \"outputTokensPerSecond\": 216.53,\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/gpt-6.1-sol\": {\n \"measuredAt\": \"2026-10-20T18:12:51Z\",\n \"latencyMs\": 11324,\n \"p95LatencyMs\": 12747.6,\n \"outputTokensPerSecond\": 45.11,\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\";\nimport { estimateTokens, sampleForScan, scanLimit } from \"./tokens.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 /** A code artifact or coding action is present, not merely a language name. */\n codeArtifact: 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 = estimateTokens(fullText);\n const limit = scanLimit(options.config.classifier.promptTruncationChars);\n const scannedPrompt = sampleForScan(prompt, limit);\n const scannedSystemPrompt = sampleForScan(systemPrompt ?? \"\", limit);\n // Only the deep-web-research clue detectors below read the system prompt,\n // and they are gated on a web-research tool surface. Every other feature\n // reads the user turn: a host's standing instructions (\"be quick\", \"follow\n // security best practices\", a Mandarin persona) describe the assistant, not\n // this request, and must not move its scoring or language band.\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 // A CamelCase error class (TypeError, NullPointerException) is a runtime\n // artifact, not prose about errors; case-sensitive on purpose.\n const errorClassSignal = /\\b[A-Z][A-Za-z]*(?:Error|Exception)\\b/.test(scannedPrompt);\n const hasCode = explicitCodeSignal || codeConstructSignal || nativeCodeSignal || errorClassSignal;\n // Stronger than hasCode: an actual code artifact or coding action, never a\n // bare language name (\"What is Python?\" is trivia, not a code task) and\n // never the English word \"exception\" on its own (\"please make an\n // exception\"); a thrown exception shows up as a CamelCase class above.\n const codeArtifact =\n /```|\\b(?:stack trace|traceback)\\b|\\.(?:ts|tsx|js|py|go|rs)\\b/i.test(scannedPrompt) ||\n codeConstructSignal ||\n nativeCodeSignal ||\n errorClassSignal;\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 scannedPrompt,\n );\n const highStakes =\n /\\b(?:production|security|payment|legal|medical|financial|audit)\\b|生产|安全|支付|法律|医疗|财务|审计/i.test(\n scannedPrompt,\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(scannedPrompt) ? \"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 errorClassSignal ||\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 codeArtifact,\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 \"deepseek/deepseek-v4.1-flash\",\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 \"openai/gpt-6.1-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 // Rules set the capability tier; the strategy is stateless, so one instance serves every request.\n private readonly rules = new RulesStrategy();\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 = this.rules.route(prompt, systemPrompt, maxOutputTokens, {\n ...options,\n requiresTools: features.needsTools,\n });\n const tierConfigs = base.tierConfigs;\n if (!tierConfigs) return base;\n // The rules score sets the capability tier, but two task types carry a\n // floor of their own: a compact reasoning problem belongs on the\n // reasoning chain however short it is, and a code edit or stack trace\n // belongs at least on the MEDIUM chain — the SIMPLE chain is curated for\n // trivia and translation and has no model with code affinity. The code\n // floor requires a code artifact or coding action: `debug` and `code_edit`\n // are also assigned from bare verbs (\"rewrite this sentence\", \"margin of\n // error\") and bare language names (\"What is Python?\"), and that prose\n // must stay on the cheap chain.\n const targetTier: Tier =\n (features.taskType === \"reasoning_mcq\" || features.taskType === \"reasoning_math\") &&\n (base.tier === \"SIMPLE\" || base.tier === \"MEDIUM\")\n ? \"REASONING\"\n : (features.taskType === \"debug\" || features.taskType === \"code_edit\") &&\n features.codeArtifact &&\n base.tier === \"SIMPLE\"\n ? \"MEDIUM\"\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 = new Set(\n chain.filter((model) => isEligible(model, features, maxOutputTokens, options)),\n );\n // When nothing is eligible the whole chain competes, scored as incapable.\n const eligibleCandidates = eligible.size > 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 = eligible.has(model) ? 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 // Every observed dimension fades toward its neutral prior as the\n // observation ages, exactly like reliability below. Fading speed\n // toward zero instead ranked any model with a stale probe below a\n // model nobody had measured, which the latter's 0.5 silently won.\n const observedSpeed = profile\n ? profile.speed * profile.freshness + 0.5 * (1 - profile.freshness)\n : 0.5;\n const observedTailSpeed = profile\n ? profile.tailSpeed * profile.freshness + 0.5 * (1 - profile.freshness)\n : 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","/** Pure public-catalog parsing. Fetching, caching and UI ordering belong to hosts. */\nimport { DEFAULT_MODEL_CAPABILITIES, type ModelCapabilities } from \"./model-capabilities.js\";\nimport type { ModelPricing } from \"./selector.js\";\n\nexport const MODEL_KINDS = [\"chat\", \"image\", \"video\", \"music\"] as const;\nexport type ModelKind = (typeof MODEL_KINDS)[number];\n\n/** Gateway units are preserved: token prices per 1M tokens; media per unit. */\nexport interface CatalogPricing {\n input?: number;\n output?: number;\n per_image?: number;\n per_second?: number;\n per_track?: number;\n cache_read?: number;\n cache_write?: number;\n transaction_fee?: number;\n per_call_surcharge?: number;\n default_duration_seconds?: number;\n max_duration_seconds?: number;\n}\n\nexport interface CatalogModel {\n id: string;\n name: string;\n categories: readonly string[];\n kinds: readonly ModelKind[];\n billingMode?: string;\n /** Zero pricing alone does not imply a free model. */\n free: boolean;\n pricing: CatalogPricing;\n contextWindow?: number;\n maxOutputTokens?: number;\n}\n\nexport interface ModelCatalog {\n models: readonly CatalogModel[];\n chat: readonly CatalogModel[];\n image: readonly CatalogModel[];\n video: readonly CatalogModel[];\n music: readonly CatalogModel[];\n /**\n * IDs whose authoritative row says `available: false`. The gateway does not\n * reject these; it substitutes another model. Absence from the listing is\n * not unavailability: hidden IDs are still served.\n */\n unavailable: readonly string[];\n}\n\nconst PRICE_KEYS = [\n \"input\", \"output\", \"per_image\", \"per_second\", \"per_track\", \"cache_read\", \"cache_write\",\n \"transaction_fee\", \"per_call_surcharge\", \"default_duration_seconds\", \"max_duration_seconds\",\n] as const;\nconst UNIT_PRICE = { image: \"per_image\", video: \"per_second\", music: \"per_track\" } as const;\nconst MODEL_ID = /^[a-z0-9][a-z0-9._-]*\\/[a-zA-Z0-9][a-zA-Z0-9._:+-]*$/;\nconst record = (value: unknown): value is Record =>\n value !== null && typeof value === \"object\" && !Array.isArray(value);\nconst price = (value: unknown): value is number =>\n typeof value === \"number\" && Number.isFinite(value) && value >= 0;\nconst capacity = (value: unknown): number | undefined =>\n typeof value === \"number\" && Number.isSafeInteger(value) && value > 0 ? value : undefined;\n\n/**\n * Normalize GET /api/v1/models without a model-ID allowlist. New provider IDs\n * appear immediately. Hidden/unavailable rows and invalid per-kind prices are\n * omitted. A malformed envelope throws so a host can retain its last good list;\n * an explicitly empty `data` array is a valid empty catalog.\n *\n * IDs explicitly marked `available: false` are also listed in `unavailable`.\n * Rows outside MODEL_KINDS (speech, sound effects) are omitted.\n *\n * Last duplicate wins, including a final unavailable/invalid row. No sorting,\n * price markup, network request, capability probe or media routing is performed.\n */\nexport function parseModelCatalog(value: unknown): ModelCatalog {\n if (!record(value) || !Array.isArray(value.data)) {\n throw new TypeError(\"Model catalog must contain a data array\");\n }\n const entries = new Map>();\n for (const entry of value.data) {\n if (record(entry) && typeof entry.id === \"string\" && entry.id.length <= 200 && MODEL_ID.test(entry.id)) {\n entries.set(entry.id, entry);\n }\n }\n const result: ModelCatalog = { models: [], chat: [], image: [], video: [], music: [], unavailable: [] };\n const models: CatalogModel[] = [];\n const unavailable: string[] = [];\n for (const [id, entry] of entries) {\n if (entry.available === false) unavailable.push(id);\n if ((entry.available !== undefined && entry.available !== true) ||\n (entry.hidden !== undefined && entry.hidden !== false) ||\n !Array.isArray(entry.categories) || !record(entry.pricing)) continue;\n const categories = [...new Set(entry.categories.filter((c): c is string => typeof c === \"string\"))];\n const rawPricing = entry.pricing;\n const pricing: CatalogPricing = {};\n for (const key of PRICE_KEYS) if (price(rawPricing[key])) pricing[key] = rawPricing[key];\n const kinds = MODEL_KINDS.filter(kind => categories.includes(kind) && (kind === \"chat\"\n ? price(rawPricing.input) && price(rawPricing.output)\n : price(rawPricing[UNIT_PRICE[kind]])));\n if (!kinds.length) continue;\n const model: CatalogModel = {\n id, name: typeof entry.name === \"string\" && entry.name.trim() ? entry.name : id,\n categories, kinds, pricing,\n free: kinds.includes(\"chat\") && entry.billing_mode === \"free\" && pricing.input === 0 && pricing.output === 0,\n ...(typeof entry.billing_mode === \"string\" ? { billingMode: entry.billing_mode } : {}),\n ...(capacity(entry.context_window) !== undefined ? { contextWindow: capacity(entry.context_window) } : {}),\n ...(capacity(entry.max_output) !== undefined ? { maxOutputTokens: capacity(entry.max_output) } : {}),\n };\n models.push(model);\n }\n result.models = models;\n result.unavailable = unavailable;\n for (const kind of MODEL_KINDS) result[kind] = models.filter(model => model.kinds.includes(kind));\n return result;\n}\n\nexport interface CatalogRoutingOptions {\n /** Host evidence, merged over (and overriding per ID) the bundled verified table. */\n verifiedCapabilities?: Readonly>;\n}\n\nexport interface RoutingCatalog {\n modelPricing: Map;\n modelCapabilities: Record;\n unavailableModels: string[];\n}\n\n/**\n * Adapt only the chat catalog for route(). Media never enters LLM candidate\n * chains. Tool support comes from verified evidence, never a name or category.\n * Unknown capacities are zero, rather than invented defaults.\n *\n * Only rows the gateway explicitly marks `available: false` become\n * unavailableModels. Configured IDs that are merely absent from the listing\n * stay routable: the gateway serves hidden IDs, and only the configured chain\n * knows about them.\n */\nexport function toRoutingCatalog(catalog: ModelCatalog, options: CatalogRoutingOptions = {}): RoutingCatalog {\n const verified = { ...DEFAULT_MODEL_CAPABILITIES, ...options.verifiedCapabilities };\n const modelPricing = new Map();\n const modelCapabilities: Record = {};\n for (const model of catalog.chat) {\n modelPricing.set(model.id, { inputPrice: model.pricing.input!, outputPrice: model.pricing.output! });\n const evidence = verified[model.id];\n modelCapabilities[model.id] = {\n contextWindow: model.contextWindow ?? evidence?.contextWindow ?? 0,\n maxOutputTokens: model.maxOutputTokens ?? evidence?.maxOutputTokens ?? 0,\n supportsTools: evidence?.supportsTools === true,\n supportsVision: model.categories.includes(\"vision\"),\n };\n }\n return { modelPricing, modelCapabilities, unavailableModels: [...catalog.unavailable] };\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 { estimateTokens } from \"./tokens.js\";\nexport { MODEL_KINDS, parseModelCatalog, toRoutingCatalog } from \"./catalog.js\";\nexport type {\n ModelKind, CatalogPricing, CatalogModel, ModelCatalog, CatalogRoutingOptions, RoutingCatalog,\n} from \"./catalog.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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A;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,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;AA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","names":["confidence","decision","price","model"]} \ No newline at end of file diff --git a/index.ts b/index.ts index 1bcf6ab..15ca088 100644 --- a/index.ts +++ b/index.ts @@ -33,6 +33,10 @@ export { PortfolioStrategy } from "./portfolio.js"; export { classifyByRules } from "./rules.js"; export { inferToolRequirement } from "./tool-intent.js"; export { estimateTokens } from "./tokens.js"; +export { MODEL_KINDS, parseModelCatalog, toRoutingCatalog } from "./catalog.js"; +export type { + ModelKind, CatalogPricing, CatalogModel, ModelCatalog, CatalogRoutingOptions, RoutingCatalog, +} from "./catalog.js"; export { getFallbackChain, getFallbackChainFiltered,