fix(ai): treat gpt-5.x-codex slugs as vision-capable

The document/lab-OCR vision gate excluded every `-codex` slug from the
GPT-5.x line as text-only. That is stale: the `codex/responses` wire reads
an `input_image` block on these slugs (docs/codex-protocol-spec.md plus the
current model lineup), and the 5.2-Codex line is vision-tuned. An operator
pinned to a `-codex` slug therefore resolved no vision-capable provider and
hit a 422 "No vision-capable AI provider is configured" when reading a
document with AI.

Drop the `-codex` exclusion from the gpt-5 branch so a codex-only chain
resolves a document-vision provider; keep the `-mini`/`-preview`
reasoning-slug guard. Lab-OCR on a `-codex` pin gains vision the same way.
This commit is contained in:
Marc-André Bombeck committed 2026-07-09 13:41:59 +02:00
1 parent 45b7eb53ff
commit 1e2b1d2c6a
2 files changed
+20 -11

No files matched your search

@@ -71,7 +71,7 @@ describe("supportsVisionForConfig", () => {
expect(supportsVisionForConfig("local", null)).toBe(true);
});
it("reports vision for codex only on multimodal slugs", () => {
it("reports vision for codex on multimodal slugs, including -codex", () => {
for (const model of [
"gpt-5.5",
"gpt-5.4",
@@ -79,6 +79,13 @@ describe("supportsVisionForConfig", () => {
"gpt-4o",
"gpt-4.1",
"o1",
// The GPT-5.x `-codex` specialists are vision-capable: the wire reads
// an `input_image` block on these slugs (docs/codex-protocol-spec.md +
// OpenAI's current model lineup). The old "-codex is text-only"
// exclusion was stale.
"gpt-5-codex",
"gpt-5.3-codex",
"gpt-5.1-codex-mini",
]) {
expect(supportsVisionForConfig("codex", model)).toBe(true);
}
@@ -86,9 +93,6 @@ 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);
// Text-only o-series variants are excluded for codex too.
expect(supportsVisionForConfig("codex", "o1-mini")).toBe(false);
expect(supportsVisionForConfig("codex", "o3-mini")).toBe(false);
+12 -7
View File
@@ -73,9 +73,10 @@ function openaiSupportsVision(model: string): boolean {
/**
* Codex (ChatGPT-OAuth) vision models. Image INPUT is reachable over the
* `codex/responses` endpoint (docs/codex-protocol-spec.md §2b) on a multimodal
* slug — no API key needed. The accepted GPT-5.x line is text+vision; the older
* `-codex` specialist slugs and the legacy `gpt-4`-class non-multimodal pins
* are text-only. The slug we test is the codex client's resolved working slug
* slug — no API key needed. The whole GPT-5.x line is text+vision, including
* the `-codex` specialist slugs (gpt-5.x-codex); only the legacy `gpt-4`-class
* non-multimodal pins are text-only. The slug we test is the codex client's
* resolved working slug
* (cached or chain head), so a slug rotation onto a non-vision model degrades
* to false rather than 400-ing the user at the image block.
*
@@ -85,10 +86,14 @@ function openaiSupportsVision(model: string): boolean {
function codexSupportsVision(model: string): boolean {
const m = model.toLowerCase();
return (
// 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")) ||
// GPT-5.x line is multimodal (text + vision) — INCLUDING the `-codex`
// specialist slugs (gpt-5.x-codex), which gained vision in the 5.2-Codex
// line (screenshots / diagrams / charts). Verified against
// docs/codex-protocol-spec.md (an `input_image` block on a gpt-5-codex
// request) plus OpenAI's current model lineup. The historical
// "-codex is text-only" exclusion was stale — the wire reads images on
// these slugs, so lab-OCR and document reads both succeed on a `-codex` pin.
m.startsWith("gpt-5") ||
m.startsWith("gpt-4o") ||
m.startsWith("gpt-4.1") ||
m.startsWith("gpt-4-turbo") ||