Skip to content

fix(catalog): stop Codex CLI model-catalog refresh from erroring - #3481

Merged
diegosouzapw merged 1 commit into
release/v3.8.18from
fix/codex-models-catalog
Jun 9, 2026
Merged

diegosouzapw merged 1 commit into
release/v3.8.18from
fix/codex-models-catalog

Conversation

@diegosouzapw

Copy link
Copy Markdown
Collaborator

Problem

The Codex CLI's model-catalog refresh (codex_models_manager) does GET /v1/models?client_version=<v> and decodes a JSON object with a top-level models array. OmniRoute answers in the OpenAI-standard {object,data} shape, so codex fails with:

ERROR codex_models_manager: failed to refresh available models:
  failed to decode models response: missing field `models`

…logging failed to refresh available models on 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:

  1. Detection signal: codex sends originator: codex_exec / codex_cli_rs and a codex_* User-Agent on its GET /v1/models?client_version=... refresh.

  2. Required schema: the wire response must contain a top-level models: [] (13 required ModelInfo fields 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).

  3. 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:

    • refresh failing (today) → 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 models would break codex's agent behaviour. Returning an empty models: [] keeps codex on its built-in model info — same inference as before, minus the error.

Fix

Detect codex clients via the originator / user-agent headers and add an empty top-level models: [] to the GET /v1/models response. Non-codex OpenAI clients get the byte-identical {object,data} response (no models key). Scope is restricted to the response shape — auth, inference routing, and other endpoints are untouched.

Validation

  • TDD — tests/unit/codex-models-catalog-refresh.test.ts (RED→GREEN): codex via originator, codex via user-agent, and non-codex (unchanged shape). 3/3 green.
  • End-to-end vs codex 0.137 against the real getUnifiedModelsResponse handler: failed to refresh available models → 0 occurrences, inference instructions preserved (built-in Codex agent prompt, not empty).
  • Lint clean (changed files); typecheck (tsc -p tsconfig.json) reports 0 errors in catalog.ts / the test; existing catalog tests ([BUG] playground chat model list cannot fetch properly #3200, cc-compatible) pass — no regression.
  • Note: the worktree next build fails on a pre-existing, unrelated fumadocs MDX schema error in docs/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

Loading
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