From 7bdf128d75378bff6f2ddff897090daebaded788 Mon Sep 17 00:00:00 2001 From: kuswardhanietidims-svg Date: Mon, 24 Aug 2026 03:37:42 +0000 Subject: [PATCH] feat: recognize OrcaRouter as a first-class provider --- README.md | 16 +++++++++++++ plugins/codex/scripts/lib/codex.mjs | 3 ++- tests/fake-codex-fixture.mjs | 16 +++++++++++++ tests/runtime.test.mjs | 37 +++++++++++++++++++++++++++++ 4 files changed, 71 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 937a3037b..ca57fedce 100644 --- a/README.md +++ b/README.md @@ -318,3 +318,19 @@ Yes. If you already use Codex, the plugin picks up the same [configuration](#com Yes. Because the plugin uses your local Codex CLI, your existing sign-in method and config still apply. If you need to point the built-in OpenAI provider at a different endpoint, set `openai_base_url` in your [Codex config](https://developers.openai.com/codex/config-advanced/#config-and-state-locations). + +### Can I use another model provider? + +Yes. The plugin reflects the active provider from your Codex config, so you can route Codex through any provider Codex supports by defining it under `[model_providers]`. For example, to use [OrcaRouter](https://www.orcarouter.ai), an OpenAI-compatible AI gateway, add this to your `~/.codex/config.toml`: + +```toml +model = "anthropic/claude-sonnet-5" +model_provider = "orcarouter" + +[model_providers.orcarouter] +name = "OrcaRouter" +base_url = "https://api.orcarouter.ai/v1" +env_key = "ORCAROUTER_API_KEY" +``` + +After that, `/codex:setup` and `/codex:status` show `OrcaRouter` as the active provider. diff --git a/plugins/codex/scripts/lib/codex.mjs b/plugins/codex/scripts/lib/codex.mjs index fead00cc4..04f676e77 100644 --- a/plugins/codex/scripts/lib/codex.mjs +++ b/plugins/codex/scripts/lib/codex.mjs @@ -758,7 +758,8 @@ function buildResultStatus(turnState) { const BUILTIN_PROVIDER_LABELS = new Map([ ["openai", "OpenAI"], ["ollama", "Ollama"], - ["lmstudio", "LM Studio"] + ["lmstudio", "LM Studio"], + ["orcarouter", "OrcaRouter"] ]); function normalizeProviderId(value) { diff --git a/tests/fake-codex-fixture.mjs b/tests/fake-codex-fixture.mjs index f83c96a0d..8265a0916 100644 --- a/tests/fake-codex-fixture.mjs +++ b/tests/fake-codex-fixture.mjs @@ -72,6 +72,7 @@ function buildAccountReadResult() { return { account: null, requiresOpenaiAuth: true }; case "provider-no-auth": case "env-key-provider": + case "orcarouter-provider": return { account: null, requiresOpenaiAuth: false }; case "api-key-account-only": return { account: { type: "apiKey" }, requiresOpenaiAuth: true }; @@ -104,6 +105,21 @@ function buildConfigReadResult() { }, origins: {} }; + case "orcarouter-provider": + return { + config: { + model_provider: "orcarouter", + model_providers: { + orcarouter: { + name: "OrcaRouter", + base_url: "https://api.orcarouter.ai/v1", + env_key: "ORCAROUTER_API_KEY", + requires_openai_auth: false + } + } + }, + origins: {} + }; default: return { config: { model_provider: "openai" }, diff --git a/tests/runtime.test.mjs b/tests/runtime.test.mjs index 8f276835b..c32e273ff 100644 --- a/tests/runtime.test.mjs +++ b/tests/runtime.test.mjs @@ -119,6 +119,43 @@ test("setup treats custom providers with app-server-ready config as ready", () = assert.match(payload.auth.detail, /configured and does not require OpenAI authentication/i); }); +test("setup recognizes OrcaRouter as the active provider without OpenAI auth", () => { + const binDir = makeTempDir(); + installFakeCodex(binDir, "orcarouter-provider"); + + const result = run("node", [SCRIPT, "setup", "--json"], { + cwd: ROOT, + env: buildEnv(binDir) + }); + + assert.equal(result.status, 0, result.stderr); + const payload = JSON.parse(result.stdout); + assert.equal(payload.ready, true); + assert.equal(payload.auth.loggedIn, true); + assert.equal(payload.auth.authMethod, null); + assert.equal(payload.auth.source, "app-server"); + assert.equal(payload.auth.provider, "orcarouter"); + assert.match(payload.auth.detail, /OrcaRouter is configured and does not require OpenAI authentication/i); +}); + +test("task runs when OrcaRouter is the active provider", () => { + const repo = makeTempDir(); + const binDir = makeTempDir(); + installFakeCodex(binDir, "orcarouter-provider"); + initGitRepo(repo); + fs.writeFileSync(path.join(repo, "README.md"), "hello\n"); + run("git", ["add", "README.md"], { cwd: repo }); + run("git", ["commit", "-m", "init"], { cwd: repo }); + + const result = run("node", [SCRIPT, "task", "check orcarouter provider"], { + cwd: repo, + env: buildEnv(binDir) + }); + + assert.equal(result.status, 0, result.stderr); + assert.match(result.stdout, /Handled the requested task/); +}); + test("setup reports not ready when app-server config read fails", () => { const binDir = makeTempDir(); installFakeCodex(binDir, "config-read-fails");