From 25a36cb8292881a30a95b79cf6b0c30ee5e1a9ee Mon Sep 17 00:00:00 2001 From: Jeremy Rose <172423086+nornagon-openai@users.noreply.github.com> Date: Fri, 10 Oct 2025 12:36:14 -0700 Subject: [PATCH] Fixes #5033 Normalize model family detection to handle prefixed slugs so OpenRouter models retain reasoning effort. --- codex-rs/core/src/model_family.rs | 38 ++++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 11 deletions(-) diff --git a/codex-rs/core/src/model_family.rs b/codex-rs/core/src/model_family.rs index 80b3f27986..b82d96248b 100644 --- a/codex-rs/core/src/model_family.rs +++ b/codex-rs/core/src/model_family.rs @@ -82,37 +82,39 @@ pub fn find_family_for_model(mut slug: &str) -> Option { if matches!(std::env::var("CODEX_EXPERIMENTAL").as_deref(), Ok("1")) { slug = "codex-experimental"; } - if slug.starts_with("o3") { + let normalized_slug = slug.rsplit('/').next().unwrap_or(slug); + + if normalized_slug.starts_with("o3") { model_family!( slug, "o3", supports_reasoning_summaries: true, needs_special_apply_patch_instructions: true, ) - } else if slug.starts_with("o4-mini") { + } else if normalized_slug.starts_with("o4-mini") { model_family!( slug, "o4-mini", supports_reasoning_summaries: true, needs_special_apply_patch_instructions: true, ) - } else if slug.starts_with("codex-mini-latest") { + } else if normalized_slug.starts_with("codex-mini-latest") { model_family!( slug, "codex-mini-latest", supports_reasoning_summaries: true, uses_local_shell_tool: true, needs_special_apply_patch_instructions: true, ) - } else if slug.starts_with("gpt-4.1") { + } else if normalized_slug.starts_with("gpt-4.1") { model_family!( slug, "gpt-4.1", needs_special_apply_patch_instructions: true, ) - } else if slug.starts_with("gpt-oss") || slug.starts_with("openai/gpt-oss") { + } else if normalized_slug.starts_with("gpt-oss") { model_family!(slug, "gpt-oss", apply_patch_tool_type: Some(ApplyPatchToolType::Function)) - } else if slug.starts_with("gpt-4o") { + } else if normalized_slug.starts_with("gpt-4o") { model_family!(slug, "gpt-4o", needs_special_apply_patch_instructions: true) - } else if slug.starts_with("gpt-3.5") { + } else if normalized_slug.starts_with("gpt-3.5") { model_family!(slug, "gpt-3.5", needs_special_apply_patch_instructions: true) - } else if slug.starts_with("test-gpt-5-codex") { + } else if normalized_slug.starts_with("test-gpt-5-codex") { model_family!( slug, slug, supports_reasoning_summaries: true, @@ -128,7 +130,7 @@ pub fn find_family_for_model(mut slug: &str) -> Option { ) // Internal models. - } else if slug.starts_with("codex-") { + } else if normalized_slug.starts_with("codex-") { model_family!( slug, slug, supports_reasoning_summaries: true, @@ -144,7 +146,7 @@ pub fn find_family_for_model(mut slug: &str) -> Option { ) // Production models. - } else if slug.starts_with("gpt-5-codex") { + } else if normalized_slug.starts_with("gpt-5-codex") { model_family!( slug, slug, supports_reasoning_summaries: true, @@ -152,7 +154,7 @@ pub fn find_family_for_model(mut slug: &str) -> Option { base_instructions: GPT_5_CODEX_INSTRUCTIONS.to_string(), apply_patch_tool_type: Some(ApplyPatchToolType::Freeform), ) - } else if slug.starts_with("gpt-5") { + } else if normalized_slug.starts_with("gpt-5") { model_family!( slug, "gpt-5", supports_reasoning_summaries: true, @@ -177,3 +179,17 @@ pub fn derive_default_model_family(model: &str) -> ModelFamily { experimental_supported_tools: Vec::new(), } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn openrouter_prefixed_gpt5_codex_supports_reasoning() { + let model_family = + find_family_for_model("openai/gpt-5-codex").expect("expected to resolve model family"); + + assert!(model_family.supports_reasoning_summaries); + assert_eq!(model_family.slug, "openai/gpt-5-codex"); + } +}