diff --git a/scripts/generate-jawcode-metadata.ts b/scripts/generate-jawcode-metadata.ts index 2b73133d7..7780b7d31 100644 --- a/scripts/generate-jawcode-metadata.ts +++ b/scripts/generate-jawcode-metadata.ts @@ -27,10 +27,6 @@ const sourcePath = process.env.JAWCODE_MODELS_JSON const outPath = process.env.JAWCODE_METADATA_OUT ? resolve(process.env.JAWCODE_METADATA_OUT) : resolve(process.cwd(), "src/generated/jawcode-model-metadata.ts"); -const CONTEXT_WINDOW_OVERRIDES: Record = { - "anthropic/claude-sonnet-4-6": 200_000, - "anthropic/claude-sonnet-4-6[1m]": 200_000, -}; if (!existsSync(sourcePath)) { throw new Error(`jawcode models.json not found: ${sourcePath}`); @@ -91,7 +87,7 @@ for (const provider of allowedProviders) { .sort(([a], [b]) => a.localeCompare(b)) .map(([id, model]) => compactRow([ id, - CONTEXT_WINDOW_OVERRIDES[`${provider}/${id}`] ?? model.contextWindow, + model.contextWindow, model.maxTokens, Array.isArray(model.input) ? model.input.join(",") : undefined, model.reasoning === undefined ? undefined : (model.reasoning ? 1 : 0), diff --git a/src/claude/agents-inject.ts b/src/claude/agents-inject.ts index a994b1d82..47508b7bd 100644 --- a/src/claude/agents-inject.ts +++ b/src/claude/agents-inject.ts @@ -15,7 +15,7 @@ import { lstatSync, mkdirSync, readdirSync, readFileSync, renameSync, unlinkSync import { join } from "node:path"; import type { OcxConfig } from "../types"; import { claudeCodeAlias, claudeCodeNativeAlias } from "./alias"; -import { resolveAutoContext, stripOneMillionMarker, withOneMillionMarker } from "./context-windows"; +import { AUTO_CONTEXT_OFF, shouldMarkOneMillion, stripOneMillionMarker, withOneMillionMarker } from "./context-windows"; import { claudeConfigDir } from "./gateway-cache"; import { DEFAULT_SUBAGENT_MODELS, hasOwnProvider } from "../config"; import { effectiveBlockedSkillNames, resolveInboundModel } from "./inbound"; @@ -55,6 +55,23 @@ function pickerDefaultModel(configDir: string): string | null { } } +/** + * Generated subagents cannot rely on parent auto-context compaction before + * routed requests reach the real model limit. + */ +function withSubagentContextMarker(selector: string, windows: Record): string { + const bare = stripOneMillionMarker(selector); + const wasMarked = selector !== bare; + const canonicalExact = wasMarked ? `${bare}[1m]` : selector; + const authoritativeWindow = windows[selector] ?? windows[canonicalExact] ?? windows[bare]; + if (typeof authoritativeWindow === "number" && authoritativeWindow > 0) { + return shouldMarkOneMillion(authoritativeWindow, AUTO_CONTEXT_OFF) + ? (withOneMillionMarker(selector, windows) ?? selector) + : bare; + } + return wasMarked ? selector : bare; +} + /** Roster entry -> alias + display parts. Entries are bare native slugs or "provider/id". * Codex-facing encoded ids (`provider/vendor-model`) decode to the native slash id first * so the alias joins the raw-native context-window map (context-windows.ts). */ @@ -72,7 +89,6 @@ function entryParts(entry: string, config: OcxConfig): { alias: string; id: stri } export function buildClaudeAgentDefs(config: OcxConfig, windows: Record, configDir = claudeConfigDir()): ClaudeAgentDef[] { - const auto = resolveAutoContext(config.claudeCode); const blockedSkills = effectiveBlockedSkillNames(config.claudeCode); const blockedSkillsFor = (model: string): readonly string[] => { const unmarked = stripOneMillionMarker(model); @@ -87,8 +103,7 @@ export function buildClaudeAgentDefs(config: OcxConfig, windows: Record(); const push = (name: string, alias: string, description: string) => { - // Effective model value: [1m] marking follows the same predicate as env slots. - const model = withOneMillionMarker(alias, windows, auto) ?? alias; + const model = withSubagentContextMarker(alias, windows); const bare = alias.toLowerCase(); if (coveredModels.has(bare)) return; coveredModels.add(bare); @@ -120,7 +135,7 @@ export function buildClaudeAgentDefs(config: OcxConfig, windows: Record no self def. const selfModel = pickerDefaultModel(configDir) ?? (config.claudeCode?.model?.trim() || null); if (selfModel) { - const marked = withOneMillionMarker(selfModel, windows, auto) ?? selfModel; + const marked = withSubagentContextMarker(selfModel, windows); defs.push({ file: `${OWNED_PREFIX}self.md`, name: `${OWNED_PREFIX}self`, diff --git a/src/generated/jawcode-model-metadata.ts b/src/generated/jawcode-model-metadata.ts index 75d9e9664..94360f6a3 100644 --- a/src/generated/jawcode-model-metadata.ts +++ b/src/generated/jawcode-model-metadata.ts @@ -36,7 +36,7 @@ const PROVIDER_ALIASES: Record = { type Row = readonly [id: string, contextWindow?: number | null, maxTokens?: number | null, input?: string | null, reasoning?: 0 | 1 | null, wireModelId?: string | null, costInput?: number | null, costOutput?: number | null, costCacheRead?: number | null, costCacheWrite?: number | null]; const DATA: Record = { "amazon-bedrock": [["anthropic.claude-3-5-haiku-20241022-v1:0",200000,8192,"text,image",0,null,0.8,4,0.08,1],["anthropic.claude-3-5-sonnet-20240620-v1:0",200000,8192,"text,image",0,null,3,15,0.3,3.75],["anthropic.claude-3-5-sonnet-20241022-v2:0",200000,8192,"text,image",0,null,3,15,0.3,3.75],["anthropic.claude-3-haiku-20240307-v1:0",200000,4096,"text,image",0,null,0.25,1.25,0,0],["anthropic.claude-3-opus-20240229-v1:0",200000,4096,"text,image",0,null,15,75,0,0],["anthropic.claude-3-sonnet-20240229-v1:0",200000,4096,"text,image",0,null,3,15,0,0],["anthropic.claude-fable-5",1000000,128000,"text,image",1,null,10,50,1,12.5],["anthropic.claude-opus-4-6-v1",1000000,128000,"text,image",1,null,5,25,0.5,6.25],["anthropic.claude-opus-4-7",1000000,128000,"text,image",1,null,5,25,0.5,6.25],["anthropic.claude-opus-4-8",1000000,128000,"text,image",1,null,5,25,0.5,6.25],["anthropic.claude-opus-5",1000000,128000,"text,image",1,null,5,25,0.5,6.25],["anthropic.claude-sonnet-5",1000000,128000,"text,image",1,null,2,10,0.2,2.5],["au.anthropic.claude-haiku-4-5-20251001-v1:0",200000,64000,"text,image",1,null,1,5,0.1,1.25],["au.anthropic.claude-opus-4-6-v1",1000000,128000,"text,image",1,null,16.5,82.5,0.5,6.25],["au.anthropic.claude-opus-4-8",1000000,128000,"text,image",1,null,5,25,0.5,6.25],["au.anthropic.claude-opus-5",1000000,128000,"text,image",1,null,5,25,0.5,6.25],["au.anthropic.claude-sonnet-4-5-20250929-v1:0",200000,64000,"text,image",1,null,3,15,0.3,3.75],["au.anthropic.claude-sonnet-4-6",1000000,128000,"text,image",1,null,3.3,16.5,0.33,4.125],["au.anthropic.claude-sonnet-5",1000000,128000,"text,image",1,null,2,10,0.2,2.5],["cohere.command-r-plus-v1:0",128000,4096,"text",0,null,3,15,0,0],["cohere.command-r-v1:0",128000,4096,"text",0,null,0.5,1.5,0,0],["deepseek.v3-v1:0",163840,81920,"text",1,null,0.58,1.68,0,0],["deepseek.v3.2",163840,81920,"text",1,null,0.62,1.85,0,0],["deepseek.v3.2-v1:0",163840,81920,"text",1,null,0.62,1.85,0,0],["eu.anthropic.claude-3-5-haiku-20241022-v1:0",200000,8192,"text,image",0,null,0.8,4,0.08,1],["eu.anthropic.claude-3-5-sonnet-20240620-v1:0",200000,8192,"text,image",0,null,3,15,0.3,3.75],["eu.anthropic.claude-3-5-sonnet-20241022-v2:0",200000,8192,"text,image",0,null,3,15,0.3,3.75],["eu.anthropic.claude-3-7-sonnet-20250219-v1:0",200000,8192,"text,image",0,null,3,15,0.3,3.75],["eu.anthropic.claude-3-haiku-20240307-v1:0",200000,4096,"text,image",0,null,0.25,1.25,0,0],["eu.anthropic.claude-3-opus-20240229-v1:0",200000,4096,"text,image",0,null,15,75,0,0],["eu.anthropic.claude-3-sonnet-20240229-v1:0",200000,4096,"text,image",0,null,3,15,0,0],["eu.anthropic.claude-fable-5",1000000,128000,"text,image",1,null,10,50,1,12.5],["eu.anthropic.claude-haiku-4-5-20251001-v1:0",200000,64000,"text,image",1,null,1.1,5.5,0.11,1.375],["eu.anthropic.claude-opus-4-1-20250805-v1:0",200000,32000,"text,image",1,null,15,75,1.5,18.75],["eu.anthropic.claude-opus-4-20250514-v1:0",200000,32000,"text,image",1,null,15,75,1.5,18.75],["eu.anthropic.claude-opus-4-5-20251101-v1:0",200000,64000,"text,image",1,null,5.5,27.5,0.55,6.875],["eu.anthropic.claude-opus-4-6-v1",1000000,128000,"text,image",1,null,5,25,0.5,6.25],["eu.anthropic.claude-opus-4-7",1000000,128000,"text,image",1,null,5.5,27.5,0.55,6.875],["eu.anthropic.claude-opus-4-8",1000000,128000,"text,image",1,null,5.5,27.5,0.55,6.875],["eu.anthropic.claude-opus-5",1000000,128000,"text,image",1,null,5.5,27.5,0.55,6.875],["eu.anthropic.claude-sonnet-4-20250514-v1:0",200000,64000,"text,image",1,null,3,15,0.3,3.75],["eu.anthropic.claude-sonnet-4-5-20250929-v1:0",200000,64000,"text,image",1,null,3,15,0.3,3.75],["eu.anthropic.claude-sonnet-4-6",1000000,64000,"text,image",1,null,3,15,0.3,3.75],["eu.anthropic.claude-sonnet-5",1000000,128000,"text,image",1,null,2,10,0.2,2.5],["global.amazon.nova-2-lite-v1:0",128000,4096,"text,image",1,null,0.33,2.75,0,0],["global.anthropic.claude-fable-5",1000000,128000,"text,image",1,null,10,50,1,12.5],["global.anthropic.claude-haiku-4-5-20251001-v1:0",200000,64000,"text,image",1,null,1,5,0.1,1.25],["global.anthropic.claude-opus-4-5-20251101-v1:0",200000,64000,"text,image",1,null,5,25,0.5,6.25],["global.anthropic.claude-opus-4-6-v1",1000000,128000,"text,image",1,null,5,25,0.5,6.25],["global.anthropic.claude-opus-4-7",1000000,128000,"text,image",1,null,5,25,0.5,6.25],["global.anthropic.claude-opus-4-8",1000000,128000,"text,image",1,null,5,25,0.5,6.25],["global.anthropic.claude-opus-5",1000000,128000,"text,image",1,null,5,25,0.5,6.25],["global.anthropic.claude-sonnet-4-20250514-v1:0",200000,64000,"text,image",1,null,3,15,0.3,3.75],["global.anthropic.claude-sonnet-4-5-20250929-v1:0",200000,64000,"text,image",1,null,3,15,0.3,3.75],["global.anthropic.claude-sonnet-4-6",1000000,64000,"text,image",1,null,3,15,0.3,3.75],["global.anthropic.claude-sonnet-5",1000000,128000,"text,image",1,null,2,10,0.2,2.5],["google.gemma-3-27b-it",202752,8192,"text,image",0,null,0.12,0.2,0,0],["google.gemma-3-4b-it",128000,4096,"text,image",0,null,0.04,0.08,0,0],["jp.anthropic.claude-haiku-4-5-20251001-v1:0",200000,64000,"text,image",1,null,1,5,0.1,1.25],["jp.anthropic.claude-opus-4-7",1000000,128000,"text,image",1,null,5,25,0.5,6.25],["jp.anthropic.claude-opus-4-8",1000000,128000,"text,image",1,null,5,25,0.5,6.25],["jp.anthropic.claude-opus-5",1000000,128000,"text,image",1,null,5,25,0.5,6.25],["jp.anthropic.claude-sonnet-4-5-20250929-v1:0",200000,64000,"text,image",1,null,3,15,0.3,3.75],["jp.anthropic.claude-sonnet-4-6",1000000,64000,"text,image",1,null,3,15,0.3,3.75],["jp.anthropic.claude-sonnet-5",1000000,128000,"text,image",1,null,2,10,0.2,2.5],["meta.llama3-1-405b-instruct-v1:0",128000,4096,"text",0,null,2.4,2.4,0,0],["meta.llama3-1-70b-instruct-v1:0",128000,4096,"text",0,null,0.72,0.72,0,0],["meta.llama3-1-8b-instruct-v1:0",128000,4096,"text",0,null,0.22,0.22,0,0],["minimax.minimax-m2",204608,128000,"text",1,null,0.3,1.2,0,0],["minimax.minimax-m2.1",204800,131072,"text",1,null,0.3,1.2,0,0],["minimax.minimax-m2.5",196608,98304,"text",1,null,0.3,1.2,0,0],["mistral.devstral-2-123b",256000,8192,"text",0,null,0.4,2,0,0],["mistral.magistral-small-2509",128000,40000,"text,image",1,null,0.5,1.5,0,0],["mistral.ministral-3-14b-instruct",128000,4096,"text",0,null,0.2,0.2,0,0],["mistral.ministral-3-3b-instruct",256000,8192,"text,image",0,null,0.1,0.1,0,0],["mistral.ministral-3-8b-instruct",128000,4096,"text",0,null,0.15,0.15,0,0],["mistral.mistral-large-2402-v1:0",128000,4096,"text",0,null,0.5,1.5,0,0],["mistral.mistral-large-3-675b-instruct",256000,8192,"text,image",0,null,0.5,1.5,0,0],["mistral.pixtral-large-2502-v1:0",128000,8192,"text,image",0,null,2,6,0,0],["mistral.voxtral-mini-3b-2507",128000,4096,"text",0,null,0.04,0.04,0,0],["mistral.voxtral-small-24b-2507",32000,8192,"text",0,null,0.15,0.35,0,0],["moonshot.kimi-k2-thinking",262143,16000,"text",1,null,0.6,2.5,0,0],["moonshotai.kimi-k2.5",262143,16000,"text,image",1,null,0.6,3,0,0],["nvidia.nemotron-nano-12b-v2",128000,4096,"text,image",0,null,0.2,0.6,0,0],["nvidia.nemotron-nano-3-30b",128000,4096,"text",1,null,0.06,0.24,0,0],["nvidia.nemotron-nano-9b-v2",128000,4096,"text",0,null,0.06,0.23,0,0],["nvidia.nemotron-super-3-120b",262144,131072,"text",1,null,0.15,0.65,0,0],["openai.gpt-5.4",272000,128000,"text,image",1,null,2.75,16.5,0.275,0],["openai.gpt-5.5",272000,128000,"text,image",1,null,5.5,33,0.55,0],["openai.gpt-5.6-luna",373000,128000,"text,image",1,null,1,6,0.1,1.25],["openai.gpt-5.6-sol",373000,128000,"text,image",1,null,5,30,0.5,6.25],["openai.gpt-5.6-terra",373000,128000,"text,image",1,null,2.5,15,0.25,3.125],["openai.gpt-oss-120b",128000,16384,"text",1,null,0.15,0.6,0,0],["openai.gpt-oss-120b-1:0",128000,16384,"text",1,null,0.15,0.6,0,0],["openai.gpt-oss-20b",128000,16384,"text",1,null,0.07,0.3,0,0],["openai.gpt-oss-20b-1:0",128000,16384,"text",1,null,0.07,0.3,0,0],["openai.gpt-oss-safeguard-120b",128000,16384,"text",0,null,0.15,0.6,0,0],["openai.gpt-oss-safeguard-20b",128000,16384,"text",0,null,0.07,0.2,0,0],["qwen.qwen3-235b-a22b-2507-v1:0",262144,131072,"text",0,null,0.22,0.88,0,0],["qwen.qwen3-32b-v1:0",16384,16384,"text",1,null,0.15,0.6,0,0],["qwen.qwen3-coder-30b-a3b-v1:0",262144,131072,"text",0,null,0.15,0.6,0,0],["qwen.qwen3-coder-480b-a35b-v1:0",131072,65536,"text",0,null,0.22,1.8,0,0],["qwen.qwen3-coder-next",131072,65536,"text",1,null,0.22,1.8,0,0],["qwen.qwen3-next-80b-a3b",262000,262000,"text",0,null,0.14,1.4,0,0],["qwen.qwen3-vl-235b-a22b",262000,262000,"text,image",0,null,0.3,1.5,0,0],["us.amazon.nova-lite-v1:0",300000,8192,"text,image",0,null,0.06,0.24,0.015,0],["us.amazon.nova-micro-v1:0",128000,8192,"text",0,null,0.035,0.14,0.00875,0],["us.amazon.nova-premier-v1:0",1000000,16384,"text,image",1,null,2.5,12.5,0,0],["us.amazon.nova-pro-v1:0",300000,8192,"text,image",0,null,0.8,3.2,0.2,0],["us.anthropic.claude-3-7-sonnet-20250219-v1:0",200000,8192,"text,image",0,null,3,15,0.3,3.75],["us.anthropic.claude-fable-5",1000000,128000,"text,image",1,null,10,50,1,12.5],["us.anthropic.claude-haiku-4-5-20251001-v1:0",200000,64000,"text,image",1,null,1,5,0.1,1.25],["us.anthropic.claude-opus-4-1-20250805-v1:0",200000,32000,"text,image",1,null,15,75,1.5,18.75],["us.anthropic.claude-opus-4-20250514-v1:0",200000,32000,"text,image",1,null,15,75,1.5,18.75],["us.anthropic.claude-opus-4-5-20251101-v1:0",200000,64000,"text,image",1,null,5,25,0.5,6.25],["us.anthropic.claude-opus-4-6-v1",1000000,128000,"text,image",1,null,5,25,0.5,6.25],["us.anthropic.claude-opus-4-7",1000000,128000,"text,image",1,null,5,25,0.5,6.25],["us.anthropic.claude-opus-4-8",1000000,128000,"text,image",1,null,5,25,0.5,6.25],["us.anthropic.claude-opus-5",1000000,128000,"text,image",1,null,5,25,0.5,6.25],["us.anthropic.claude-sonnet-4-20250514-v1:0",200000,64000,"text,image",1,null,3,15,0.3,3.75],["us.anthropic.claude-sonnet-4-5-20250929-v1:0",200000,64000,"text,image",1,null,3,15,0.3,3.75],["us.anthropic.claude-sonnet-4-6",1000000,64000,"text,image",1,null,3,15,0.3,3.75],["us.anthropic.claude-sonnet-5",1000000,128000,"text,image",1,null,2,10,0.2,2.5],["us.deepseek.r1-v1:0",128000,32768,"text",1,null,1.35,5.4,0,0],["us.meta.llama3-2-11b-instruct-v1:0",128000,4096,"text,image",0,null,0.16,0.16,0,0],["us.meta.llama3-2-1b-instruct-v1:0",131000,4096,"text",0,null,0.1,0.1,0,0],["us.meta.llama3-2-3b-instruct-v1:0",131000,4096,"text",0,null,0.15,0.15,0,0],["us.meta.llama3-2-90b-instruct-v1:0",128000,4096,"text,image",0,null,0.72,0.72,0,0],["us.meta.llama3-3-70b-instruct-v1:0",128000,4096,"text",0,null,0.72,0.72,0,0],["us.meta.llama4-maverick-17b-instruct-v1:0",1000000,16384,"text,image",0,null,0.24,0.97,0,0],["us.meta.llama4-scout-17b-instruct-v1:0",3500000,16384,"text,image",0,null,0.17,0.66,0,0],["writer.palmyra-x4-v1:0",122880,8192,"text",1,null,2.5,10,0,0],["writer.palmyra-x5-v1:0",1040000,8192,"text",1,null,0.6,6,0,0],["xai.grok-4.3",1000000,131072,"text,image",1,null,1.25,2.5,0.2,0],["zai.glm-4.7",204800,131072,"text",1,null,0.6,2.2,0,0],["zai.glm-4.7-flash",200000,131072,"text",1,null,0.07,0.4,0,0],["zai.glm-5",202752,101376,"text",1,null,1,3.2,0,0]], - "anthropic": [["claude-3-5-sonnet-20240620",200000,8192,"text,image",0,null,3,15,0.3,3.75],["claude-3-5-sonnet-20241022",200000,8192,"text,image",0,null,3,15,0.3,3.75],["claude-3-haiku-20240307",200000,4096,"text,image",0,null,0.25,1.25,0.03,0.3],["claude-fable-5",1000000,128000,"text,image",1,null,10,50,1,12.5],["claude-haiku-4-5",200000,64000,"text,image",1,null,1,5,0.1,1.25],["claude-haiku-4-5-20251001",200000,64000,"text,image",1,null,1,5,0.1,1.25],["claude-opus-4-0",200000,32000,"text,image",1,null,15,75,1.5,18.75],["claude-opus-4-1",200000,32000,"text,image",1,null,15,75,1.5,18.75],["claude-opus-4-1-20250805",200000,32000,"text,image",1,null,15,75,1.5,18.75],["claude-opus-4-20250514",200000,32000,"text,image",1,null,15,75,1.5,18.75],["claude-opus-4-5",200000,64000,"text,image",1,null,5,25,0.5,6.25],["claude-opus-4-5-20251101",200000,64000,"text,image",1,null,5,25,0.5,6.25],["claude-opus-4-6",1000000,128000,"text,image",1,null,5,25,0.5,6.25],["claude-opus-4-6[1m]",1000000,128000,"text,image",1,"claude-opus-4-6",5,25,0.5,6.25],["claude-opus-4-7",1000000,128000,"text,image",1,null,5,25,0.5,6.25],["claude-opus-4-7[1m]",1000000,128000,"text,image",1,"claude-opus-4-7",5,25,0.5,6.25],["claude-opus-4-8",1000000,128000,"text,image",1,null,5,25,0.5,6.25],["claude-opus-4-8[1m]",1000000,128000,"text,image",1,"claude-opus-4-8",5,25,0.5,6.25],["claude-opus-5",1000000,128000,"text,image",1,null,5,25,0.5,6.25],["claude-sonnet-4-0",200000,64000,"text,image",1,null,3,15,0.3,3.75],["claude-sonnet-4-20250514",200000,64000,"text,image",1,null,3,15,0.3,3.75],["claude-sonnet-4-5",1000000,64000,"text,image",1,null,3,15,0.3,3.75],["claude-sonnet-4-5-20250929",1000000,64000,"text,image",1,null,3,15,0.3,3.75],["claude-sonnet-4-6",200000,128000,"text,image",1,null,3,15,0.3,3.75],["claude-sonnet-4-6[1m]",200000,64000,"text,image",1,"claude-sonnet-4-6",3,15,0.3,3.75],["claude-sonnet-5",1000000,128000,"text,image",1,null,2,10,0.2,2.5]], + "anthropic": [["claude-3-5-sonnet-20240620",200000,8192,"text,image",0,null,3,15,0.3,3.75],["claude-3-5-sonnet-20241022",200000,8192,"text,image",0,null,3,15,0.3,3.75],["claude-3-haiku-20240307",200000,4096,"text,image",0,null,0.25,1.25,0.03,0.3],["claude-fable-5",1000000,128000,"text,image",1,null,10,50,1,12.5],["claude-haiku-4-5",200000,64000,"text,image",1,null,1,5,0.1,1.25],["claude-haiku-4-5-20251001",200000,64000,"text,image",1,null,1,5,0.1,1.25],["claude-opus-4-0",200000,32000,"text,image",1,null,15,75,1.5,18.75],["claude-opus-4-1",200000,32000,"text,image",1,null,15,75,1.5,18.75],["claude-opus-4-1-20250805",200000,32000,"text,image",1,null,15,75,1.5,18.75],["claude-opus-4-20250514",200000,32000,"text,image",1,null,15,75,1.5,18.75],["claude-opus-4-5",200000,64000,"text,image",1,null,5,25,0.5,6.25],["claude-opus-4-5-20251101",200000,64000,"text,image",1,null,5,25,0.5,6.25],["claude-opus-4-6",1000000,128000,"text,image",1,null,5,25,0.5,6.25],["claude-opus-4-6[1m]",1000000,128000,"text,image",1,"claude-opus-4-6",5,25,0.5,6.25],["claude-opus-4-7",1000000,128000,"text,image",1,null,5,25,0.5,6.25],["claude-opus-4-7[1m]",1000000,128000,"text,image",1,"claude-opus-4-7",5,25,0.5,6.25],["claude-opus-4-8",1000000,128000,"text,image",1,null,5,25,0.5,6.25],["claude-opus-4-8[1m]",1000000,128000,"text,image",1,"claude-opus-4-8",5,25,0.5,6.25],["claude-opus-5",1000000,128000,"text,image",1,null,5,25,0.5,6.25],["claude-sonnet-4-0",200000,64000,"text,image",1,null,3,15,0.3,3.75],["claude-sonnet-4-20250514",200000,64000,"text,image",1,null,3,15,0.3,3.75],["claude-sonnet-4-5",1000000,64000,"text,image",1,null,3,15,0.3,3.75],["claude-sonnet-4-5-20250929",1000000,64000,"text,image",1,null,3,15,0.3,3.75],["claude-sonnet-4-6",1000000,128000,"text,image",1,null,3,15,0.3,3.75],["claude-sonnet-4-6[1m]",1000000,64000,"text,image",1,"claude-sonnet-4-6",3,15,0.3,3.75],["claude-sonnet-5",1000000,128000,"text,image",1,null,2,10,0.2,2.5]], "azure-openai": [["gpt-4.1",1047576,32768,"text,image",0,null,2,8,0.5,0],["gpt-4o",128000,16384,"text,image",0,null,2.5,10,1.25,0],["gpt-4o-mini",128000,16384,"text,image",0,null,0.15,0.6,0.075,0],["o3",200000,100000,"text,image",1,null,2,8,0.5,0],["o3-mini",200000,100000,"text",1,null,1.1,4.4,0.55,0]], "cerebras": [["gemma-4-31b",131072,40960,"text,image",1,null,0.99,1.49,0,0],["gpt-oss-120b",131072,40960,"text",1,null,0.35,0.75,0,0],["llama3.1-8b",32000,8000,"text",0,null,0.1,0.1,0,0],["qwen-3-235b-a22b-instruct-2507",131000,32000,"text",0,null,0.6,1.2,0,0],["qwen-3-coder-480b",131072,32768,"text",0,null,0,0,0,0],["zai-glm-4.6",131072,32768,"text",0,null,0,0,0,0],["zai-glm-4.7",131072,40960,"text",1,null,2.25,2.75,2.25,0]], "deepseek": [["deepseek-v4-flash",1000000,384000,"text",1,null,0.14,0.28,0.0028,0],["deepseek-v4-pro",1000000,384000,"text",1,null,0.435,0.87,0.003625,0]], diff --git a/src/providers/registry.ts b/src/providers/registry.ts index e336c2f39..48eea873e 100644 --- a/src/providers/registry.ts +++ b/src/providers/registry.ts @@ -214,7 +214,7 @@ export type ProviderConfigSeed = Pick< // 260710 context refresh: Tier-2 evidence in // devlog/_plan/260710_provider_hardening/001_research_frontier.md. const ANTHROPIC_MODELS = ["claude-fable-5", "claude-sonnet-5", "claude-opus-5", "claude-opus-4-8", "claude-opus-4-7", "claude-opus-4-6", "claude-sonnet-4-6", "claude-haiku-4-5"]; -const ANTHROPIC_MODEL_CONTEXT_WINDOWS: Record = { "claude-sonnet-5": 1_000_000, "claude-fable-5": 1_000_000, "claude-opus-5": 1_000_000, "claude-opus-4-8": 1_000_000, "claude-haiku-4-5": 200_000 }; +const ANTHROPIC_MODEL_CONTEXT_WINDOWS: Record = { "claude-sonnet-5": 1_000_000, "claude-fable-5": 1_000_000, "claude-opus-5": 1_000_000, "claude-opus-4-8": 1_000_000, "claude-opus-4-7": 1_000_000, "claude-opus-4-6": 1_000_000, "claude-sonnet-4-6": 1_000_000, "claude-haiku-4-5": 200_000 }; const ZAI_GLM_52_MODELS = ["glm-5.2", "glm-5.2[1m]"]; const ZAI_GLM_52_REASONING_EFFORTS = ["low", "medium", "high", "xhigh", "max"]; diff --git a/tests/claude-agents-inject.test.ts b/tests/claude-agents-inject.test.ts index 623a193b2..182a233e4 100644 --- a/tests/claude-agents-inject.test.ts +++ b/tests/claude-agents-inject.test.ts @@ -3,6 +3,9 @@ import { mkdirSync, mkdtempSync, readdirSync, readFileSync, rmSync, symlinkSync, import { tmpdir } from "node:os"; import { join } from "node:path"; import { buildClaudeAgentDefs, injectClaudeAgentDefs, syncClaudeAgentDefs } from "../src/claude/agents-inject"; +import { buildClaudeContextWindows } from "../src/claude/context-windows"; +import { fetchProviderModels } from "../src/codex/catalog/provider-fetch"; +import { OAUTH_PROVIDERS } from "../src/oauth"; import type { OcxConfig } from "../src/types"; const dirs: string[] = []; @@ -24,24 +27,161 @@ function generatedBodies(config: OcxConfig, dir: string): string[] { } describe("buildClaudeAgentDefs (devlog 070 + audit 071)", () => { - test("roster + pinned self from settings.json; [1m] marking; name collision suffix", () => { + test("roster + pinned self mark only authoritative 1M windows; name collision suffix", () => { const windows = { "claude-ocx-native--gpt-5.6-sol": 372_000, "claude-ocx-cursor--gpt-5.6-sol": 1_000_000 }; const dir = tempDir(); writeFileSync(join(dir, "settings.json"), JSON.stringify({ model: "claude-ocx-native--gpt-5.6-sol[1m]" })); const defs = buildClaudeAgentDefs(cfg({ subagentModels: ["gpt-5.6-sol", "cursor/gpt-5.6-sol"], - claudeCode: {}, + claudeCode: { autoContext: true }, }), windows, dir); const byName = Object.fromEntries(defs.map(d => [d.name, d])); - expect(byName["ocx-gpt-5-6-sol"]!.model).toBe("claude-ocx-native--gpt-5.6-sol[1m]"); // 372k >= 350k default + expect(byName["ocx-gpt-5-6-sol"]!.model).toBe("claude-ocx-native--gpt-5.6-sol"); expect(byName["ocx-gpt-5-6-sol-2"]!.model).toBe("claude-ocx-cursor--gpt-5.6-sol[1m]"); // collision suffix - // Self pins the picker-saved default (inherit disproven live — devlog 072). - expect(byName["ocx-self"]!.model).toBe("claude-ocx-native--gpt-5.6-sol[1m]"); + // Self pins the picker-saved default but cannot inherit an unsafe auto-context marker. + expect(byName["ocx-self"]!.model).toBe("claude-ocx-native--gpt-5.6-sol"); expect(defs).toHaveLength(3); // Dispatcher directive (live repro: model:"fable" override broke inherit). for (const d of defs) expect(d.description).toContain("`model` argument is ignored"); }); + test("generated profiles retain catalog-derived 1M markers for Claude 4.6 and 4.7", async () => { + const anthropic = structuredClone(OAUTH_PROVIDERS.anthropic.providerConfig); + anthropic.liveModels = false; + const config = cfg({ + defaultProvider: "anthropic", + providers: { anthropic }, + subagentModels: [ + "anthropic/claude-sonnet-4-6", + "anthropic/claude-opus-4-6", + "anthropic/claude-opus-4-7", + ], + }); + const catalog = await fetchProviderModels("anthropic", anthropic, 0); + const windows = buildClaudeContextWindows([], catalog); + const defs = buildClaudeAgentDefs(config, windows, tempDir()); + const models = Object.fromEntries(defs.map(def => [def.name, def.model])); + + expect(models).toEqual({ + "ocx-claude-sonnet-4-6": "claude-sonnet-4-6[1m]", + "ocx-claude-opus-4-6": "claude-opus-4-6[1m]", + "ocx-claude-opus-4-7": "claude-opus-4-7[1m]", + }); + }); + + test("generated profiles preserve registry-routed [1m] selector ids for roster and self", async () => { + const kimi = structuredClone(OAUTH_PROVIDERS.kimi.providerConfig); + kimi.liveModels = false; + const config = cfg({ + defaultProvider: "kimi", + providers: { kimi }, + subagentModels: ["kimi/k3[1m]"], + }); + const catalog = await fetchProviderModels("kimi", kimi, 0); + const windows = buildClaudeContextWindows([], catalog); + const dir = tempDir(); + writeFileSync(join(dir, "settings.json"), JSON.stringify({ model: "claude-ocx-kimi--k3[1m]" })); + const defs = buildClaudeAgentDefs(config, windows, dir); + const models = Object.fromEntries(defs.map(def => [def.name, def.model])); + + expect(windows["claude-ocx-kimi--k3"]).toBe(262_144); + expect(windows["claude-ocx-kimi--k3[1m]"]).toBe(1_048_576); + expect(models).toEqual({ + "ocx-k3-1m": "claude-ocx-kimi--k3[1m]", + "ocx-self": "claude-ocx-kimi--k3[1m]", + }); + + const cappedCatalog = await fetchProviderModels("kimi", kimi, 0, 350_000); + const cappedWindows = buildClaudeContextWindows([], cappedCatalog); + const cappedDir = tempDir(); + writeFileSync(join(cappedDir, "settings.json"), JSON.stringify({ model: "claude-ocx-kimi--k3[1m]" })); + const cappedDefs = buildClaudeAgentDefs(config, cappedWindows, cappedDir); + + expect(cappedWindows["claude-ocx-kimi--k3[1m]"]).toBe(350_000); + expect(Object.fromEntries(cappedDefs.map(def => [def.name, def.model]))).toEqual({ + "ocx-k3-1m": "claude-ocx-kimi--k3", + "ocx-self": "claude-ocx-kimi--k3", + }); + + const exactCapWins = { ...cappedWindows, "claude-ocx-kimi--k3": 1_048_576 }; + const exactCapDefs = buildClaudeAgentDefs(config, exactCapWins, cappedDir); + expect(Object.fromEntries(exactCapDefs.map(def => [def.name, def.model]))).toEqual({ + "ocx-k3-1m": "claude-ocx-kimi--k3", + "ocx-self": "claude-ocx-kimi--k3", + }); + }); + + test("generated profiles normalize marker case before exact context lookup", async () => { + const kimi = structuredClone(OAUTH_PROVIDERS.kimi.providerConfig); + kimi.liveModels = false; + const config = cfg({ + defaultProvider: "kimi", + providers: { kimi }, + subagentModels: ["kimi/k3[1M]"], + }); + const catalog = await fetchProviderModels("kimi", kimi, 0); + const windows = buildClaudeContextWindows([], catalog); + const dir = tempDir(); + const upperSelector = "claude-ocx-kimi--k3[1M]"; + const lowerSelector = "claude-ocx-kimi--k3[1m]"; + const bareSelector = "claude-ocx-kimi--k3"; + writeFileSync(join(dir, "settings.json"), JSON.stringify({ model: upperSelector })); + const modelMap = (contextWindows: Record) => Object.fromEntries( + buildClaudeAgentDefs(config, contextWindows, dir).map(def => [def.name, def.model]), + ); + + expect(modelMap(windows)).toEqual({ + "ocx-k3-1m": upperSelector, + "ocx-self": upperSelector, + }); + expect(modelMap({ ...windows, [bareSelector]: 1_048_576, [lowerSelector]: 350_000 })).toEqual({ + "ocx-k3-1m": bareSelector, + "ocx-self": bareSelector, + }); + expect(modelMap({ ...windows, [upperSelector]: 350_000 })).toEqual({ + "ocx-k3-1m": bareSelector, + "ocx-self": bareSelector, + }); + }); + + test("generated profiles preserve marked catalog selectors when context metadata is incomplete", () => { + const anthropic = structuredClone(OAUTH_PROVIDERS.anthropic.providerConfig); + anthropic.liveModels = false; + const config = cfg({ + defaultProvider: "anthropic", + providers: { anthropic }, + subagentModels: [ + "anthropic/claude-opus-4-6[1m]", + "anthropic/claude-opus-4-7[1m]", + ], + }); + const catalog = [ + { provider: "anthropic", id: "claude-opus-4-6[1m]" }, + { provider: "anthropic", id: "claude-opus-4-7[1m]" }, + ]; + const windows = buildClaudeContextWindows([], catalog); + const dir = tempDir(); + writeFileSync(join(dir, "settings.json"), JSON.stringify({ model: "claude-opus-4-7[1m]" })); + const models = (contextWindows: Record) => Object.fromEntries( + buildClaudeAgentDefs(config, contextWindows, dir).map(def => [def.name, def.model]), + ); + + expect(windows).toEqual({}); + expect(models(windows)).toEqual({ + "ocx-claude-opus-4-6-1m": "claude-opus-4-6[1m]", + "ocx-claude-opus-4-7-1m": "claude-opus-4-7[1m]", + "ocx-self": "claude-opus-4-7[1m]", + }); + expect(models({ + "claude-opus-4-6[1m]": 200_000, + "claude-opus-4-7[1m]": 200_000, + })).toEqual({ + "ocx-claude-opus-4-6-1m": "claude-opus-4-6", + "ocx-claude-opus-4-7-1m": "claude-opus-4-7", + "ocx-self": "claude-opus-4-7", + }); + }); + test("placeholder guidance recommends haiku, never sonnet (issue #252)", () => { const dir = tempDir(); writeFileSync(join(dir, "settings.json"), JSON.stringify({ model: "claude-ocx-native--gpt-5.6-sol" })); diff --git a/tests/codex-catalog.test.ts b/tests/codex-catalog.test.ts index 650d60676..3a00105a6 100644 --- a/tests/codex-catalog.test.ts +++ b/tests/codex-catalog.test.ts @@ -2207,16 +2207,16 @@ describe("Codex catalog routed normalization", () => { expect(models).toEqual([]); }); - test("anthropic sonnet 4.6 uses the 200k opencodex catalog cap", () => { + test("anthropic sonnet 4.6 keeps the upstream 1M context window", () => { const entries = buildCatalogEntries(nativeTemplate(), [], [ { provider: "anthropic", id: "claude-sonnet-4-6" }, ]); const routed = entries.find(e => e.slug === "anthropic/claude-sonnet-4-6"); - expect(routed?.context_window).toBe(200_000); - expect(routed?.max_context_window).toBe(200_000); - expect(routed?.auto_compact_token_limit).toBe(180_000); - expect(getJawcodeModelMetadata("anthropic", "claude-sonnet-4-6")?.contextWindow).toBe(200_000); + expect(routed?.context_window).toBe(1_000_000); + expect(routed?.max_context_window).toBe(1_000_000); + expect(routed?.auto_compact_token_limit).toBe(900_000); + expect(getJawcodeModelMetadata("anthropic", "claude-sonnet-4-6")?.contextWindow).toBe(1_000_000); }); test("routed entries resolve jawcode provider aliases", () => { diff --git a/tests/provider-registry-parity.test.ts b/tests/provider-registry-parity.test.ts index 1df1ea442..a4aaefbd3 100644 --- a/tests/provider-registry-parity.test.ts +++ b/tests/provider-registry-parity.test.ts @@ -607,6 +607,12 @@ describe("provider registry parity", () => { expect(OAUTH_PROVIDERS.anthropic.providerConfig.models).toContain("claude-sonnet-5"); expect(OAUTH_PROVIDERS.anthropic.providerConfig.models).toContain("claude-fable-5"); expect(OAUTH_PROVIDERS.anthropic.providerConfig.modelContextWindows?.["claude-sonnet-5"]).toBe(1_000_000); + expect(OAUTH_PROVIDERS.anthropic.providerConfig.modelContextWindows?.["claude-opus-4-7"]).toBe(1_000_000); + expect(OAUTH_PROVIDERS.anthropic.providerConfig.modelContextWindows?.["claude-opus-4-6"]).toBe(1_000_000); + expect(OAUTH_PROVIDERS.anthropic.providerConfig.modelContextWindows?.["claude-sonnet-4-6"]).toBe(1_000_000); + for (const model of OAUTH_PROVIDERS.anthropic.providerConfig.models ?? []) { + expect(OAUTH_PROVIDERS.anthropic.providerConfig.modelContextWindows?.[model]).toBeGreaterThan(0); + } expect(OAUTH_PROVIDERS.xai.providerConfig.defaultModel).toBe("grok-4.5"); expect(OAUTH_PROVIDERS.xai.providerConfig.liveModels).toBe(true); expect(OAUTH_PROVIDERS.xai.providerConfig.models).toContain("grok-4.5");