From a583818ef532e006d1ae44dc6f3baf0c6b4645e1 Mon Sep 17 00:00:00 2001 From: Roo Code Date: Tue, 14 Apr 2026 06:44:59 +0000 Subject: [PATCH] feat: add GPT-5.4 Codex fast mode models (codex, spark variants) Adds three new model entries to the OpenAI Codex provider: - gpt-5.4-codex: Full GPT-5.4 optimized for agentic coding (1M context) - gpt-5.4-codex-spark: Fast, text-only GPT-5.4 variant (128k context, 8k output) - gpt-5.4-mini-codex-spark: Fast, text-only GPT-5.4 Mini variant (128k context, 8k output) Follows the same pattern as existing gpt-5.3-codex and gpt-5.3-codex-spark models. Closes #12112 --- packages/types/src/providers/openai-codex.ts | 42 +++++++++++++ .../providers/__tests__/openai-codex.spec.ts | 62 +++++++++++++++---- 2 files changed, 92 insertions(+), 12 deletions(-) diff --git a/packages/types/src/providers/openai-codex.ts b/packages/types/src/providers/openai-codex.ts index 47809723761..7429c1dd4d5 100644 --- a/packages/types/src/providers/openai-codex.ts +++ b/packages/types/src/providers/openai-codex.ts @@ -172,6 +172,48 @@ export const openAiCodexModels = { supportsTemperature: false, description: "GPT-5.1 Codex Mini: Faster version for coding tasks via ChatGPT subscription", }, + "gpt-5.4-codex": { + maxTokens: 128000, + contextWindow: 1_050_000, + includedTools: ["apply_patch"], + excludedTools: ["apply_diff", "write_to_file"], + supportsImages: true, + supportsPromptCache: true, + supportsReasoningEffort: ["low", "medium", "high", "xhigh"], + reasoningEffort: "medium", + inputPrice: 0, + outputPrice: 0, + supportsTemperature: false, + description: "GPT-5.4 Codex: GPT-5.4 optimized for agentic coding via ChatGPT subscription", + }, + "gpt-5.4-codex-spark": { + maxTokens: 8192, + contextWindow: 128000, + includedTools: ["apply_patch"], + excludedTools: ["apply_diff", "write_to_file"], + supportsImages: false, + supportsPromptCache: true, + supportsReasoningEffort: ["low", "medium", "high", "xhigh"], + reasoningEffort: "medium", + inputPrice: 0, + outputPrice: 0, + supportsTemperature: false, + description: "GPT-5.4 Codex Spark: Fast, text-only coding model via ChatGPT subscription", + }, + "gpt-5.4-mini-codex-spark": { + maxTokens: 8192, + contextWindow: 128000, + includedTools: ["apply_patch"], + excludedTools: ["apply_diff", "write_to_file"], + supportsImages: false, + supportsPromptCache: true, + supportsReasoningEffort: ["low", "medium", "high", "xhigh"], + reasoningEffort: "medium", + inputPrice: 0, + outputPrice: 0, + supportsTemperature: false, + description: "GPT-5.4 Mini Codex Spark: Fast, text-only mini coding model via ChatGPT subscription", + }, "gpt-5.4": { maxTokens: 128000, contextWindow: 1_050_000, diff --git a/src/api/providers/__tests__/openai-codex.spec.ts b/src/api/providers/__tests__/openai-codex.spec.ts index dcc0c4d0357..8c7f2ab4795 100644 --- a/src/api/providers/__tests__/openai-codex.spec.ts +++ b/src/api/providers/__tests__/openai-codex.spec.ts @@ -3,18 +3,25 @@ import { OpenAiCodexHandler } from "../openai-codex" describe("OpenAiCodexHandler.getModel", () => { - it.each(["gpt-5.1", "gpt-5", "gpt-5.1-codex", "gpt-5-codex", "gpt-5-codex-mini", "gpt-5.3-codex-spark"])( - "should return specified model when a valid model id is provided: %s", - (apiModelId) => { - const handler = new OpenAiCodexHandler({ apiModelId }) - const model = handler.getModel() - - expect(model.id).toBe(apiModelId) - expect(model.info).toBeDefined() - // Default reasoning effort for GPT-5 family - expect(model.info.reasoningEffort).toBe("medium") - }, - ) + it.each([ + "gpt-5.1", + "gpt-5", + "gpt-5.1-codex", + "gpt-5-codex", + "gpt-5-codex-mini", + "gpt-5.3-codex-spark", + "gpt-5.4-codex", + "gpt-5.4-codex-spark", + "gpt-5.4-mini-codex-spark", + ])("should return specified model when a valid model id is provided: %s", (apiModelId) => { + const handler = new OpenAiCodexHandler({ apiModelId }) + const model = handler.getModel() + + expect(model.id).toBe(apiModelId) + expect(model.info).toBeDefined() + // Default reasoning effort for GPT-5 family + expect(model.info.reasoningEffort).toBe("medium") + }) it("should fall back to default model when an invalid model id is provided", () => { const handler = new OpenAiCodexHandler({ apiModelId: "not-a-real-model" }) @@ -41,4 +48,35 @@ describe("OpenAiCodexHandler.getModel", () => { expect(model.id).toBe("gpt-5.4-mini") expect(model.info).toBeDefined() }) + + it("should use GPT-5.4 Codex capabilities when selected", () => { + const handler = new OpenAiCodexHandler({ apiModelId: "gpt-5.4-codex" }) + const model = handler.getModel() + + expect(model.id).toBe("gpt-5.4-codex") + expect(model.info.contextWindow).toBe(1_050_000) + expect(model.info.maxTokens).toBe(128000) + expect(model.info.supportsImages).toBe(true) + expect(model.info.reasoningEffort).toBe("medium") + }) + + it("should use GPT-5.4 Codex Spark-specific limits and capabilities", () => { + const handler = new OpenAiCodexHandler({ apiModelId: "gpt-5.4-codex-spark" }) + const model = handler.getModel() + + expect(model.id).toBe("gpt-5.4-codex-spark") + expect(model.info.contextWindow).toBe(128000) + expect(model.info.maxTokens).toBe(8192) + expect(model.info.supportsImages).toBe(false) + }) + + it("should use GPT-5.4 Mini Codex Spark-specific limits and capabilities", () => { + const handler = new OpenAiCodexHandler({ apiModelId: "gpt-5.4-mini-codex-spark" }) + const model = handler.getModel() + + expect(model.id).toBe("gpt-5.4-mini-codex-spark") + expect(model.info.contextWindow).toBe(128000) + expect(model.info.maxTokens).toBe(8192) + expect(model.info.supportsImages).toBe(false) + }) })