mirror of
https://github.com/badlogic/pi-mono.git
synced 2026-11-05 23:37:25 +00:00
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:
parent
48c8f32284
commit
fdce48eb40
21 changed files with 53 additions and 77 deletions
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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 });
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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}`,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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" },
|
||||
|
|
|
|||
|
|
@ -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 });
|
||||
},
|
||||
);
|
||||
|
|
|
|||
|
|
@ -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 });
|
||||
},
|
||||
);
|
||||
|
|
|
|||
|
|
@ -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.",
|
||||
|
|
|
|||
|
|
@ -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: [
|
||||
|
|
|
|||
|
|
@ -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: [
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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"],
|
||||
|
|
|
|||
|
|
@ -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 });
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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 () => {
|
||||
|
|
|
|||
|
|
@ -86,7 +86,6 @@ describe("getSupportedThinkingLevels", () => {
|
|||
});
|
||||
|
||||
it.each([
|
||||
"gpt-5.5",
|
||||
"gpt-5.6-sol",
|
||||
"gpt-5.6-terra",
|
||||
"gpt-5.6-luna",
|
||||
|
|
|
|||
|
|
@ -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 });
|
||||
},
|
||||
);
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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 });
|
||||
},
|
||||
);
|
||||
|
|
|
|||
|
|
@ -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 });
|
||||
|
|
|
|||
|
|
@ -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 });
|
||||
},
|
||||
);
|
||||
|
|
|
|||
|
|
@ -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("");
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue