Repository navigation
fix(catalog): stop Codex CLI model-catalog refresh from erroring - #3481
Merged
Merged
Conversation
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.
Problem
The Codex CLI's model-catalog refresh (
codex_models_manager) doesGET /v1/models?client_version=<v>and decodes a JSON object with a top-levelmodelsarray. OmniRoute answers in the OpenAI-standard{object,data}shape, so codex fails with:…logging
failed to refresh available modelson every startup. Inference still works (it falls back to codex's built-in model info), but the error is noisy and the catalog refresh is broken.Root cause & key finding (verified empirically against codex 0.137)
Using a request-capturing local stub I confirmed:
Detection signal: codex sends
originator: codex_exec/codex_cli_rsand acodex_*User-Agent on itsGET /v1/models?client_version=...refresh.Required schema: the wire response must contain a top-level
models: [](13 requiredModelInfofields per entry:slug,display_name,supported_reasoning_levels,shell_type,visibility,supported_in_api,priority,base_instructions,supports_reasoning_summaries,support_verbosity,truncation_policy,supports_parallel_tool_calls,experimental_supported_tools).Why we do NOT populate the catalog: codex replaces its built-in per-model agent prompt (
base_instructions, ~21k chars) with whatever a populated entry carries for the selected model. Proven:instructions= full Codex agent prompt (21,335 chars)base_instructions: ""→instructions= 0 chars (agent prompt destroyed)base_instructions: <ours>→instructions= ours (hijacked)OmniRoute can't (and shouldn't) ship OpenAI's proprietary Codex prompt, so mirroring our catalog into
modelswould break codex's agent behaviour. Returning an emptymodels: []keeps codex on its built-in model info — same inference as before, minus the error.Fix
Detect codex clients via the
originator/user-agentheaders and add an empty top-levelmodels: []to theGET /v1/modelsresponse. Non-codex OpenAI clients get the byte-identical{object,data}response (nomodelskey). Scope is restricted to the response shape — auth, inference routing, and other endpoints are untouched.Validation
tests/unit/codex-models-catalog-refresh.test.ts(RED→GREEN): codex viaoriginator, codex viauser-agent, and non-codex (unchanged shape). 3/3 green.getUnifiedModelsResponsehandler:failed to refresh available models→ 0 occurrences, inferenceinstructionspreserved (built-in Codex agent prompt, not empty).tsc -p tsconfig.json) reports 0 errors incatalog.ts/ the test; existing catalog tests ([BUG] playground chat model list cannot fetch properly #3200, cc-compatible) pass — no regression.next buildfails on a pre-existing, unrelated fumadocs MDX schema error indocs/meta.json(src/app/docs/api/search/route.ts); that file is untouched by this PR and the error reproduces on the clean release branch.🤖 Generated with Claude Code