feat(llm): add OrcaRouter as a first-class provider with API-key and OAuth 2.0 + PKCE login - #328
Open
zsanig22-dotcom wants to merge 1 commit into
Open
zsanig22-dotcom wants to merge 1 commit into
zsanig22-dotcom wants to merge 1 commit into
Conversation
…OAuth 2.0 + PKCE login Signed-off-by: zsanig22-dotcom <zsanig22-dotcom@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds OrcaRouter as a first-class LLM provider: a named entry in the provider table, a real model dropdown built from the gateway's own catalogue, and two ways to authenticate — a pasted
sk-orca-…key and a Connect with OrcaRouter OAuth 2.0 + PKCE login. Both entries are usable independently and both end at the same downstream credential.What OrcaRouter is
OrcaRouter is an OpenAI-compatible AI gateway built for both models and agents, with adaptive routing, automatic failover, zero-markup inference, observability, guardrails, and agent-tool governance.
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.
Discord: discord.gg/YEubt8enRA · X: https://x.com/OrcaRouter
I'm an engineer on the OrcaRouter team.
Authentication (both entries, one seam)
Credential acquisition is a small interface (
CredentialSourceinresearchclaw/llm/orcarouter.py) with two adapters; provider requests, model discovery and every AI entry point read the resolved credential and never re-implement auth.api_key_env: ORCAROUTER_API_KEY,researchclaw orcarouter key --set, or the settings pageresearchclaw orcarouter login, or the Connect buttonorcarouterorcarouter-oauthCredentialStore, same masking/clear path--flow loopback. The repository's product surface is a CLI plus a localresearchclaw servedashboard — both run where a browser redirect back to127.0.0.1is not guaranteed (headless/remote boxes), so the OOB code is the flow that always works; loopback is available and tested where a local browser exists. Flow C device grant is not implemented — it does not replace PKCE.base64url(sha256(verifier)), no padding. A fresh verifier andstateare drawn fromsecretsper attempt, the verifier never leaves the process until exchange (never in a URL, log, telemetry, or the page), and the loopback callback comparesstatein constant time before the code is used.https://www.orcarouter.aiwithauthorizeat/authand exchange atPOST /api/v1/auth/keys; inference and the catalogue default tohttps://api.orcarouter.ai/v1.ORCA_AUTH_BASE_URL/ORCA_API_BASE_URL/ sharedORCA_BASE_URLoverride explicitly and win over the defaults; remote origins must be HTTPS, HTTP is accepted only for loopback.https://api.orcarouter.ai/v1/auth/keysis never built — the code path that would construct it raises instead, and a test asserts the string is absent from user-facing output.needsReauth, so an in-flight failure from a previous generation cannot contaminate a fresh login, and the old secret is not silently deleted before a new login succeeds.statemismatch, timeout, expired/reused code,403,429, and network errors all terminate with an actionable message instead of hanging or hot-looping, and response bodies are scrubbed of credential material before they reach a message.pagehide. A monotonic attempt/generation id stops a stale response from overwriting a newer login;pagehideclears the busy state and hint synchronously and issues akeepalivecancel to the server rather than relying on afinallythat the generation guard would swallow.Model catalogue and capability filtering
The model control is a real dropdown/search selector fed by
GET https://api.orcarouter.ai/v1/modelswith the user's own bearer key, so the list is what that workspace can actually call. Vendor/modelnamespace is preserved verbatim. The key stays on the server: the browser receives minimal model metadata only.Options are recomputed per entry point and re-filtered when the provider, task type, or attachment set changes; a selected model that no longer fits is cleared with a prompt to re-choose, never silently kept.
?capability=chatandsupported_endpoint_types∩ {openai, anthropic, gemini, openai-response}; image-generation / openai-video / jina-rerank models excludedarchitecture.input_modalitiesmust explicitly contain the modality actually being sent; undeclared capability fails closed?capability=embedding(or strictembeddingsendpoint match)?capability=image(or strictimage-generation)openai-videojina-rerankA live response is authoritative. On failure a small, verified cold-start seed / last-known-good catalogue is used with a degraded/refresh state shown in the UI — never free text, and a restored model id is re-validated against the current filtered list before it is re-selected. The seed is
orcarouter/auto,anthropic/claude-opus-4.8,openai/gpt-5.5,google/gemini-3.5-flash,deepseek/deepseek-v4-pro, with verified context / input-modality / reasoning metadata retained (including GPT-5.5's low/medium/high/xhigh).AI entry points covered
This repository's AI request surface, traced from
create_llm_clientoutward, is text chat/agent completion — the research pipeline stages, the debate/tournament engines, code agents, and theresearchclawCLI all route through it — plus embedding/rerank and image generation, which are wired to their own backends. The OrcaRouter provider is registered in the central provider table (README.md,config.researchclaw.example.yaml,researchclaw/llm/__init__.py) and is therefore reachable from every chat/agent entry point at once. The capability filters above are implemented and tested for all six kinds even where this repository has no caller yet, so a future entry point cannot leak an incompatible model into its selector. No entry point in this repository sends an image to the chat client — messages are{role, content}text and the only image producer is pinned to Gemini's native API — so the multimodal selector is not applicable here and is recorded as such rather than faked.Evidence
POST https://api.orcarouter.ai/v1/chat/completions, OpenAI-compatible (verified with a real request throughcreate_llm_client)GET https://api.orcarouter.ai/v1/models(verified live; 16 chat models returned for the test workspace)https://www.orcarouter.ai/authauthorize,POST https://www.orcarouter.ai/api/v1/auth/keysexchange, PKCE S256, no client secret, no pre-registered redirect URI401that marks only that credential generation for reauthenticationScreenshots of the real settings page (
/providers) — both authentication entries side by side with the key masked, and the real model dropdown expanded — are produced byscripts/orcarouter_ui_evidence.py(real FastAPI app, real Chromium, live catalogue) and validated against the delivery checklist before hand-over. The bundle stays out of the patch: evidence has to be the output of a run of the code under test, soorca-evidence/is git-ignored andtests/test_orcarouter_ui.pygenerates it, holds it to the checklist, and asserts nothing under it is tracked.Tests
Run with
pytest, perCONTRIBUTING.md:pytest tests/test_orcarouter_provider.py tests/test_orcarouter_cli.py -qpytest tests/test_orcarouter_pkce.py -qpytest tests/test_orcarouter_catalog.py tests/test_orcarouter_model_select.py -qpytest tests/test_orcarouter_server.py tests/test_orcarouter_ui.py -qpytest tests/test_orcarouter_live.py -q(live, real key)pytest tests/ -qBoth adapters are asserted to produce the same credential result, and provider requests plus catalogue discovery are asserted not to care which adapter produced it. Tests cover API-key save/read/clear/masking; verifier/challenge/
stategeneration; the authorize URL; the exact exchange path and body; successful persistence; denial; Flow Astatemismatch; code reuse and expiry; scope downgrade; terminal classification of a corrupt key; precise-account reconnect on401;429and network failure; and the assertion that neither the verifier nor the key appears in any log or error. Auth requests are asserted to reach only the auth origin and inference/catalogue only the API origin (or an explicit override), and a revoked key is asserted not to trigger a pseudo-refresh while a stale generation cannot overwrite fresh credentials. The PKCE tests drive the shipped connect adapter against a local fake auth server end to end (authorize → callback/OOB → exchange → persist); the live check drivescreate_llm_clientand the model selector through the real gateway. All fixtures use fake keys and codes.A note on the final commit: an earlier revision of this branch had committed the generated
orca-evidence/bundle into the repository. That is backwards — a committed screenshot is stale by construction and the delivery checklist refuses a patch that ships one — so the bundle is now git-ignored, generated at its default in-repo output by the test run, and checked from there.