From ad7eaa80f9d8cfab1d899936b44e05baa2c4639a Mon Sep 17 00:00:00 2001 From: Ahmed Ibrahim Date: Wed, 12 Nov 2025 19:44:53 -0800 Subject: [PATCH] Change model picker to include gpt5.1 (#6569) - Change the presets - Change the tests that make sure we keep the list of tools updated - Filter out deprecated models --- .../app-server/tests/suite/v2/model_list.rs | 16 ++-- codex-rs/common/src/model_presets.rs | 77 ++++++++++++++++++- codex-rs/core/src/tools/spec.rs | 72 +++++++++++++++++ codex-rs/core/tests/suite/model_tools.rs | 6 +- codex-rs/tui/src/chatwidget.rs | 4 +- ...ests__model_reasoning_selection_popup.snap | 2 +- ...twidget__tests__model_selection_popup.snap | 5 +- ...tests__rate_limit_switch_prompt_popup.snap | 5 +- codex-rs/tui/src/chatwidget/tests.rs | 12 +-- 9 files changed, 171 insertions(+), 28 deletions(-) diff --git a/codex-rs/app-server/tests/suite/v2/model_list.rs b/codex-rs/app-server/tests/suite/v2/model_list.rs index 667d9e001..c55a87c19 100644 --- a/codex-rs/app-server/tests/suite/v2/model_list.rs +++ b/codex-rs/app-server/tests/suite/v2/model_list.rs @@ -46,9 +46,9 @@ async fn list_models_returns_all_models_with_large_limit() -> Result<()> { let expected_models = vec![ Model { - id: "gpt-5-codex".to_string(), - model: "gpt-5-codex".to_string(), - display_name: "gpt-5-codex".to_string(), + id: "gpt-5.1-codex".to_string(), + model: "gpt-5.1-codex".to_string(), + display_name: "gpt-5.1-codex".to_string(), description: "Optimized for codex.".to_string(), supported_reasoning_efforts: vec![ ReasoningEffortOption { @@ -69,9 +69,9 @@ async fn list_models_returns_all_models_with_large_limit() -> Result<()> { is_default: true, }, Model { - id: "gpt-5".to_string(), - model: "gpt-5".to_string(), - display_name: "gpt-5".to_string(), + id: "gpt-5.1".to_string(), + model: "gpt-5.1".to_string(), + display_name: "gpt-5.1".to_string(), description: "Broad world knowledge with strong general reasoning.".to_string(), supported_reasoning_efforts: vec![ ReasoningEffortOption { @@ -132,7 +132,7 @@ async fn list_models_pagination_works() -> Result<()> { } = to_response::(first_response)?; assert_eq!(first_items.len(), 1); - assert_eq!(first_items[0].id, "gpt-5-codex"); + assert_eq!(first_items[0].id, "gpt-5.1-codex"); let next_cursor = first_cursor.ok_or_else(|| anyhow!("cursor for second page"))?; let second_request = mcp @@ -154,7 +154,7 @@ async fn list_models_pagination_works() -> Result<()> { } = to_response::(second_response)?; assert_eq!(second_items.len(), 1); - assert_eq!(second_items[0].id, "gpt-5"); + assert_eq!(second_items[0].id, "gpt-5.1"); assert!(second_cursor.is_none()); Ok(()) } diff --git a/codex-rs/common/src/model_presets.rs b/codex-rs/common/src/model_presets.rs index 43d66e703..510ce746b 100644 --- a/codex-rs/common/src/model_presets.rs +++ b/codex-rs/common/src/model_presets.rs @@ -32,6 +32,76 @@ pub struct ModelPreset { } const PRESETS: &[ModelPreset] = &[ + ModelPreset { + id: "gpt-5.1-codex", + model: "gpt-5.1-codex", + display_name: "gpt-5.1-codex", + description: "Optimized for codex.", + default_reasoning_effort: ReasoningEffort::Medium, + supported_reasoning_efforts: &[ + ReasoningEffortPreset { + effort: ReasoningEffort::Low, + description: "Fastest responses with limited reasoning", + }, + ReasoningEffortPreset { + effort: ReasoningEffort::Medium, + description: "Dynamically adjusts reasoning based on the task", + }, + ReasoningEffortPreset { + effort: ReasoningEffort::High, + description: "Maximizes reasoning depth for complex or ambiguous problems", + }, + ], + is_default: true, + recommended_upgrade_model: None, + }, + ModelPreset { + id: "gpt-5.1-codex-mini", + model: "gpt-5.1-codex-mini", + display_name: "gpt-5.1-codex-mini", + description: "Optimized for codex. Cheaper, faster, but less capable.", + default_reasoning_effort: ReasoningEffort::Medium, + supported_reasoning_efforts: &[ + ReasoningEffortPreset { + effort: ReasoningEffort::Medium, + description: "Dynamically adjusts reasoning based on the task", + }, + ReasoningEffortPreset { + effort: ReasoningEffort::High, + description: "Maximizes reasoning depth for complex or ambiguous problems", + }, + ], + is_default: false, + recommended_upgrade_model: None, + }, + ModelPreset { + id: "gpt-5.1", + model: "gpt-5.1", + display_name: "gpt-5.1", + description: "Broad world knowledge with strong general reasoning.", + default_reasoning_effort: ReasoningEffort::Medium, + supported_reasoning_efforts: &[ + ReasoningEffortPreset { + effort: ReasoningEffort::Minimal, + description: "Fastest responses with little reasoning", + }, + ReasoningEffortPreset { + effort: ReasoningEffort::Low, + description: "Balances speed with some reasoning; useful for straightforward queries and short explanations", + }, + ReasoningEffortPreset { + effort: ReasoningEffort::Medium, + description: "Provides a solid balance of reasoning depth and latency for general-purpose tasks", + }, + ReasoningEffortPreset { + effort: ReasoningEffort::High, + description: "Maximizes reasoning depth for complex or ambiguous problems", + }, + ], + is_default: false, + recommended_upgrade_model: None, + }, + // Deprecated models. ModelPreset { id: "gpt-5-codex", model: "gpt-5-codex", @@ -52,7 +122,7 @@ const PRESETS: &[ModelPreset] = &[ description: "Maximizes reasoning depth for complex or ambiguous problems", }, ], - is_default: true, + is_default: false, recommended_upgrade_model: Some("gpt-5.1-codex"), }, ModelPreset { @@ -107,7 +177,10 @@ pub fn builtin_model_presets(auth_mode: Option) -> Vec { let allow_codex_mini = matches!(auth_mode, Some(AuthMode::ChatGPT)); PRESETS .iter() - .filter(|preset| allow_codex_mini || preset.id != "gpt-5-codex-mini") + .filter(|preset| { + (allow_codex_mini || preset.id != "gpt-5.1-codex-mini") + && preset.recommended_upgrade_model.is_none() + }) .copied() .collect() } diff --git a/codex-rs/core/src/tools/spec.rs b/codex-rs/core/src/tools/spec.rs index 82ef57d65..0a9fefdde 100644 --- a/codex-rs/core/src/tools/spec.rs +++ b/codex-rs/core/src/tools/spec.rs @@ -1257,6 +1257,23 @@ mod tests { ); } + #[test] + fn test_build_specs_gpt51_codex_default() { + assert_model_tools( + "gpt-5.1-codex", + &Features::with_defaults(), + &[ + "shell", + "list_mcp_resources", + "list_mcp_resource_templates", + "read_mcp_resource", + "update_plan", + "apply_patch", + "view_image", + ], + ); + } + #[test] fn test_build_specs_gpt5_codex_unified_exec_web_search() { assert_model_tools( @@ -1278,6 +1295,27 @@ mod tests { ); } + #[test] + fn test_build_specs_gpt51_codex_unified_exec_web_search() { + assert_model_tools( + "gpt-5.1-codex", + Features::with_defaults() + .enable(Feature::UnifiedExec) + .enable(Feature::WebSearchRequest), + &[ + "exec_command", + "write_stdin", + "list_mcp_resources", + "list_mcp_resource_templates", + "read_mcp_resource", + "update_plan", + "apply_patch", + "web_search", + "view_image", + ], + ); + } + #[test] fn test_codex_mini_defaults() { assert_model_tools( @@ -1294,6 +1332,40 @@ mod tests { ); } + #[test] + fn test_codex_5_1_mini_defaults() { + assert_model_tools( + "gpt-5.1-codex-mini", + &Features::with_defaults(), + &[ + "shell", + "list_mcp_resources", + "list_mcp_resource_templates", + "read_mcp_resource", + "update_plan", + "apply_patch", + "view_image", + ], + ); + } + + #[test] + fn test_gpt_5_1_defaults() { + assert_model_tools( + "gpt-5.1", + &Features::with_defaults(), + &[ + "shell", + "list_mcp_resources", + "list_mcp_resource_templates", + "read_mcp_resource", + "update_plan", + "apply_patch", + "view_image", + ], + ); + } + #[test] fn test_porcupine_defaults() { assert_model_tools( diff --git a/codex-rs/core/tests/suite/model_tools.rs b/codex-rs/core/tests/suite/model_tools.rs index 6689b042b..b98d64328 100644 --- a/codex-rs/core/tests/suite/model_tools.rs +++ b/codex-rs/core/tests/suite/model_tools.rs @@ -140,10 +140,10 @@ async fn model_selects_expected_tools() { "update_plan".to_string(), "apply_patch".to_string() ], - "gpt-5-codex should expose the apply_patch tool", + "gpt-5.1-codex should expose the apply_patch tool", ); - let gpt51_tools = collect_tool_identifiers_for_model("gpt-5-codex").await; + let gpt51_tools = collect_tool_identifiers_for_model("gpt-5.1").await; assert_eq!( gpt51_tools, vec![ @@ -154,6 +154,6 @@ async fn model_selects_expected_tools() { "update_plan".to_string(), "apply_patch".to_string() ], - "gpt-5-codex should expose the apply_patch tool", + "gpt-5.1 should expose the apply_patch tool", ); } diff --git a/codex-rs/tui/src/chatwidget.rs b/codex-rs/tui/src/chatwidget.rs index 37c832949..a92b28db6 100644 --- a/codex-rs/tui/src/chatwidget.rs +++ b/codex-rs/tui/src/chatwidget.rs @@ -132,7 +132,7 @@ struct RunningCommand { } const RATE_LIMIT_WARNING_THRESHOLDS: [f64; 3] = [75.0, 90.0, 95.0]; -const NUDGE_MODEL_SLUG: &str = "gpt-5-codex-mini"; +const NUDGE_MODEL_SLUG: &str = "gpt-5.1-codex-mini"; const RATE_LIMIT_SWITCH_PROMPT_THRESHOLD: f64 = 90.0; #[derive(Default)] @@ -1937,7 +1937,7 @@ impl ChatWidget { let warning = "⚠ High reasoning effort can quickly consume Plus plan rate limits."; let show_warning = - preset.model.starts_with("gpt-5-codex") && effort == ReasoningEffortConfig::High; + preset.model.starts_with("gpt-5.1-codex") && effort == ReasoningEffortConfig::High; let selected_description = show_warning.then(|| { description .as_ref() diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__model_reasoning_selection_popup.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__model_reasoning_selection_popup.snap index d2ef858a6..060d1f82a 100644 --- a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__model_reasoning_selection_popup.snap +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__model_reasoning_selection_popup.snap @@ -2,7 +2,7 @@ source: tui/src/chatwidget/tests.rs expression: popup --- - Select Reasoning Level for gpt-5-codex + Select Reasoning Level for gpt-5.1-codex 1. Low Fastest responses with limited reasoning 2. Medium (default) Dynamically adjusts reasoning based on the task diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__model_selection_popup.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__model_selection_popup.snap index 56be5c875..ff0f9ac8c 100644 --- a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__model_selection_popup.snap +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__model_selection_popup.snap @@ -5,8 +5,7 @@ expression: popup Select Model and Effort Access legacy models by running codex -m or in your config -› 1. gpt-5-codex (current) Optimized for codex. - 2. gpt-5 Broad world knowledge with strong general - reasoning. +› 1. gpt-5.1-codex Optimized for codex. + 2. gpt-5.1 Broad world knowledge with strong general reasoning. Press enter to select reasoning effort, or esc to dismiss. diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__rate_limit_switch_prompt_popup.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__rate_limit_switch_prompt_popup.snap index c89d65a50..e210d1f0a 100644 --- a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__rate_limit_switch_prompt_popup.snap +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__rate_limit_switch_prompt_popup.snap @@ -1,12 +1,11 @@ --- source: tui/src/chatwidget/tests.rs -assertion_line: 500 expression: popup --- Approaching rate limits - Switch to gpt-5-codex-mini for lower credit usage? + Switch to gpt-5.1-codex-mini for lower credit usage? -› 1. Switch to gpt-5-codex-mini Optimized for codex. Cheaper, +› 1. Switch to gpt-5.1-codex-mini Optimized for codex. Cheaper, faster, but less capable. 2. Keep current model 3. Keep current model (never show again) Hide future rate limit reminders diff --git a/codex-rs/tui/src/chatwidget/tests.rs b/codex-rs/tui/src/chatwidget/tests.rs index cc917a478..7c6f93699 100644 --- a/codex-rs/tui/src/chatwidget/tests.rs +++ b/codex-rs/tui/src/chatwidget/tests.rs @@ -1504,13 +1504,13 @@ fn windows_auto_mode_instructions_popup_lists_install_steps() { fn model_reasoning_selection_popup_snapshot() { let (mut chat, _rx, _op_rx) = make_chatwidget_manual(); - chat.config.model = "gpt-5-codex".to_string(); + chat.config.model = "gpt-5.1-codex".to_string(); chat.config.model_reasoning_effort = Some(ReasoningEffortConfig::High); let preset = builtin_model_presets(None) .into_iter() - .find(|preset| preset.model == "gpt-5-codex") - .expect("gpt-5-codex preset"); + .find(|preset| preset.model == "gpt-5.1-codex") + .expect("gpt-5.1-codex preset"); chat.open_reasoning_popup(preset); let popup = render_bottom_popup(&chat, 80); @@ -1582,13 +1582,13 @@ fn feedback_upload_consent_popup_snapshot() { fn reasoning_popup_escape_returns_to_model_popup() { let (mut chat, _rx, _op_rx) = make_chatwidget_manual(); - chat.config.model = "gpt-5".to_string(); + chat.config.model = "gpt-5.1".to_string(); chat.open_model_popup(); let presets = builtin_model_presets(None) .into_iter() - .find(|preset| preset.model == "gpt-5-codex") - .expect("gpt-5-codex preset"); + .find(|preset| preset.model == "gpt-5.1-codex") + .expect("gpt-5.1-codex preset"); chat.open_reasoning_popup(presets); let before_escape = render_bottom_popup(&chat, 80);