From caec11513823f821a2cdcaf02c9d43bd506e24d8 Mon Sep 17 00:00:00 2001 From: xinweigao Date: Sat, 8 Aug 2026 00:21:06 +0800 Subject: [PATCH 1/4] fix(catalog): restore DeepSeek V4 context window on routed rebuilds DeepSeek routed models were rebuilt with a 128k context window after every sync because the registry entry had no jawcodeBundle, so the catalog metadata restore step could not resolve the provider and the strict-fields fallback overwrote the window. Users who saved the provider under a title-cased key ("DeepSeek") also missed the alias table, which was case-sensitive. Add jawcodeBundle: "deepseek" to the registry entry and fold provider case in resolveJawcodeProvider, then regenerate the metadata snapshot with the official 1,048,576-token window for both V4 models. Routed deepseek entries now restore 1,048,576 instead of the 128k fallback. --- scripts/generate-model-metadata.ts | 2 +- src/providers/registry.ts | 8 +++++++- tests/codex-catalog.test.ts | 20 ++++++++++++++++++++ tests/provider-registry-parity.test.ts | 8 ++++++-- 4 files changed, 34 insertions(+), 4 deletions(-) diff --git a/scripts/generate-model-metadata.ts b/scripts/generate-model-metadata.ts index edd8d35609..af13fed711 100644 --- a/scripts/generate-model-metadata.ts +++ b/scripts/generate-model-metadata.ts @@ -105,7 +105,7 @@ for (const provider of allowedProviders) { lines.push("};"); lines.push(""); lines.push("export function resolveMetadataProvider(provider: string): string | undefined {"); -lines.push(" return PROVIDER_ALIASES[provider];"); +lines.push(" return PROVIDER_ALIASES[provider] ?? PROVIDER_ALIASES[provider.toLowerCase()];"); lines.push("}"); lines.push(""); lines.push("export function getModelMetadata(provider: string, modelId: string): ModelMetadata | undefined {"); diff --git a/src/providers/registry.ts b/src/providers/registry.ts index 375c4ada76..590c0ffcc4 100644 --- a/src/providers/registry.ts +++ b/src/providers/registry.ts @@ -1299,11 +1299,17 @@ export const PROVIDER_REGISTRY: readonly ProviderRegistryEntry[] = [ adapter: "openai-chat", authKind: "key", dashboardUrl: "https://platform.deepseek.com/api_keys", + // Route DeepSeek's own catalog bundle so routed rebuilds restore the official + // context window from jawcode metadata instead of falling back to the 128k + // strict-fields default (jawcode models.json, verified 2026-08-08). + jawcodeBundle: "deepseek", // deepseek-chat/deepseek-reasoner are upstream-deprecated at 2026-07-24 15:59 UTC; // kept until then. Evidence: devlog/_plan/260710_provider_hardening/002_research_cn.md. models: ["deepseek-chat", "deepseek-reasoner", ...DEEPSEEK_THINKING_MODELS], defaultModel: "deepseek-v4-flash", - modelContextWindows: { "deepseek-v4-flash": 1_000_000, "deepseek-v4-pro": 1_000_000 }, + // Official DeepSeek Codex setup (codex-deepseek-setup.sh) advertises 1,048,576 + // for both V4 models; the older 1,000,000 figure was a rounded approximation. + modelContextWindows: { "deepseek-v4-flash": 1_048_576, "deepseek-v4-pro": 1_048_576 }, // DeepSeek documents V4-Flash as a native Responses API model adapted for Codex. The // API id is `deepseek-v4-flash`; `DeepSeek-V4-Flash-0731` is a release/version label. modelWireDefaults: { diff --git a/tests/codex-catalog.test.ts b/tests/codex-catalog.test.ts index a65fe0417d..12cba1b048 100644 --- a/tests/codex-catalog.test.ts +++ b/tests/codex-catalog.test.ts @@ -2826,6 +2826,26 @@ describe("Codex catalog routed normalization", () => { expect(routed?.input_modalities).toEqual(["text"]); }); + test("DeepSeek routed entries restore the official context window from jawcode metadata", () => { + const entries = buildCatalogEntries(nativeTemplate(), [], [ + { provider: "deepseek", id: "deepseek-v4-flash" }, + { provider: "deepseek", id: "deepseek-v4-pro" }, + ]); + const flash = entries.find(e => e.slug === "deepseek/deepseek-v4-flash"); + const pro = entries.find(e => e.slug === "deepseek/deepseek-v4-pro"); + + for (const routed of [flash, pro]) { + expect(routed?.context_window).toBe(1_048_576); + expect(routed?.max_context_window).toBe(1_048_576); + expect(routed?.auto_compact_token_limit).toBe(943_718); // floor(1048576 * 0.9) + expect(routed?.input_modalities).toEqual(["text"]); + } + // The catalog rebuild falls back to the strict 128k default when metadata is missing, + // so this assertion proves the jawcode bundle lookup actually ran. + expect(resolveMetadataProvider("deepseek")).toBe("deepseek"); + expect(getModelMetadata("deepseek", "deepseek-v4-flash")?.contextWindow).toBe(1_048_576); + }); + test("provider context-cap applies before jawcode catalog metadata reaches Codex", () => { const entries = buildCatalogEntries(nativeTemplate(), [], [ { provider: "opencode-go", id: "deepseek-v4-pro", contextCap: 350_000, contextCapped: false }, diff --git a/tests/provider-registry-parity.test.ts b/tests/provider-registry-parity.test.ts index 2bef5e6968..0b24e63a4c 100644 --- a/tests/provider-registry-parity.test.ts +++ b/tests/provider-registry-parity.test.ts @@ -234,8 +234,8 @@ describe("provider registry parity", () => { baseUrl: "https://api.deepseek.com", defaultModel: "deepseek-v4-flash", modelContextWindows: { - "deepseek-v4-flash": 1_000_000, - "deepseek-v4-pro": 1_000_000, + "deepseek-v4-flash": 1_048_576, + "deepseek-v4-pro": 1_048_576, }, }); @@ -761,6 +761,7 @@ describe("provider registry parity", () => { "google-antigravity": "google", "antigravity": "google", "gemini-antigravity": "google", + deepseek: "deepseek", moonshot: "moonshot", minimax: "minimax", "minimax-cn": "minimax", @@ -769,6 +770,9 @@ describe("provider registry parity", () => { }); expect(resolveMetadataProvider("gemini")).toBe("google"); expect(resolveMetadataProvider("minimax-cn")).toBe("minimax"); + expect(resolveMetadataProvider("deepseek")).toBe("deepseek"); + // User-saved provider keys can be title-cased ("DeepSeek"); alias lookup folds case. + expect(resolveMetadataProvider("DeepSeek")).toBe("deepseek"); }); test("legacy azure adapter spelling remains accepted", () => { From 7a8756cc6d0c92830b77461107e78f3f0d46616f Mon Sep 17 00:00:00 2001 From: xinweigao Date: Sat, 8 Aug 2026 10:17:08 +0800 Subject: [PATCH 2/4] fix(providers): reconcile DeepSeek deprecation note with retired aliases deepseek-chat/deepseek-reasoner were deprecated upstream on 2026-07-24 15:59 UTC and official identifiers are now deepseek-v4-flash/deepseek-v4-pro. The aliases stay in the registry only as compatibility aliases so existing saved configs and requests keep validating and routing; the comment now documents that post-deprecation reason instead of a stale future-dated note. --- src/providers/registry.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/providers/registry.ts b/src/providers/registry.ts index 590c0ffcc4..b9d6d50cbb 100644 --- a/src/providers/registry.ts +++ b/src/providers/registry.ts @@ -1303,8 +1303,12 @@ export const PROVIDER_REGISTRY: readonly ProviderRegistryEntry[] = [ // context window from jawcode metadata instead of falling back to the 128k // strict-fields default (jawcode models.json, verified 2026-08-08). jawcodeBundle: "deepseek", - // deepseek-chat/deepseek-reasoner are upstream-deprecated at 2026-07-24 15:59 UTC; - // kept until then. Evidence: devlog/_plan/260710_provider_hardening/002_research_cn.md. + // deepseek-chat/deepseek-reasoner were deprecated upstream on 2026-07-24 15:59 UTC; + // official identifiers are now deepseek-v4-flash / deepseek-v4-pro. They stay in + // the list only as compatibility aliases so existing saved configs and requests + // keep validating and routing (they previously mapped to v4-flash; devlog + // _plan/260710_provider_hardening/002_research_cn.md). The current offerings are + // the V4 ids — defaultModel and the model-specific wiring above use them. models: ["deepseek-chat", "deepseek-reasoner", ...DEEPSEEK_THINKING_MODELS], defaultModel: "deepseek-v4-flash", // Official DeepSeek Codex setup (codex-deepseek-setup.sh) advertises 1,048,576 From 8a804281b3fab678e0f728185e5be9133bbb6e04 Mon Sep 17 00:00:00 2001 From: xinweigao Date: Sat, 8 Aug 2026 18:36:31 +0800 Subject: [PATCH 3/4] fix(catalog): restore DeepSeek V4 context window via vendored metadata pipeline The metadata pipeline was de-jawcoded upstream: the bundled snapshot now lives at scripts/model-metadata.source.json and generates src/generated/model-metadata.ts. Move the DeepSeek V4 context-window fix onto that pipeline (1048576 for flash and pro per DeepSeek's official Codex setup docs) and regenerate the committed output so routed rebuilds stop falling back to the 128k strict-fields default. --- scripts/model-metadata.source.json | 6 +++--- src/generated/model-metadata.ts | 5 +++-- src/providers/registry.ts | 7 ++++--- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/scripts/model-metadata.source.json b/scripts/model-metadata.source.json index 7fdc723220..e59a4e525c 100644 --- a/scripts/model-metadata.source.json +++ b/scripts/model-metadata.source.json @@ -9439,7 +9439,7 @@ "cacheRead": 0.0028, "cacheWrite": 0 }, - "contextWindow": 1000000, + "contextWindow": 1048576, "maxTokens": 384000, "compat": { "supportsDeveloperRole": false, @@ -9485,7 +9485,7 @@ "cacheRead": 0.003625, "cacheWrite": 0 }, - "contextWindow": 1000000, + "contextWindow": 1048576, "maxTokens": 384000, "compat": { "supportsDeveloperRole": false, @@ -85724,4 +85724,4 @@ } } } -} \ No newline at end of file +} diff --git a/src/generated/model-metadata.ts b/src/generated/model-metadata.ts index 78f305dd88..d58b66d09f 100644 --- a/src/generated/model-metadata.ts +++ b/src/generated/model-metadata.ts @@ -27,6 +27,7 @@ const PROVIDER_ALIASES: Record = { "google-antigravity": "google", "antigravity": "google", "gemini-antigravity": "google", + "deepseek": "deepseek", "moonshot": "moonshot", "zhipu-bigmodel": "zai", "zhipu-bigmodel-coding": "zai", @@ -40,7 +41,7 @@ const DATA: Record = { "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]], + "deepseek": [["deepseek-v4-flash",1048576,384000,"text",1,null,0.14,0.28,0.0028,0],["deepseek-v4-pro",1048576,384000,"text",1,null,0.435,0.87,0.003625,0]], "google": [["deep-research-max-preview-04-2026",131072,65536,"text,image",1,null,2,12,0.2,0],["deep-research-preview-04-2026",131072,65536,"text,image",1,null,2,12,0.2,0],["gemini-1.5-flash",1000000,8192,"text,image",0,null,0.075,0.3,0.01875,0],["gemini-1.5-flash-8b",1000000,8192,"text,image",0,null,0.0375,0.15,0.01,0],["gemini-1.5-pro",1000000,8192,"text,image",0,null,1.25,5,0.3125,0],["gemini-2.0-flash",1048576,8192,"text,image",0,null,0.1,0.4,0.025,0],["gemini-2.0-flash-lite",1048576,8192,"text,image",0,null,0.075,0.3,0,0],["gemini-2.5-computer-use-preview-10-2025",131072,65536,"text,image",1,null,1.25,10,0,0],["gemini-2.5-flash",1048576,65536,"text,image",1,null,0.3,2.5,0.03,0],["gemini-2.5-flash-lite",1048576,65536,"text,image",1,null,0.1,0.4,0.01,0],["gemini-2.5-flash-lite-preview-06-17",1048576,65536,"text,image",1,null,0.1,0.4,0.025,0],["gemini-2.5-flash-lite-preview-09-2025",1048576,65536,"text,image",1,null,0.1,0.4,0.025,0],["gemini-2.5-flash-preview-04-17",1048576,65536,"text,image",1,null,0.15,0.6,0.0375,0],["gemini-2.5-flash-preview-05-20",1048576,65536,"text,image",1,null,0.15,0.6,0.0375,0],["gemini-2.5-flash-preview-09-2025",1048576,65536,"text,image",1,null,0.3,2.5,0.075,0],["gemini-2.5-pro",1048576,65536,"text,image",1,null,1.25,10,0.125,0],["gemini-2.5-pro-preview-05-06",1048576,65536,"text,image",1,null,1.25,10,0.31,0],["gemini-2.5-pro-preview-06-05",1048576,65536,"text,image",1,null,1.25,10,0.31,0],["gemini-3-flash-preview",1048576,65536,"text,image",1,null,0.5,3,0.05,0],["gemini-3-pro-preview",1048576,65536,"text,image",1,null,2,12,0.2,0],["gemini-3.1-flash-lite",1048576,65536,"text,image",1,null,0.25,1.5,0.025,0],["gemini-3.1-flash-lite-image",65536,65536,"text,image",1,null,0.25,30,0,0],["gemini-3.1-flash-lite-preview",1048576,65536,"text,image",1,null,0.25,1.5,0.025,0],["gemini-3.1-flash-live-preview",131072,65536,"text,image",1,null,0.75,4.5,0,0],["gemini-3.1-pro-preview",1048576,65536,"text,image",1,null,2,12,0.2,0],["gemini-3.1-pro-preview-customtools",1048576,65536,"text,image",1,null,2,12,0.2,0],["gemini-3.5-flash",1048576,65536,"text,image",1,null,1.5,9,0.15,0],["gemini-3.5-flash-lite",1048576,65536,"text,image",1,null,0.3,2.5,0.03,0],["gemini-3.6-flash",1048576,65536,"text,image",1,null,1.5,7.5,0.15,0],["gemini-flash-latest",1048576,65536,"text,image",1,null,1.5,9,0.15,0],["gemini-flash-lite-latest",1048576,65536,"text,image",1,null,0.25,1.5,0.025,0],["gemini-live-2.5-flash",128000,8000,"text,image",1,null,0.5,2,0,0],["gemini-live-2.5-flash-preview-native-audio",131072,65536,"text",1,null,0.5,2,0,0],["gemini-robotics-er-1.6-preview",131072,65536,"text,image",1,null,1,5,0,0],["gemma-3-27b-it",131072,8192,"text,image",0,null,0,0,0,0],["gemma-4-26b",256000,8192,"text,image",1,null,0,0,0,0],["gemma-4-26b-a4b-it",262144,32768,"text,image",1,null,0,0,0,0],["gemma-4-26b-it",256000,8192,"text,image",1,null,0,0,0,0],["gemma-4-31b",256000,8192,"text,image",1,null,0,0,0,0],["gemma-4-31b-it",262144,32768,"text,image",1,null,0,0,0,0],["gemma-4-E2B-it",131072,8192,"text,image",1,null,0,0,0,0],["gemma-4-E4B-it",131072,8192,"text,image",1,null,0,0,0,0]], "minimax": [["MiniMax-M2",196608,128000,"text",1,null,0.3,1.2,0,0],["MiniMax-M2.1",204800,131072,"text",1,null,0.3,1.2,0,0],["MiniMax-M2.5",204800,131072,"text",1,null,0.3,1.2,0.03,0.375],["MiniMax-M2.5-highspeed",204800,131072,"text",1,null,0.6,2.4,0.06,0.375],["MiniMax-M2.5-lightning",204800,32000,"text",1,null,0.3,2.4,0,0],["MiniMax-M2.7",204800,131072,"text",1,null,0.3,1.2,0.06,0.375],["MiniMax-M2.7-highspeed",204800,131072,"text",1,null,0.6,2.4,0.06,0.375],["minimax-m3",512000,128000,"text,image",1,null,0.6,2.4,0.12,0],["MiniMax-M3",1000000,128000,"text,image,video",1,null,0.3,1.2,0.06,0]], "mistral": [["codestral-latest",256000,4096,"text",0,null,0.3,0.9,0,0],["devstral-2512",262144,262144,"text",0,null,0.4,2,0,0],["devstral-latest",262144,262144,"text",0,null,0.4,2,0,0],["devstral-medium-2507",128000,128000,"text",0,null,0.4,2,0,0],["devstral-medium-latest",262144,262144,"text",0,null,0.4,2,0,0],["devstral-small-2505",128000,128000,"text",0,null,0.1,0.3,0,0],["devstral-small-2507",128000,128000,"text",0,null,0.1,0.3,0,0],["labs-devstral-small-2512",256000,256000,"text,image",0,null,0,0,0,0],["magistral-medium-latest",128000,16384,"text",1,null,2,5,0,0],["magistral-small",128000,128000,"text",1,null,0.5,1.5,0,0],["ministral-3b-latest",128000,128000,"text",0,null,0.04,0.04,0,0],["ministral-8b-latest",128000,128000,"text",0,null,0.1,0.1,0,0],["mistral-large-2411",131072,16384,"text",0,null,2,6,0,0],["mistral-large-2512",262144,262144,"text,image",0,null,0.5,1.5,0,0],["mistral-large-latest",262144,262144,"text,image",0,null,0.5,1.5,0,0],["mistral-medium-2505",131072,131072,"text,image",0,null,0.4,2,0,0],["mistral-medium-2508",262144,262144,"text,image",0,null,0.4,2,0,0],["mistral-medium-2604",262144,262144,"text,image",1,null,1.5,7.5,0,0],["mistral-medium-latest",262144,262144,"text,image",1,null,1.5,7.5,0,0],["mistral-nemo",128000,128000,"text",0,null,0.15,0.15,0,0],["mistral-small-2506",128000,16384,"text,image",0,null,0.1,0.3,0,0],["mistral-small-2603",256000,256000,"text,image",1,null,0.15,0.6,0,0],["mistral-small-latest",256000,256000,"text,image",1,null,0.15,0.6,0,0],["open-mistral-7b",8000,8000,"text",0,null,0.25,0.25,0,0],["open-mistral-nemo",128000,128000,"text",0,null,0.15,0.15,0,0],["open-mixtral-8x22b",64000,64000,"text",0,null,2,6,0,0],["open-mixtral-8x7b",32000,32000,"text",0,null,0.7,0.7,0,0],["pixtral-12b",128000,128000,"text,image",0,null,0.15,0.15,0,0],["pixtral-large-latest",128000,128000,"text,image",0,null,2,6,0,0]], @@ -54,7 +55,7 @@ const DATA: Record = { }; export function resolveMetadataProvider(provider: string): string | undefined { - return PROVIDER_ALIASES[provider]; + return PROVIDER_ALIASES[provider] ?? PROVIDER_ALIASES[provider.toLowerCase()]; } export function getModelMetadata(provider: string, modelId: string): ModelMetadata | undefined { diff --git a/src/providers/registry.ts b/src/providers/registry.ts index b9d6d50cbb..6568162538 100644 --- a/src/providers/registry.ts +++ b/src/providers/registry.ts @@ -1300,14 +1300,15 @@ export const PROVIDER_REGISTRY: readonly ProviderRegistryEntry[] = [ authKind: "key", dashboardUrl: "https://platform.deepseek.com/api_keys", // Route DeepSeek's own catalog bundle so routed rebuilds restore the official - // context window from jawcode metadata instead of falling back to the 128k - // strict-fields default (jawcode models.json, verified 2026-08-08). + // context window from the vendored model-metadata bundle instead of falling + // back to the 128k strict-fields default (scripts/model-metadata.source.json, + // verified 2026-08-08). jawcodeBundle: "deepseek", // deepseek-chat/deepseek-reasoner were deprecated upstream on 2026-07-24 15:59 UTC; // official identifiers are now deepseek-v4-flash / deepseek-v4-pro. They stay in // the list only as compatibility aliases so existing saved configs and requests // keep validating and routing (they previously mapped to v4-flash; devlog - // _plan/260710_provider_hardening/002_research_cn.md). The current offerings are + // _fin/260710_provider_hardening/002_research_cn.md). The current offerings are // the V4 ids — defaultModel and the model-specific wiring above use them. models: ["deepseek-chat", "deepseek-reasoner", ...DEEPSEEK_THINKING_MODELS], defaultModel: "deepseek-v4-flash", From 7f536489186e7b811d7cd0ea97097d72b16e8d2c Mon Sep 17 00:00:00 2001 From: xinweigao Date: Sat, 8 Aug 2026 18:49:59 +0800 Subject: [PATCH 4/4] fix(catalog): restore DeepSeek V4 rows when /v1/models returns an empty list Add deepseek to the catalog augmentation allowlist so metadata-sourced V4 rows are appended when live discovery returns nothing, and cover the empty-discovery path with a regression test asserting the official 1,048,576 context window, auto-compact limit, and text-only input. --- src/codex/catalog/parsing.ts | 2 +- tests/codex-catalog.test.ts | 21 +++++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/codex/catalog/parsing.ts b/src/codex/catalog/parsing.ts index a4cc9e0730..fa0028759a 100644 --- a/src/codex/catalog/parsing.ts +++ b/src/codex/catalog/parsing.ts @@ -126,7 +126,7 @@ export type RawEntry = Record; export type RawCatalog = { models?: RawEntry[]; [k: string]: unknown }; -export const JAWCODE_CATALOG_AUGMENT_PROVIDERS = new Set(["opencode-go"]); +export const JAWCODE_CATALOG_AUGMENT_PROVIDERS = new Set(["opencode-go", "deepseek"]); export const ROUTED_MODEL_COMPATIBILITY_EXCLUSIONS = new Set([ // Issue #82: Zen Go /models advertises HY3, but Console Go rejects it as outside the lite list. diff --git a/tests/codex-catalog.test.ts b/tests/codex-catalog.test.ts index 12cba1b048..a468354634 100644 --- a/tests/codex-catalog.test.ts +++ b/tests/codex-catalog.test.ts @@ -2846,6 +2846,27 @@ describe("Codex catalog routed normalization", () => { expect(getModelMetadata("deepseek", "deepseek-v4-flash")?.contextWindow).toBe(1_048_576); }); + test("DeepSeek catalog sync appends V4 rows missing from /v1/models", () => { + const models = augmentRoutedModelsWithMetadata([], ["deepseek"]); + const slugs = new Set(models.map(m => `${m.provider}/${m.id}`)); + + expect(slugs.has("deepseek/deepseek-v4-flash")).toBe(true); + expect(slugs.has("deepseek/deepseek-v4-pro")).toBe(true); + for (const model of models) { + expect(model.contextWindow).toBe(1_048_576); + expect(model.inputModalities).toEqual(["text"]); + } + + const entries = buildCatalogEntries(nativeTemplate(), [], models); + for (const id of ["deepseek-v4-flash", "deepseek-v4-pro"]) { + const routed = entries.find(e => e.slug === `deepseek/${id}`); + expect(routed?.context_window).toBe(1_048_576); + expect(routed?.max_context_window).toBe(1_048_576); + expect(routed?.auto_compact_token_limit).toBe(943_718); // floor(1048576 * 0.9) + expect(routed?.input_modalities).toEqual(["text"]); + } + }); + test("provider context-cap applies before jawcode catalog metadata reaches Codex", () => { const entries = buildCatalogEntries(nativeTemplate(), [], [ { provider: "opencode-go", id: "deepseek-v4-pro", contextCap: 350_000, contextCapped: false },