model_reasoning_effort not forwarded to third-party providers
What version of Codex is running?
codex-cli 0.64.0
What subscription do you have?
gpt-5.1-codex via ZenMux API
Which model were you using?
gpt-5.1-codex
What platform is your computer?
Microsoft Windows NT 10.0.19045.0 x64
What issue are you seeing?
Configured model_reasoning_effort = "high" (and model_reasoning_summary = "auto"). When routing via a custom provider (base_url points to a relay that adds an openai/ prefix to model names), Codex does not forward reasoning controls:
1) Chat wire (POST /v1/chat/completions): Body never contains a top‑level "reasoning_effort" key.
2) Responses wire (POST /v1/responses): "reasoning" becomes null unless the model slug matches specific patterns (appears tied to CONTEXT_WINDOW_272K‑related checks). With the relay’s openai/ prefix, the slug check never matches, so "reasoning" stays null.
Representative (redacted) downstream log (Chat wire):
POST /chat/completions
Headers: { "authorization": "Bearer ****(masked)", "accept": "text/event-stream", ... }
JSON Body:
{
"model": "openai/gpt-5.1-codex",
"messages": [
{"role":"system","content":"..."},
{"role":"user","content":"test"}
]
// No "reasoning_effort" present
}
Code pointer found while investigating:
pub(crate) fn get_model_info(model_family: &ModelFamily) -> Option<ModelInfo> {
let slug = model_family.slug.as_str();
match slug {
// ...
_ if slug.starts_with("gpt-5-codex")
|| slug.starts_with("gpt-5.1-codex")
|| slug.starts_with("gpt-5.1-codex-max") => {
Some(ModelInfo::new(CONTEXT_WINDOW_272K))
}
_ if slug.starts_with("gpt-5") => Some(ModelInfo::new(CONTEXT_WINDOW_272K)),
_ if slug.starts_with("codex-") => Some(ModelInfo::new(CONTEXT_WINDOW_272K)),
_ if slug.starts_with("exp-") => Some(ModelInfo::new(CONTEXT_WINDOW_272K)),
_ => None,
}
}
Observation (correlation, not proof): In our testing, models whose names match the above prefixes tend to produce a non-null "reasoning" in responses mode, while names that do not match (relay prefixes them with openai/…) result in "reasoning": null.
What steps can reproduce the bug?
1) Start a local transparent proxy to print requests and forward to the real third‑party relay (any simple HTTP proxy that dumps JSON is fine).
2) Configure Codex to use a custom provider with that proxy’s base_url.
config.toml (redacted)
model = "openai/gpt-5.1-codex"
model_provider = "my3p"
model_reasoning_effort = "high"
model_reasoning_summary = "auto"
[model_providers.my3p]
name = "ThirdParty"
base_url = "http://127.0.0.1:8787/v1" # points to local proxy
env_key = "THIRDPARTY_API_KEY"
wire_api = "chat" # also test "responses"
3) Run Codex once (any trivial prompt, e.g., “test”).
4) Inspect the proxy logs.
Observed:
- With
wire_api="chat"→ body lacks"reasoning_effort". - With
wire_api="responses"→"reasoning"isnullunless the model slug matches internal patterns; when the relay prefixes model withopenai/…, it never matches, so"reasoning"staysnull.
Note: The relay consistently rewrites the model name to include openai/ (e.g., openai/gpt-5.1-codex).
What is the expected behavior?
- When
model_reasoning_effortis set in config: - Chat wire should include a top‑level
"reasoning_effort": "<low|medium|high|minimal>"in the request body. - Responses wire should include
"reasoning": { "effort": "<…>", "summary": "<auto|…>" }". - Emission of these fields should not depend on model‑name heuristics or context‑window families. Providers that don’t support the field can reject it server‑side.
Additional information
_No response_
This issue has 4 comments on GitHub. Read the full discussion on GitHub ↗