From f806372ad8c1ca19d4a8a1b71401676f1efa3149 Mon Sep 17 00:00:00 2001 From: Ingwannu Date: Sat, 1 Aug 2026 04:25:38 +0000 Subject: [PATCH 1/2] fix(router): pin Codex auto review to OpenAI --- src/router.ts | 7 ++++++- tests/router.test.ts | 10 ++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/router.ts b/src/router.ts index fb093d986..05c30cf94 100644 --- a/src/router.ts +++ b/src/router.ts @@ -306,8 +306,13 @@ export class NoEnabledOpenAiProviderError extends Error { } } +// Codex uses a small number of control-plane model ids that are not part of the public GPT/o +// naming families. Keep this exact: a broad `codex-*` rule could capture a third-party model. +const CODEX_INTERNAL_OPENAI_MODELS = new Set(["codex-auto-review"]); + function isBareOpenAiFamilyModel(modelId: string): boolean { - return !modelId.includes("/") && /^(?:gpt-|o1-|o3-|o4-)/.test(modelId); + return !modelId.includes("/") + && (/^(?:gpt-|o1-|o3-|o4-)/.test(modelId) || CODEX_INTERNAL_OPENAI_MODELS.has(modelId)); } function routeResult(providerName: string, provider: OcxProviderConfig, modelId: string): RouteResult { diff --git a/tests/router.test.ts b/tests/router.test.ts index ac6fe6d7e..2bab28a19 100644 --- a/tests/router.test.ts +++ b/tests/router.test.ts @@ -139,12 +139,22 @@ describe("routeModel registry effort defaults", () => { }, }; expect(routeModel(base, "gpt-5.5")).toMatchObject({ providerName: "openai", codexAccountMode: "pool" }); + expect(routeModel(base, "codex-auto-review")).toMatchObject({ + providerName: "openai", + modelId: "codex-auto-review", + codexAccountMode: "pool", + }); + expect(routeModel(base, "codex-third-party-model")).toMatchObject({ + providerName: "openai-apikey", + modelId: "codex-third-party-model", + }); expect(routeModel({ ...base, providers: { ...base.providers, openai: { ...forward, codexAccountMode: "direct" } } }, "gpt-5.5")) .toMatchObject({ providerName: "openai", codexAccountMode: "direct" }); expect(() => routeModel({ ...base, providers: { ...base.providers, openai: { ...forward, disabled: true } } }, "gpt-5.5")) .toThrow(/requires the canonical openai provider/); const unavailable = { ...base, providers: { "openai-proxy": base.providers["openai-proxy"] } }; expect(() => routeModel(unavailable, "gpt-5.5")).toThrow(/ocx provider add openai/); + expect(() => routeModel(unavailable, "codex-auto-review")).toThrow(NoEnabledOpenAiProviderError); }); test("rejects legacy chatgpt namespaces even when configured", () => { From 514b91e0842c60f3f4634821efce85467f3f2bcf Mon Sep 17 00:00:00 2001 From: Ingwannu Date: Sat, 1 Aug 2026 04:48:40 +0000 Subject: [PATCH 2/2] test(router): cover non-OpenAI default fallthrough --- tests/router.test.ts | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/tests/router.test.ts b/tests/router.test.ts index 2bab28a19..14a263b67 100644 --- a/tests/router.test.ts +++ b/tests/router.test.ts @@ -148,6 +148,26 @@ describe("routeModel registry effort defaults", () => { providerName: "openai-apikey", modelId: "codex-third-party-model", }); + const withDeepSeekDefault: OcxConfig = { + ...base, + defaultProvider: "deepseek", + providers: { + ...base.providers, + deepseek: { + adapter: "openai-chat", + baseUrl: "https://api.deepseek.com/v1", + defaultModel: "deepseek-chat", + }, + }, + }; + expect(routeModel(withDeepSeekDefault, "codex-auto-review")).toMatchObject({ + providerName: "openai", + modelId: "codex-auto-review", + }); + expect(routeModel(withDeepSeekDefault, "codex-third-party-model")).toMatchObject({ + providerName: "deepseek", + modelId: "codex-third-party-model", + }); expect(routeModel({ ...base, providers: { ...base.providers, openai: { ...forward, codexAccountMode: "direct" } } }, "gpt-5.5")) .toMatchObject({ providerName: "openai", codexAccountMode: "direct" }); expect(() => routeModel({ ...base, providers: { ...base.providers, openai: { ...forward, disabled: true } } }, "gpt-5.5"))