From 67441e2eec2791542a765c050851fbb88be6502d Mon Sep 17 00:00:00 2001 From: roboomp Date: Tue, 4 Aug 2026 03:32:06 +0000 Subject: [PATCH] fix(config): bumped openai-models-list discovery cache namespace Warm context-v2 rows cached before server input-modality parsing pinned vision-capable ids at input: ["text"] until a forced refresh. Bump the namespace to context-v3 so the modality fix takes effect on the next online-if-uncached refresh, and add a regression proving v2 rows are orphaned. --- .../coding-agent/src/config/model-registry.ts | 5 +- .../coding-agent/test/model-registry.test.ts | 49 ++++++++++++++++++- 2 files changed, 52 insertions(+), 2 deletions(-) diff --git a/packages/coding-agent/src/config/model-registry.ts b/packages/coding-agent/src/config/model-registry.ts index 1662b2fed..45a87627b 100644 --- a/packages/coding-agent/src/config/model-registry.ts +++ b/packages/coding-agent/src/config/model-registry.ts @@ -1715,7 +1715,10 @@ export class ModelRegistry { return resolveOllamaModelCacheProviderId(providerConfig.provider, providerConfig.baseUrl); } if (providerConfig.discovery.type === "openai-models-list") { - return `${providerConfig.provider}:openai-models-list-context-v2`; + // context-v3 invalidates rows cached before server-advertised input + // modalities were parsed from `/v1/models`; warm v2 rows pinned + // vision-capable ids at `input: ["text"]` until a forced refresh. + return `${providerConfig.provider}:openai-models-list-context-v3`; } if (providerConfig.discovery.type === "litellm") { // rich-v2 invalidates rows cached before reseller usage-suffix stripping diff --git a/packages/coding-agent/test/model-registry.test.ts b/packages/coding-agent/test/model-registry.test.ts index 87f1f7247..591c3cb53 100644 --- a/packages/coding-agent/test/model-registry.test.ts +++ b/packages/coding-agent/test/model-registry.test.ts @@ -1876,6 +1876,7 @@ describe("ModelRegistry", () => { let vertexStale: ModelRegistry; let litellmStaleNamespaceCache: ModelRegistry; let litellmCurrentNamespaceCache: ModelRegistry; + let openaiModelsListStaleNamespaceCache: ModelRegistry; const vertexProjectModel = () => buildModel({ id: "zai-org/glm-4.7-maas", @@ -2101,7 +2102,7 @@ describe("ModelRegistry", () => { { seedCache: dbPath => writeModelCache( - "cached-compact-proxy:openai-models-list-context-v2", + "cached-compact-proxy:openai-models-list-context-v3", Date.now(), [ buildModel({ @@ -2171,6 +2172,45 @@ describe("ModelRegistry", () => { dbPath, ), }); + openaiModelsListStaleNamespaceCache = readonlyRegistry( + { + providers: { + "stale-openai-proxy": { + baseUrl: "https://stale-proxy.example.com/v1", + apiKey: "TEST_KEY", + api: "openai-completions", + discovery: { type: "openai-models-list" }, + models: [], + }, + }, + }, + { + // Row under the retired pre-modality namespace; the context-v3 + // bump must orphan it instead of serving the stale text-only row. + seedCache: dbPath => + writeModelCache( + "stale-openai-proxy:openai-models-list-context-v2", + Date.now(), + [ + buildModel({ + id: "stale-vlm", + name: "Stale VLM", + api: "openai-completions", + provider: "stale-openai-proxy", + baseUrl: "https://stale-proxy.example.com/v1", + reasoning: false, + input: ["text"], + cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, + contextWindow: 128_000, + maxTokens: 16_384, + }), + ], + true, + "", + dbPath, + ), + }, + ); }); test("legacy cached discovery sentinels are ignored after nullable limit cutover", () => { @@ -2223,6 +2263,13 @@ describe("ModelRegistry", () => { expect(model?.provider).toBe("litellm-proxy"); }); + test("ignores openai-models-list rows cached under the retired context-v2 namespace", () => { + // PR #7584 added server-advertised input-modality parsing; warm v2 rows + // pinned vision-capable ids at text-only and must not load. + expect(openaiModelsListStaleNamespaceCache.find("stale-openai-proxy", "stale-vlm")).toBeUndefined(); + expect(getModelsForProvider(openaiModelsListStaleNamespaceCache, "stale-openai-proxy")).toHaveLength(0); + }); + test("replaces bundled google-vertex models with authoritative Vertex project discovery", () => { const vertexModels = getModelsForProvider(vertexAuthoritative, "google-vertex"); expect(vertexModels.map(model => model.id)).toEqual(["zai-org/glm-4.7-maas"]);