From 4ded547cb5438719025d8051ae5a5428d7881e76 Mon Sep 17 00:00:00 2001 From: amosblomqvist Date: Thu, 24 Sep 2026 02:10:06 +0300 Subject: [PATCH] =?UTF-8?q?Context-meter=20amendment:=20CONTEXT=5FLIMITS?= =?UTF-8?q?=20dies=20=E2=80=94=20pi's=20live=20catalog=20is=20the=20only?= =?UTF-8?q?=20limit=20source?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Owner ruling (2026-09-23, amendment to 04e336d): no hardcoded fallback exists anywhere. contextWindow(record, limits) resolves the denominator ONLY from the live index (provider:id -> contextWindow straight from pi's catalog); a model missing from it (historical session, package update, failed fetch) reads limit null and the meter renders usage-only — the honest-render precedent, never a fake window. - src/core/prices.ts: the 1354-entry CONTEXT_LIMITS table (65KB) and its generation apparatus deleted; the fold returns limit: number | null. PRICES untouched (regen verified byte-identical via the reworked sync-pricing script). - scripts/sync-pricing.ts: generates PRICES only; contextWindow leaves the priced map, the guard, and the template. - The dock meter's owner-selected treatment: the activity feed carries the limit server-side. catalogContextLimits() (server/model-catalog.ts) builds the index over the same keyed providers the picker federates; activityFeed() joins it onto every running job (ActivityJob.contextLimit, null when the model is missing — the dock reads it off the feed, no client-side table, no regression while the UI's catalog-join chunk lands). - components/activity-dock.tsx: toBlobs reads job.contextLimit (import of CONTEXT_LIMITS gone); stats-bar renders usage-only on null limit (mechanical interim — UI stream's join chunk follows). - tests: usage.test.ts pins the no-fallback contract (index hit / absent / empty / missing-model -> null); activity-feed.test.ts pins the server join (catalog model -> 1048576, unknown -> null, no-usage -> null); render pins updated to the interim usage-only render. --- components/activity-dock.tsx | 13 +- components/stats-bar.tsx | 4 +- scripts/sync-pricing.ts | 21 +- src/core/contracts/jobs.ts | 8 +- src/core/prices.ts | 1381 +-------------------------- src/server/model-catalog.ts | 19 + src/server/observability.ts | 16 +- tests/activity-feed.test.ts | 39 + tests/render-activity-dock.test.tsx | 15 +- tests/render-stats-bar.test.tsx | 14 +- tests/usage.test.ts | 120 ++- 11 files changed, 200 insertions(+), 1450 deletions(-) diff --git a/components/activity-dock.tsx b/components/activity-dock.tsx index 6f30cbc..659bf7f 100644 --- a/components/activity-dock.tsx +++ b/components/activity-dock.tsx @@ -4,7 +4,7 @@ import { createContext, useCallback, useContext, useEffect, useMemo, useRef, use import { ActivityIcon, BotIcon, FileTextIcon, PenToolIcon, PlayIcon, SearchIcon, SquareIcon, WaypointsIcon } from "lucide-react"; import { cn } from "@/lib/utils"; import type { CallUsage, JobKind, JobRecord } from "@/src/core"; -import { CONTEXT_LIMITS, isModelsRefusal, jobCost } from "@/src/core"; +import { isModelsRefusal, jobCost } from "@/src/core"; import { formatTokens, formatUsd } from "@/components/usage-format"; /** @@ -48,6 +48,9 @@ interface FeedUsage extends NonNullable { export interface FeedJob extends JobRecord { title: string; usage?: FeedUsage; + /** Server-joined live catalog limit (owner amendment 2026-09-23) — + * null when the model is missing from pi's catalog (no context line). */ + contextLimit: number | null; } export interface FeedExtraction { @@ -171,8 +174,12 @@ export function toBlobs(feed: ActivityFeed): ActivityBlob[] { const usage = job.usage; let context: ActivityBlob["context"] = null; const lastStep = usage?.lastStep; - const limit = usage ? CONTEXT_LIMITS[usage.model] : undefined; - if (usage && lastStep && limit !== undefined && lastStep.inputTokens !== undefined) { + // Context-meter amendment (owner 2026-09-23): the limit comes off + // the FEED (server-joined from pi's live catalog) — no client-side + // table. Null limit = no context line (usage-only render is the + // blob shape's call — here the line simply hides). + const limit = job.contextLimit; + if (usage && lastStep && limit !== null && lastStep.inputTokens !== undefined) { context = { used: lastStep.inputTokens + (lastStep.outputTokens ?? 0), limit }; } return { diff --git a/components/stats-bar.tsx b/components/stats-bar.tsx index 77b3dec..a5d64d5 100644 --- a/components/stats-bar.tsx +++ b/components/stats-bar.tsx @@ -92,7 +92,7 @@ export function StatsBar({ className="flex items-center gap-1.5 tabular-nums transition-colors hover:text-foreground" > - {ctx ? `${formatTokens(ctx.usedTokens)} / ${formatTokens(ctx.limit)}` : "—"} + {ctx ? (ctx.limit !== null ? `${formatTokens(ctx.usedTokens)} / ${formatTokens(ctx.limit)}` : formatTokens(ctx.usedTokens)) : "—"} · {costLabel} @@ -109,7 +109,7 @@ export function StatsBar({
Context (last call) - {ctx ? `${formatTokens(ctx.usedTokens)} / ${formatTokens(ctx.limit)}` : "—"} + {ctx ? (ctx.limit !== null ? `${formatTokens(ctx.usedTokens)} / ${formatTokens(ctx.limit)}` : formatTokens(ctx.usedTokens)) : "—"}
diff --git a/scripts/sync-pricing.ts b/scripts/sync-pricing.ts index a212dd2..c997e1a 100644 --- a/scripts/sync-pricing.ts +++ b/scripts/sync-pricing.ts @@ -37,13 +37,12 @@ interface CatalogModel { id: string; name: string; cost: { input: number; output: number; cacheRead: number; cacheWrite: number }; - contextWindow: number; } function main(): void { // Every data file is {api: {modelId: entry}} — ids are per-provider // namespaced already (openrouter's are slugs, native ones plain). - const priced = new Map(); + const priced = new Map(); for (const file of fs.readdirSync(DATA_DIR).filter((f) => f.endsWith(".json"))) { const provider = file.slice(0, -".json".length); const catalog = JSON.parse(fs.readFileSync(path.join(DATA_DIR, file), "utf-8")) as Record< @@ -52,13 +51,13 @@ function main(): void { >; for (const models of Object.values(catalog)) { for (const [id, m] of Object.entries(models)) { - // A catalog entry without pricing/limit data gets no key at all - // (cost renders "—", never zero; the limit renders unknown). - if (!m.cost || m.contextWindow === undefined) continue; + // A catalog entry without pricing data gets no key at all + // (cost renders "—", never zero). + if (!m.cost) continue; // First writer wins (an id can appear under two apis within one // file with identical pricing; cross-file collisions cannot // happen — keys are provider-qualified). - priced.set(`${provider}:${id}`, { cost: m.cost, contextWindow: m.contextWindow }); + priced.set(`${provider}:${id}`, { cost: m.cost }); } } } @@ -68,25 +67,21 @@ function main(): void { .sort(([a], [b]) => a.localeCompare(b)) .map(([key, m]) => ({ price: `\t${JSON.stringify(key)}: { input: ${m.cost.input}, output: ${m.cost.output}, cacheRead: ${m.cost.cacheRead}, cacheWrite: ${m.cost.cacheWrite} },`, - limit: `\t${JSON.stringify(key)}: ${m.contextWindow},`, })); const tables = `/** Token prices, USD per 1M tokens. A missing model makes cost render * as absent ("—"), never zero. Keys are provider-qualified ("provider:id") * since the model slots wave; openrouter ids ALSO appear under their bare * slug (the legacy stamp format, kept so pre-wave records keep pricing). + * Context-window limits are NOT a table (owner amendment, 2026-09-23): + * every meter's denominator reads pi's LIVE catalog (GET /api/models / + * the activity feed's server-side join) — missing model, usage-only. * Refresh: bump @earendil-works/pi-ai, then npx tsx scripts/sync-pricing.ts * (reads pi-ai's shipped catalogs — the same source the engine and the * picker use). */ export const PRICES: Record = { ${rows.map((r) => r.price).join("\n")} }; - -/** Context-window limits (tokens) per model — generated alongside PRICES, - * same key families. */ -export const CONTEXT_LIMITS: Record = { -${rows.map((r) => r.limit).join("\n")} -}; `; const src = fs.readFileSync(OUT, "utf-8"); diff --git a/src/core/contracts/jobs.ts b/src/core/contracts/jobs.ts index ea24ae3..1d424ae 100644 --- a/src/core/contracts/jobs.ts +++ b/src/core/contracts/jobs.ts @@ -53,9 +53,11 @@ export interface JobUsage { /** How many model calls the run has made (each bills separately). */ steps: number; /** The MOST RECENT model call's accounting (2026-09 dock contract): the - * per-blob context line reads last-step input+output against the model's - * CONTEXT_LIMITS — never the cumulative totals. Absent until the first - * call completes; absent provider fields stay absent (never zero). */ + * per-blob context line reads last-step input+output against the + * model's LIVE catalog limit (server-joined onto the activity feed — + * never the cumulative totals, never a client-side table). Absent + * until the first call completes; absent provider fields stay absent + * (never zero). */ lastStep?: CallUsage; } diff --git a/src/core/prices.ts b/src/core/prices.ts index 4edf4ef..cb60c6b 100644 --- a/src/core/prices.ts +++ b/src/core/prices.ts @@ -31,6 +31,9 @@ export interface ModelPrice { * as absent ("—"), never zero. Keys are provider-qualified ("provider:id") * since the model slots wave; openrouter ids ALSO appear under their bare * slug (the legacy stamp format, kept so pre-wave records keep pricing). + * Context-window limits are NOT a table (owner amendment, 2026-09-23): + * every meter's denominator reads pi's LIVE catalog (GET /api/models / + * the activity feed's server-side join) — missing model, usage-only. * Refresh: bump @earendil-works/pi-ai, then npx tsx scripts/sync-pricing.ts * (reads pi-ai's shipped catalogs — the same source the engine and the * picker use). */ @@ -1391,1365 +1394,6 @@ export const PRICES: Record = { "zai:glm-5.3-highspeed": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, }; -/** Context-window limits (tokens) per model — generated alongside PRICES, - * same key families. */ -export const CONTEXT_LIMITS: Record = { - "amazon-bedrock:amazon.nova-2-lite-v1:0": 128000, - "amazon-bedrock:amazon.nova-lite-v1:0": 300000, - "amazon-bedrock:amazon.nova-micro-v1:0": 128000, - "amazon-bedrock:amazon.nova-pro-v1:0": 300000, - "amazon-bedrock:anthropic.claude-fable-5": 1000000, - "amazon-bedrock:anthropic.claude-fable-5-1": 1000000, - "amazon-bedrock:anthropic.claude-haiku-4-5-20251001-v1:0": 200000, - "amazon-bedrock:anthropic.claude-opus-4-1-20250805-v1:0": 200000, - "amazon-bedrock:anthropic.claude-opus-4-5-20251101-v1:0": 200000, - "amazon-bedrock:anthropic.claude-opus-4-6-v1": 1000000, - "amazon-bedrock:anthropic.claude-opus-4-7": 1000000, - "amazon-bedrock:anthropic.claude-opus-4-8": 1000000, - "amazon-bedrock:anthropic.claude-sonnet-4-5-20250929-v1:0": 200000, - "amazon-bedrock:anthropic.claude-sonnet-4-6": 1000000, - "amazon-bedrock:anthropic.claude-sonnet-5": 1000000, - "amazon-bedrock:au.anthropic.claude-haiku-4-5-20251001-v1:0": 200000, - "amazon-bedrock:au.anthropic.claude-opus-4-6-v1": 1000000, - "amazon-bedrock:au.anthropic.claude-opus-4-8": 1000000, - "amazon-bedrock:au.anthropic.claude-opus-5": 1000000, - "amazon-bedrock:au.anthropic.claude-sonnet-4-5-20250929-v1:0": 200000, - "amazon-bedrock:au.anthropic.claude-sonnet-4-6": 1000000, - "amazon-bedrock:au.anthropic.claude-sonnet-5": 1000000, - "amazon-bedrock:deepseek.r1-v1:0": 128000, - "amazon-bedrock:deepseek.v3-v1:0": 163840, - "amazon-bedrock:deepseek.v3.2": 163840, - "amazon-bedrock:eu.anthropic.claude-fable-5": 1000000, - "amazon-bedrock:eu.anthropic.claude-haiku-4-5-20251001-v1:0": 200000, - "amazon-bedrock:eu.anthropic.claude-opus-4-5-20251101-v1:0": 200000, - "amazon-bedrock:eu.anthropic.claude-opus-4-6-v1": 1000000, - "amazon-bedrock:eu.anthropic.claude-opus-4-7": 1000000, - "amazon-bedrock:eu.anthropic.claude-opus-4-8": 1000000, - "amazon-bedrock:eu.anthropic.claude-opus-5": 1000000, - "amazon-bedrock:eu.anthropic.claude-sonnet-4-5-20250929-v1:0": 200000, - "amazon-bedrock:eu.anthropic.claude-sonnet-4-6": 1000000, - "amazon-bedrock:eu.anthropic.claude-sonnet-5": 1000000, - "amazon-bedrock:global.anthropic.claude-fable-5": 1000000, - "amazon-bedrock:global.anthropic.claude-fable-5-1": 1000000, - "amazon-bedrock:global.anthropic.claude-haiku-4-5-20251001-v1:0": 200000, - "amazon-bedrock:global.anthropic.claude-opus-4-5-20251101-v1:0": 200000, - "amazon-bedrock:global.anthropic.claude-opus-4-6-v1": 1000000, - "amazon-bedrock:global.anthropic.claude-opus-4-7": 1000000, - "amazon-bedrock:global.anthropic.claude-opus-4-8": 1000000, - "amazon-bedrock:global.anthropic.claude-opus-5": 1000000, - "amazon-bedrock:global.anthropic.claude-sonnet-4-5-20250929-v1:0": 200000, - "amazon-bedrock:global.anthropic.claude-sonnet-4-6": 1000000, - "amazon-bedrock:global.anthropic.claude-sonnet-5": 1000000, - "amazon-bedrock:global.openai.gpt-5.6-luna": 1050000, - "amazon-bedrock:global.openai.gpt-5.6-sol": 1050000, - "amazon-bedrock:global.openai.gpt-5.6-terra": 1050000, - "amazon-bedrock:google.gemma-3-27b-it": 202752, - "amazon-bedrock:google.gemma-3-4b-it": 128000, - "amazon-bedrock:jp.anthropic.claude-haiku-4-5-20251001-v1:0": 200000, - "amazon-bedrock:jp.anthropic.claude-opus-4-7": 1000000, - "amazon-bedrock:jp.anthropic.claude-opus-4-8": 1000000, - "amazon-bedrock:jp.anthropic.claude-opus-5": 1000000, - "amazon-bedrock:jp.anthropic.claude-sonnet-4-5-20250929-v1:0": 200000, - "amazon-bedrock:jp.anthropic.claude-sonnet-4-6": 1000000, - "amazon-bedrock:jp.anthropic.claude-sonnet-5": 1000000, - "amazon-bedrock:meta.llama3-1-70b-instruct-v1:0": 128000, - "amazon-bedrock:meta.llama3-1-8b-instruct-v1:0": 128000, - "amazon-bedrock:meta.llama3-3-70b-instruct-v1:0": 128000, - "amazon-bedrock:meta.llama4-maverick-17b-instruct-v1:0": 1000000, - "amazon-bedrock:meta.llama4-scout-17b-instruct-v1:0": 3500000, - "amazon-bedrock:minimax.minimax-m2": 204608, - "amazon-bedrock:minimax.minimax-m2.1": 204800, - "amazon-bedrock:minimax.minimax-m2.5": 196608, - "amazon-bedrock:mistral.devstral-2-123b": 256000, - "amazon-bedrock:mistral.magistral-small-2509": 128000, - "amazon-bedrock:mistral.ministral-3-14b-instruct": 128000, - "amazon-bedrock:mistral.ministral-3-3b-instruct": 256000, - "amazon-bedrock:mistral.ministral-3-8b-instruct": 128000, - "amazon-bedrock:mistral.mistral-large-3-675b-instruct": 256000, - "amazon-bedrock:mistral.pixtral-large-2502-v1:0": 128000, - "amazon-bedrock:mistral.voxtral-mini-3b-2507": 128000, - "amazon-bedrock:mistral.voxtral-small-24b-2507": 32000, - "amazon-bedrock:moonshot.kimi-k2-thinking": 262143, - "amazon-bedrock:moonshotai.kimi-k2.5": 262143, - "amazon-bedrock:nvidia.nemotron-nano-12b-v2": 128000, - "amazon-bedrock:nvidia.nemotron-nano-3-30b": 128000, - "amazon-bedrock:nvidia.nemotron-nano-9b-v2": 128000, - "amazon-bedrock:nvidia.nemotron-super-3-120b": 262144, - "amazon-bedrock:openai.gpt-5.4": 272000, - "amazon-bedrock:openai.gpt-5.5": 272000, - "amazon-bedrock:openai.gpt-5.6-luna": 1050000, - "amazon-bedrock:openai.gpt-5.6-sol": 1050000, - "amazon-bedrock:openai.gpt-5.6-terra": 1050000, - "amazon-bedrock:openai.gpt-oss-120b": 128000, - "amazon-bedrock:openai.gpt-oss-120b-1:0": 128000, - "amazon-bedrock:openai.gpt-oss-20b": 128000, - "amazon-bedrock:openai.gpt-oss-20b-1:0": 128000, - "amazon-bedrock:openai.gpt-oss-safeguard-120b": 128000, - "amazon-bedrock:openai.gpt-oss-safeguard-20b": 128000, - "amazon-bedrock:qwen.qwen3-235b-a22b-2507-v1:0": 262144, - "amazon-bedrock:qwen.qwen3-32b-v1:0": 16384, - "amazon-bedrock:qwen.qwen3-coder-30b-a3b-v1:0": 262144, - "amazon-bedrock:qwen.qwen3-coder-480b-a35b-v1:0": 131072, - "amazon-bedrock:qwen.qwen3-coder-next": 131072, - "amazon-bedrock:qwen.qwen3-next-80b-a3b": 262000, - "amazon-bedrock:qwen.qwen3-vl-235b-a22b": 262000, - "amazon-bedrock:us.anthropic.claude-fable-5": 1000000, - "amazon-bedrock:us.anthropic.claude-fable-5-1": 1000000, - "amazon-bedrock:us.anthropic.claude-haiku-4-5-20251001-v1:0": 200000, - "amazon-bedrock:us.anthropic.claude-opus-4-1-20250805-v1:0": 200000, - "amazon-bedrock:us.anthropic.claude-opus-4-5-20251101-v1:0": 200000, - "amazon-bedrock:us.anthropic.claude-opus-4-6-v1": 1000000, - "amazon-bedrock:us.anthropic.claude-opus-4-7": 1000000, - "amazon-bedrock:us.anthropic.claude-opus-4-8": 1000000, - "amazon-bedrock:us.anthropic.claude-opus-5": 1000000, - "amazon-bedrock:us.anthropic.claude-sonnet-4-5-20250929-v1:0": 200000, - "amazon-bedrock:us.anthropic.claude-sonnet-4-6": 1000000, - "amazon-bedrock:us.anthropic.claude-sonnet-5": 1000000, - "amazon-bedrock:us.deepseek.r1-v1:0": 128000, - "amazon-bedrock:us.meta.llama4-maverick-17b-instruct-v1:0": 1000000, - "amazon-bedrock:us.meta.llama4-scout-17b-instruct-v1:0": 3500000, - "amazon-bedrock:writer.palmyra-x4-v1:0": 122880, - "amazon-bedrock:writer.palmyra-x5-v1:0": 1040000, - "amazon-bedrock:xai.grok-4.3": 1000000, - "amazon-bedrock:xai.grok-4.6": 500000, - "amazon-bedrock:zai.glm-4.7": 204800, - "amazon-bedrock:zai.glm-4.7-flash": 200000, - "amazon-bedrock:zai.glm-5": 202752, - "ant-ling:Ling-2.6-1T": 262144, - "ant-ling:Ling-2.6-flash": 262144, - "ant-ling:Ring-2.6-1T": 262144, - "anthropic:claude-fable-5": 1000000, - "anthropic:claude-fable-5-1": 1000000, - "anthropic:claude-haiku-4-5": 200000, - "anthropic:claude-haiku-4-5-20251001": 200000, - "anthropic:claude-opus-4-5": 200000, - "anthropic:claude-opus-4-5-20251101": 200000, - "anthropic:claude-opus-4-6": 1000000, - "anthropic:claude-opus-4-7": 1000000, - "anthropic:claude-opus-4-8": 1000000, - "anthropic:claude-opus-5": 1000000, - "anthropic:claude-sonnet-4-5": 1000000, - "anthropic:claude-sonnet-4-5-20250929": 1000000, - "anthropic:claude-sonnet-4-6": 1000000, - "anthropic:claude-sonnet-5": 1000000, - "azure-openai-responses:gpt-4": 8192, - "azure-openai-responses:gpt-4-turbo": 128000, - "azure-openai-responses:gpt-4.1": 1047576, - "azure-openai-responses:gpt-4.1-mini": 1047576, - "azure-openai-responses:gpt-4.1-nano": 1047576, - "azure-openai-responses:gpt-4o": 128000, - "azure-openai-responses:gpt-4o-2024-05-13": 128000, - "azure-openai-responses:gpt-4o-2024-08-06": 128000, - "azure-openai-responses:gpt-4o-2024-11-20": 128000, - "azure-openai-responses:gpt-4o-mini": 128000, - "azure-openai-responses:gpt-5": 400000, - "azure-openai-responses:gpt-5-chat-latest": 128000, - "azure-openai-responses:gpt-5-mini": 400000, - "azure-openai-responses:gpt-5-nano": 400000, - "azure-openai-responses:gpt-5-pro": 400000, - "azure-openai-responses:gpt-5.1": 400000, - "azure-openai-responses:gpt-5.2": 400000, - "azure-openai-responses:gpt-5.2-chat-latest": 128000, - "azure-openai-responses:gpt-5.2-pro": 400000, - "azure-openai-responses:gpt-5.3-chat-latest": 128000, - "azure-openai-responses:gpt-5.3-codex": 400000, - "azure-openai-responses:gpt-5.3-codex-spark": 128000, - "azure-openai-responses:gpt-5.4": 1050000, - "azure-openai-responses:gpt-5.4-mini": 400000, - "azure-openai-responses:gpt-5.4-nano": 400000, - "azure-openai-responses:gpt-5.4-pro": 1050000, - "azure-openai-responses:gpt-5.5": 1050000, - "azure-openai-responses:gpt-5.5-pro": 1050000, - "azure-openai-responses:gpt-5.6-luna": 1050000, - "azure-openai-responses:gpt-5.6-sol": 1050000, - "azure-openai-responses:gpt-5.6-terra": 1050000, - "azure-openai-responses:gpt-6-astra": 272000, - "azure-openai-responses:gpt-realtime-2.1": 128000, - "azure-openai-responses:o1": 200000, - "azure-openai-responses:o1-pro": 200000, - "azure-openai-responses:o3": 200000, - "azure-openai-responses:o3-mini": 200000, - "azure-openai-responses:o3-pro": 200000, - "azure-openai-responses:o4-mini": 200000, - "baseten:deepseek-ai/DeepSeek-V4-Flash-0731": 1048576, - "baseten:deepseek-ai/DeepSeek-V4-Pro": 1048576, - "baseten:deepseek-ai/DeepSeek-V4-Pro-0813": 1048576, - "baseten:moonshotai/Kimi-K2.5": 262000, - "baseten:moonshotai/Kimi-K2.6": 262000, - "baseten:moonshotai/Kimi-K2.7-Code": 262000, - "baseten:moonshotai/Kimi-K3": 1048576, - "baseten:nvidia/Nemotron-120B-A12B": 202800, - "baseten:nvidia/NVIDIA-Nemotron-3-Ultra-550B-A55B": 202800, - "baseten:openai/gpt-oss-120b": 128072, - "baseten:thinkingmachines/inkling": 1048576, - "baseten:thinkingmachines/inkling-small": 1048576, - "baseten:zai-org/GLM-4.7": 200000, - "baseten:zai-org/GLM-5": 202800, - "baseten:zai-org/GLM-5.1": 202800, - "baseten:zai-org/GLM-5.2": 1048576, - "baseten:zai-org/GLM-5.2-Fast": 1048576, - "baseten:zai-org/GLM-5.3": 1048576, - "baseten:zai-org/GLM-5.3-Fast": 1048576, - "baseten:zai-org/GLM-5.3-Flash": 1048576, - "cerebras:gemma-4-31b": 131072, - "cerebras:gpt-oss-120b": 131072, - "cloudflare-ai-gateway:claude-fable-5": 1000000, - "cloudflare-ai-gateway:claude-fable-5.1": 1000000, - "cloudflare-ai-gateway:claude-haiku-4.5": 200000, - "cloudflare-ai-gateway:claude-opus-4.5": 200000, - "cloudflare-ai-gateway:claude-opus-4.6": 1000000, - "cloudflare-ai-gateway:claude-opus-4.7": 1000000, - "cloudflare-ai-gateway:claude-opus-4.8": 1000000, - "cloudflare-ai-gateway:claude-opus-5": 1000000, - "cloudflare-ai-gateway:claude-sonnet-4.5": 1000000, - "cloudflare-ai-gateway:claude-sonnet-4.6": 1000000, - "cloudflare-ai-gateway:claude-sonnet-5": 1000000, - "cloudflare-ai-gateway:gpt-4.1": 1047576, - "cloudflare-ai-gateway:gpt-4.1-mini": 1047576, - "cloudflare-ai-gateway:gpt-4.1-nano": 1000000, - "cloudflare-ai-gateway:gpt-4o": 128000, - "cloudflare-ai-gateway:gpt-4o-mini": 128000, - "cloudflare-ai-gateway:gpt-5": 128000, - "cloudflare-ai-gateway:gpt-5-mini": 128000, - "cloudflare-ai-gateway:gpt-5-nano": 128000, - "cloudflare-ai-gateway:gpt-5.1": 128000, - "cloudflare-ai-gateway:gpt-5.4": 1000000, - "cloudflare-ai-gateway:gpt-5.4-mini": 128000, - "cloudflare-ai-gateway:gpt-5.4-nano": 128000, - "cloudflare-ai-gateway:gpt-5.4-pro": 1000000, - "cloudflare-ai-gateway:gpt-5.5": 1000000, - "cloudflare-ai-gateway:gpt-5.5-pro": 1000000, - "cloudflare-ai-gateway:gpt-5.6-luna": 1050000, - "cloudflare-ai-gateway:gpt-5.6-sol": 1050000, - "cloudflare-ai-gateway:gpt-5.6-terra": 1050000, - "cloudflare-ai-gateway:o3": 200000, - "cloudflare-ai-gateway:o3-mini": 200000, - "cloudflare-ai-gateway:o4-mini": 200000, - "cloudflare-ai-gateway:workers-ai/@cf/deepseek-ai/deepseek-v4-flash-0731": 1310720, - "cloudflare-ai-gateway:workers-ai/@cf/deepseek-ai/deepseek-v4-pro-0813": 1048576, - "cloudflare-ai-gateway:workers-ai/@cf/google/gemma-4-26b-a4b-it": 256000, - "cloudflare-ai-gateway:workers-ai/@cf/ibm-granite/granite-4.0-h-micro": 131000, - "cloudflare-ai-gateway:workers-ai/@cf/meta/llama-3.3-70b-instruct-fp8-fast": 24000, - "cloudflare-ai-gateway:workers-ai/@cf/meta/llama-4-scout-17b-16e-instruct": 131000, - "cloudflare-ai-gateway:workers-ai/@cf/mistralai/mistral-small-3.1-24b-instruct": 128000, - "cloudflare-ai-gateway:workers-ai/@cf/moonshotai/kimi-k2.6": 262144, - "cloudflare-ai-gateway:workers-ai/@cf/moonshotai/kimi-k2.7-code": 262144, - "cloudflare-ai-gateway:workers-ai/@cf/nvidia/nemotron-3-120b-a12b": 256000, - "cloudflare-ai-gateway:workers-ai/@cf/openai/gpt-oss-120b": 128000, - "cloudflare-ai-gateway:workers-ai/@cf/openai/gpt-oss-20b": 128000, - "cloudflare-ai-gateway:workers-ai/@cf/qwen/qwen3-30b-a3b-fp8": 32768, - "cloudflare-ai-gateway:workers-ai/@cf/qwen/qwen3.8-27b": 262144, - "cloudflare-ai-gateway:workers-ai/@cf/zai-org/glm-4.7-flash": 131072, - "cloudflare-ai-gateway:workers-ai/@cf/zai-org/glm-5.2": 262144, - "cloudflare-ai-gateway:workers-ai/@cf/zai-org/glm-5.3": 1310720, - "cloudflare-ai-gateway:workers-ai/@cf/zai-org/glm-5.3-flash": 1310720, - "cloudflare-workers-ai:@cf/deepseek-ai/deepseek-v4-flash-0731": 1310720, - "cloudflare-workers-ai:@cf/deepseek-ai/deepseek-v4-pro-0813": 1048576, - "cloudflare-workers-ai:@cf/google/gemma-4-26b-a4b-it": 256000, - "cloudflare-workers-ai:@cf/ibm-granite/granite-4.0-h-micro": 131000, - "cloudflare-workers-ai:@cf/meta/llama-3.3-70b-instruct-fp8-fast": 24000, - "cloudflare-workers-ai:@cf/meta/llama-4-scout-17b-16e-instruct": 131000, - "cloudflare-workers-ai:@cf/mistralai/mistral-small-3.1-24b-instruct": 128000, - "cloudflare-workers-ai:@cf/moonshotai/kimi-k2.6": 262144, - "cloudflare-workers-ai:@cf/moonshotai/kimi-k2.7-code": 262144, - "cloudflare-workers-ai:@cf/nvidia/nemotron-3-120b-a12b": 256000, - "cloudflare-workers-ai:@cf/openai/gpt-oss-120b": 128000, - "cloudflare-workers-ai:@cf/openai/gpt-oss-20b": 128000, - "cloudflare-workers-ai:@cf/qwen/qwen3-30b-a3b-fp8": 32768, - "cloudflare-workers-ai:@cf/qwen/qwen3.8-27b": 262144, - "cloudflare-workers-ai:@cf/zai-org/glm-4.7-flash": 131072, - "cloudflare-workers-ai:@cf/zai-org/glm-5.2": 262144, - "cloudflare-workers-ai:@cf/zai-org/glm-5.3": 1310720, - "cloudflare-workers-ai:@cf/zai-org/glm-5.3-flash": 1310720, - "deepseek:deepseek-v4-flash": 1000000, - "deepseek:deepseek-v4-flash-vision-exp": 1000000, - "deepseek:deepseek-v4-pro": 1000000, - "fireworks:accounts/fireworks/models/deepseek-v4-flash-0731": 1000000, - "fireworks:accounts/fireworks/models/deepseek-v4-flash-vision-exp": 1000000, - "fireworks:accounts/fireworks/models/deepseek-v4-pro-0813": 1000000, - "fireworks:accounts/fireworks/models/glm-5p2": 1048575, - "fireworks:accounts/fireworks/models/glm-5p3": 1000000, - "fireworks:accounts/fireworks/models/glm-5p3-flash": 1000000, - "fireworks:accounts/fireworks/models/gpt-oss-120b": 131072, - "fireworks:accounts/fireworks/models/inkling": 1048576, - "fireworks:accounts/fireworks/models/kimi-k2p6": 262000, - "fireworks:accounts/fireworks/models/kimi-k2p7-code": 262000, - "fireworks:accounts/fireworks/models/kimi-k3": 1048576, - "fireworks:accounts/fireworks/models/minimax-m3": 512000, - "fireworks:accounts/fireworks/models/muse-glimmer-30b": 131072, - "fireworks:accounts/fireworks/models/nemotron-3-ultra-nvfp4": 262144, - "fireworks:accounts/fireworks/models/nemotron-lightning-3p5-30b-a3b": 262144, - "fireworks:accounts/fireworks/models/qwen3p7-plus": 262144, - "fireworks:accounts/fireworks/models/qwen3p8-2p4t-a95b": 262144, - "fireworks:accounts/fireworks/models/qwen3p8-max": 262144, - "fireworks:accounts/fireworks/routers/glm-5p2-fast": 1048575, - "fireworks:accounts/fireworks/routers/kimi-k3-fast": 1048576, - "github-copilot:claude-fable-5": 1000000, - "github-copilot:claude-fable-5.1": 1000000, - "github-copilot:claude-haiku-4.5": 200000, - "github-copilot:claude-opus-4.7": 1000000, - "github-copilot:claude-opus-4.8": 1000000, - "github-copilot:claude-opus-5": 1000000, - "github-copilot:claude-sonnet-4.6": 1000000, - "github-copilot:claude-sonnet-5": 1000000, - "github-copilot:gemini-3.5-flash": 200000, - "github-copilot:gemini-3.6-flash": 1000000, - "github-copilot:gemini-3.7-flash": 1000000, - "github-copilot:gemini-3.8-flash": 1000000, - "github-copilot:gpt-5-mini": 264000, - "github-copilot:gpt-5.3-codex": 1000000, - "github-copilot:gpt-5.4": 1000000, - "github-copilot:gpt-5.4-mini": 400000, - "github-copilot:gpt-5.4-nano": 400000, - "github-copilot:gpt-5.5": 1000000, - "github-copilot:gpt-5.6-luna": 1050000, - "github-copilot:gpt-5.6-sol": 1050000, - "github-copilot:gpt-5.6-terra": 1050000, - "github-copilot:gpt-6-astra": 1050000, - "github-copilot:grok-4.5": 500000, - "github-copilot:grok-4.6": 500000, - "github-copilot:kimi-k2.7-code": 256000, - "github-copilot:kimi-k3": 1048576, - "github-copilot:mai-code-1-flash-picker": 256000, - "github-copilot:mai-code-1.1-flash": 256000, - "google-vertex:gemini-2.5-flash": 1048576, - "google-vertex:gemini-2.5-flash-lite": 1048576, - "google-vertex:gemini-2.5-pro": 1048576, - "google-vertex:gemini-3-flash-preview": 1048576, - "google-vertex:gemini-3.1-flash-lite": 1048576, - "google-vertex:gemini-3.1-pro-preview": 1048576, - "google-vertex:gemini-3.1-pro-preview-customtools": 1048576, - "google-vertex:gemini-3.5-flash": 1048576, - "google-vertex:gemini-3.5-flash-lite": 1048576, - "google-vertex:gemini-3.6-flash": 1048576, - "google-vertex:gemini-3.7-flash": 1048576, - "google-vertex:gemini-3.8-flash": 1048576, - "google-vertex:gemini-flash-latest": 1048576, - "google-vertex:gemini-flash-lite-latest": 1048576, - "google:deep-research-max-preview-04-2026": 131072, - "google:deep-research-preview-04-2026": 131072, - "google:gemini-2.5-computer-use-preview-10-2025": 131072, - "google:gemini-2.5-flash": 1048576, - "google:gemini-2.5-flash-lite": 1048576, - "google:gemini-2.5-pro": 1048576, - "google:gemini-3-flash-preview": 1048576, - "google:gemini-3.1-flash-lite": 1048576, - "google:gemini-3.1-flash-lite-image": 65536, - "google:gemini-3.1-flash-lite-preview": 1048576, - "google:gemini-3.1-flash-live-preview": 131072, - "google:gemini-3.1-pro-preview": 1048576, - "google:gemini-3.1-pro-preview-customtools": 1048576, - "google:gemini-3.5-flash": 1048576, - "google:gemini-3.5-flash-lite": 1048576, - "google:gemini-3.6-flash": 1048576, - "google:gemini-3.7-flash": 1048576, - "google:gemini-3.8-flash": 1048576, - "google:gemini-flash-latest": 1048576, - "google:gemini-flash-lite-latest": 1048576, - "google:gemma-4-26b-a4b-it": 262144, - "google:gemma-4-31b-it": 262144, - "groq:llama-3.1-8b-instant": 131072, - "groq:llama-3.3-70b-versatile": 131072, - "groq:openai/gpt-oss-120b": 131072, - "groq:openai/gpt-oss-20b": 131072, - "groq:openai/gpt-oss-safeguard-20b": 131072, - "groq:qwen/qwen3.6-27b": 131072, - "groq:qwen/qwen3.8-27b": 131042, - "huggingface:deepseek-ai/DeepSeek-R1": 64000, - "huggingface:deepseek-ai/DeepSeek-R1-0528": 163840, - "huggingface:deepseek-ai/DeepSeek-V3": 64000, - "huggingface:deepseek-ai/DeepSeek-V3-0324": 163840, - "huggingface:deepseek-ai/DeepSeek-V3.1": 131072, - "huggingface:deepseek-ai/DeepSeek-V3.2": 163840, - "huggingface:deepseek-ai/DeepSeek-V4-Flash": 1048576, - "huggingface:deepseek-ai/DeepSeek-V4-Flash-0731": 1048576, - "huggingface:deepseek-ai/DeepSeek-V4-Flash-Vision-Exp": 1048576, - "huggingface:deepseek-ai/DeepSeek-V4-Pro": 1048576, - "huggingface:deepseek-ai/DeepSeek-V4-Pro-0813": 1000000, - "huggingface:google/gemma-4-26B-A4B-it": 262144, - "huggingface:google/gemma-4-31B-it": 262144, - "huggingface:meta-llama/Llama-3.1-8B-Instruct": 131072, - "huggingface:meta-llama/Llama-3.3-70B-Instruct": 131072, - "huggingface:MiniMaxAI/MiniMax-M2": 204800, - "huggingface:MiniMaxAI/MiniMax-M2.1": 204800, - "huggingface:MiniMaxAI/MiniMax-M2.5": 204800, - "huggingface:MiniMaxAI/MiniMax-M2.7": 204800, - "huggingface:MiniMaxAI/MiniMax-M3": 524288, - "huggingface:moonshotai/Kimi-K2-Instruct": 131072, - "huggingface:moonshotai/Kimi-K2-Instruct-0905": 262144, - "huggingface:moonshotai/Kimi-K2-Thinking": 262144, - "huggingface:moonshotai/Kimi-K2.5": 262144, - "huggingface:moonshotai/Kimi-K2.6": 262144, - "huggingface:moonshotai/Kimi-K2.7-Code": 262144, - "huggingface:moonshotai/Kimi-K3": 1000000, - "huggingface:openai/gpt-oss-120b": 131072, - "huggingface:openai/gpt-oss-20b": 131072, - "huggingface:Qwen/Qwen2.5-Coder-32B-Instruct": 131072, - "huggingface:Qwen/Qwen3-235B-A22B": 40960, - "huggingface:Qwen/Qwen3-235B-A22B-Instruct-2507": 262144, - "huggingface:Qwen/Qwen3-235B-A22B-Thinking-2507": 262144, - "huggingface:Qwen/Qwen3-30B-A3B": 40960, - "huggingface:Qwen/Qwen3-32B": 131072, - "huggingface:Qwen/Qwen3-Coder-30B-A3B-Instruct": 262144, - "huggingface:Qwen/Qwen3-Coder-480B-A35B-Instruct": 262144, - "huggingface:Qwen/Qwen3-Coder-Next": 262144, - "huggingface:Qwen/Qwen3-Next-80B-A3B-Instruct": 262144, - "huggingface:Qwen/Qwen3-Next-80B-A3B-Thinking": 262144, - "huggingface:Qwen/Qwen3-VL-235B-A22B-Instruct": 131072, - "huggingface:Qwen/Qwen3-VL-235B-A22B-Thinking": 131072, - "huggingface:Qwen/Qwen3.5-122B-A10B": 262144, - "huggingface:Qwen/Qwen3.5-27B": 262144, - "huggingface:Qwen/Qwen3.5-35B-A3B": 262144, - "huggingface:Qwen/Qwen3.5-397B-A17B": 262144, - "huggingface:Qwen/Qwen3.5-9B": 262144, - "huggingface:Qwen/Qwen3.6-27B": 262144, - "huggingface:Qwen/Qwen3.6-35B-A3B": 262144, - "huggingface:Qwen/Qwen3.8-2.4T-A95B": 262144, - "huggingface:Qwen/Qwen3.8-27B": 262144, - "huggingface:stepfun-ai/Step-3.5-Flash": 262144, - "huggingface:stepfun-ai/Step-3.7-Flash": 262144, - "huggingface:tencent/Hy3": 262144, - "huggingface:thinkingmachines/Inkling": 1048576, - "huggingface:thinkingmachines/Inkling-Small": 524288, - "huggingface:XiaomiMiMo/MiMo-V2-Flash": 262144, - "huggingface:XiaomiMiMo/MiMo-V2.5": 262144, - "huggingface:XiaomiMiMo/MiMo-V2.5-Pro": 1048576, - "huggingface:zai-org/GLM-4.5": 131072, - "huggingface:zai-org/GLM-4.5-Air": 131072, - "huggingface:zai-org/GLM-4.5V": 65536, - "huggingface:zai-org/GLM-4.6": 204800, - "huggingface:zai-org/GLM-4.6V-Flash": 131072, - "huggingface:zai-org/GLM-4.7": 204800, - "huggingface:zai-org/GLM-4.7-Flash": 200000, - "huggingface:zai-org/GLM-5": 202752, - "huggingface:zai-org/GLM-5.1": 202752, - "huggingface:zai-org/GLM-5.2": 262144, - "huggingface:zai-org/GLM-5.3": 1048576, - "huggingface:zai-org/GLM-5.3-Flash": 1048576, - "kimi-coding:k3": 1048576, - "kimi-coding:k3-256k": 262144, - "kimi-coding:kimi-for-coding": 262144, - "kimi-coding:kimi-for-coding-highspeed": 262144, - "minimax-cn:MiniMax-M2.7": 204800, - "minimax-cn:MiniMax-M2.7-highspeed": 204800, - "minimax-cn:MiniMax-M3": 1048576, - "minimax:MiniMax-M2.7": 204800, - "minimax:MiniMax-M2.7-highspeed": 204800, - "minimax:MiniMax-M3": 1048576, - "mistral:codestral-latest": 256000, - "mistral:devstral-2512": 262144, - "mistral:devstral-latest": 262144, - "mistral:devstral-medium-2507": 128000, - "mistral:devstral-medium-latest": 262144, - "mistral:devstral-small-2505": 128000, - "mistral:devstral-small-2507": 128000, - "mistral:labs-devstral-small-2512": 256000, - "mistral:magistral-medium-latest": 128000, - "mistral:magistral-small": 128000, - "mistral:ministral-3b-latest": 128000, - "mistral:ministral-8b-latest": 128000, - "mistral:mistral-large-2411": 131072, - "mistral:mistral-large-2512": 262144, - "mistral:mistral-large-latest": 262144, - "mistral:mistral-medium-2505": 131072, - "mistral:mistral-medium-2508": 262144, - "mistral:mistral-medium-2604": 262144, - "mistral:mistral-medium-3.5": 262144, - "mistral:mistral-medium-latest": 262144, - "mistral:mistral-nemo": 128000, - "mistral:mistral-small-2506": 128000, - "mistral:mistral-small-2603": 256000, - "mistral:mistral-small-latest": 256000, - "mistral:open-mistral-7b": 8000, - "mistral:open-mistral-nemo": 128000, - "mistral:open-mixtral-8x22b": 64000, - "mistral:open-mixtral-8x7b": 32000, - "mistral:pixtral-12b": 128000, - "mistral:pixtral-large-latest": 128000, - "mistral:voxtral-small-latest": 32000, - "mistral:zai-glm-5-2": 1000000, - "moonshotai-cn:kimi-k2-0711-preview": 131072, - "moonshotai-cn:kimi-k2-0905-preview": 262144, - "moonshotai-cn:kimi-k2-thinking": 262144, - "moonshotai-cn:kimi-k2-thinking-turbo": 262144, - "moonshotai-cn:kimi-k2-turbo-preview": 262144, - "moonshotai-cn:kimi-k2.5": 262144, - "moonshotai-cn:kimi-k2.6": 262144, - "moonshotai-cn:kimi-k2.7-code": 262144, - "moonshotai-cn:kimi-k2.7-code-highspeed": 262144, - "moonshotai-cn:kimi-k3": 1048576, - "moonshotai:kimi-k2-0711-preview": 131072, - "moonshotai:kimi-k2-0905-preview": 262144, - "moonshotai:kimi-k2-thinking": 262144, - "moonshotai:kimi-k2-thinking-turbo": 262144, - "moonshotai:kimi-k2-turbo-preview": 262144, - "moonshotai:kimi-k2.5": 262144, - "moonshotai:kimi-k2.6": 262144, - "moonshotai:kimi-k2.7-code": 262144, - "moonshotai:kimi-k2.7-code-highspeed": 262144, - "moonshotai:kimi-k3": 1048576, - "nvidia:deepseek-ai/deepseek-v4-flash-0731": 1000000, - "nvidia:deepseek-ai/deepseek-v4-pro-0813": 1000000, - "nvidia:google/gemma-3-12b-it": 131072, - "nvidia:google/gemma-3-4b-it": 131072, - "nvidia:meta/llama-3.2-11b-vision-instruct": 128000, - "nvidia:meta/llama-3.2-90b-vision-instruct": 128000, - "nvidia:meta/muse-glimmer-30b": 131072, - "nvidia:minimaxai/minimax-m3": 1000000, - "nvidia:mistralai/mistral-7b-instruct-v0.3": 65536, - "nvidia:moonshotai/kimi-k2.6": 262144, - "nvidia:moonshotai/kimi-k3": 1048576, - "nvidia:nvidia/cosmos-reason2-8b": 131072, - "nvidia:nvidia/llama-3.1-nemotron-70b-instruct": 128000, - "nvidia:nvidia/llama-3.1-nemotron-ultra-253b-v1": 128000, - "nvidia:nvidia/nemotron-3-nano-omni-30b-a3b-reasoning": 256000, - "nvidia:nvidia/nemotron-3-super-120b-a12b": 262144, - "nvidia:nvidia/nemotron-3-ultra-550b-a55b": 1000000, - "nvidia:nvidia/nemotron-3.5-lightning-30b-a3b": 262144, - "nvidia:openai/gpt-oss-20b": 131072, - "nvidia:poolside/laguna-xs-2.1": 262144, - "openai-codex:gpt-5.3-codex-spark": 128000, - "openai-codex:gpt-5.4": 272000, - "openai-codex:gpt-5.4-mini": 272000, - "openai-codex:gpt-5.5": 272000, - "openai-codex:gpt-5.6-luna": 272000, - "openai-codex:gpt-5.6-sol": 272000, - "openai-codex:gpt-5.6-terra": 272000, - "openai-codex:gpt-6-astra": 272000, - "openai:gpt-4": 8192, - "openai:gpt-4-turbo": 128000, - "openai:gpt-4.1": 1047576, - "openai:gpt-4.1-mini": 1047576, - "openai:gpt-4.1-nano": 1047576, - "openai:gpt-4o": 128000, - "openai:gpt-4o-2024-05-13": 128000, - "openai:gpt-4o-2024-08-06": 128000, - "openai:gpt-4o-2024-11-20": 128000, - "openai:gpt-4o-mini": 128000, - "openai:gpt-5": 400000, - "openai:gpt-5-chat-latest": 128000, - "openai:gpt-5-mini": 400000, - "openai:gpt-5-nano": 400000, - "openai:gpt-5-pro": 400000, - "openai:gpt-5.1": 400000, - "openai:gpt-5.2": 400000, - "openai:gpt-5.2-chat-latest": 128000, - "openai:gpt-5.2-pro": 400000, - "openai:gpt-5.3-chat-latest": 128000, - "openai:gpt-5.3-codex": 400000, - "openai:gpt-5.3-codex-spark": 128000, - "openai:gpt-5.4": 272000, - "openai:gpt-5.4-mini": 400000, - "openai:gpt-5.4-nano": 400000, - "openai:gpt-5.4-pro": 1050000, - "openai:gpt-5.5": 272000, - "openai:gpt-5.5-pro": 1050000, - "openai:gpt-5.6-luna": 272000, - "openai:gpt-5.6-sol": 272000, - "openai:gpt-5.6-terra": 272000, - "openai:gpt-6-astra": 272000, - "openai:gpt-realtime-2.1": 128000, - "openai:o1": 200000, - "openai:o1-pro": 200000, - "openai:o3": 200000, - "openai:o3-mini": 200000, - "openai:o3-pro": 200000, - "openai:o4-mini": 200000, - "opencode-go:deepseek-v4-flash": 1000000, - "opencode-go:deepseek-v4-flash-vision-exp": 1000000, - "opencode-go:deepseek-v4-pro": 1000000, - "opencode-go:glm-5.1": 202752, - "opencode-go:glm-5.2": 1000000, - "opencode-go:glm-5.3": 1000000, - "opencode-go:glm-5.3-flash": 1000000, - "opencode-go:gpt-5.6-luna": 1050000, - "opencode-go:grok-4.6": 500000, - "opencode-go:hy3": 256000, - "opencode-go:hy4-preview": 1024000, - "opencode-go:kimi-k2.6": 262144, - "opencode-go:kimi-k2.7-code": 262144, - "opencode-go:kimi-k3": 1048576, - "opencode-go:longcat-2.0": 1000000, - "opencode-go:mimo-v2.5": 1000000, - "opencode-go:mimo-v2.5-pro": 1048576, - "opencode-go:minimax-m2.7": 204800, - "opencode-go:minimax-m3": 1000000, - "opencode-go:muse-spark-1.2-contributor": 1048576, - "opencode-go:muse-spark-1.3-contributor": 1048576, - "opencode-go:omen-alpha": 500000, - "opencode-go:qwen3.6-plus": 1000000, - "opencode-go:qwen3.7-max": 1000000, - "opencode-go:qwen3.7-plus": 1000000, - "opencode-go:qwen3.8-flash": 1000000, - "opencode-go:qwen3.8-max": 1000000, - "opencode:big-pickle": 200000, - "opencode:claude-fable-5": 1000000, - "opencode:claude-fable-5-1": 1000000, - "opencode:claude-haiku-4-5": 200000, - "opencode:claude-opus-4-5": 200000, - "opencode:claude-opus-4-6": 1000000, - "opencode:claude-opus-4-7": 1000000, - "opencode:claude-opus-4-8": 1000000, - "opencode:claude-opus-5": 1000000, - "opencode:claude-sonnet-4": 200000, - "opencode:claude-sonnet-4-5": 200000, - "opencode:claude-sonnet-4-6": 1000000, - "opencode:claude-sonnet-5": 1000000, - "opencode:deepseek-v4-flash": 1000000, - "opencode:deepseek-v4-flash-vision-exp": 1000000, - "opencode:deepseek-v4-pro": 1000000, - "opencode:gemini-3-flash": 1048576, - "opencode:gemini-3.1-pro": 1048576, - "opencode:gemini-3.5-flash": 1048576, - "opencode:gemini-3.5-flash-lite": 1048576, - "opencode:gemini-3.6-flash": 1048576, - "opencode:gemini-3.7-flash": 1048576, - "opencode:gemini-3.8-flash": 1048576, - "opencode:glm-5": 204800, - "opencode:glm-5.1": 204800, - "opencode:glm-5.2": 1000000, - "opencode:glm-5.3": 1000000, - "opencode:glm-5.3-flash": 1000000, - "opencode:gpt-5": 400000, - "opencode:gpt-5-codex": 400000, - "opencode:gpt-5-nano": 400000, - "opencode:gpt-5.1": 400000, - "opencode:gpt-5.1-codex": 400000, - "opencode:gpt-5.1-codex-max": 400000, - "opencode:gpt-5.1-codex-mini": 400000, - "opencode:gpt-5.2": 400000, - "opencode:gpt-5.2-codex": 400000, - "opencode:gpt-5.3-codex": 400000, - "opencode:gpt-5.4": 272000, - "opencode:gpt-5.4-mini": 400000, - "opencode:gpt-5.4-nano": 400000, - "opencode:gpt-5.4-pro": 1050000, - "opencode:gpt-5.5": 1050000, - "opencode:gpt-5.5-pro": 1050000, - "opencode:gpt-5.6-luna": 1050000, - "opencode:gpt-5.6-sol": 1050000, - "opencode:gpt-5.6-terra": 1050000, - "opencode:gpt-6-astra": 1050000, - "opencode:grok-4.5": 500000, - "opencode:grok-4.6": 500000, - "opencode:grok-build-0.1": 256000, - "opencode:kimi-k2.5": 262144, - "opencode:kimi-k2.6": 262144, - "opencode:kimi-k2.7-code": 262144, - "opencode:kimi-k3": 1048576, - "opencode:ling-3.0-flash-fin-free": 262144, - "opencode:mimo-v2.5-free": 200000, - "opencode:minimax-m2.5": 204800, - "opencode:minimax-m2.7": 204800, - "opencode:minimax-m3": 512000, - "opencode:muse-spark-1.2": 1048576, - "opencode:muse-spark-1.2-contributor-free": 1048576, - "opencode:muse-spark-1.3": 1048576, - "opencode:muse-spark-1.3-contributor-free": 1048576, - "opencode:nemotron-3-ultra-free": 1000000, - "opencode:nemotron-3.5-lightning-free": 262144, - "opencode:qwen3.5-plus": 262144, - "opencode:qwen3.6-plus": 262144, - "openrouter:~anthropic/claude-fable-latest": 1000000, - "openrouter:~anthropic/claude-haiku-latest": 200000, - "openrouter:~anthropic/claude-opus-latest": 1000000, - "openrouter:~anthropic/claude-sonnet-latest": 1000000, - "openrouter:~deepseek/deepseek-v4-flash-latest": 1048576, - "openrouter:~google/gemini-flash-latest": 1048576, - "openrouter:~google/gemini-pro-latest": 1048576, - "openrouter:~moonshotai/kimi-latest": 1048576, - "openrouter:~openai/gpt-latest": 1050000, - "openrouter:~openai/gpt-mini-latest": 400000, - "openrouter:~x-ai/grok-latest": 500000, - "openrouter:~z-ai/glm-flash-latest": 1048576, - "openrouter:~z-ai/glm-latest": 262144, - "openrouter:aion-labs/aion-2.0": 131072, - "openrouter:aion-labs/aion-3.0": 131072, - "openrouter:aion-labs/aion-3.0-mini": 131072, - "openrouter:amazon/nova-2-lite-v1": 1000000, - "openrouter:amazon/nova-lite-v1": 300000, - "openrouter:amazon/nova-micro-v1": 128000, - "openrouter:amazon/nova-premier-v1": 1000000, - "openrouter:amazon/nova-pro-v1": 300000, - "openrouter:anthropic/claude-3-haiku": 200000, - "openrouter:anthropic/claude-fable-5": 1000000, - "openrouter:anthropic/claude-fable-5:batch": 1000000, - "openrouter:anthropic/claude-fable-5.1": 1000000, - "openrouter:anthropic/claude-fable-5.1:batch": 1000000, - "openrouter:anthropic/claude-haiku-4.5": 200000, - "openrouter:anthropic/claude-haiku-4.5:batch": 200000, - "openrouter:anthropic/claude-opus-4": 200000, - "openrouter:anthropic/claude-opus-4.1": 200000, - "openrouter:anthropic/claude-opus-4.1:batch": 200000, - "openrouter:anthropic/claude-opus-4.5": 200000, - "openrouter:anthropic/claude-opus-4.5:batch": 200000, - "openrouter:anthropic/claude-opus-4.6": 1000000, - "openrouter:anthropic/claude-opus-4.6:batch": 1000000, - "openrouter:anthropic/claude-opus-4.7": 1000000, - "openrouter:anthropic/claude-opus-4.7:batch": 1000000, - "openrouter:anthropic/claude-opus-4.8": 1000000, - "openrouter:anthropic/claude-opus-4.8:batch": 1000000, - "openrouter:anthropic/claude-opus-5": 1000000, - "openrouter:anthropic/claude-opus-5:batch": 1000000, - "openrouter:anthropic/claude-sonnet-4": 200000, - "openrouter:anthropic/claude-sonnet-4.5": 1000000, - "openrouter:anthropic/claude-sonnet-4.5:batch": 1000000, - "openrouter:anthropic/claude-sonnet-4.6": 1000000, - "openrouter:anthropic/claude-sonnet-4.6:batch": 1000000, - "openrouter:anthropic/claude-sonnet-5": 1000000, - "openrouter:anthropic/claude-sonnet-5:batch": 1000000, - "openrouter:arcee-ai/trinity-large-thinking": 262144, - "openrouter:auto": 2000000, - "openrouter:bytedance-seed/seed-1.6": 262144, - "openrouter:bytedance-seed/seed-1.6-flash": 262144, - "openrouter:bytedance-seed/seed-2-1-turbo": 262144, - "openrouter:bytedance-seed/seed-2.0-code": 262144, - "openrouter:bytedance-seed/seed-2.0-lite": 262144, - "openrouter:bytedance-seed/seed-2.0-mini": 262144, - "openrouter:cohere/command-r-08-2024": 128000, - "openrouter:cohere/command-r-plus-08-2024": 128000, - "openrouter:cohere/north-mini-code:free": 256000, - "openrouter:deepseek/deepseek-chat": 163840, - "openrouter:deepseek/deepseek-chat-v3-0324": 163840, - "openrouter:deepseek/deepseek-chat-v3.1": 161000, - "openrouter:deepseek/deepseek-r1": 64000, - "openrouter:deepseek/deepseek-r1-0528": 163840, - "openrouter:deepseek/deepseek-v3.1-terminus": 131072, - "openrouter:deepseek/deepseek-v3.2": 163840, - "openrouter:deepseek/deepseek-v3.2-exp": 163840, - "openrouter:deepseek/deepseek-v4-flash": 1024000, - "openrouter:deepseek/deepseek-v4-flash-0731": 1048576, - "openrouter:deepseek/deepseek-v4-flash-0731:batch": 1048576, - "openrouter:deepseek/deepseek-v4-flash-vision-exp": 1048576, - "openrouter:deepseek/deepseek-v4-pro": 1024000, - "openrouter:deepseek/deepseek-v4-pro-0813": 1024000, - "openrouter:deepseek/deepseek-v4-pro-0813:batch": 1048576, - "openrouter:dots-studio/dots-3-note-preview:free": 512000, - "openrouter:google/gemini-2.5-flash": 1048576, - "openrouter:google/gemini-2.5-flash-lite": 1048576, - "openrouter:google/gemini-2.5-flash-lite:batch": 1048576, - "openrouter:google/gemini-2.5-flash:batch": 1048576, - "openrouter:google/gemini-2.5-pro": 1048576, - "openrouter:google/gemini-2.5-pro-preview": 1048576, - "openrouter:google/gemini-2.5-pro-preview-05-06": 1048576, - "openrouter:google/gemini-2.5-pro:batch": 1048576, - "openrouter:google/gemini-3-flash-preview": 1048576, - "openrouter:google/gemini-3-flash-preview:batch": 1048576, - "openrouter:google/gemini-3-pro-image": 65536, - "openrouter:google/gemini-3.1-flash-lite": 1048576, - "openrouter:google/gemini-3.1-flash-lite-preview": 1048576, - "openrouter:google/gemini-3.1-flash-lite:batch": 1048576, - "openrouter:google/gemini-3.1-pro-preview": 1048576, - "openrouter:google/gemini-3.1-pro-preview-customtools": 1048576, - "openrouter:google/gemini-3.1-pro-preview:batch": 1048576, - "openrouter:google/gemini-3.5-flash": 1048576, - "openrouter:google/gemini-3.5-flash-lite": 1048576, - "openrouter:google/gemini-3.5-flash-lite:batch": 1048576, - "openrouter:google/gemini-3.5-flash:batch": 1048576, - "openrouter:google/gemini-3.6-flash": 1048576, - "openrouter:google/gemini-3.6-flash:batch": 1048576, - "openrouter:google/gemini-3.7-flash": 1048576, - "openrouter:google/gemini-3.7-flash:batch": 1048576, - "openrouter:google/gemini-3.8-flash": 1048576, - "openrouter:google/gemini-3.8-flash:batch": 1048576, - "openrouter:google/gemma-3-12b-it": 131072, - "openrouter:google/gemma-3-27b-it": 131072, - "openrouter:google/gemma-4-26b-a4b-it": 262144, - "openrouter:google/gemma-4-26b-a4b-it:free": 262144, - "openrouter:google/gemma-4-31b-it": 262144, - "openrouter:google/gemma-4-31b-it:batch": 262144, - "openrouter:google/gemma-4-31b-it:free": 262144, - "openrouter:ibm-granite/granite-4.2-8b": 131072, - "openrouter:inception/mercury-2": 128000, - "openrouter:inception/mercury-2.5-preview": 260000, - "openrouter:inclusionai/ling-3.0-flash": 262144, - "openrouter:inclusionai/ling-3.0-flash-fin": 262144, - "openrouter:inclusionai/ling-3.0-flash-fin:free": 262144, - "openrouter:inclusionai/ling-3.0-flash-sante:free": 262144, - "openrouter:kwaipilot/kat-coder-pro-v2": 262144, - "openrouter:kwaipilot/kat-coder-pro-v2.5": 262144, - "openrouter:liquid/lfm-2.5-2.6b:free": 65536, - "openrouter:meituan/longcat-2.0": 1048756, - "openrouter:meta-llama/llama-3.1-70b-instruct": 131072, - "openrouter:meta-llama/llama-3.1-8b-instruct": 131072, - "openrouter:meta-llama/llama-3.3-70b-instruct": 131072, - "openrouter:meta-llama/llama-4-maverick": 128000, - "openrouter:meta-llama/llama-4-scout": 327680, - "openrouter:meta/muse-glimmer-30b": 131072, - "openrouter:meta/muse-glimmer-30b:batch": 131072, - "openrouter:meta/muse-spark-1.1": 1048576, - "openrouter:meta/muse-spark-1.2": 1048576, - "openrouter:meta/muse-spark-1.2-contributor": 1048576, - "openrouter:meta/muse-spark-1.3": 1048576, - "openrouter:meta/muse-spark-1.3-contributor": 1048576, - "openrouter:minimax/minimax-m1": 1000000, - "openrouter:minimax/minimax-m2": 204800, - "openrouter:minimax/minimax-m2.1": 204800, - "openrouter:minimax/minimax-m2.5": 200000, - "openrouter:minimax/minimax-m2.7": 204800, - "openrouter:minimax/minimax-m2.7:free": 196608, - "openrouter:minimax/minimax-m3": 524288, - "openrouter:minimax/minimax-m3:batch": 524288, - "openrouter:minimax/minimax-m3:free": 1048576, - "openrouter:mistralai/codestral-2508": 256000, - "openrouter:mistralai/devstral-2512": 262144, - "openrouter:mistralai/ministral-14b-2512": 262144, - "openrouter:mistralai/ministral-3b-2512": 131072, - "openrouter:mistralai/ministral-8b-2512": 262144, - "openrouter:mistralai/mistral-large": 128000, - "openrouter:mistralai/mistral-large-2407": 131072, - "openrouter:mistralai/mistral-large-2512": 262144, - "openrouter:mistralai/mistral-medium-3": 131072, - "openrouter:mistralai/mistral-medium-3-5": 262144, - "openrouter:mistralai/mistral-medium-3-5:batch": 32768, - "openrouter:mistralai/mistral-medium-3.1": 131072, - "openrouter:mistralai/mistral-nemo": 131072, - "openrouter:mistralai/mistral-saba": 32768, - "openrouter:mistralai/mistral-small-2603": 262144, - "openrouter:mistralai/mistral-small-3.2-24b-instruct": 128000, - "openrouter:mistralai/mixtral-8x22b-instruct": 65536, - "openrouter:mistralai/voxtral-small-24b-2507": 32768, - "openrouter:moonshotai/kimi-k2": 131072, - "openrouter:moonshotai/kimi-k2-0905": 262144, - "openrouter:moonshotai/kimi-k2-thinking": 262144, - "openrouter:moonshotai/kimi-k2.5": 262144, - "openrouter:moonshotai/kimi-k2.6": 262144, - "openrouter:moonshotai/kimi-k2.7-code": 262144, - "openrouter:moonshotai/kimi-k3": 1048576, - "openrouter:moonshotai/kimi-k3:batch": 1048576, - "openrouter:nex-agi/nex-n2-mini": 262144, - "openrouter:nex-agi/nex-n2-pro": 262144, - "openrouter:nvidia/nemotron-3-nano-30b-a3b": 262144, - "openrouter:nvidia/nemotron-3-nano-omni-30b-a3b-reasoning:free": 256000, - "openrouter:nvidia/nemotron-3-super-120b-a12b": 262144, - "openrouter:nvidia/nemotron-3-super-120b-a12b:free": 262144, - "openrouter:nvidia/nemotron-3-ultra-550b-a55b": 256000, - "openrouter:nvidia/nemotron-3-ultra-550b-a55b:free": 1000000, - "openrouter:nvidia/nemotron-3.5-lightning": 262144, - "openrouter:nvidia/nemotron-3.5-lightning:free": 1000000, - "openrouter:openai/gpt-3.5-turbo": 16385, - "openrouter:openai/gpt-3.5-turbo-0613": 4095, - "openrouter:openai/gpt-3.5-turbo-16k": 16385, - "openrouter:openai/gpt-3.5-turbo:batch": 16385, - "openrouter:openai/gpt-4": 8191, - "openrouter:openai/gpt-4-turbo": 128000, - "openrouter:openai/gpt-4-turbo-preview": 128000, - "openrouter:openai/gpt-4-turbo:batch": 128000, - "openrouter:openai/gpt-4.1": 1047576, - "openrouter:openai/gpt-4.1-mini": 1047576, - "openrouter:openai/gpt-4.1-mini:batch": 1047576, - "openrouter:openai/gpt-4.1-nano": 1047576, - "openrouter:openai/gpt-4.1-nano:batch": 1047576, - "openrouter:openai/gpt-4.1:batch": 1047576, - "openrouter:openai/gpt-4o": 128000, - "openrouter:openai/gpt-4o-2024-05-13": 128000, - "openrouter:openai/gpt-4o-2024-08-06": 128000, - "openrouter:openai/gpt-4o-2024-11-20": 128000, - "openrouter:openai/gpt-4o-mini": 128000, - "openrouter:openai/gpt-4o-mini-2024-07-18": 128000, - "openrouter:openai/gpt-4o-mini:batch": 128000, - "openrouter:openai/gpt-4o:batch": 128000, - "openrouter:openai/gpt-5": 400000, - "openrouter:openai/gpt-5-mini": 400000, - "openrouter:openai/gpt-5-mini:batch": 400000, - "openrouter:openai/gpt-5-nano": 400000, - "openrouter:openai/gpt-5-nano:batch": 400000, - "openrouter:openai/gpt-5-pro": 400000, - "openrouter:openai/gpt-5-pro:batch": 400000, - "openrouter:openai/gpt-5:batch": 400000, - "openrouter:openai/gpt-5.1": 400000, - "openrouter:openai/gpt-5.1-codex": 400000, - "openrouter:openai/gpt-5.1-codex-max": 400000, - "openrouter:openai/gpt-5.1-codex-mini": 400000, - "openrouter:openai/gpt-5.1:batch": 400000, - "openrouter:openai/gpt-5.2": 400000, - "openrouter:openai/gpt-5.2-chat": 128000, - "openrouter:openai/gpt-5.2-codex": 400000, - "openrouter:openai/gpt-5.2-pro": 400000, - "openrouter:openai/gpt-5.2-pro:batch": 400000, - "openrouter:openai/gpt-5.2:batch": 400000, - "openrouter:openai/gpt-5.3-codex": 400000, - "openrouter:openai/gpt-5.4": 1050000, - "openrouter:openai/gpt-5.4-mini": 400000, - "openrouter:openai/gpt-5.4-mini:batch": 400000, - "openrouter:openai/gpt-5.4-nano": 400000, - "openrouter:openai/gpt-5.4-nano:batch": 400000, - "openrouter:openai/gpt-5.4-pro": 1050000, - "openrouter:openai/gpt-5.4-pro:batch": 1050000, - "openrouter:openai/gpt-5.4:batch": 1050000, - "openrouter:openai/gpt-5.5": 1050000, - "openrouter:openai/gpt-5.5-pro": 1050000, - "openrouter:openai/gpt-5.5-pro:batch": 1050000, - "openrouter:openai/gpt-5.5:batch": 1050000, - "openrouter:openai/gpt-5.6-luna": 1050000, - "openrouter:openai/gpt-5.6-luna-pro": 1050000, - "openrouter:openai/gpt-5.6-luna-pro:batch": 1050000, - "openrouter:openai/gpt-5.6-luna:batch": 1050000, - "openrouter:openai/gpt-5.6-sol": 1050000, - "openrouter:openai/gpt-5.6-sol-pro": 1050000, - "openrouter:openai/gpt-5.6-sol-pro:batch": 1050000, - "openrouter:openai/gpt-5.6-sol:batch": 1050000, - "openrouter:openai/gpt-5.6-terra": 1050000, - "openrouter:openai/gpt-5.6-terra-pro": 1050000, - "openrouter:openai/gpt-5.6-terra-pro:batch": 1050000, - "openrouter:openai/gpt-5.6-terra:batch": 1050000, - "openrouter:openai/gpt-6-astra": 1050000, - "openrouter:openai/gpt-6-astra-pro": 1050000, - "openrouter:openai/gpt-6-astra-pro:batch": 1050000, - "openrouter:openai/gpt-6-astra:batch": 1050000, - "openrouter:openai/gpt-audio": 128000, - "openrouter:openai/gpt-audio-mini": 128000, - "openrouter:openai/gpt-chat-latest": 400000, - "openrouter:openai/gpt-oss-120b": 131072, - "openrouter:openai/gpt-oss-120b:batch": 131072, - "openrouter:openai/gpt-oss-20b": 131072, - "openrouter:openai/gpt-oss-safeguard-20b": 131072, - "openrouter:openai/o1": 200000, - "openrouter:openai/o3": 200000, - "openrouter:openai/o3-mini": 200000, - "openrouter:openai/o3-mini-high": 200000, - "openrouter:openai/o3-mini:batch": 200000, - "openrouter:openai/o3-pro": 200000, - "openrouter:openai/o3:batch": 200000, - "openrouter:openai/o4-mini": 200000, - "openrouter:openai/o4-mini-high": 200000, - "openrouter:openai/o4-mini:batch": 200000, - "openrouter:openrouter/auto": 2000000, - "openrouter:openrouter/auto-beta": 2000000, - "openrouter:openrouter/free": 200000, - "openrouter:openrouter/fusion": 1000000, - "openrouter:poolside/laguna-s-2.1": 1048576, - "openrouter:poolside/laguna-s-2.1:free": 262144, - "openrouter:poolside/laguna-xs-2.1": 262144, - "openrouter:poolside/laguna-xs-2.1:free": 262144, - "openrouter:qwen/qwen-2.5-72b-instruct": 32768, - "openrouter:qwen/qwen-2.5-7b-instruct": 32768, - "openrouter:qwen/qwen-plus": 1000000, - "openrouter:qwen/qwen-plus-2025-07-28": 1000000, - "openrouter:qwen/qwen3-14b": 40960, - "openrouter:qwen/qwen3-235b-a22b": 131072, - "openrouter:qwen/qwen3-235b-a22b-2507": 262144, - "openrouter:qwen/qwen3-235b-a22b-thinking-2507": 131072, - "openrouter:qwen/qwen3-30b-a3b": 40960, - "openrouter:qwen/qwen3-30b-a3b-instruct-2507": 128000, - "openrouter:qwen/qwen3-30b-a3b-thinking-2507": 81920, - "openrouter:qwen/qwen3-32b": 40960, - "openrouter:qwen/qwen3-8b": 131072, - "openrouter:qwen/qwen3-coder": 262144, - "openrouter:qwen/qwen3-coder-30b-a3b-instruct": 262144, - "openrouter:qwen/qwen3-coder-flash": 1000000, - "openrouter:qwen/qwen3-coder-next": 262144, - "openrouter:qwen/qwen3-coder-plus": 1000000, - "openrouter:qwen/qwen3-max": 262144, - "openrouter:qwen/qwen3-max-thinking": 262144, - "openrouter:qwen/qwen3-next-80b-a3b-instruct": 262144, - "openrouter:qwen/qwen3-next-80b-a3b-thinking": 131072, - "openrouter:qwen/qwen3-vl-235b-a22b-instruct": 131072, - "openrouter:qwen/qwen3-vl-235b-a22b-thinking": 131072, - "openrouter:qwen/qwen3-vl-30b-a3b-instruct": 262144, - "openrouter:qwen/qwen3-vl-30b-a3b-thinking": 131072, - "openrouter:qwen/qwen3-vl-32b-instruct": 131072, - "openrouter:qwen/qwen3-vl-8b-instruct": 131072, - "openrouter:qwen/qwen3-vl-8b-thinking": 131072, - "openrouter:qwen/qwen3.5-122b-a10b": 262144, - "openrouter:qwen/qwen3.5-27b": 262144, - "openrouter:qwen/qwen3.5-35b-a3b": 262144, - "openrouter:qwen/qwen3.5-397b-a17b": 262144, - "openrouter:qwen/qwen3.5-9b": 262144, - "openrouter:qwen/qwen3.5-9b:batch": 262144, - "openrouter:qwen/qwen3.5-flash-02-23": 1000000, - "openrouter:qwen/qwen3.5-plus-02-15": 1000000, - "openrouter:qwen/qwen3.5-plus-20260420": 1000000, - "openrouter:qwen/qwen3.6-27b": 262144, - "openrouter:qwen/qwen3.6-35b-a3b": 262144, - "openrouter:qwen/qwen3.6-flash": 1000000, - "openrouter:qwen/qwen3.6-max-preview": 262144, - "openrouter:qwen/qwen3.6-plus": 1000000, - "openrouter:qwen/qwen3.7-flash": 1000000, - "openrouter:qwen/qwen3.7-max": 1000000, - "openrouter:qwen/qwen3.7-plus": 1000000, - "openrouter:qwen/qwen3.8-2.4t-a95b": 1000000, - "openrouter:qwen/qwen3.8-2.4t-a95b:batch": 1010000, - "openrouter:qwen/qwen3.8-27b": 1000000, - "openrouter:qwen/qwen3.8-flash": 1000000, - "openrouter:qwen/qwen3.8-max-0902": 1000000, - "openrouter:rekaai/reka-edge": 16384, - "openrouter:relace/relace-search": 256000, - "openrouter:sakana/fugu-ultra": 1000000, - "openrouter:sakana/sakana-namazu": 262144, - "openrouter:sao10k/l3.1-euryale-70b": 131072, - "openrouter:stepfun/step-3.5-flash": 262144, - "openrouter:stepfun/step-3.7-flash": 256000, - "openrouter:tencent/hy3": 262144, - "openrouter:tencent/hy3-preview": 262144, - "openrouter:tencent/hy4-preview": 1048576, - "openrouter:thedrummer/unslopnemo-12b": 32768, - "openrouter:thinkingmachines/inkling": 524288, - "openrouter:thinkingmachines/inkling-small": 524288, - "openrouter:thinkingmachines/inkling-small:batch": 524288, - "openrouter:thinkingmachines/inkling-small:free": 1048576, - "openrouter:thinkingmachines/inkling:batch": 524288, - "openrouter:thinkingmachines/inkling:free": 1048576, - "openrouter:upstage/solar-pro-3": 131072, - "openrouter:upstage/solar-pro4": 524288, - "openrouter:x-ai/grok-4.20": 2000000, - "openrouter:x-ai/grok-4.3": 1000000, - "openrouter:x-ai/grok-4.3:batch": 1000000, - "openrouter:x-ai/grok-4.5": 500000, - "openrouter:x-ai/grok-4.6": 500000, - "openrouter:x-ai/grok-build-0.1": 256000, - "openrouter:xiaomi/mimo-v2.5": 1048576, - "openrouter:xiaomi/mimo-v2.5-pro": 1048576, - "openrouter:z-ai/glm-4.5": 131072, - "openrouter:z-ai/glm-4.5-air": 131072, - "openrouter:z-ai/glm-4.5v": 65536, - "openrouter:z-ai/glm-4.6": 204800, - "openrouter:z-ai/glm-4.6v": 131072, - "openrouter:z-ai/glm-4.7": 202752, - "openrouter:z-ai/glm-4.7-flash": 202752, - "openrouter:z-ai/glm-5": 198000, - "openrouter:z-ai/glm-5-turbo": 202752, - "openrouter:z-ai/glm-5.1": 200000, - "openrouter:z-ai/glm-5.2": 1048576, - "openrouter:z-ai/glm-5.2:free": 256000, - "openrouter:z-ai/glm-5.3": 1048576, - "openrouter:z-ai/glm-5.3-flash": 1048576, - "openrouter:z-ai/glm-5.3-flash:batch": 1048575, - "openrouter:z-ai/glm-5v-turbo": 202752, - "qwen-token-plan-cn:deepseek-v3.2": 131072, - "qwen-token-plan-cn:deepseek-v4-flash": 1000000, - "qwen-token-plan-cn:deepseek-v4-flash-0731": 1000000, - "qwen-token-plan-cn:deepseek-v4-pro": 1000000, - "qwen-token-plan-cn:deepseek-v4-pro-0813": 1000000, - "qwen-token-plan-cn:glm-5": 202752, - "qwen-token-plan-cn:glm-5.1": 202752, - "qwen-token-plan-cn:glm-5.2": 1000000, - "qwen-token-plan-cn:kimi-k2.5": 262144, - "qwen-token-plan-cn:kimi-k2.6": 262144, - "qwen-token-plan-cn:kimi-k2.7-code": 262144, - "qwen-token-plan-cn:MiniMax-M2.5": 196608, - "qwen-token-plan-cn:qwen3.6-flash": 1000000, - "qwen-token-plan-cn:qwen3.6-plus": 1000000, - "qwen-token-plan-cn:qwen3.7-max": 1000000, - "qwen-token-plan-cn:qwen3.7-plus": 1000000, - "qwen-token-plan-cn:qwen3.8-flash": 1000000, - "qwen-token-plan-cn:qwen3.8-max": 1000000, - "qwen-token-plan-individual:deepseek-v4-flash-0731": 1000000, - "qwen-token-plan-individual:deepseek-v4-pro": 1000000, - "qwen-token-plan-individual:deepseek-v4-pro-0813": 1000000, - "qwen-token-plan-individual:glm-5.2": 1000000, - "qwen-token-plan-individual:qwen3.6-flash": 1000000, - "qwen-token-plan-individual:qwen3.7-max": 1000000, - "qwen-token-plan-individual:qwen3.7-plus": 1000000, - "qwen-token-plan-individual:qwen3.8-flash": 1000000, - "qwen-token-plan-individual:qwen3.8-max": 1000000, - "qwen-token-plan:deepseek-v3.2": 131072, - "qwen-token-plan:deepseek-v4-flash": 1000000, - "qwen-token-plan:deepseek-v4-flash-0731": 1000000, - "qwen-token-plan:deepseek-v4-pro": 1000000, - "qwen-token-plan:deepseek-v4-pro-0813": 1000000, - "qwen-token-plan:glm-5": 202752, - "qwen-token-plan:glm-5.1": 202752, - "qwen-token-plan:glm-5.2": 1000000, - "qwen-token-plan:kimi-k2.5": 262144, - "qwen-token-plan:kimi-k2.6": 262144, - "qwen-token-plan:kimi-k2.7-code": 262144, - "qwen-token-plan:MiniMax-M2.5": 196608, - "qwen-token-plan:qwen3.6-flash": 1000000, - "qwen-token-plan:qwen3.6-plus": 1000000, - "qwen-token-plan:qwen3.7-max": 1000000, - "qwen-token-plan:qwen3.7-plus": 1000000, - "qwen-token-plan:qwen3.8-flash": 1000000, - "qwen-token-plan:qwen3.8-max": 1000000, - "together:deepseek-ai/DeepSeek-V4-Flash-0731": 1000000, - "together:deepseek-ai/DeepSeek-V4-Pro": 512000, - "together:deepseek-ai/DeepSeek-V4-Pro-0813": 1048576, - "together:google/gemma-4-31B-it": 262144, - "together:meta-llama/Llama-3.3-70B-Instruct-Turbo": 131072, - "together:MiniMaxAI/MiniMax-M2.7": 202752, - "together:MiniMaxAI/MiniMax-M3": 524288, - "together:moonshotai/Kimi-K2.6": 262144, - "together:moonshotai/Kimi-K2.7-Code": 262144, - "together:moonshotai/Kimi-K3": 1048576, - "together:nvidia/nemotron-3-ultra-550b-a55b": 512300, - "together:openai/gpt-oss-120b": 131072, - "together:openai/gpt-oss-20b": 131072, - "together:Qwen/Qwen2.5-7B-Instruct-Turbo": 32768, - "together:Qwen/Qwen3.5-9B": 262144, - "together:Qwen/Qwen3.6-Plus": 1000000, - "together:Qwen/Qwen3.7-Max": 1000000, - "together:thinkingmachines/Inkling": 524288, - "together:zai-org/GLM-5.2": 512000, - "together:zai-org/GLM-5.3": 1048576, - "together:zai-org/GLM-5.3-Flash": 1048575, - "vercel-ai-gateway:alibaba/qwen-3-14b": 40960, - "vercel-ai-gateway:alibaba/qwen-3-235b": 262144, - "vercel-ai-gateway:alibaba/qwen-3-30b": 40960, - "vercel-ai-gateway:alibaba/qwen-3-32b": 128000, - "vercel-ai-gateway:alibaba/qwen-3.6-max-preview": 240000, - "vercel-ai-gateway:alibaba/qwen3-235b-a22b-thinking": 131072, - "vercel-ai-gateway:alibaba/qwen3-coder": 262144, - "vercel-ai-gateway:alibaba/qwen3-coder-30b-a3b": 262144, - "vercel-ai-gateway:alibaba/qwen3-coder-next": 256000, - "vercel-ai-gateway:alibaba/qwen3-coder-plus": 1000000, - "vercel-ai-gateway:alibaba/qwen3-max": 262144, - "vercel-ai-gateway:alibaba/qwen3-max-preview": 262144, - "vercel-ai-gateway:alibaba/qwen3-max-thinking": 256000, - "vercel-ai-gateway:alibaba/qwen3-next-80b-a3b-instruct": 131072, - "vercel-ai-gateway:alibaba/qwen3-next-80b-a3b-thinking": 131072, - "vercel-ai-gateway:alibaba/qwen3-vl-235b-a22b-instruct": 131072, - "vercel-ai-gateway:alibaba/qwen3-vl-instruct": 131072, - "vercel-ai-gateway:alibaba/qwen3-vl-thinking": 131072, - "vercel-ai-gateway:alibaba/qwen3.5-flash": 1000000, - "vercel-ai-gateway:alibaba/qwen3.5-plus": 1000000, - "vercel-ai-gateway:alibaba/qwen3.6-27b": 256000, - "vercel-ai-gateway:alibaba/qwen3.6-plus": 1000000, - "vercel-ai-gateway:alibaba/qwen3.7-flash": 991000, - "vercel-ai-gateway:alibaba/qwen3.7-max": 991000, - "vercel-ai-gateway:alibaba/qwen3.7-plus": 1000000, - "vercel-ai-gateway:alibaba/qwen3.8-2.4t-a95b": 262144, - "vercel-ai-gateway:alibaba/qwen3.8-27b": 1000000, - "vercel-ai-gateway:alibaba/qwen3.8-flash": 991000, - "vercel-ai-gateway:alibaba/qwen3.8-flash-next": 1048576, - "vercel-ai-gateway:alibaba/qwen3.8-max": 1000000, - "vercel-ai-gateway:alibaba/qwen3.8-max-0902": 991000, - "vercel-ai-gateway:amazon/nova-2-lite": 1000000, - "vercel-ai-gateway:amazon/nova-lite": 300000, - "vercel-ai-gateway:amazon/nova-micro": 128000, - "vercel-ai-gateway:amazon/nova-pro": 300000, - "vercel-ai-gateway:anthropic/claude-3-haiku": 200000, - "vercel-ai-gateway:anthropic/claude-fable-5": 1000000, - "vercel-ai-gateway:anthropic/claude-fable-5.1": 1000000, - "vercel-ai-gateway:anthropic/claude-haiku-4.5": 200000, - "vercel-ai-gateway:anthropic/claude-opus-4": 200000, - "vercel-ai-gateway:anthropic/claude-opus-4.5": 200000, - "vercel-ai-gateway:anthropic/claude-opus-4.6": 1000000, - "vercel-ai-gateway:anthropic/claude-opus-4.7": 1000000, - "vercel-ai-gateway:anthropic/claude-opus-4.8": 1000000, - "vercel-ai-gateway:anthropic/claude-opus-4.8-fast": 1000000, - "vercel-ai-gateway:anthropic/claude-opus-5": 1000000, - "vercel-ai-gateway:anthropic/claude-opus-5-fast": 1000000, - "vercel-ai-gateway:anthropic/claude-sonnet-4": 1000000, - "vercel-ai-gateway:anthropic/claude-sonnet-4.5": 1000000, - "vercel-ai-gateway:anthropic/claude-sonnet-4.6": 1000000, - "vercel-ai-gateway:anthropic/claude-sonnet-5": 1000000, - "vercel-ai-gateway:arcee-ai/trinity-large-thinking": 262100, - "vercel-ai-gateway:bytedance/seed-1.6": 256000, - "vercel-ai-gateway:bytedance/seed-1.8": 256000, - "vercel-ai-gateway:cohere/command-a": 256000, - "vercel-ai-gateway:deepseek/deepseek-r1": 128000, - "vercel-ai-gateway:deepseek/deepseek-v3.1": 163840, - "vercel-ai-gateway:deepseek/deepseek-v3.1-terminus": 131072, - "vercel-ai-gateway:deepseek/deepseek-v3.2": 128000, - "vercel-ai-gateway:deepseek/deepseek-v3.2-thinking": 128000, - "vercel-ai-gateway:deepseek/deepseek-v4-flash": 1000000, - "vercel-ai-gateway:deepseek/deepseek-v4-flash-0731": 1000000, - "vercel-ai-gateway:deepseek/deepseek-v4-flash-vision-exp": 1048576, - "vercel-ai-gateway:deepseek/deepseek-v4-pro": 1000000, - "vercel-ai-gateway:deepseek/deepseek-v4-pro-0813": 1000000, - "vercel-ai-gateway:google/gemini-2.5-flash": 1000000, - "vercel-ai-gateway:google/gemini-2.5-flash-lite": 1048576, - "vercel-ai-gateway:google/gemini-2.5-pro": 1048576, - "vercel-ai-gateway:google/gemini-3-flash": 1000000, - "vercel-ai-gateway:google/gemini-3.1-flash-lite": 1000000, - "vercel-ai-gateway:google/gemini-3.1-pro-preview": 1000000, - "vercel-ai-gateway:google/gemini-3.5-flash": 1000000, - "vercel-ai-gateway:google/gemini-3.5-flash-lite": 1000000, - "vercel-ai-gateway:google/gemini-3.6-flash": 1000000, - "vercel-ai-gateway:google/gemini-3.7-flash": 1000000, - "vercel-ai-gateway:google/gemini-3.8-flash": 1000000, - "vercel-ai-gateway:google/gemma-4-26b-a4b-it": 262144, - "vercel-ai-gateway:google/gemma-4-31b-it": 262144, - "vercel-ai-gateway:inception/mercury-2": 128000, - "vercel-ai-gateway:inception/mercury-coder-small": 32000, - "vercel-ai-gateway:inclusionai/ling-3.0-flash": 256000, - "vercel-ai-gateway:inclusionai/ling-3.0-flash-fin": 256000, - "vercel-ai-gateway:inclusionai/ling-3.0-flash-fin-free": 256000, - "vercel-ai-gateway:inclusionai/ling-3.0-flash-sante": 256000, - "vercel-ai-gateway:inclusionai/ling-3.0-flash-sante-free": 256000, - "vercel-ai-gateway:interfaze/interfaze-beta": 1000000, - "vercel-ai-gateway:kwaipilot/kat-coder-air-v2.5": 256000, - "vercel-ai-gateway:kwaipilot/kat-coder-pro-v1": 256000, - "vercel-ai-gateway:kwaipilot/kat-coder-pro-v2": 256000, - "vercel-ai-gateway:kwaipilot/kat-coder-pro-v2.5": 256000, - "vercel-ai-gateway:meta/llama-3.1-70b": 128000, - "vercel-ai-gateway:meta/llama-3.1-8b": 128000, - "vercel-ai-gateway:meta/llama-3.3-70b": 128000, - "vercel-ai-gateway:meta/llama-4-maverick": 128000, - "vercel-ai-gateway:meta/llama-4-scout": 128000, - "vercel-ai-gateway:meta/muse-glimmer-30b": 131072, - "vercel-ai-gateway:meta/muse-spark-1.1": 1048576, - "vercel-ai-gateway:meta/muse-spark-1.2": 1048576, - "vercel-ai-gateway:meta/muse-spark-1.2-contributor": 1048576, - "vercel-ai-gateway:meta/muse-spark-1.3": 1048576, - "vercel-ai-gateway:meta/muse-spark-1.3-contributor": 1048576, - "vercel-ai-gateway:minimax/minimax-m2": 205000, - "vercel-ai-gateway:minimax/minimax-m2.1": 204800, - "vercel-ai-gateway:minimax/minimax-m2.1-lightning": 204800, - "vercel-ai-gateway:minimax/minimax-m2.5": 204800, - "vercel-ai-gateway:minimax/minimax-m2.5-highspeed": 204800, - "vercel-ai-gateway:minimax/minimax-m2.7": 204800, - "vercel-ai-gateway:minimax/minimax-m2.7-free": 196608, - "vercel-ai-gateway:minimax/minimax-m2.7-highspeed": 204800, - "vercel-ai-gateway:minimax/minimax-m3": 512000, - "vercel-ai-gateway:minimax/minimax-m3-free": 1048576, - "vercel-ai-gateway:mistral/codestral": 128000, - "vercel-ai-gateway:mistral/devstral-2": 256000, - "vercel-ai-gateway:mistral/devstral-small-2": 256000, - "vercel-ai-gateway:mistral/ministral-14b": 256000, - "vercel-ai-gateway:mistral/ministral-3b": 128000, - "vercel-ai-gateway:mistral/ministral-8b": 128000, - "vercel-ai-gateway:mistral/mistral-large-3": 256000, - "vercel-ai-gateway:mistral/mistral-medium": 128000, - "vercel-ai-gateway:mistral/mistral-medium-3.5": 256000, - "vercel-ai-gateway:mistral/mistral-nemo": 128000, - "vercel-ai-gateway:mistral/mistral-small": 32000, - "vercel-ai-gateway:mistral/pixtral-12b": 128000, - "vercel-ai-gateway:moonshotai/kimi-k2": 131072, - "vercel-ai-gateway:moonshotai/kimi-k2-thinking": 216144, - "vercel-ai-gateway:moonshotai/kimi-k2.5": 262114, - "vercel-ai-gateway:moonshotai/kimi-k2.6": 262000, - "vercel-ai-gateway:moonshotai/kimi-k2.7-code": 256000, - "vercel-ai-gateway:moonshotai/kimi-k2.7-code-highspeed": 262144, - "vercel-ai-gateway:moonshotai/kimi-k3": 1000000, - "vercel-ai-gateway:moonshotai/kimi-k3-fast": 1000000, - "vercel-ai-gateway:nvidia/nemotron-3-nano-30b-a3b": 262144, - "vercel-ai-gateway:nvidia/nemotron-3-super-120b-a12b": 256000, - "vercel-ai-gateway:nvidia/nemotron-3-ultra-550b-a55b": 1000000, - "vercel-ai-gateway:nvidia/nemotron-3.5-lightning": 262144, - "vercel-ai-gateway:nvidia/nemotron-nano-12b-v2-vl": 131072, - "vercel-ai-gateway:nvidia/nemotron-nano-9b-v2": 131072, - "vercel-ai-gateway:openai/gpt-3.5-turbo": 16385, - "vercel-ai-gateway:openai/gpt-4-turbo": 128000, - "vercel-ai-gateway:openai/gpt-4.1": 1047576, - "vercel-ai-gateway:openai/gpt-4.1-fast": 1047576, - "vercel-ai-gateway:openai/gpt-4.1-mini": 1047576, - "vercel-ai-gateway:openai/gpt-4.1-mini-fast": 1047576, - "vercel-ai-gateway:openai/gpt-4.1-nano": 1047576, - "vercel-ai-gateway:openai/gpt-4.1-nano-fast": 1047576, - "vercel-ai-gateway:openai/gpt-4o": 128000, - "vercel-ai-gateway:openai/gpt-4o-fast": 128000, - "vercel-ai-gateway:openai/gpt-4o-mini": 128000, - "vercel-ai-gateway:openai/gpt-4o-mini-fast": 128000, - "vercel-ai-gateway:openai/gpt-5": 400000, - "vercel-ai-gateway:openai/gpt-5-codex": 400000, - "vercel-ai-gateway:openai/gpt-5-fast": 400000, - "vercel-ai-gateway:openai/gpt-5-mini": 400000, - "vercel-ai-gateway:openai/gpt-5-mini-fast": 400000, - "vercel-ai-gateway:openai/gpt-5-nano": 400000, - "vercel-ai-gateway:openai/gpt-5-pro": 400000, - "vercel-ai-gateway:openai/gpt-5.1-codex": 400000, - "vercel-ai-gateway:openai/gpt-5.1-codex-max": 400000, - "vercel-ai-gateway:openai/gpt-5.1-codex-mini": 400000, - "vercel-ai-gateway:openai/gpt-5.1-thinking": 400000, - "vercel-ai-gateway:openai/gpt-5.1-thinking-fast": 400000, - "vercel-ai-gateway:openai/gpt-5.2": 400000, - "vercel-ai-gateway:openai/gpt-5.2-codex": 400000, - "vercel-ai-gateway:openai/gpt-5.2-fast": 400000, - "vercel-ai-gateway:openai/gpt-5.2-pro": 400000, - "vercel-ai-gateway:openai/gpt-5.3-codex": 400000, - "vercel-ai-gateway:openai/gpt-5.3-codex-fast": 400000, - "vercel-ai-gateway:openai/gpt-5.4": 1050000, - "vercel-ai-gateway:openai/gpt-5.4-fast": 1050000, - "vercel-ai-gateway:openai/gpt-5.4-mini": 400000, - "vercel-ai-gateway:openai/gpt-5.4-mini-fast": 400000, - "vercel-ai-gateway:openai/gpt-5.4-nano": 400000, - "vercel-ai-gateway:openai/gpt-5.4-pro": 1050000, - "vercel-ai-gateway:openai/gpt-5.5": 1000000, - "vercel-ai-gateway:openai/gpt-5.5-fast": 1000000, - "vercel-ai-gateway:openai/gpt-5.5-pro": 1000000, - "vercel-ai-gateway:openai/gpt-5.6-luna": 1050000, - "vercel-ai-gateway:openai/gpt-5.6-luna-fast": 1050000, - "vercel-ai-gateway:openai/gpt-5.6-sol": 1050000, - "vercel-ai-gateway:openai/gpt-5.6-sol-fast": 1050000, - "vercel-ai-gateway:openai/gpt-5.6-terra": 1050000, - "vercel-ai-gateway:openai/gpt-5.6-terra-fast": 1050000, - "vercel-ai-gateway:openai/gpt-6-astra": 1050000, - "vercel-ai-gateway:openai/gpt-6-astra-fast": 1050000, - "vercel-ai-gateway:openai/gpt-oss-120b": 131072, - "vercel-ai-gateway:openai/gpt-oss-20b": 131072, - "vercel-ai-gateway:openai/gpt-oss-safeguard-120b": 128000, - "vercel-ai-gateway:openai/gpt-oss-safeguard-20b": 128000, - "vercel-ai-gateway:openai/o1": 200000, - "vercel-ai-gateway:openai/o3": 200000, - "vercel-ai-gateway:openai/o3-fast": 200000, - "vercel-ai-gateway:openai/o3-mini": 200000, - "vercel-ai-gateway:openai/o3-pro": 200000, - "vercel-ai-gateway:openai/o4-mini": 200000, - "vercel-ai-gateway:openai/o4-mini-fast": 200000, - "vercel-ai-gateway:poolside/laguna-s-2.1": 1000000, - "vercel-ai-gateway:poolside/laguna-s-2.1-free": 256000, - "vercel-ai-gateway:sakana/fugu-ultra": 1000000, - "vercel-ai-gateway:sakana/namazu": 256000, - "vercel-ai-gateway:spacexai/grok-4.1-fast-non-reasoning": 1000000, - "vercel-ai-gateway:spacexai/grok-4.1-fast-reasoning": 1000000, - "vercel-ai-gateway:spacexai/grok-4.20-multi-agent": 2000000, - "vercel-ai-gateway:spacexai/grok-4.20-multi-agent-beta": 2000000, - "vercel-ai-gateway:spacexai/grok-4.20-non-reasoning": 2000000, - "vercel-ai-gateway:spacexai/grok-4.20-non-reasoning-beta": 2000000, - "vercel-ai-gateway:spacexai/grok-4.20-reasoning": 2000000, - "vercel-ai-gateway:spacexai/grok-4.20-reasoning-beta": 2000000, - "vercel-ai-gateway:spacexai/grok-4.3": 1000000, - "vercel-ai-gateway:spacexai/grok-4.5": 500000, - "vercel-ai-gateway:spacexai/grok-4.6": 500000, - "vercel-ai-gateway:spacexai/grok-build-0.1": 256000, - "vercel-ai-gateway:stepfun/step-3.5-flash": 262114, - "vercel-ai-gateway:stepfun/step-3.7-flash": 256000, - "vercel-ai-gateway:tencent/hy3": 262144, - "vercel-ai-gateway:tencent/hy4-preview": 1024000, - "vercel-ai-gateway:thinkingmachines/inkling": 256000, - "vercel-ai-gateway:thinkingmachines/inkling-small": 1000000, - "vercel-ai-gateway:xiaomi/mimo-v2.5": 1050000, - "vercel-ai-gateway:xiaomi/mimo-v2.5-pro": 1050000, - "vercel-ai-gateway:xiaomi/mimo-v2.5-pro-ultraspeed": 1048576, - "vercel-ai-gateway:zai/glm-4.5": 128000, - "vercel-ai-gateway:zai/glm-4.5-air": 128000, - "vercel-ai-gateway:zai/glm-4.5v": 66000, - "vercel-ai-gateway:zai/glm-4.6": 200000, - "vercel-ai-gateway:zai/glm-4.7": 200000, - "vercel-ai-gateway:zai/glm-4.7-flash": 200000, - "vercel-ai-gateway:zai/glm-4.7-flashx": 200000, - "vercel-ai-gateway:zai/glm-5": 202800, - "vercel-ai-gateway:zai/glm-5-turbo": 202800, - "vercel-ai-gateway:zai/glm-5.1": 202800, - "vercel-ai-gateway:zai/glm-5.2": 1000000, - "vercel-ai-gateway:zai/glm-5.2-fast": 1000000, - "vercel-ai-gateway:zai/glm-5.3": 1000000, - "vercel-ai-gateway:zai/glm-5.3-fast": 1048576, - "vercel-ai-gateway:zai/glm-5.3-flash": 1000000, - "vercel-ai-gateway:zai/glm-5.3-promo-50": 1048576, - "vercel-ai-gateway:zai/glm-5v-turbo": 200000, - "xai:grok-4.3": 1000000, - "xai:grok-4.5": 500000, - "xai:grok-4.6": 500000, - "xiaomi-token-plan-ams:mimo-v2.5": 1048576, - "xiaomi-token-plan-ams:mimo-v2.5-pro": 1048576, - "xiaomi-token-plan-cn:mimo-v2.5": 1048576, - "xiaomi-token-plan-cn:mimo-v2.5-pro": 1048576, - "xiaomi-token-plan-sgp:mimo-v2.5": 1048576, - "xiaomi-token-plan-sgp:mimo-v2.5-pro": 1048576, - "xiaomi:mimo-v2.5": 1048576, - "xiaomi:mimo-v2.5-pro": 1048576, - "xiaomi:mimo-v2.5-pro-ultraspeed": 1048576, - "zai-coding-cn:glm-4.6v": 128000, - "zai-coding-cn:glm-4.7": 204800, - "zai-coding-cn:glm-5-turbo": 200000, - "zai-coding-cn:glm-5.1": 200000, - "zai-coding-cn:glm-5.2": 1000000, - "zai-coding-cn:glm-5.2-highspeed": 1000000, - "zai-coding-cn:glm-5.3": 1000000, - "zai-coding-cn:glm-5.3-flash": 1000000, - "zai-coding-cn:glm-5.3-highspeed": 1000000, - "zai-coding-cn:glm-5v-turbo": 200000, - "zai:glm-4.7": 204800, - "zai:glm-5-turbo": 200000, - "zai:glm-5.2": 1000000, - "zai:glm-5.2-highspeed": 1000000, - "zai:glm-5.3": 1000000, - "zai:glm-5.3-flash": 1000000, - "zai:glm-5.3-highspeed": 1000000, -}; - // ─── Pure helpers (folds + cost inference) ─────────────────────────────────── /** Sum a list of per-step usages into one CallUsage. A field stays @@ -2824,11 +1468,15 @@ export function sessionCost(record: Pick): { cost: number; * (= pi's own totalTokens semantics; the fields are persisted in every * CallUsage). * - * DENOMINATOR: the LIVE catalog wins — `limits`, when given, is the - * client/server-held index of provider:id → contextWindow straight from - * pi's catalog (GET /api/models serves it per model); CONTEXT_LIMITS is - * a generated snapshot kept ONLY as the fallback for models the live - * catalog doesn't carry. + * DENOMINATOR (owner ruling, 2026-09-23 — the amendment): the live + * catalog is the ONLY source — `limits`, when given, is the index of + * provider:id → contextWindow straight from pi's catalog (GET + * /api/models serves it per model; the server's catalogContextLimits + * builds the same index). No hardcoded fallback: a model missing from + * the live index (historical session, package update removed it, a + * failed catalog fetch) resolves limit null and the meter renders + * usage-only — the honest-render precedent (never a fake window, + * same shape as unpriced models never showing $0). * * Zeroed-step fallback: an aborted/failed last call reports zeroed * usage — that is NOT the session footprint; fall back to the previous @@ -2837,12 +1485,11 @@ export function sessionCost(record: Pick): { cost: number; export function contextWindow( record: Pick, limits?: ReadonlyMap, -): { model: string; usedTokens: number; limit: number } | null { +): { model: string; usedTokens: number; limit: number | null } | null { const turns = record.turns ?? []; const last = turns[turns.length - 1]; if (!last) return null; - const limit = limits?.get(last.model) ?? CONTEXT_LIMITS[last.model]; - if (limit === undefined) return null; + const limit = limits?.get(last.model) ?? null; // The last step with a real (non-zero) footprint — zeroed usage (an // abort artifact) is not a reading; fall back to the previous step. for (let i = last.steps.length - 1; i >= 0; i--) { diff --git a/src/server/model-catalog.ts b/src/server/model-catalog.ts index f0764db..80263ff 100644 --- a/src/server/model-catalog.ts +++ b/src/server/model-catalog.ts @@ -153,6 +153,25 @@ export function toModelDto(model: Model): ModelDto { }; } +/** The live-limits index (context-meter amendment, owner 2026-09-23): + * provider:id → contextWindow from pi's catalog, over the SAME keyed + * providers the picker federates. The one source for every context + * meter's denominator — the stats-bar join holds /api/models' copy, + * and the activity feed (observability.ts) resolves job limits + * server-side through this. No hardcoded fallback exists anywhere: + * a model missing here reads limit-null (usage-only, honest render). */ +export function catalogContextLimits(): Map { + const keyed = keyedProviderIds(); + const index = new Map(); + for (const provider of piModels().getProviders()) { + if (!keyed.has(provider.id)) continue; + for (const model of piModels().getModels(provider.id)) { + index.set(`${provider.id}:${model.id}`, model.contextWindow); + } + } + return index; +} + /** The full picker payload: every model of every configured provider * (sorted by provider then id — stable, diff-friendly) + the config * defaults a settings-less chat runs + the background roles' resolved diff --git a/src/server/observability.ts b/src/server/observability.ts index bd0b84a..8ef2cac 100644 --- a/src/server/observability.ts +++ b/src/server/observability.ts @@ -22,15 +22,22 @@ import { extractionStatuses, type ExtractionPhase } from "../agent/subagents/extraction.ts"; import { chatStore } from "../store/chats.ts"; import { graphRevision } from "./graph.ts"; +import { catalogContextLimits } from "./model-catalog.ts"; import { listJobs } from "./jobs.ts"; import type { JobRecord } from "../core/contracts.ts"; export { abortExtraction, extractionStatuses, type ExtractionPhase, type RunningExtraction } from "../agent/subagents/extraction.ts"; export { chatStore } from "../store/chats.ts"; -/** A running sub-agent job, joined with its chat's title for the dock. */ +/** A running sub-agent job, joined with its chat's title for the dock. + * contextLimit (context-meter amendment, owner 2026-09-23): the model's + * live catalog limit, resolved SERVER-SIDE from pi's catalog — the dock + * reads it off the feed instead of any client-side table. Null when the + * model is missing from the catalog (the blob then renders no context + * line — never a fake window). */ export interface ActivityJob extends JobRecord { title: string; + contextLimit: number | null; } /** One extraction-pipeline run (title joined), oldest first. */ @@ -54,11 +61,16 @@ export interface ActivityExtraction { * returns the same stamp. */ export function activityFeed(): { jobs: ActivityJob[]; extractions: ActivityExtraction[]; graphRevision: number } { const chats = chatStore.listChats(); + const limits = catalogContextLimits(); const jobs: ActivityJob[] = []; for (const chat of chats) { for (const job of listJobs(chat.id)) { if (job.status === "running") { - jobs.push({ ...job, title: chat.title ?? chat.id }); + jobs.push({ + ...job, + title: chat.title ?? chat.id, + contextLimit: job.usage ? (limits.get(job.usage.model) ?? null) : null, + }); } } } diff --git a/tests/activity-feed.test.ts b/tests/activity-feed.test.ts index 2c65c28..eaa3e12 100644 --- a/tests/activity-feed.test.ts +++ b/tests/activity-feed.test.ts @@ -59,3 +59,42 @@ test("activityFeed: running jobs across ALL chats, running-only, title-joined, o } } }); + +test("activityFeed: contextLimit is the server's live-catalog join (owner amendment, 2026-09-23)", () => { + // keyed-provider federation — the same env-key pattern as the + // model-catalog tests; file-local (each test file is its own process) + process.env.OPENROUTER_API_KEY ??= "test-key-openrouter-catalog"; + const chat = chatStore.createChat("limit join chat"); + const createdJobs: string[] = []; + const usageFor = (model: string) => ({ + model, + inputTokens: 1_000, + outputTokens: 100, + cacheReadTokens: 0, + cacheWriteTokens: 0, + reasoningTokens: 0, + steps: 1, + }); + try { + const known = jobStore.createJob({ kind: "research", chatId: chat.id, toolCallId: "tc_known" }); + const unknown = jobStore.createJob({ kind: "research", chatId: chat.id, toolCallId: "tc_unknown" }); + const bare = jobStore.createJob({ kind: "research", chatId: chat.id, toolCallId: "tc_bare" }); + createdJobs.push(known.id, unknown.id, bare.id); + jobStore.updateJob(known.id, { usage: usageFor("openrouter:z-ai/glm-5.3-flash") }); + jobStore.updateJob(unknown.id, { usage: usageFor("nope/unknown") }); + + const feed = activityFeed(); + const knownJob = feed.jobs.find((j) => j.id === known.id)!; + assert.equal(knownJob.contextLimit, 1_048_576, "pi's catalog, joined server-side onto the feed"); + const unknownJob = feed.jobs.find((j) => j.id === unknown.id)!; + assert.equal(unknownJob.contextLimit, null, "missing from the live catalog → null, never a guessed window"); + const bareJob = feed.jobs.find((j) => j.id === bare.id)!; + assert.equal(bareJob.contextLimit, null, "no usage yet → no context line"); + } finally { + fs.unlinkSync(`${PATHS.chats}/${chat.id}.json`); + const jobsDir = path.join(PATHS.data, "jobs"); + for (const id of createdJobs) { + fs.unlinkSync(path.join(jobsDir, `${id}.json`)); + } + } +}); diff --git a/tests/render-activity-dock.test.tsx b/tests/render-activity-dock.test.tsx index b87826f..1f9128a 100644 --- a/tests/render-activity-dock.test.tsx +++ b/tests/render-activity-dock.test.tsx @@ -26,6 +26,7 @@ function job(over: Partial = {}): ActivityFeed["jo createdAt: new Date(NOW - 45_000).toISOString(), updatedAt: new Date(NOW - 1000).toISOString(), title: "Limits lesson", + contextLimit: null, ...over, }; } @@ -91,19 +92,23 @@ describe("activity dock pure layer", () => { }; const withLast = job({ usage: { ...base, lastStep: step(90_000, 2_000) }, + // The amendment (owner 2026-09-23): the limit is the server's + // live-catalog join riding the feed — the dock never resolves it. + contextLimit: 131_072, }); const blob = toBlobs({ jobs: [withLast], extractions: [] })[0]!; assert.equal(blob.context?.used, 92_000); - assert.equal(blob.context?.limit, 1048576); + assert.equal(blob.context?.limit, 131_072); // No lastStep yet (capture pending) → "—", even though usage exists. const stripped = toBlobs({ jobs: [job({ usage: { ...base } })], extractions: [] })[0]!; assert.equal(stripped.context, null); - // Unknown model → no limit → "—". - const unknownModel = toBlobs({ - jobs: [job({ usage: { ...base, model: "nope/unknown", lastStep: step(5, 5) } })], + // Model missing from the live catalog (historical session, + // package update) → the feed carries null → no context line. + const uncatalogued = toBlobs({ + jobs: [job({ usage: { ...base, model: "nope/unknown", lastStep: step(5, 5), } })], extractions: [], })[0]!; - assert.equal(unknownModel.context, null); + assert.equal(uncatalogued.context, null); }); it("extraction blobs carry no money/context (—, the doctrine)", () => { diff --git a/tests/render-stats-bar.test.tsx b/tests/render-stats-bar.test.tsx index 3598771..d4dca6d 100644 --- a/tests/render-stats-bar.test.tsx +++ b/tests/render-stats-bar.test.tsx @@ -50,9 +50,11 @@ describe("stats bar", () => { const html = renderToStaticMarkup( , ); - // last turn's last call: 10k in + 1k out = 11k; pi catalog limit - // 1_048_576 → "1M" (tables regenerated from pi-ai's catalog) - assert.match(html, /data-testid="stats-context">11k \/ 1M11k\$0\.0020 { , ); assert.match(html, /data-testid="stats-cost">——11k { diff --git a/tests/usage.test.ts b/tests/usage.test.ts index d49d985..4207838 100644 --- a/tests/usage.test.ts +++ b/tests/usage.test.ts @@ -78,18 +78,22 @@ test("turnCost sums steps; sessionCost reports unpriced turns", () => { assert.ok(totals.cost > 0); }); -test("contextWindow: last call's footprint against the model's limit", () => { - const cw = contextWindow({ - turns: [ - { id: "t1", messageId: "m1", at: "x", model: "openrouter:z-ai/glm-5.3-flash", steps: [call({ inputTokens: 9_000, outputTokens: 1_000 })] }, - { id: "t2", messageId: "m2", at: "x", model: "openrouter:z-ai/glm-5.3-flash", steps: [call({ inputTokens: 90_000, outputTokens: 10_000 })] }, - ], - }); +test("contextWindow: last call's footprint against the live index's limit", () => { + const limits = new Map([["openrouter:z-ai/glm-5.3-flash", 1_048_576]]); + const cw = contextWindow( + { + turns: [ + { id: "t1", messageId: "m1", at: "x", model: "openrouter:z-ai/glm-5.3-flash", steps: [call({ inputTokens: 9_000, outputTokens: 1_000 })] }, + { id: "t2", messageId: "m2", at: "x", model: "openrouter:z-ai/glm-5.3-flash", steps: [call({ inputTokens: 90_000, outputTokens: 10_000 })] }, + ], + }, + limits, + ); assert.ok(cw); assert.equal(cw.model, "openrouter:z-ai/glm-5.3-flash"); assert.equal(cw.usedTokens, 100_000); assert.equal(cw.limit, 1_048_576); - assert.equal(contextWindow({ turns: [] }), null); + assert.equal(contextWindow({ turns: [] }, limits), null); }); test("contextWindow NUMERATOR: cache tokens count (owner audit, 2026-09-23)", () => { @@ -97,70 +101,86 @@ test("contextWindow NUMERATOR: cache tokens count (owner audit, 2026-09-23)", () // while the real footprint was ~190k — provider `input` EXCLUDES the // cached portion, so input+output alone is wildly low. The fold is // pi's totalTokens semantics: all four fields. - const cw = contextWindow({ - turns: [ - { - id: "t1", - messageId: "m1", - at: "x", - model: "openrouter:z-ai/glm-5.3-flash", - steps: [call({ inputTokens: 40_000, outputTokens: 1_000, cacheReadTokens: 145_000, cacheWriteTokens: 4_000 })], - }, - ], - }); + const limits = new Map([["openrouter:z-ai/glm-5.3-flash", 1_048_576]]); + const cw = contextWindow( + { + turns: [ + { + id: "t1", + messageId: "m1", + at: "x", + model: "openrouter:z-ai/glm-5.3-flash", + steps: [call({ inputTokens: 40_000, outputTokens: 1_000, cacheReadTokens: 145_000, cacheWriteTokens: 4_000 })], + }, + ], + }, + limits, + ); assert.ok(cw); assert.equal(cw.usedTokens, 40_000 + 1_000 + 145_000 + 4_000, "input + output + cacheRead + cacheWrite"); // Cache fields absent (non-caching providers): the fold is unchanged. - const plain = contextWindow({ - turns: [{ id: "t1", messageId: "m1", at: "x", model: "openrouter:z-ai/glm-5.3-flash", steps: [call({ inputTokens: 9_000, outputTokens: 1_000 })] }], - }); + const plain = contextWindow( + { turns: [{ id: "t1", messageId: "m1", at: "x", model: "openrouter:z-ai/glm-5.3-flash", steps: [call({ inputTokens: 9_000, outputTokens: 1_000 })] }] }, + limits, + ); assert.ok(plain); assert.equal(plain.usedTokens, 10_000); }); -test("contextWindow DENOMINATOR: the live-limits index wins; CONTEXT_LIMITS is the fallback", () => { +test("contextWindow DENOMINATOR: the live index is the ONLY source — no fallback (owner amendment, 2026-09-23)", () => { const turns = [ { id: "t1", messageId: "m1", at: "x", model: "openrouter:z-ai/glm-5.3-flash", steps: [call({ inputTokens: 10_000, outputTokens: 1_000 })] }, ]; - // The live catalog (GET /api/models) wins even when it disagrees with - // the generated table. const live = new Map([["openrouter:z-ai/glm-5.3-flash", 65_536]]); const cw = contextWindow({ turns }, live); assert.ok(cw); - assert.equal(cw.limit, 65_536, "the live index beats the static table"); - // No live entry: the generated table serves the uncatalogued model. - assert.equal(contextWindow({ turns })!.limit, 1_048_576); - const emptyLive = new Map(); - assert.equal(contextWindow({ turns }, emptyLive)!.limit, 1_048_576, "an empty live index falls back too"); - // Unknown to both: null (no meter, never a guessed limit). - assert.equal(contextWindow({ turns: [{ ...turns[0]!, model: "unknown/model" }] }), null); - assert.equal(contextWindow({ turns: [{ ...turns[0]!, model: "unknown/model" }] }, live), null); + assert.equal(cw.limit, 65_536, "pi's catalog, via the index, is the one source"); + // No index at all (a client that hasn't fetched the catalog): the + // meter renders usage-only — limit null, never a guessed window. + const noIndex = contextWindow({ turns }); + assert.ok(noIndex); + assert.equal(noIndex.usedTokens, 11_000); + assert.equal(noIndex.limit, null); + const emptyIndex = contextWindow({ turns }, new Map()); + assert.ok(emptyIndex); + assert.equal(emptyIndex.limit, null, "an empty index (failed fetch) is usage-only too"); + // A model missing from the live catalog (historical session, package + // update removed it): usage-only, never a fake window. + const missing = contextWindow({ turns: [{ ...turns[0]!, model: "nope/gone-model" }] }, live); + assert.ok(missing); + assert.equal(missing.limit, null); + assert.equal(missing.usedTokens, 11_000, "the footprint still reads honestly"); }); test("contextWindow ride-along: a zeroed/aborted last step falls back to the previous step", () => { // An aborted last call reports zeroed usage — that is not the session // footprint. The honest reading is the previous step's usage. - const cw = contextWindow({ - turns: [ - { - id: "t1", - messageId: "m1", - at: "x", - model: "openrouter:z-ai/glm-5.3-flash", - steps: [ - call({ inputTokens: 80_000, outputTokens: 5_000 }), - call({ inputTokens: 0, outputTokens: 0 }), // aborted — zeroed - ], - }, - ], - }); + const limits = new Map([["openrouter:z-ai/glm-5.3-flash", 1_048_576]]); + const cw = contextWindow( + { + turns: [ + { + id: "t1", + messageId: "m1", + at: "x", + model: "openrouter:z-ai/glm-5.3-flash", + steps: [ + call({ inputTokens: 80_000, outputTokens: 5_000 }), + call({ inputTokens: 0, outputTokens: 0 }), // aborted — zeroed + ], + }, + ], + }, + limits, + ); assert.ok(cw); assert.equal(cw.usedTokens, 85_000, "the previous step's footprint, not a bogus tiny meter"); // ALL steps zeroed (a first-call abort): no reading at all — null. assert.equal( - contextWindow({ - turns: [{ id: "t1", messageId: "m1", at: "x", model: "openrouter:z-ai/glm-5.3-flash", steps: [call({ inputTokens: 0, outputTokens: 0 })] }], - }), + contextWindow( + { turns: [{ id: "t1", messageId: "m1", at: "x", model: "openrouter:z-ai/glm-5.3-flash", steps: [call({ inputTokens: 0, outputTokens: 0 })] }] }, + limits, + ), null, ); });