Skip to content

model_reasoning_effort is silently ignored for multi-segment custom model slugs #30697

Description

@canfengfei

What happened?

When using a third-party Responses API-compatible provider with a multi-segment custom model slug, Codex records model_reasoning_effort locally but does not forward it in the /v1/responses request body.

The request is sent with:

"reasoning": null

This happens even when model_reasoning_effort = "xhigh" is explicitly configured.

Expected behavior

If the user explicitly configures:

model_reasoning_effort = "xhigh"

Codex should either forward it as:

"reasoning": {
  "effort": "xhigh"
}

or emit a clear warning/error that the setting is ignored because the selected model has fallback metadata and is not marked as reasoning-capable.

It should not silently show/store the configured effort while omitting it from the actual request.

Reproduction

Use a custom provider with wire_api = "responses" and a model slug with more than one slash, for example:

model = "provider/group/gpt-5.5"
model_provider = "custom"
model_reasoning_effort = "xhigh"

[model_providers.custom]
name = "custom"
base_url = "https://example.com/v1"
wire_api = "responses"

Run:

codex exec --skip-git-repo-check --sandbox read-only --json 'reply OK'

Capture the outgoing /v1/responses request body.

Observed:

"reasoning": null

Why this appears to happen

Tested with codex-cli 0.142.4; source checked against tag rust-v0.142.4.

In codex-rs/models-manager/src/manager.rs, model metadata matching only supports a single namespace segment:

fn find_model_by_namespaced_suffix(model: &str, candidates: &[ModelInfo]) -> Option<ModelInfo> {
    let (namespace, suffix) = model.split_once('/')?;
    if suffix.contains('/') {
        return None;
    }
    ...
}

So a model like:

provider/group/gpt-5.5

does not inherit the known gpt-5.5 model metadata and falls back to model_info_from_slug.

In codex-rs/models-manager/src/model_info.rs, fallback metadata sets:

default_reasoning_level: None,
supported_reasoning_levels: Vec::new(),
supports_reasoning_summaries: false,
used_fallback_model_metadata: true,

Then in codex-rs/core/src/client.rs, build_reasoning() gates the entire reasoning request field on supports_reasoning_summaries:

fn build_reasoning(...) -> Option<Reasoning> {
    if model_info.supports_reasoning_summaries {
        Some(Reasoning { ... })
    } else {
        None
    }
}

Because fallback metadata has supports_reasoning_summaries = false, Codex drops the explicitly configured model_reasoning_effort.

Workaround

Providing a model_catalog_json entry for the custom model slug fixes the issue. Once the custom slug is declared with the same reasoning levels as gpt-5.5, Codex sends:

"reasoning": {
  "effort": "xhigh"
}

and the provider response confirms the requested effort.

Possible fixes

A few possible fixes:

  • If model_reasoning_effort is explicitly configured, forward reasoning.effort even when model metadata is fallback.
  • Emit a warning when model_reasoning_effort is configured but ignored because supports_reasoning_summaries = false.
  • Support metadata suffix matching for multi-segment provider slugs, e.g. provider/group/gpt-5.5 -> gpt-5.5.
  • Add a clearer config option such as model_family = "gpt-5.5" for custom provider model names.

Related stale/closed issue: #7590

Metadata

Metadata

Assignees

No one assigned

    Labels

    CLIIssues related to the Codex CLIbugSomething isn't workingconfigIssues involving config.toml, config keys, config merging, or config updatescustom-modelIssues related to custom model providers (including local models)

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions