diff --git a/src/lib/ai/__tests__/vision-capability.test.ts b/src/lib/ai/__tests__/vision-capability.test.ts index 7edebe2fb..9a1e03c24 100644 --- a/src/lib/ai/__tests__/vision-capability.test.ts +++ b/src/lib/ai/__tests__/vision-capability.test.ts @@ -69,6 +69,9 @@ describe("supportsVisionForConfig", () => { expect(supportsVisionForConfig("codex", "gpt-4")).toBe(false); expect(supportsVisionForConfig("codex", "gpt-3.5-turbo")).toBe(false); expect(supportsVisionForConfig("codex", null)).toBe(false); + // The `-codex` specialist slugs are text-only despite the gpt-5 prefix. + expect(supportsVisionForConfig("codex", "gpt-5-codex")).toBe(false); + expect(supportsVisionForConfig("codex", "gpt-5.1-codex-mini")).toBe(false); }); it("never reports vision for none", () => { diff --git a/src/lib/ai/vision-capability.ts b/src/lib/ai/vision-capability.ts index 10f0950fd..daf382900 100644 --- a/src/lib/ai/vision-capability.ts +++ b/src/lib/ai/vision-capability.ts @@ -71,7 +71,10 @@ function openaiSupportsVision(model: string): boolean { function codexSupportsVision(model: string): boolean { const m = model.toLowerCase(); return ( - m.startsWith("gpt-5") || // GPT-5.x line is multimodal (text + vision) + // GPT-5.x line is multimodal (text + vision) — but the `-codex` specialist + // slugs (e.g. gpt-5-codex) are text-only, so they must not claim vision or + // every lab-OCR upload burns a doomed image attempt before falling back. + (m.startsWith("gpt-5") && !m.includes("-codex")) || m.startsWith("gpt-4o") || m.startsWith("gpt-4.1") || m.startsWith("gpt-4-turbo") ||