fix(ai): drop Codex models rejected for ChatGPT accounts (#11173)

The openai-codex provider authenticates with a ChatGPT account, and the
Codex backend rejects gpt-5.5 and gpt-5.3-codex-spark for those accounts
("not supported when using Codex with a ChatGPT account"). Remove them
from the catalog so model pickers stop offering models that always fail.

Codex e2e tests that used openai-codex/gpt-5.5 now use gpt-6.1-sol, the
openai-codex default. The context overflow test uses gpt-5.6-sol to keep
its prompt smaller.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Lucas Meijer 2026-10-20 15:55:48 +02:00 • committed by GitHub
parent 48c8f32284
commit fdce48eb40
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
21 changed files with 53 additions and 77 deletions

View file

@ -3144,13 +3144,14 @@ async function generateModels() {
// OpenAI Codex (ChatGPT OAuth) models
// NOTE: These are not fetched from models.dev; we keep a small, explicit list to avoid aliases.
// Older model limits are based on observed server behavior; GPT-5.6 and GPT-6 use Codex's 272k default catalog limit.
// Only list models the Codex backend accepts for ChatGPT accounts. GPT-5.5 and GPT-5.3 Codex Spark are rejected
// with "not supported when using Codex with a ChatGPT account".
// GPT-5.6 and GPT-6 use Codex's 272k default catalog limit.
// GPT-6.1 Sol uses the 500k default returned by /backend-api/codex/models.
const CODEX_BASE_URL = "https://chatgpt.com/backend-api";
const CODEX_CONTEXT = 272000;
const CODEX_GPT_61_SOL_CONTEXT = 500000;
const CODEX_GPT_56_CONTEXT = 272000;
const CODEX_SPARK_CONTEXT = 128000;
const CODEX_MAX_TOKENS = 128000;
const codexModels: Model<"openai-codex-responses">[] = [
{
@ -3201,30 +3202,6 @@ async function generateModels() {
contextWindow: CODEX_CONTEXT,
maxTokens: CODEX_MAX_TOKENS,
},
{
id: "gpt-5.3-codex-spark",
name: "GPT-5.3 Codex Spark",
api: "openai-codex-responses",
provider: "openai-codex",
baseUrl: CODEX_BASE_URL,
reasoning: true,
input: ["text"],
cost: { input: 1.75, output: 14, cacheRead: 0.175, cacheWrite: 0 },
contextWindow: CODEX_SPARK_CONTEXT,
maxTokens: CODEX_MAX_TOKENS,
},
{
id: "gpt-5.5",
name: "GPT-5.5",
api: "openai-codex-responses",
provider: "openai-codex",
baseUrl: CODEX_BASE_URL,
reasoning: true,
input: ["text", "image"],
cost: withOpenAiLongContextPricing({ input: 5, output: 30, cacheRead: 0.5, cacheWrite: 0 }),
contextWindow: CODEX_CONTEXT,
maxTokens: CODEX_MAX_TOKENS,
},
{
id: "gpt-5.6-luna",
name: "GPT-5.6 Luna",

View file

@ -323,12 +323,12 @@ describe("AI Providers Abort Tests", () => {
describe("OpenAI Codex Provider Abort", () => {
it.skipIf(!openaiCodexToken)("should abort mid-stream", { retry: 3 }, async () => {
const llm = getModel("openai-codex", "gpt-5.5");
const llm = getModel("openai-codex", "gpt-6.1-sol");
await testAbortSignal(llm, { apiKey: openaiCodexToken });
});
it.skipIf(!openaiCodexToken)("should handle immediate abort", { retry: 3 }, async () => {
const llm = getModel("openai-codex", "gpt-5.5");
const llm = getModel("openai-codex", "gpt-6.1-sol");
await testImmediateAbort(llm, { apiKey: openaiCodexToken });
});
});

View file

@ -163,8 +163,8 @@ function percentile(values: number[], p: number): number {
async function main(): Promise<void> {
const args = parseArgs(process.argv.slice(2));
const model = getModel("openai-codex", "gpt-5.5") as Model<"openai-codex-responses"> | undefined;
if (!model) throw new Error("Model openai-codex/gpt-5.5 not found");
const model = getModel("openai-codex", "gpt-6.1-sol") as Model<"openai-codex-responses"> | undefined;
if (!model) throw new Error("Model openai-codex/gpt-6.1-sol not found");
const modelWithMaxTokens = { ...model, maxTokens: args.maxTokens };
const modelRuntime = await ModelRuntime.create();
const apiKey =
@ -181,7 +181,7 @@ async function main(): Promise<void> {
const elapsed: number[] = [];
resetOpenAICodexWebSocketDebugStats(args.sessionId);
console.log(`provider openai-codex, model gpt-5.5`);
console.log(`provider openai-codex, model gpt-6.1-sol`);
console.log(`sessionId ${args.sessionId}`);
console.log(
`turns ${args.turns}, transport ${args.transport}, reasoning ${args.reasoning}, maxTokens ${args.maxTokens}`,

View file

@ -228,9 +228,9 @@ describe("Context overflow error handling", () => {
describe("OpenAI Codex (OAuth)", () => {
it.skipIf(!openaiCodexToken)(
"gpt-5.5 - should detect overflow via isContextOverflow",
"gpt-5.6-sol - should detect overflow via isContextOverflow",
async () => {
const model = getModel("openai-codex", "gpt-5.5");
const model = getModel("openai-codex", "gpt-5.6-sol");
const result = await testContextOverflow(model, openaiCodexToken!);
logResult(result);

View file

@ -66,7 +66,7 @@ const PROVIDER_MODEL_PAIRS: ProviderModelPair[] = [
{ provider: "openai", model: "gpt-5-mini", label: "openai-responses-gpt-5-mini" },
{ provider: "azure", model: "gpt-4o-mini", label: "azure-gpt-4o-mini" },
// OpenAI Codex
{ provider: "openai-codex", model: "gpt-5.5", label: "openai-codex-gpt-5.5" },
{ provider: "openai-codex", model: "gpt-6.1-sol", label: "openai-codex-gpt-6.1-sol" },
// GitHub Copilot
{ provider: "github-copilot", model: "claude-sonnet-4.5", label: "copilot-claude-sonnet-4.5" },
{ provider: "github-copilot", model: "gpt-5.1-codex", label: "copilot-gpt-5.1-codex" },

View file

@ -784,37 +784,37 @@ describe("AI Providers Empty Message Tests", () => {
describe("OpenAI Codex Provider Empty Messages", () => {
it.skipIf(!openaiCodexToken)(
"gpt-5.5 - should handle empty content array",
"gpt-6.1-sol - should handle empty content array",
{ retry: 3, timeout: 30000 },
async () => {
const llm = getModel("openai-codex", "gpt-5.5");
const llm = getModel("openai-codex", "gpt-6.1-sol");
await testEmptyMessage(llm, { apiKey: openaiCodexToken });
},
);
it.skipIf(!openaiCodexToken)(
"gpt-5.5 - should handle empty string content",
"gpt-6.1-sol - should handle empty string content",
{ retry: 3, timeout: 30000 },
async () => {
const llm = getModel("openai-codex", "gpt-5.5");
const llm = getModel("openai-codex", "gpt-6.1-sol");
await testEmptyStringMessage(llm, { apiKey: openaiCodexToken });
},
);
it.skipIf(!openaiCodexToken)(
"gpt-5.5 - should handle whitespace-only content",
"gpt-6.1-sol - should handle whitespace-only content",
{ retry: 3, timeout: 30000 },
async () => {
const llm = getModel("openai-codex", "gpt-5.5");
const llm = getModel("openai-codex", "gpt-6.1-sol");
await testWhitespaceOnlyMessage(llm, { apiKey: openaiCodexToken });
},
);
it.skipIf(!openaiCodexToken)(
"gpt-5.5 - should handle empty assistant message in conversation",
"gpt-6.1-sol - should handle empty assistant message in conversation",
{ retry: 3, timeout: 30000 },
async () => {
const llm = getModel("openai-codex", "gpt-5.5");
const llm = getModel("openai-codex", "gpt-6.1-sol");
await testEmptyAssistantMessage(llm, { apiKey: openaiCodexToken });
},
);

View file

@ -530,19 +530,19 @@ describe("Tool Results with Images", () => {
describe("OpenAI Codex Provider", () => {
it.skipIf(!openaiCodexToken)(
"gpt-5.5 - should handle tool result with only image",
"gpt-6.1-sol - should handle tool result with only image",
{ retry: 3, timeout: 30000 },
async () => {
const llm = getModel("openai-codex", "gpt-5.5");
const llm = getModel("openai-codex", "gpt-6.1-sol");
await handleToolWithImageResult(llm, { apiKey: openaiCodexToken });
},
);
it.skipIf(!openaiCodexToken)(
"gpt-5.5 - should handle tool result with text and image",
"gpt-6.1-sol - should handle tool result with text and image",
{ retry: 3, timeout: 30000 },
async () => {
const llm = getModel("openai-codex", "gpt-5.5");
const llm = getModel("openai-codex", "gpt-6.1-sol");
await handleToolWithTextAndImageResult(llm, { apiKey: openaiCodexToken });
},
);

View file

@ -7,7 +7,7 @@ const codexToken = await resolveApiKey("openai-codex");
describe("openai-codex cache affinity e2e", () => {
it.skipIf(!codexToken)("handles SSE requests with aligned cache-affinity identifiers", async () => {
const model = getModel("openai-codex", "gpt-5.5");
const model = getModel("openai-codex", "gpt-6.1-sol");
const sessionId = "0195d6e4-4cf9-7f44-a2d8-f8f7f49ee9d3";
const context: Context = {
systemPrompt: "You are a helpful assistant. Reply exactly as requested.",

View file

@ -18,7 +18,7 @@ const usage: Usage = {
describe("OpenAI Responses foreign tool call ID normalization", () => {
it("hashes foreign Copilot tool item IDs into a bounded Codex-safe fc_<hash> shape", () => {
const model = getModel("openai-codex", "gpt-5.5");
const model = getModel("openai-codex", "gpt-6.1-sol");
const assistant: AssistantMessage = {
role: "assistant",
content: [

View file

@ -15,7 +15,7 @@ const usage: Usage = {
describe("OpenAI Responses message ID conversion", () => {
it("generates unique fallback message IDs for multiple text blocks in one assistant turn", () => {
const model = getModel("openai-codex", "gpt-5.5");
const model = getModel("openai-codex", "gpt-6.1-sol");
const assistant: AssistantMessage = {
role: "assistant",
content: [

View file

@ -177,8 +177,8 @@ describe("Responses API tool result images", () => {
);
});
describe("OpenAI Codex Responses Provider (gpt-5.5)", () => {
const model = getModel("openai-codex", "gpt-5.5");
describe("OpenAI Codex Responses Provider (gpt-6.1-sol)", () => {
const model = getModel("openai-codex", "gpt-6.1-sol");
it.skipIf(!openaiCodexToken)(
"should send tool result images in function_call_output",

View file

@ -175,7 +175,7 @@ describe("builtin providers", () => {
["openai", "gpt-5.4"],
["openai", "gpt-5.5"],
["openai", "gpt-6-astra"],
["openai-codex", "gpt-5.5"],
["openai-codex", "gpt-5.6-sol"],
["anthropic", "claude-opus-5"],
["opencode", "gpt-5.4"],
["opencode", "gpt-5.6-terra"],

View file

@ -113,7 +113,7 @@ describe("responseId E2E Tests", () => {
describe("OpenAI Codex Provider", () => {
it.skipIf(!openaiCodexToken)("should expose responseId", { retry: 3, timeout: 30000 }, async () => {
const llm = getModel("openai-codex", "gpt-5.5");
const llm = getModel("openai-codex", "gpt-6.1-sol");
await expectResponseId(llm, { apiKey: openaiCodexToken });
});
});

View file

@ -1453,8 +1453,8 @@ describe("Generate E2E Tests", () => {
});
});
describe("OpenAI Codex Provider (gpt-5.5)", () => {
const llm = getModel("openai-codex", "gpt-5.5");
describe("OpenAI Codex Provider (gpt-6.1-sol)", () => {
const llm = getModel("openai-codex", "gpt-6.1-sol");
it.skipIf(!openaiCodexToken)("should complete basic text generation", { retry: 3 }, async () => {
await basicTextGeneration(llm, { apiKey: openaiCodexToken });
@ -1481,8 +1481,8 @@ describe("Generate E2E Tests", () => {
});
});
describe("OpenAI Codex Provider (gpt-5.5 via WebSocket)", () => {
const llm = getModel("openai-codex", "gpt-5.5");
describe("OpenAI Codex Provider (gpt-6.1-sol via WebSocket)", () => {
const llm = getModel("openai-codex", "gpt-6.1-sol");
const wsOptions = { apiKey: openaiCodexToken, transport: "websocket" as const };
it.skipIf(!openaiCodexToken)("should complete basic text generation", { retry: 3 }, async () => {

View file

@ -86,7 +86,6 @@ describe("getSupportedThinkingLevels", () => {
});
it.each([
"gpt-5.5",
"gpt-5.6-sol",
"gpt-5.6-terra",
"gpt-5.6-luna",

View file

@ -354,10 +354,10 @@ describe("Token Statistics on Abort", () => {
describe("OpenAI Codex Provider", () => {
it.skipIf(!openaiCodexToken)(
"gpt-5.5 - should include token stats when aborted mid-stream",
"gpt-6.1-sol - should include token stats when aborted mid-stream",
{ retry: 3, timeout: 30000 },
async () => {
const llm = getModel("openai-codex", "gpt-5.5");
const llm = getModel("openai-codex", "gpt-6.1-sol");
await testTokensOnAbort(llm, { apiKey: openaiCodexToken });
},
);

View file

@ -37,7 +37,7 @@ const echoTool: Tool<typeof echoToolSchema> = {
*
* 1. Use github-copilot gpt-5.5 to generate a tool call
* 2. Switch to openrouter openai/gpt-5.5 and complete
* 3. Switch to openai-codex gpt-5.5 and complete
* 3. Switch to openai-codex gpt-6.1-sol and complete
*
* Both should succeed without "call_id too long" errors.
*/
@ -116,7 +116,7 @@ describe("Tool Call ID Normalization - Live Handoff", () => {
"github-copilot -> openai-codex should normalize pipe-separated IDs",
async () => {
const copilotModel = getModel("github-copilot", "gpt-5.5");
const codexModel = getModel("openai-codex", "gpt-5.5");
const codexModel = getModel("openai-codex", "gpt-6.1-sol");
// Step 1: Generate tool call with github-copilot
const userMessage: Message = {
@ -265,7 +265,7 @@ describe("Tool Call ID Normalization - Prefilled Context", () => {
it.skipIf(!codexToken)(
"openai-codex should handle prefilled context with long pipe-separated IDs",
async () => {
const model = getModel("openai-codex", "gpt-5.5");
const model = getModel("openai-codex", "gpt-6.1-sol");
const messages = buildPrefilledMessages();
const response = await completeSimple(

View file

@ -348,10 +348,10 @@ describe("Tool Call Without Result Tests", () => {
describe("OpenAI Codex Provider", () => {
it.skipIf(!openaiCodexToken)(
"gpt-5.5 - should filter out tool calls without corresponding tool results",
"gpt-6.1-sol - should filter out tool calls without corresponding tool results",
{ retry: 3, timeout: 30000 },
async () => {
const model = getModel("openai-codex", "gpt-5.5");
const model = getModel("openai-codex", "gpt-6.1-sol");
await testToolCallWithoutResult(model, { apiKey: openaiCodexToken });
},
);

View file

@ -863,10 +863,10 @@ describe("totalTokens field", () => {
describe("OpenAI Codex (OAuth)", () => {
it.skipIf(!openaiCodexToken)(
"gpt-5.5 - should return totalTokens equal to sum of components",
"gpt-6.1-sol - should return totalTokens equal to sum of components",
{ retry: 3, timeout: 60000 },
async () => {
const llm = getModel("openai-codex", "gpt-5.5");
const llm = getModel("openai-codex", "gpt-6.1-sol");
console.log(`\nOpenAI Codex / ${llm.id}:`);
const { first, second } = await testTotalTokensWithCache(llm, { apiKey: openaiCodexToken });

View file

@ -810,28 +810,28 @@ describe("AI Providers Unicode Surrogate Pair Tests", () => {
describe("OpenAI Codex Provider Unicode Handling", () => {
it.skipIf(!openaiCodexToken)(
"gpt-5.5 - should handle emoji in tool results",
"gpt-6.1-sol - should handle emoji in tool results",
{ retry: 3, timeout: 30000 },
async () => {
const llm = getModel("openai-codex", "gpt-5.5");
const llm = getModel("openai-codex", "gpt-6.1-sol");
await testEmojiInToolResults(llm, { apiKey: openaiCodexToken });
},
);
it.skipIf(!openaiCodexToken)(
"gpt-5.5 - should handle real-world LinkedIn comment data with emoji",
"gpt-6.1-sol - should handle real-world LinkedIn comment data with emoji",
{ retry: 3, timeout: 30000 },
async () => {
const llm = getModel("openai-codex", "gpt-5.5");
const llm = getModel("openai-codex", "gpt-6.1-sol");
await testRealWorldLinkedInData(llm, { apiKey: openaiCodexToken });
},
);
it.skipIf(!openaiCodexToken)(
"gpt-5.5 - should handle unpaired high surrogate (0xD83D) in tool results",
"gpt-6.1-sol - should handle unpaired high surrogate (0xD83D) in tool results",
{ retry: 3, timeout: 30000 },
async () => {
const llm = getModel("openai-codex", "gpt-5.5");
const llm = getModel("openai-codex", "gpt-6.1-sol");
await testUnpairedHighSurrogate(llm, { apiKey: openaiCodexToken });
},
);

View file

@ -136,7 +136,7 @@ Options:
Notes:
- Uses createAgentSession() from the coding-agent SDK
- Provider/model fixed to openai-codex/gpt-5.5
- Provider/model fixed to openai-codex/gpt-6.1-sol
- Thinking level fixed to low
- Activates exactly one deterministic custom tool
- Prompts are intentionally > 1024 tokens and explicitly describe the test
@ -281,9 +281,9 @@ async function main(): Promise<void> {
const authStorage = AuthStorage.create();
const modelRegistry = await createModelRegistry(authStorage);
const model = getModel("openai-codex", "gpt-5.5");
const model = getModel("openai-codex", "gpt-6.1-sol");
if (!model) {
throw new Error("Model openai-codex/gpt-5.5 not found");
throw new Error("Model openai-codex/gpt-6.1-sol not found");
}
const baseModel = { ...model, maxTokens: args.maxTokens };
const streamSimpleOpenAICodexResponsesForRegistry = (
@ -334,7 +334,7 @@ async function main(): Promise<void> {
const turnElapsedMs: number[] = [];
let previousCacheRead: number | null = null;
console.log(`provider openai-codex, model gpt-5.5`);
console.log(`provider openai-codex, model gpt-6.1-sol`);
console.log(`session ${session.sessionFile}`);
console.log(`turns ${args.turns}, transport ${args.transport}, reasoning low, maxTokens ${args.maxTokens}`);
console.log("");