Skip to content

fix(server): return Codex metadata from /v1/models - #304

Open
elyasmnvidian wants to merge 3 commits into
mainfrom
emehtabuddin/fix-codex-model-discovery
Open

fix(server): return Codex metadata from /v1/models#304
elyasmnvidian wants to merge 3 commits into
mainfrom
emehtabuddin/fix-codex-model-discovery

Conversation

@elyasmnvidian

@elyasmnvidian elyasmnvidian commented Aug 5, 2026

Copy link
Copy Markdown
Contributor
{
  "object": "list",
  "data": [{"id": "switchyard", "object": "model"}],
  "model_pool": ["switchyard"]
}

What happens

Codex direct-provider discovery decodes this response as a Codex model catalog, not only as an OpenAI model list.

failed to decode models response: missing field `models`
Unknown model switchyard is used. This will use fallback model metadata.

Why

GET /v1/models currently returns only the OpenAI-compatible data array. Codex expects a top-level models array whose entries include its model metadata fields, so it discards the route's declared context window and tool support.

The endpoint now returns both arrays from the same route registry. Existing data, model_pool, and default-model fields remain unchanged. Each Codex entry reflects the route's declared context window, tool support, and reasoning, which the route registry owns and feeds to both arrays. The constant Codex card shape is a static mirror of Codex's ModelInfo; the launcher builds the same card in switchyard/cli/launchers/codex_model_catalog.py, and the two are kept in step by hand.

This is an additive response change. Existing OpenAI-compatible model discovery keeps the same fields and values.

Proof

The same local route now returns both catalogs:

keys: data, default_model, first_id, has_more, last_id, model_pool, models, object
models[0].slug: switchyard
models[0].context_window: 128000
models[0].shell_type: shell_command

The installed Codex CLI then completes the direct-provider request without the decode or fallback warning:

codex
pong

The proof used a local OpenAI-compatible upstream; it did not contact a model provider.

How tested

cargo test -p switchyard-server --test server models_endpoint_reports_declared_route_capabilities_and_null_when_undeclared

The regression test checks the OpenAI and Codex catalogs together, including declared, restricted, and undeclared route capabilities.

Summary by CodeRabbit

  • New Features
    • Added Codex-compatible model metadata to the models endpoint.
    • Model entries now include context-window details, shell support, patch tool information, priority, and reasoning capabilities.
  • Bug Fixes
    • Improved model metadata coverage for declared, restricted, and undeclared routes.

@elyasmnvidian
elyasmnvidian requested a review from a team as a code owner August 5, 2026 17:35
@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

The /v1/models response now includes an ordered Codex-compatible models array. Each entry contains capability-derived metadata, context-window values, and fixed feature flags. Integration tests cover declared, restricted, and undeclared capabilities.

Changes

Codex model discovery

Layer / File(s) Summary
Codex metadata generation
crates/switchyard-server/src/lib.rs
codex_model_entry_json generates Codex model metadata from route names and capabilities.
Model-list integration and validation
crates/switchyard-server/src/lib.rs, crates/switchyard-server/tests/server.rs
model_list_payload adds ordered Codex entries. Integration tests validate metadata for declared, restricted, and undeclared capabilities.

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

Poem

A rabbit checked the model list,
“Codex fields are here,” it hissed.
Tools and windows line up bright,
Routes reveal their granted might.
Tests nod twice: the shape is right.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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 to return Codex metadata from the /v1/models endpoint.

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
crates/switchyard-server/tests/server.rs (1)

1152-1156: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Assert the raw Codex array before collecting it into BTreeMap.

BTreeMap removes entry order and collapses duplicate slug values. The test can pass when models has extra duplicate entries or incorrect priorities. Assert raw-array length, order relative to data, and each zero-based priority before building codex_metadata.

Proposed test coverage
     let codex_models = body["models"].as_array().cloned().unwrap_or_default();
+    assert_eq!(codex_models.len(), data.len());
+    for (priority, (codex_model, data_model)) in codex_models.iter().zip(data.iter()).enumerate() {
+        assert_eq!(codex_model["slug"], data_model["id"]);
+        assert_eq!(codex_model["priority"], json!(priority));
+    }
+
     let codex_metadata = codex_models

As per PR objectives, the models array must preserve order and assign priorities.

🤖 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 `@crates/switchyard-server/tests/server.rs` around lines 1152 - 1156, Update
the test around the raw `body["models"]` value before constructing
`codex_metadata`: assert the array length, verify its order against `data`, and
validate each entry’s zero-based `priority`. Keep the existing `BTreeMap`
collection only for subsequent lookup, so duplicate slugs or reordered entries
cannot make the test pass.
🤖 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.

Nitpick comments:
In `@crates/switchyard-server/tests/server.rs`:
- Around line 1152-1156: Update the test around the raw `body["models"]` value
before constructing `codex_metadata`: assert the array length, verify its order
against `data`, and validate each entry’s zero-based `priority`. Keep the
existing `BTreeMap` collection only for subsequent lookup, so duplicate slugs or
reordered entries cannot make the test pass.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: f8f63007-afbe-4494-976e-73a64d82570f

📥 Commits

Reviewing files that changed from the base of the PR and between 016a511 and abf1b38.

📒 Files selected for processing (2)
  • crates/switchyard-server/src/lib.rs
  • crates/switchyard-server/tests/server.rs

@elyasmnvidian
elyasmnvidian force-pushed the emehtabuddin/fix-codex-model-discovery branch from abf1b38 to bbb667c Compare August 5, 2026 18:17
@github-actions

github-actions Bot commented Aug 5, 2026

Copy link
Copy Markdown
PR Preview Action v1.8.1

🚀 View preview at
https://NVIDIA-NeMo.github.io/Switchyard/pr-preview/pr-304/

Built to branch gh-pages at 2026-08-05 21:59 UTC.
Preview will be ready when the GitHub Pages deployment is complete.

{"effort": "medium", "description": "Balances speed and reasoning depth"},
{"effort": "high", "description": "Greater reasoning depth"},
{"effort": "xhigh", "description": "Extra high reasoning depth"},
])

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.

There's a lot of assumptions in here for reasoning levels (they are all over the place in real models), and in codex_model_entry_json.

Is there a way (likely later) we can load this from the backend?We're a proxy after all, we should re-publish what the backend has.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Good call — I added a TODO in codex_model_entry_json for this (81f2d13). Only context_window, tool_calling, and reasoning are model facts a backend can publish, so those should come from the backend, with the route's config value as the fallback. The rest of the card — shell_type, apply_patch_tool_type, base_instructions, the reasoning-level presets — are Codex client conventions that no backend returns, so they stay constant.

It only works where the backend publishes the data. OpenRouter's /api/v1/models returns context_length and supported_parameters, so the packaged OpenRouter deployment can load all three. The NVIDIA gateway returns id-only models and blocks /model/info for our key, so config stays the fallback there. I'll file the follow-up.

@elyasmnvidian
elyasmnvidian force-pushed the emehtabuddin/fix-codex-model-discovery branch from bbb667c to b18869c Compare August 5, 2026 20:46
@elyasmnvidian
elyasmnvidian enabled auto-merge (squash) August 5, 2026 20:52
Signed-off-by: Elyas Mehtabuddin <emehtabuddin@nvidia.com>
Signed-off-by: Elyas Mehtabuddin <emehtabuddin@nvidia.com>
Signed-off-by: Elyas Mehtabuddin <emehtabuddin@nvidia.com>
@elyasmnvidian
elyasmnvidian force-pushed the emehtabuddin/fix-codex-model-discovery branch from 81f2d13 to 271fd5a Compare August 5, 2026 21:58
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.

2 participants