feat(provider): add OpenRouter as an API-key provider riding the Codex CLI#554
Open
AndreSierraM wants to merge 3 commits into
Open
feat(provider): add OpenRouter as an API-key provider riding the Codex CLI#554AndreSierraM wants to merge 3 commits into
AndreSierraM wants to merge 3 commits into
Conversation
…x CLI OpenRouter connects through the existing bundled codex binary pointed at OpenRouter's OpenAI-compatible endpoint with a Houston-managed API key — no parallel CLI or subscription flow. Engine - New `CodexBackend` on the `ProviderAdapter` trait: a provider that rides `codex exec` against a custom endpoint describes its slug / base_url / env_key / wire_api / default_model. The codex command builder turns it into `-c model_provider` overrides; the runner injects the API-key env var. So every codex dispatch site (session_dispatch, session_io, provider_oneshot, cli_process) treats "openai" | "openrouter" identically and the next OpenAI-compatible provider is one adapter file — no dispatch edits. - `wire_api = "responses"` (the bundled codex dropped "chat", codex#7782). - Adapter + HTTP-status error classifier (401/402/404/429/5xx/network → shared ProviderError taxonomy, fully unit-tested). - Generic key storage at `<houston-home>/providers/<slug>/.env` (atomic, 0600); set/strip via engine-core; route `/providers/openrouter/credentials`. - Title / compaction / generate helpers wired for openrouter. Frontend - `providers.ts` entry (loginKind: apiKey) with a curated set of cheap, capable open-source models (DeepSeek V3 default, Llama 3.3 70B, Qwen2.5 72B, Mistral Nemo). Picker is data-driven, so it appears automatically. - Generic `ApiKeyConnectDialog` (replaces the gemini-specific dialog in the picker + settings) + generic `setProviderApiKey` client method. - Official OpenRouter logo, en/es/pt strings. Docs: agent-manifest, provider-errors, engine-protocol, auth. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ifier
OpenRouter sessions complete fine, but codex prints two non-fatal diagnostics
on stderr that were producing false provider-error cards:
- `codex_models_manager` logs a failed catalog refresh (OpenRouter returns
`{"data":[...]}`, codex expects `{"models":[...]}`) and dumps the entire
multi-hundred-KB catalog body. That body almost always contains a bare
"401" (pricing/ids), which `is_auth_error`'s substring check turned into a
false "Reconnect to OpenRouter" Unauthenticated card on an otherwise
successful turn.
- `rmcp::` logs auth failures for MCP servers configured in the user's own
`~/.codex/config.toml` — the user's MCP, not the OpenRouter turn.
`classify_stderr` now early-returns `None` for these codex-internal lines.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Two speed/correctness improvements for OpenRouter (both ride the same codex backend mechanism, so they're surgical): - **Isolated CODEX_HOME.** OpenRouter sessions now run codex against `<houston-home>/codex-home` instead of the user's `~/.codex`, so codex never loads the user's personal `~/.codex/config.toml` (their own MCP servers + settings) into a Houston session. This removes a per-spawn MCP connection attempt (the user's MCP failing auth was leaking a stray reconnect card) and cut a real session's input from ~23k to ~13k tokens — the user's MCP tool-defs were being injected into context every turn. Native codex (OpenAI) keeps `~/.codex` (it needs the OAuth `auth.json` there). `codex_rollout` now searches both homes for token-usage, so the context gauge keeps working. - **No reasoning effort.** The curated OpenRouter models are non-reasoning chat models, so `model_reasoning_effort` is dead overhead; the adapter now reports no effort levels and the runner omits the flag. Skipped `:nitro` throughput routing on purpose — it routes to premium providers and would undercut the "cheap open-source" model curation. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.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.
What
Adds OpenRouter as a provider. It reuses the bundled
codexbinary pointed at OpenRouter's OpenAI-compatible endpoint with a Houston-managed API key — no parallel CLI or subscription flow.How it's wired (scalable)
New
CodexBackendon theProviderAdaptertrait: a provider that ridescodex execagainst a custom endpoint just describes itsslug / base_url / env_key / wire_api / default_model. The codex command builder turns that into-c model_provideroverrides; the runner injects the API-key env var.Result: every codex dispatch site (
session_dispatch,session_io,provider_oneshot,cli_process) treats"openai" | "openrouter"identically — the next OpenAI-compatible provider is one adapter file, no dispatch edits.wire_api = "responses"(the bundled codex dropped"chat", codex#7782).ProviderErrortaxonomy), fully unit-tested.<houston-home>/providers/<slug>/.env(atomic, mode 0600); set/strip in engine-core; routePOST /v1/providers/openrouter/credentials.Frontend
providers.tsentry (loginKind: apiKey) with a curated set of cheap, capable open-source models: DeepSeek V3 (default), Llama 3.3 70B, Qwen2.5 72B, Mistral Nemo. The picker is data-driven, so it appears automatically.ApiKeyConnectDialog(replaces the gemini-specific dialog in picker + settings) + genericsetProviderApiKeyclient method.Tests
cargo testgreen across terminal-manager / engine-core / engine-server (incl. new classifier, codex override, credential, and providers-route tests).pnpm tsc --noEmit+pnpm check-localesgreen.Docs
agent-manifest,provider-errors,engine-protocol,authupdated.🤖 Generated with Claude Code