diff --git a/open-sse/config/providerRegistry.ts b/open-sse/config/providerRegistry.ts index 0309f486a5..2cbfc1bd19 100644 --- a/open-sse/config/providerRegistry.ts +++ b/open-sse/config/providerRegistry.ts @@ -385,7 +385,8 @@ export const REGISTRY: Record = { { id: "codex-auto-review", name: "Codex Auto Review", targetFormat: "openai-responses" }, { id: "gpt-5.5-xhigh", name: "GPT 5.5 (xHigh)", ...GPT_5_5_CODEX_CAPABILITIES }, { id: "gpt-5.5-high", name: "GPT 5.5 (High)", ...GPT_5_5_CODEX_CAPABILITIES }, - { id: "gpt-5.5", name: "GPT 5.5 (Medium)", ...GPT_5_5_CODEX_CAPABILITIES }, + { id: "gpt-5.5-medium", name: "GPT 5.5 (Medium)", ...GPT_5_5_CODEX_CAPABILITIES }, + { id: "gpt-5.5", name: "GPT 5.5", ...GPT_5_5_CODEX_CAPABILITIES }, { id: "gpt-5.5-low", name: "GPT 5.5 (Low)", ...GPT_5_5_CODEX_CAPABILITIES }, { id: "gpt-5.5-mini", name: "GPT 5.5 Mini", targetFormat: "openai-responses" }, { id: "gpt-5.4", name: "GPT 5.4", targetFormat: "openai-responses" }, diff --git a/open-sse/executors/codex.ts b/open-sse/executors/codex.ts index 6d81606273..f934a392cc 100644 --- a/open-sse/executors/codex.ts +++ b/open-sse/executors/codex.ts @@ -10,6 +10,7 @@ import { PROVIDERS } from "../config/constants.ts"; import { getCodexClientVersion, getCodexUserAgent } from "../config/codexClient.ts"; import { getAccessToken } from "../services/tokenRefresh.ts"; import { getThinkingBudgetConfig, ThinkingMode } from "../services/thinkingBudget.ts"; +import { getCorsOrigin } from "../utils/cors.ts"; import { createRequire } from "module"; // ─── wreq-js lazy loader ─────────────────────────────────────────────────── @@ -30,8 +31,10 @@ type WebsocketFn = (url: string, opts?: Record) => Promise = { supportsThinking: true, supportsTools: true, supportsVision: true, - aliases: ["gpt-5.5-xhigh", "gpt-5.5-high", "gpt-5.5-medium", "gpt-5.5-low", "gpt-5.5-none"], }, // ── Gemini 3 Flash series ─────────────────────────────────────── diff --git a/tests/unit/executor-codex.test.ts b/tests/unit/executor-codex.test.ts index a1b6080b0f..f129b1b22f 100644 --- a/tests/unit/executor-codex.test.ts +++ b/tests/unit/executor-codex.test.ts @@ -3,6 +3,7 @@ import assert from "node:assert/strict"; import { CodexExecutor, + __setCodexWebSocketTransportForTesting, encodeResponseSseEvent, getCodexModelScope, getCodexRateLimitKey, @@ -19,6 +20,7 @@ import { test.afterEach(() => { setThinkingBudgetConfig(DEFAULT_THINKING_CONFIG); + __setCodexWebSocketTransportForTesting(undefined); }); async function withEnv(entries, fn) { @@ -62,7 +64,9 @@ test("Codex helper functions isolate rate-limit scopes and parse quota headers", assert.equal(getCodexModelScope("gpt-5.3-codex"), "codex"); assert.equal(getCodexModelScope("gpt-5.5-xhigh"), "codex"); assert.equal(getCodexUpstreamModel("gpt-5.5-xhigh"), "gpt-5.5"); + assert.equal(getCodexUpstreamModel("gpt-5.5-medium"), "gpt-5.5"); assert.equal(isCodexResponsesWebSocketRequired("gpt-5.5-xhigh", {}), true); + assert.equal(isCodexResponsesWebSocketRequired("gpt-5.5-medium", {}), true); assert.equal(isCodexResponsesWebSocketRequired("gpt-5.5-mini", {}), false); assert.equal(getCodexRateLimitKey("acct-1", "codex-spark-mini"), "acct-1:spark"); assert.equal(quota.usage5h, 100); @@ -294,6 +298,25 @@ test("CodexExecutor.transformRequest keeps gpt-5.5 as the model and applies xhig assert.equal(result.reasoning.effort, "xhigh"); }); +test("CodexExecutor.execute returns 503 when gpt-5.5 websocket transport is unavailable", async () => { + __setCodexWebSocketTransportForTesting(null); + const executor = new CodexExecutor(); + + const result = await executor.execute({ + model: "gpt-5.5-xhigh", + body: { model: "gpt-5.5-xhigh", input: [{ role: "user", content: "hello" }] }, + stream: true, + credentials: { accessToken: "codex-token" }, + }); + const body = await result.response.json(); + + assert.equal(result.response.status, 503); + assert.equal(result.response.headers.get("Access-Control-Allow-Origin"), "*"); + assert.equal(body.error.code, "wreq_unavailable"); + assert.match(body.error.message, /WebSocket transport unavailable/); + assert.equal(result.transformedBody.model, "gpt-5.5"); +}); + test("CodexExecutor maps Codex websocket error events to response.failed SSE", () => { const raw = JSON.stringify({ type: "error", diff --git a/tests/unit/plan3-p0.test.ts b/tests/unit/plan3-p0.test.ts index efc5fc819e..4e7fa7a390 100644 --- a/tests/unit/plan3-p0.test.ts +++ b/tests/unit/plan3-p0.test.ts @@ -40,6 +40,12 @@ test("getModelInfoCore resolves gpt-5.5 to codex", async () => { assert.equal(info.model, "gpt-5.5"); }); +test("getModelInfoCore keeps explicit gpt-5.5-medium separate from gpt-5.5", async () => { + const info = await getModelInfoCore("gpt-5.5-medium", {}); + assert.equal(info.provider, "codex"); + assert.equal(info.model, "gpt-5.5-medium"); +}); + test("getModelInfoCore resolves explicit gpt-5.5 Codex model", async () => { const info = await getModelInfoCore("cx/gpt-5.5", {}); assert.equal(info.provider, "codex"); diff --git a/tests/unit/t12-pricing-updates.test.ts b/tests/unit/t12-pricing-updates.test.ts index b47a399bc3..bf0f0cfe81 100644 --- a/tests/unit/t12-pricing-updates.test.ts +++ b/tests/unit/t12-pricing-updates.test.ts @@ -38,9 +38,13 @@ test("T12: pricing table includes MiniMax, GLM, Kimi and gpt-5.4 mini entries", test("T12: codex catalog includes GPT 5.5 entries", () => { const codexModels = new Map(REGISTRY.codex.models.map((m) => [m.id, m])); assert.ok(codexModels.has("gpt-5.5"), "missing codex/gpt-5.5"); + assert.ok(codexModels.has("gpt-5.5-medium"), "missing codex/gpt-5.5-medium"); assert.ok(codexModels.has("gpt-5.5-mini"), "missing codex/gpt-5.5-mini"); + assert.equal(codexModels.get("gpt-5.5")?.name, "GPT 5.5"); + assert.equal(codexModels.get("gpt-5.5-medium")?.name, "GPT 5.5 (Medium)"); assert.equal(codexModels.get("gpt-5.5")?.contextLength, 1050000); assert.equal(codexModels.get("gpt-5.5")?.supportsXHighEffort, true); + assert.equal(codexModels.get("gpt-5.5-medium")?.targetFormat, "openai-responses"); assert.equal(codexModels.get("gpt-5.5-xhigh")?.targetFormat, "openai-responses"); });