Skip to content

feat: add OrcaRouter as a builtin OpenAI-compatible provider - #1034

Open
jinhaosong-source wants to merge 1 commit into
ChatGPTBox-dev:masterfrom
jinhaosong-source:feat/orcarouter-provider
Open

feat: add OrcaRouter as a builtin OpenAI-compatible provider#1034
jinhaosong-source wants to merge 1 commit into
ChatGPTBox-dev:masterfrom
jinhaosong-source:feat/orcarouter-provider

Conversation

@jinhaosong-source

@jinhaosong-source jinhaosong-source commented Aug 1, 2026

Copy link
Copy Markdown

Summary

Adds OrcaRouter as a builtin OpenAI-compatible provider. OrcaRouter is a model routing gateway that exposes 180+ models from OpenAI, Anthropic, Google, xAI, DeepSeek, Qwen, Moonshot, Z.ai and MiniMax behind a single endpoint and API key, plus named routers (orcarouter/auto, free, fusion) that pick an upstream per request.

It also runs gateway-level, zero-trust security for AI agents on the same endpoint — screening every prompt/response and governing every tool call on a default-deny basis, with no application code changes.

I'm an engineer on the OrcaRouter team.

What this changes

This mirrors the existing openrouter provider wiring exactly — no new mechanism, no changes to the shared request path.

  • src/services/apis/provider-registry.mjs — registers orcarouter in BUILTIN_PROVIDER_TEMPLATE (base URL https://api.orcarouter.ai/v1, /chat/completions + /completions), and resolves the provider from legacy orcaRouter_* model names in resolveProviderIdFromLegacyModelName.
  • src/config/index.mjs — adds orcaRouterApiModelKeys (22 presets) plus their Models entries, the orcaRouterApiModelKeysOrcaRouter (API) group, orcaRouterApiKey in defaultConfig, isUsingOrcaRouterApiModel, orcaRouter_auto / orcaRouter_free in defaultApiModeIds, and orcarouter in NEWLY_RESERVED_BUILTIN_PROVIDER_IDS so a user who had already hand-rolled a custom provider with that ID gets the same one-time secret migration as xai / nvidia-nim / mistral.
  • src/config/openai-provider-mappings.mjsorcarouterorcaRouterApiKey and orcaRouterApiModelKeysorcarouter.
  • src/background/index.mjs — includes the provider in isUsingOpenAICompatibleApiSession.
  • src/popup/sections/GeneralPart.jsx — API key setup link (https://www.orcarouter.ai/console; keys start with sk-orca-).
  • Tests — 4 new predicate tests (including one asserting OrcaRouter and OpenRouter model keys never cross-match, since the two prefixes are only two characters apart), a duplicate-picker-entry guard mirroring the AI/ML one, the new provider ID added to the newlyReservedBuiltinProviders migration fixture, and an orcarouter-api row in the thin-adapters base-URL/auth table.

Preset list (all IDs verified live against GET /v1/models and a real chat completion):

Model key Model ID
orcaRouter_auto / _free / _fusion / _fusion_flash / _fusion_mini orcarouter/auto, orcarouter/free, orcarouter/fusion, orcarouter/fusion-flash, orcarouter/fusion-mini
Anthropic anthropic/claude-opus-5, anthropic/claude-sonnet-5, anthropic/claude-haiku-4.5
OpenAI openai/gpt-5.6-sol, openai/gpt-5.5, openai/gpt-5.5-pro, openai/gpt-5.4-mini
Google google/gemini-3.6-flash, google/gemini-3.5-flash, google/gemini-3.1-pro-preview
Others grok/grok-4.5, kimi/kimi-k3, qwen/qwen3.7-max, z-ai/glm-5.2, deepseek/deepseek-v4-pro, deepseek/deepseek-v4-flash, minimax/minimax-m3

Models outside this list are still reachable through the existing Custom Model / custom-provider flow, same as for OpenRouter.

Verification

Ran locally on Windows (Node 22):

  • npm run test954 passed, 0 failed (948 on master before this change; the 6 new cases are the ones listed above).
  • npm run lint — clean.
  • npm run build — all four variants built; api.orcarouter.ai present in build/chromium/background.js and build/chromium/popup.js.
  • npx prettier --check on the changed files (LF content) — clean.

Live end-to-end check against the real API, driving generateAnswersWithOpenAICompatibleApi with a real sk-orca- key and no fetch mocking, so the request actually left the machine through this repo's own adapter — 10/10 passed:

  • registry: getProviderById returns name OrcaRouter / base URL https://api.orcarouter.ai/v1 / builtin: true
  • resolveProviderIdForSession resolves both the orcaRouterApiModelKeys group form and the legacy orcaRouter_openai_gpt_5_5 model-name form
  • resolveOpenAICompatibleRequest produces https://api.orcarouter.ai/v1/chat/completions and picks up the key from providerSecrets.orcarouter
  • streamed answers with multiple deltas and a done message for orcarouter/auto, anthropic/claude-opus-5, openai/gpt-5.5, google/gemini-3.5-flash and z-ai/glm-5.2
  • an invalid key raises the expected auth error (Invalid token) rather than silently returning an empty answer

Browser smoke test per AGENTS.md, driving the built build/chromium/ extension loaded unpacked into Chromium — 14/14 passed:

  • the MV3 service worker registers, popup.html renders, and there are no page or console errors
  • General tab — the API Mode picker lists OrcaRouter (Auto Router) and OrcaRouter (Free Models Router) (the two entries added to defaultApiModeIds)
  • the existing OpenRouter (Auto Router) / (Free Models Router) entries are still present and still precede the OrcaRouter ones, so nothing was displaced or reordered
  • Modules → API Modes — both active OrcaRouter modes are listed; opening New shows OrcaRouter (API) in the provider-group dropdown, positioned right after OpenRouter (API)
  • selecting that group populates the model dropdown with all 22 presets

One environment note in case you reproduce it: Chrome 150 no longer honours --load-extension, so this ran on Edge 150 (same Chromium 150 engine, and the build under test is the build/chromium/ MV3 variant).

OrcaRouter is an OpenAI-compatible model routing gateway. This mirrors how the
existing OpenRouter provider is wired so users can pick OrcaRouter models from
the API mode picker and store its key like any other builtin provider.

- register `orcarouter` in the builtin provider template (base URL
  https://api.orcarouter.ai/v1)
- add the `orcaRouterApiModelKeys` group with 21 model presets, including the
  `orcarouter/auto`, `free`, `fusion`, `fusion-flash` and `fusion-mini` routers
- map the group and the `orcaRouterApiKey` legacy secret field, resolve the
  provider from legacy `orcaRouter_*` model names, and reserve the provider ID
  for one-time secret migration
- add the API key setup link and include the provider in the
  OpenAI-compatible session predicate
- extend the config predicate, migration and thin-adapter tests
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Caution

The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased.

@coderabbitai

coderabbitai Bot commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

OrcaRouter is added as a built-in OpenAI-compatible provider. The change defines its models and defaults, integrates provider detection and routing, adds API-key setup support, and extends migration and adapter tests.

Changes

OrcaRouter provider

Layer / File(s) Summary
Provider catalog and configuration
src/config/index.mjs, src/config/openai-provider-mappings.mjs
Adds OrcaRouter model keys, metadata, model groups, default modes, API-key configuration, detection, migration reservation, and provider mappings.
Runtime and setup integration
src/background/index.mjs, src/services/apis/provider-registry.mjs, src/popup/sections/GeneralPart.jsx
Adds OrcaRouter session detection, provider registration, legacy model resolution, API endpoints, and console URL handling.
Validation and migration coverage
tests/unit/config/config-predicates.test.mjs, tests/unit/config/migrate-user-config.test.mjs, tests/unit/services/apis/thin-adapters.test.mjs
Tests model predicates, picker uniqueness, migration reservation, and OpenAI-compatible adapter behavior.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Configuration
  participant Background
  participant ProviderRegistry
  participant OrcaRouterAPI
  Configuration->>Background: Select OrcaRouter model
  Background->>Background: Detect OrcaRouter API model
  Background->>ProviderRegistry: Resolve provider and endpoint
  ProviderRegistry->>OrcaRouterAPI: Send chat completion request
  OrcaRouterAPI-->>ProviderRegistry: Return completion response
Loading

Possibly related PRs

Suggested reviewers: peterdavehello, josstorer

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: adding OrcaRouter as a built-in OpenAI-compatible provider.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@qodo-code-review

Copy link
Copy Markdown
Contributor

PR Summary by Qodo

Add OrcaRouter as a built-in OpenAI-compatible provider

✨ Enhancement 🧪 Tests ⚙️ Configuration changes 🕐 20-40 Minutes

Grey Divider

AI Description

• Register OrcaRouter as a built-in OpenAI-compatible provider and base URL.
• Add OrcaRouter model presets, API key storage, and provider/group mappings.
• Extend session predicates and unit tests for migration, adapters, and key matching.
Diagram

graph TD
  UI["Popup: API key link"] --> CFG["Config: Models & groups"] --> MAP["OpenAI provider mappings"] --> ADP["Thin adapter / request builder"] --> ORCA{{"OrcaRouter API"}}
  CFG --> BG["Background: OAI-compatible session"] --> ADP
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Data-driven OpenAI-compatible provider registration
  • ➕ Reduces per-provider touch points (predicates, mappings, UI links) as more providers are added
  • ➕ Lowers risk of missing one of the required wiring locations
  • ➖ Bigger refactor and higher regression risk than a straightforward additive provider
  • ➖ May require rethinking how model groups and legacy migrations are represented
2. Ship as documentation-only (custom provider recipe) instead of built-in
  • ➕ Avoids reserving provider IDs and maintaining preset lists
  • ➕ No code changes needed beyond docs
  • ➖ Worse UX (manual provider setup, no presets, more error-prone)
  • ➖ Does not integrate with existing secret migration and picker grouping conventions

Recommendation: The PR’s approach (mirroring the existing OpenRouter built-in wiring) is the best near-term choice: it is consistent with current architecture, keeps the shared OpenAI-compatible request path unchanged, and delivers first-class UX (picker presets + built-in provider + secret migration). A more data-driven registration system could be worthwhile if many more OpenAI-compatible providers are expected, but it’s appropriately out-of-scope for this additive provider change.

Files changed (8) +188 / -1

Enhancement (3) +14 / -0
index.mjsTreat OrcaRouter sessions as OpenAI-compatible +2/-0

Treat OrcaRouter sessions as OpenAI-compatible

• Imports the new OrcaRouter config predicate and includes it in the OpenAI-compatible session check. This ensures OrcaRouter API modes follow the same background/session handling as other OpenAI-compatible providers.

src/background/index.mjs

GeneralPart.jsxAdd OrcaRouter API key setup URL +2/-0

Add OrcaRouter API key setup URL

• Extends the provider API key setup URL switch to return the OrcaRouter console link when providerId is 'orcarouter'.

src/popup/sections/GeneralPart.jsx

provider-registry.mjsRegister OrcaRouter as a built-in provider and resolve legacy names +10/-0

Register OrcaRouter as a built-in provider and resolve legacy names

• Adds a built-in provider entry for OrcaRouter with base URL 'https://api.orcarouter.ai/v1' and OpenAI-compatible paths. Updates legacy model-name resolution to map 'orcaRouter_*' presets (and the group key) to providerId 'orcarouter'.

src/services/apis/provider-registry.mjs

Tests (3) +46 / -0
config-predicates.test.mjsAdd OrcaRouter predicate and picker-entry uniqueness tests +38/-0

Add OrcaRouter predicate and picker-entry uniqueness tests

• Adds coverage for 'isUsingOrcaRouterApiModel', including representative matching, full exported key matching, and non-overlap with OpenRouter keys. Also adds a guard ensuring OrcaRouter presets do not produce duplicate picker entries (value/desc pairs).

tests/unit/config/config-predicates.test.mjs

migrate-user-config.test.mjsExtend newly-reserved provider migration fixture for OrcaRouter +1/-0

Extend newly-reserved provider migration fixture for OrcaRouter

• Adds 'orcarouter' and its legacy secret key field ('orcaRouterApiKey') to the newly-reserved builtin providers list used by migration tests.

tests/unit/config/migrate-user-config.test.mjs

thin-adapters.test.mjsAdd OrcaRouter thin-adapter base URL/auth test case +7/-0

Add OrcaRouter thin-adapter base URL/auth test case

• Adds an 'orcarouter-api' adapter fixture verifying that OrcaRouter API mode selects providerId 'orcarouter', base URL 'https://api.orcarouter.ai/v1', and reads the expected API key.

tests/unit/services/apis/thin-adapters.test.mjs

Other (2) +128 / -1
index.mjsAdd OrcaRouter model group, presets, defaults, and API key +126/-1

Add OrcaRouter model group, presets, defaults, and API key

• Defines 'orcaRouterApiModelKeys', adds an OrcaRouter model group, and registers 21 preset model entries. Adds 'orcaRouterApiKey' to default config, includes OrcaRouter in default API modes, introduces 'isUsingOrcaRouterApiModel', and reserves 'orcarouter' for one-time secret migration.

src/config/index.mjs

openai-provider-mappings.mjsMap orcarouter providerId to legacy key field and model group +2/-0

Map orcarouter providerId to legacy key field and model group

• Adds 'orcarouter -> orcaRouterApiKey' to the legacy key field map and maps 'orcaRouterApiModelKeys -> orcarouter' for OpenAI-compatible provider resolution.

src/config/openai-provider-mappings.mjs

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/background/index.mjs`:
- Line 409: Complete the required manual browser smoke test for the OrcaRouter
API session path introduced around isUsingOrcaRouterApiModel and executeApi().
If testing cannot be performed, document the reason and the specific skipped
checks in the PR description.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: c3670618-1ed0-4773-937b-1d805bbc17d4

📥 Commits

Reviewing files that changed from the base of the PR and between 51e304d and 8a20076.

📒 Files selected for processing (8)
  • src/background/index.mjs
  • src/config/index.mjs
  • src/config/openai-provider-mappings.mjs
  • src/popup/sections/GeneralPart.jsx
  • src/services/apis/provider-registry.mjs
  • tests/unit/config/config-predicates.test.mjs
  • tests/unit/config/migrate-user-config.test.mjs
  • tests/unit/services/apis/thin-adapters.test.mjs

Comment thread src/background/index.mjs
isUsingNvidiaNimApiModel(session) ||
isUsingOllamaApiModel(session) ||
isUsingOpenRouterApiModel(session) ||
isUsingOrcaRouterApiModel(session) ||

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== repo files around background =="
git ls-files | rg '(^|/)(background/promise|package\.json|PR|README|README\.md|src/.*\.mjs)$' | sed -n '1,120p'

echo
echo "== src/background/index.mjs relevant section =="
if [ -f src/background/index.mjs ]; then
  nl -ba src/background/index.mjs | sed -n '380,430p'
else
  fd -a 'index\.mjs$' . | sed -n '1,80p'
fi

echo
echo "== references to isUsingOrcaRouterApiModel =="
rg -n "isUsingOrcaRouterApiModel|OrcaRouter|routerApiModel" . || true

echo
echo "== package scripts =="
if [ -f package.json ]; then
  jq '.scripts' package.json
fi

echo
echo "== PR/objective references in tracked text files =="
rg -n "load-unpacked|manual|smoke|runtime changes|verification|ORCA|[Oo]rc[aA]|RouterApi" --glob '!node_modules/**' --glob '!dist/**' --glob '!build/**' . | sed -n '1,200p' || true

Repository: ChatGPTBox-dev/chatGPTBox

Length of output: 3654


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== src/background/index.mjs relevant section =="
awk 'NR>=380 && NR<=430 {printf "%6d\t%s\n", NR, $0}' src/background/index.mjs

echo
echo "== package scripts =="
node - <<'JS'
const fs = require('fs');
const pkg = JSON.parse(fs.readFileSync('package.json', 'utf8'));
console.log(JSON.stringify(pkg.scripts || {}, null, 2));
JS

echo
echo "== references to isUsingOrcaRouterApiModel and manual verification language =="
rg -n "isUsingOrcaRouterApiModel|OrcaRouter|routerApiModel|load-unpacked|manual|smoke|runtime changes|verification|ORCA|[Oo]rc[aA]|RouterApi" --glob '!node_modules/**' --glob '!dist/**' --glob '!build/**' . | sed -n '1,240p' || true

Repository: ChatGPTBox-dev/chatGPTBox

Length of output: 17455


Complete the required manual browser smoke test.

src/background/index.mjs now routes OrcaRouter API sessions through executeApi(), which is a general runtime behavioral change. Manual browser extension testing is required; if it is skipped, document the reason and skipped checks in the PR description.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/background/index.mjs` at line 409, Complete the required manual browser
smoke test for the OrcaRouter API session path introduced around
isUsingOrcaRouterApiModel and executeApi(). If testing cannot be performed,
document the reason and the specific skipped checks in the PR description.

Source: Coding guidelines

@qodo-code-review

Copy link
Copy Markdown
Contributor

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (1) 📜 Skill insights (0)

Context used
✅ Compliance rules (platform): 6 rules

Grey Divider


Remediation recommended

1. Missing i18n for OrcaRouter labels 📘 Rule violation ⚙ Maintainability
Description
New user-facing desc strings for OrcaRouter models/groups were added but do not have corresponding
entries in src/_locales/en/main.json. Since these desc values are passed through t(...),
non-English locales cannot translate them and will fall back to raw keys.
Code

src/config/index.mjs[R298-301]

+  orcaRouterApiModelKeys: {
+    value: orcaRouterApiModelKeys,
+    desc: 'OrcaRouter (API)',
+  },
Evidence
The checklist requires new user-facing text to be represented by localization keys in
src/_locales/en/main.json. The PR adds new OrcaRouter desc labels in src/config/index.mjs, and
the UI translation path (modelNameToDesc) passes these desc values through t(...), but
src/_locales/en/main.json does not include OrcaRouter keys alongside other model labels.

Rule 2262059: Add new English localization keys before other locales
src/config/index.mjs[298-301]
src/config/index.mjs[635-664]
src/utils/model-name-convert.mjs[26-49]
src/_locales/en/main.json[69-88]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
New OrcaRouter UI labels (e.g., `OrcaRouter (API)`, `OrcaRouter (Auto Router)`, etc.) are introduced as translatable `desc` keys, but the corresponding English localization entries are missing.

## Issue Context
`modelNameToDesc()` calls `t(Models[...].desc)` / `t(ModelGroups[...].desc)`, so newly added `desc` strings should exist as keys in `src/_locales/en/main.json` and be propagated to other locale files.

## Fix Focus Areas
- src/config/index.mjs[298-301]
- src/config/index.mjs[635-664]
- src/utils/model-name-convert.mjs[26-49]
- src/_locales/en/main.json[69-88]
- src/_locales/fr/main.json[1-10]
- src/_locales/de/main.json[1-10]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

To customize comments, go to the Qodo configuration screen, or learn more in the docs.

Qodo Logo

Comment thread src/config/index.mjs
Comment on lines +298 to +301
orcaRouterApiModelKeys: {
value: orcaRouterApiModelKeys,
desc: 'OrcaRouter (API)',
},

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remediation recommended

1. Missing i18n for orcarouter labels 📘 Rule violation ⚙ Maintainability

New user-facing desc strings for OrcaRouter models/groups were added but do not have corresponding
entries in src/_locales/en/main.json. Since these desc values are passed through t(...),
non-English locales cannot translate them and will fall back to raw keys.
Agent Prompt
## Issue description
New OrcaRouter UI labels (e.g., `OrcaRouter (API)`, `OrcaRouter (Auto Router)`, etc.) are introduced as translatable `desc` keys, but the corresponding English localization entries are missing.

## Issue Context
`modelNameToDesc()` calls `t(Models[...].desc)` / `t(ModelGroups[...].desc)`, so newly added `desc` strings should exist as keys in `src/_locales/en/main.json` and be propagated to other locale files.

## Fix Focus Areas
- src/config/index.mjs[298-301]
- src/config/index.mjs[635-664]
- src/utils/model-name-convert.mjs[26-49]
- src/_locales/en/main.json[69-88]
- src/_locales/fr/main.json[1-10]
- src/_locales/de/main.json[1-10]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

@jinhaosong-source

Copy link
Copy Markdown
Author

Complete the required manual browser smoke test for the OrcaRouter API session path introduced around isUsingOrcaRouterApiModel and executeApi().

Done — the PR description now has the results instead of a caveat. I loaded the built build/chromium/ extension unpacked and drove the popup; 14/14 checks passed:

  • MV3 service worker registers, popup.html renders, no page/console errors
  • General tab API Mode picker lists OrcaRouter (Auto Router) and OrcaRouter (Free Models Router)
  • the existing OpenRouter entries are still present and still precede the new ones, so nothing was displaced
  • Modules → API Modes → New offers OrcaRouter (API) in the provider-group dropdown, and selecting it populates the model dropdown with all 22 presets

For the request path specifically (the isUsingOrcaRouterApiModel / executeApi() line you flagged), I also ran generateAnswersWithOpenAICompatibleApi against the real API with a live sk-orca- key and no fetch mocking, so requests actually left the machine through this repo's own adapter — 10/10, covering streamed deltas plus done for four upstreams, endpoint/key resolution, and an invalid key surfacing an auth error rather than an empty answer.

One environment note: Chrome 150 no longer honours --load-extension, so the browser pass ran on Edge 150 — same Chromium 150 engine, and the artifact under test is the build/chromium/ MV3 build.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant