From cc96a03f105ae6af03f1593a167dd7dd8c9d7b47 Mon Sep 17 00:00:00 2001 From: Ahmed Ibrahim Date: Mon, 20 Apr 2026 14:52:30 -0700 Subject: [PATCH] Fix stale model test fixtures (#18719) Fixes stale test fixtures left after the active bundled model catalog updates in #18586 and #18388. Those changes made `gpt-5.4` the current default and removed several older hardcoded slugs, which left Windows Bazel shards failing TUI and config tests. What changed: - Refresh TUI model migration, availability NUX, plan-mode, status, and snapshot fixtures to use active bundled model slugs. - Update the config edit test expectation for the TOML-quoted `"gpt-5.2"` migration key. - Move the model catalog tests into `codex-rs/tui/src/app/tests/model_catalog.rs` so touching them does not trip the blob-size policy for `app.rs`. Verification: - CI Bazel/lint checks are expected to cover the affected test shards. --- codex-rs/core/src/config/edit_tests.rs | 2 +- codex-rs/tui/src/app.rs | 310 +----------------- codex-rs/tui/src/app/tests/model_catalog.rs | 293 +++++++++++++++++ ...gration_prompt_shows_for_hidden_model.snap | 12 + ..._review_denied_renders_denied_request.snap | 2 +- ...w_timed_out_renders_timed_out_request.snap | 2 +- ...artup_failure_renders_warning_history.snap | 2 +- ...i__chatwidget__tests__chatwidget_tall.snap | 2 +- ...compact_queues_user_messages_snapshot.snap | 2 +- ...pproved_exec_renders_approved_request.snap | 2 +- ...ec_renders_warning_and_denied_request.snap | 2 +- ...allel_reviews_render_aggregate_status.snap | 2 +- ...renders_warning_and_timed_out_request.snap | 2 +- ...et__tests__mcp_startup_header_booting.snap | 2 +- ...ests__model_reasoning_selection_popup.snap | 2 +- ...ng_selection_popup_extra_high_warning.snap | 16 +- ...twidget__tests__model_selection_popup.snap | 16 +- ..._tests__preamble_keeps_working_status.snap | 2 +- ...tests__rate_limit_switch_prompt_popup.snap | 6 +- ..._review_queues_user_messages_snapshot.snap | 2 +- ...e_context_label_preserves_status_line.snap | 2 +- ...ide_context_label_shows_parent_status.snap | 2 +- ...rked_side_question_while_task_running.snap | 2 +- ...atwidget__tests__status_widget_active.snap | 2 +- ...ed_exec_begin_restores_working_status.snap | 2 +- ...renders_command_in_single_details_row.snap | 2 +- .../tui/src/chatwidget/tests/plan_mode.rs | 87 +++-- .../chatwidget/tests/popups_and_settings.rs | 34 +- .../src/chatwidget/tests/slash_commands.rs | 4 +- .../chatwidget/tests/status_command_tests.rs | 4 +- ...gration_prompt_shows_for_hidden_model.snap | 11 - 31 files changed, 405 insertions(+), 428 deletions(-) create mode 100644 codex-rs/tui/src/app/tests/model_catalog.rs create mode 100644 codex-rs/tui/src/app/tests/snapshots/codex_tui__app__tests__model_catalog__model_migration_prompt_shows_for_hidden_model.snap delete mode 100644 codex-rs/tui/src/snapshots/codex_tui__app__tests__model_migration_prompt_shows_for_hidden_model.snap diff --git a/codex-rs/core/src/config/edit_tests.rs b/codex-rs/core/src/config/edit_tests.rs index d2efb2188..ec81c7c06 100644 --- a/codex-rs/core/src/config/edit_tests.rs +++ b/codex-rs/core/src/config/edit_tests.rs @@ -547,7 +547,7 @@ existing = "value" existing = "value" [notice.model_migrations] -gpt-5 = "gpt-5.4" +"gpt-5.2" = "gpt-5.4" "#; assert_eq!(contents, expected); } diff --git a/codex-rs/tui/src/app.rs b/codex-rs/tui/src/app.rs index eeba62de0..dc8ca2784 100644 --- a/codex-rs/tui/src/app.rs +++ b/codex-rs/tui/src/app.rs @@ -7114,7 +7114,6 @@ mod tests { use codex_app_server_protocol::TurnStatus; use codex_app_server_protocol::UserInput as AppServerUserInput; use codex_app_server_protocol::WarningNotification; - use codex_config::types::ModelAvailabilityNuxConfig; use codex_otel::SessionTelemetry; use codex_protocol::ThreadId; use codex_protocol::config_types::CollaborationMode; @@ -7125,7 +7124,6 @@ mod tests { use codex_protocol::models::FileSystemPermissions; use codex_protocol::models::NetworkPermissions; use codex_protocol::models::PermissionProfile; - use codex_protocol::openai_models::ModelAvailabilityNux; use codex_protocol::protocol::AskForApproval; use codex_protocol::protocol::Event; use codex_protocol::protocol::EventMsg; @@ -7152,6 +7150,8 @@ mod tests { use tempfile::tempdir; use tokio::time; + mod model_catalog; + fn test_absolute_path(path: &str) -> AbsolutePathBuf { AbsolutePathBuf::try_from(PathBuf::from(path)).expect("absolute test path") } @@ -11474,135 +11474,6 @@ guardian_approval = true .and_then(TomlValue::as_bool) } - fn all_model_presets() -> Vec { - crate::legacy_core::test_support::all_model_presets().clone() - } - - fn model_availability_nux_config(shown_count: &[(&str, u32)]) -> ModelAvailabilityNuxConfig { - ModelAvailabilityNuxConfig { - shown_count: shown_count - .iter() - .map(|(model, count)| ((*model).to_string(), *count)) - .collect(), - } - } - - fn model_migration_copy_to_plain_text( - copy: &crate::model_migration::ModelMigrationCopy, - ) -> String { - if let Some(markdown) = copy.markdown.as_ref() { - return markdown.clone(); - } - let mut s = String::new(); - for span in ©.heading { - s.push_str(&span.content); - } - s.push('\n'); - s.push('\n'); - for line in ©.content { - for span in &line.spans { - s.push_str(&span.content); - } - s.push('\n'); - } - s - } - - #[tokio::test] - async fn model_migration_prompt_only_shows_for_deprecated_models() { - let seen = BTreeMap::new(); - assert!(should_show_model_migration_prompt( - "gpt-5", - "gpt-5.2-codex", - &seen, - &all_model_presets() - )); - assert!(should_show_model_migration_prompt( - "gpt-5-codex", - "gpt-5.2-codex", - &seen, - &all_model_presets() - )); - assert!(should_show_model_migration_prompt( - "gpt-5-codex-mini", - "gpt-5.2-codex", - &seen, - &all_model_presets() - )); - assert!(should_show_model_migration_prompt( - "gpt-5.1-codex", - "gpt-5.2-codex", - &seen, - &all_model_presets() - )); - assert!(!should_show_model_migration_prompt( - "gpt-5.1-codex", - "gpt-5.1-codex", - &seen, - &all_model_presets() - )); - } - - #[test] - fn select_model_availability_nux_picks_only_eligible_model() { - let mut presets = all_model_presets(); - presets.iter_mut().for_each(|preset| { - preset.availability_nux = None; - }); - let target = presets - .iter_mut() - .find(|preset| preset.model == "gpt-5") - .expect("target preset present"); - target.availability_nux = Some(ModelAvailabilityNux { - message: "gpt-5 is available".to_string(), - }); - - let selected = select_model_availability_nux(&presets, &model_availability_nux_config(&[])); - - assert_eq!( - selected, - Some(StartupTooltipOverride { - model_slug: "gpt-5".to_string(), - message: "gpt-5 is available".to_string(), - }) - ); - } - - #[test] - fn select_model_availability_nux_skips_missing_and_exhausted_models() { - let mut presets = all_model_presets(); - presets.iter_mut().for_each(|preset| { - preset.availability_nux = None; - }); - let gpt_5 = presets - .iter_mut() - .find(|preset| preset.model == "gpt-5") - .expect("gpt-5 preset present"); - gpt_5.availability_nux = Some(ModelAvailabilityNux { - message: "gpt-5 is available".to_string(), - }); - let gpt_5_2 = presets - .iter_mut() - .find(|preset| preset.model == "gpt-5.2") - .expect("gpt-5.2 preset present"); - gpt_5_2.availability_nux = Some(ModelAvailabilityNux { - message: "gpt-5.2 is available".to_string(), - }); - - let selected = select_model_availability_nux( - &presets, - &model_availability_nux_config(&[("gpt-5", MODEL_AVAILABILITY_NUX_MAX_SHOW_COUNT)]), - ); - - assert_eq!( - selected, - Some(StartupTooltipOverride { - model_slug: "gpt-5.2".to_string(), - message: "gpt-5.2 is available".to_string(), - }) - ); - } - #[test] fn active_turn_not_steerable_turn_error_extracts_structured_server_error() { let turn_error = AppServerTurnError { @@ -11665,183 +11536,6 @@ guardian_approval = true ); } - #[test] - fn select_model_availability_nux_uses_existing_model_order_as_priority() { - let mut presets = all_model_presets(); - presets.iter_mut().for_each(|preset| { - preset.availability_nux = None; - }); - let first = presets - .iter_mut() - .find(|preset| preset.model == "gpt-5") - .expect("gpt-5 preset present"); - first.availability_nux = Some(ModelAvailabilityNux { - message: "first".to_string(), - }); - let second = presets - .iter_mut() - .find(|preset| preset.model == "gpt-5.2") - .expect("gpt-5.2 preset present"); - second.availability_nux = Some(ModelAvailabilityNux { - message: "second".to_string(), - }); - - let selected = select_model_availability_nux(&presets, &model_availability_nux_config(&[])); - - assert_eq!( - selected, - Some(StartupTooltipOverride { - model_slug: "gpt-5.2".to_string(), - message: "second".to_string(), - }) - ); - } - - #[test] - fn select_model_availability_nux_returns_none_when_all_models_are_exhausted() { - let mut presets = all_model_presets(); - presets.iter_mut().for_each(|preset| { - preset.availability_nux = None; - }); - let target = presets - .iter_mut() - .find(|preset| preset.model == "gpt-5") - .expect("target preset present"); - target.availability_nux = Some(ModelAvailabilityNux { - message: "gpt-5 is available".to_string(), - }); - - let selected = select_model_availability_nux( - &presets, - &model_availability_nux_config(&[("gpt-5", MODEL_AVAILABILITY_NUX_MAX_SHOW_COUNT)]), - ); - - assert_eq!(selected, None); - } - - #[tokio::test] - async fn model_migration_prompt_respects_hide_flag_and_self_target() { - let mut seen = BTreeMap::new(); - seen.insert("gpt-5".to_string(), "gpt-5.1".to_string()); - assert!(!should_show_model_migration_prompt( - "gpt-5", - "gpt-5.1", - &seen, - &all_model_presets() - )); - assert!(!should_show_model_migration_prompt( - "gpt-5.1", - "gpt-5.1", - &seen, - &all_model_presets() - )); - } - - #[tokio::test] - async fn model_migration_prompt_skips_when_target_missing_or_hidden() { - let mut available = all_model_presets(); - let mut current = available - .iter() - .find(|preset| preset.model == "gpt-5-codex") - .cloned() - .expect("preset present"); - current.upgrade = Some(ModelUpgrade { - id: "missing-target".to_string(), - reasoning_effort_mapping: None, - migration_config_key: HIDE_GPT5_1_MIGRATION_PROMPT_CONFIG.to_string(), - model_link: None, - upgrade_copy: None, - migration_markdown: None, - }); - available.retain(|preset| preset.model != "gpt-5-codex"); - available.push(current.clone()); - - assert!(!should_show_model_migration_prompt( - ¤t.model, - "missing-target", - &BTreeMap::new(), - &available, - )); - - assert!(target_preset_for_upgrade(&available, "missing-target").is_none()); - - let mut with_hidden_target = all_model_presets(); - let target = with_hidden_target - .iter_mut() - .find(|preset| preset.model == "gpt-5.2-codex") - .expect("target preset present"); - target.show_in_picker = false; - - assert!(!should_show_model_migration_prompt( - "gpt-5-codex", - "gpt-5.2-codex", - &BTreeMap::new(), - &with_hidden_target, - )); - assert!(target_preset_for_upgrade(&with_hidden_target, "gpt-5.2-codex").is_none()); - } - - #[tokio::test] - async fn model_migration_prompt_shows_for_hidden_model() { - let codex_home = tempdir().expect("temp codex home"); - let config = ConfigBuilder::default() - .codex_home(codex_home.path().to_path_buf()) - .build() - .await - .expect("config"); - - let mut available_models = all_model_presets(); - let current = available_models - .iter() - .find(|preset| preset.model == "gpt-5.1-codex") - .cloned() - .expect("gpt-5.1-codex preset present"); - assert!( - !current.show_in_picker, - "expected gpt-5.1-codex to be hidden from picker for this test" - ); - - let upgrade = current.upgrade.as_ref().expect("upgrade configured"); - // Test "hidden current model still prompts" even if bundled - // catalog data changes the target model's picker visibility. - available_models - .iter_mut() - .find(|preset| preset.model == upgrade.id) - .expect("upgrade target present") - .show_in_picker = true; - assert!( - should_show_model_migration_prompt( - ¤t.model, - &upgrade.id, - &config.notices.model_migrations, - &available_models, - ), - "expected migration prompt to be eligible for hidden model" - ); - - let target = target_preset_for_upgrade(&available_models, &upgrade.id) - .expect("upgrade target present"); - let target_description = - (!target.description.is_empty()).then(|| target.description.clone()); - let can_opt_out = true; - let copy = migration_copy_for_models( - ¤t.model, - &upgrade.id, - upgrade.model_link.clone(), - upgrade.upgrade_copy.clone(), - upgrade.migration_markdown.clone(), - target.display_name.clone(), - target_description, - can_opt_out, - ); - - // Snapshot the copy we would show; rendering is covered by model_migration snapshots. - assert_snapshot!( - "model_migration_prompt_shows_for_hidden_model", - model_migration_copy_to_plain_text(©) - ); - } - #[tokio::test] async fn update_reasoning_effort_updates_collaboration_mode() { let mut app = make_test_app().await; diff --git a/codex-rs/tui/src/app/tests/model_catalog.rs b/codex-rs/tui/src/app/tests/model_catalog.rs new file mode 100644 index 000000000..e74d01e6d --- /dev/null +++ b/codex-rs/tui/src/app/tests/model_catalog.rs @@ -0,0 +1,293 @@ +use super::*; +use codex_config::types::ModelAvailabilityNuxConfig; +use codex_protocol::openai_models::ModelAvailabilityNux; +use pretty_assertions::assert_eq; + +fn all_model_presets() -> Vec { + crate::legacy_core::test_support::all_model_presets().clone() +} + +fn model_availability_nux_config(shown_count: &[(&str, u32)]) -> ModelAvailabilityNuxConfig { + ModelAvailabilityNuxConfig { + shown_count: shown_count + .iter() + .map(|(model, count)| ((*model).to_string(), *count)) + .collect(), + } +} + +fn model_migration_copy_to_plain_text(copy: &crate::model_migration::ModelMigrationCopy) -> String { + if let Some(markdown) = copy.markdown.as_ref() { + return markdown.clone(); + } + let mut s = String::new(); + for span in ©.heading { + s.push_str(&span.content); + } + s.push('\n'); + s.push('\n'); + for line in ©.content { + for span in &line.spans { + s.push_str(&span.content); + } + s.push('\n'); + } + s +} + +#[tokio::test] +async fn model_migration_prompt_only_shows_for_deprecated_models() { + let seen = BTreeMap::new(); + assert!(should_show_model_migration_prompt( + "gpt-5.2", + "gpt-5.4", + &seen, + &all_model_presets() + )); + assert!(should_show_model_migration_prompt( + "gpt-5.3-codex", + "gpt-5.4", + &seen, + &all_model_presets() + )); + assert!(!should_show_model_migration_prompt( + "gpt-5.3-codex", + "gpt-5.3-codex", + &seen, + &all_model_presets() + )); +} + +#[test] +fn select_model_availability_nux_picks_only_eligible_model() { + let mut presets = all_model_presets(); + presets.iter_mut().for_each(|preset| { + preset.availability_nux = None; + }); + let target = presets + .iter_mut() + .find(|preset| preset.model == "gpt-5.4") + .expect("target preset present"); + target.availability_nux = Some(ModelAvailabilityNux { + message: "gpt-5.4 is available".to_string(), + }); + + let selected = select_model_availability_nux(&presets, &model_availability_nux_config(&[])); + + assert_eq!( + selected, + Some(StartupTooltipOverride { + model_slug: "gpt-5.4".to_string(), + message: "gpt-5.4 is available".to_string(), + }) + ); +} + +#[test] +fn select_model_availability_nux_skips_missing_and_exhausted_models() { + let mut presets = all_model_presets(); + presets.iter_mut().for_each(|preset| { + preset.availability_nux = None; + }); + let gpt_5 = presets + .iter_mut() + .find(|preset| preset.model == "gpt-5.4") + .expect("gpt-5.4 preset present"); + gpt_5.availability_nux = Some(ModelAvailabilityNux { + message: "gpt-5.4 is available".to_string(), + }); + let gpt_5_2 = presets + .iter_mut() + .find(|preset| preset.model == "gpt-5.4-mini") + .expect("gpt-5.4-mini preset present"); + gpt_5_2.availability_nux = Some(ModelAvailabilityNux { + message: "gpt-5.4-mini is available".to_string(), + }); + + let selected = select_model_availability_nux( + &presets, + &model_availability_nux_config(&[("gpt-5.4", MODEL_AVAILABILITY_NUX_MAX_SHOW_COUNT)]), + ); + + assert_eq!( + selected, + Some(StartupTooltipOverride { + model_slug: "gpt-5.4-mini".to_string(), + message: "gpt-5.4-mini is available".to_string(), + }) + ); +} + +#[test] +fn select_model_availability_nux_uses_existing_model_order_as_priority() { + let mut presets = all_model_presets(); + presets.iter_mut().for_each(|preset| { + preset.availability_nux = None; + }); + let first = presets + .iter_mut() + .find(|preset| preset.model == "gpt-5.4-mini") + .expect("gpt-5.4-mini preset present"); + first.availability_nux = Some(ModelAvailabilityNux { + message: "first".to_string(), + }); + let second = presets + .iter_mut() + .find(|preset| preset.model == "gpt-5.4") + .expect("gpt-5.4 preset present"); + second.availability_nux = Some(ModelAvailabilityNux { + message: "second".to_string(), + }); + + let selected = select_model_availability_nux(&presets, &model_availability_nux_config(&[])); + + assert_eq!( + selected, + Some(StartupTooltipOverride { + model_slug: "gpt-5.4".to_string(), + message: "second".to_string(), + }) + ); +} + +#[test] +fn select_model_availability_nux_returns_none_when_all_models_are_exhausted() { + let mut presets = all_model_presets(); + presets.iter_mut().for_each(|preset| { + preset.availability_nux = None; + }); + let target = presets + .iter_mut() + .find(|preset| preset.model == "gpt-5.4") + .expect("target preset present"); + target.availability_nux = Some(ModelAvailabilityNux { + message: "gpt-5.4 is available".to_string(), + }); + + let selected = select_model_availability_nux( + &presets, + &model_availability_nux_config(&[("gpt-5.4", MODEL_AVAILABILITY_NUX_MAX_SHOW_COUNT)]), + ); + + assert_eq!(selected, None); +} + +#[tokio::test] +async fn model_migration_prompt_respects_hide_flag_and_self_target() { + let mut seen = BTreeMap::new(); + seen.insert("gpt-5.2".to_string(), "gpt-5.4".to_string()); + assert!(!should_show_model_migration_prompt( + "gpt-5.2", + "gpt-5.4", + &seen, + &all_model_presets() + )); + assert!(!should_show_model_migration_prompt( + "gpt-5.4", + "gpt-5.4", + &seen, + &all_model_presets() + )); +} + +#[tokio::test] +async fn model_migration_prompt_skips_when_target_missing_or_hidden() { + let mut available = all_model_presets(); + let mut current = available + .iter() + .find(|preset| preset.model == "gpt-5.2") + .cloned() + .expect("preset present"); + current.upgrade = Some(ModelUpgrade { + id: "missing-target".to_string(), + reasoning_effort_mapping: None, + migration_config_key: HIDE_GPT5_1_MIGRATION_PROMPT_CONFIG.to_string(), + model_link: None, + upgrade_copy: None, + migration_markdown: None, + }); + available.retain(|preset| preset.model != "gpt-5.2"); + available.push(current.clone()); + + assert!(!should_show_model_migration_prompt( + ¤t.model, + "missing-target", + &BTreeMap::new(), + &available, + )); + + assert!(target_preset_for_upgrade(&available, "missing-target").is_none()); + + let mut with_hidden_target = all_model_presets(); + let target = with_hidden_target + .iter_mut() + .find(|preset| preset.model == "gpt-5.4") + .expect("target preset present"); + target.show_in_picker = false; + + assert!(!should_show_model_migration_prompt( + "gpt-5.2", + "gpt-5.4", + &BTreeMap::new(), + &with_hidden_target, + )); + assert!(target_preset_for_upgrade(&with_hidden_target, "gpt-5.4").is_none()); +} + +#[tokio::test] +async fn model_migration_prompt_shows_for_hidden_model() { + let codex_home = tempdir().expect("temp codex home"); + let config = ConfigBuilder::default() + .codex_home(codex_home.path().to_path_buf()) + .build() + .await + .expect("config"); + + let mut available_models = all_model_presets(); + let current = available_models + .iter_mut() + .find(|preset| preset.model == "gpt-5.3-codex") + .expect("gpt-5.3-codex preset present"); + current.show_in_picker = false; + let current = current.clone(); + assert!( + !current.show_in_picker, + "expected gpt-5.3-codex to be hidden from picker for this test" + ); + + let upgrade = current.upgrade.as_ref().expect("upgrade configured"); + available_models + .iter_mut() + .find(|preset| preset.model == upgrade.id) + .expect("upgrade target present") + .show_in_picker = true; + assert!( + should_show_model_migration_prompt( + ¤t.model, + &upgrade.id, + &config.notices.model_migrations, + &available_models, + ), + "expected migration prompt to be eligible for hidden model" + ); + + let target = + target_preset_for_upgrade(&available_models, &upgrade.id).expect("upgrade target present"); + let target_description = (!target.description.is_empty()).then(|| target.description.clone()); + let can_opt_out = true; + let copy = migration_copy_for_models( + ¤t.model, + &upgrade.id, + upgrade.model_link.clone(), + upgrade.upgrade_copy.clone(), + upgrade.migration_markdown.clone(), + target.display_name.clone(), + target_description, + can_opt_out, + ); + + assert_snapshot!( + "model_migration_prompt_shows_for_hidden_model", + model_migration_copy_to_plain_text(©) + ); +} diff --git a/codex-rs/tui/src/app/tests/snapshots/codex_tui__app__tests__model_catalog__model_migration_prompt_shows_for_hidden_model.snap b/codex-rs/tui/src/app/tests/snapshots/codex_tui__app__tests__model_catalog__model_migration_prompt_shows_for_hidden_model.snap new file mode 100644 index 000000000..c5be01e00 --- /dev/null +++ b/codex-rs/tui/src/app/tests/snapshots/codex_tui__app__tests__model_catalog__model_migration_prompt_shows_for_hidden_model.snap @@ -0,0 +1,12 @@ +--- +source: tui/src/app/tests/model_catalog.rs +assertion_line: 289 +expression: model_migration_copy_to_plain_text(©) +--- +Introducing GPT-5.4 + +Codex just got an upgrade with GPT-5.4, our most capable model for professional work. It outperforms prior models while being more token efficient, with notable improvements on long-running tasks, tool calling, computer use, and frontend development. + +Learn more: https://openai.com/index/introducing-gpt-5-4 + +You can always keep using GPT-5.3-Codex if you prefer. diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__app_server_guardian_review_denied_renders_denied_request.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__app_server_guardian_review_denied_renders_denied_request.snap index f783bd4d6..59d02ea1d 100644 --- a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__app_server_guardian_review_denied_renders_denied_request.snap +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__app_server_guardian_review_denied_renders_denied_request.snap @@ -10,4 +10,4 @@ expression: normalize_snapshot_paths(term.backend().vt100().screen().contents()) › Ask Codex to do anything - gpt-5.3-codex default · /tmp/project + gpt-5.4 default · /tmp/project diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__app_server_guardian_review_timed_out_renders_timed_out_request.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__app_server_guardian_review_timed_out_renders_timed_out_request.snap index 2bd33f635..becb20490 100644 --- a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__app_server_guardian_review_timed_out_renders_timed_out_request.snap +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__app_server_guardian_review_timed_out_renders_timed_out_request.snap @@ -17,4 +17,4 @@ expression: normalize_snapshot_paths(term.backend().vt100().screen().contents()) › Ask Codex to do anything - gpt-5.3-codex default · /tmp/project + gpt-5.4 default · /tmp/project diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__app_server_mcp_startup_failure_renders_warning_history.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__app_server_mcp_startup_failure_renders_warning_history.snap index fedd9d6bc..eb2133416 100644 --- a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__app_server_mcp_startup_failure_renders_warning_history.snap +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__app_server_mcp_startup_failure_renders_warning_history.snap @@ -8,4 +8,4 @@ expression: normalize_snapshot_paths(term.backend().vt100().screen().contents()) › Ask Codex to do anything - gpt-5.3-codex default · /tmp/project + gpt-5.4 default · /tmp/project diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__chatwidget_tall.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__chatwidget_tall.snap index a287d9d7a..1ef31b750 100644 --- a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__chatwidget_tall.snap +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__chatwidget_tall.snap @@ -26,4 +26,4 @@ expression: normalize_snapshot_paths(term.backend().vt100().screen().contents()) › Ask Codex to do anything - gpt-5.3-codex default · /tmp/project + gpt-5.4 default · /tmp/project diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__compact_queues_user_messages_snapshot.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__compact_queues_user_messages_snapshot.snap index d39932f3a..5827486bf 100644 --- a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__compact_queues_user_messages_snapshot.snap +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__compact_queues_user_messages_snapshot.snap @@ -9,4 +9,4 @@ expression: normalize_snapshot_paths(term.backend().vt100().screen().contents()) › Ask Codex to do anything - gpt-5.3-codex default · /tmp/project + gpt-5.4 default · /tmp/project diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__guardian_approved_exec_renders_approved_request.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__guardian_approved_exec_renders_approved_request.snap index 80592e0dd..ed1d644cb 100644 --- a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__guardian_approved_exec_renders_approved_request.snap +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__guardian_approved_exec_renders_approved_request.snap @@ -8,4 +8,4 @@ expression: normalize_snapshot_paths(term.backend().vt100().screen().contents()) › Ask Codex to do anything - gpt-5.3-codex default · /tmp/project + gpt-5.4 default · /tmp/project diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__guardian_denied_exec_renders_warning_and_denied_request.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__guardian_denied_exec_renders_warning_and_denied_request.snap index d910d6d6f..b8cd76c13 100644 --- a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__guardian_denied_exec_renders_warning_and_denied_request.snap +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__guardian_denied_exec_renders_warning_and_denied_request.snap @@ -14,4 +14,4 @@ expression: normalize_snapshot_paths(term.backend().vt100().screen().contents()) › Ask Codex to do anything - gpt-5.3-codex default · /tmp/project + gpt-5.4 default · /tmp/project diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__guardian_parallel_reviews_render_aggregate_status.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__guardian_parallel_reviews_render_aggregate_status.snap index 821c8d1a6..393e1a304 100644 --- a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__guardian_parallel_reviews_render_aggregate_status.snap +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__guardian_parallel_reviews_render_aggregate_status.snap @@ -9,4 +9,4 @@ expression: normalize_snapshot_paths(rendered) › Ask Codex to do anything - gpt-5.3-codex default · /tmp/project + gpt-5.4 default · /tmp/project diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__guardian_timed_out_exec_renders_warning_and_timed_out_request.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__guardian_timed_out_exec_renders_warning_and_timed_out_request.snap index dc3b54674..9d1eb96bf 100644 --- a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__guardian_timed_out_exec_renders_warning_and_timed_out_request.snap +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__guardian_timed_out_exec_renders_warning_and_timed_out_request.snap @@ -21,4 +21,4 @@ expression: normalize_snapshot_paths(term.backend().vt100().screen().contents()) › Ask Codex to do anything - gpt-5.3-codex default · /tmp/project + gpt-5.4 default · /tmp/project diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__mcp_startup_header_booting.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__mcp_startup_header_booting.snap index f3936540a..8a5dd2046 100644 --- a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__mcp_startup_header_booting.snap +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__mcp_startup_header_booting.snap @@ -8,4 +8,4 @@ expression: normalized_backend_snapshot(terminal.backend()) " " "› Ask Codex to do anything " " " -" gpt-5.3-codex default · /tmp/project " +" gpt-5.4 default · /tmp/project " 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 a4a86a41b..27c7d061e 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.1-codex-max + Select Reasoning Level for gpt-5.4 1. Low Fast responses with lighter reasoning 2. Medium (default) Balances speed and reasoning depth for everyday tasks diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__model_reasoning_selection_popup_extra_high_warning.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__model_reasoning_selection_popup_extra_high_warning.snap index 2404dced5..7cde99f3a 100644 --- a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__model_reasoning_selection_popup_extra_high_warning.snap +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__model_reasoning_selection_popup_extra_high_warning.snap @@ -1,14 +1,16 @@ --- -source: tui/src/chatwidget/tests.rs +source: tui/src/chatwidget/tests/popups_and_settings.rs expression: popup --- - Select Reasoning Level for gpt-5.1-codex-max + Select Reasoning Level for gpt-5.2 - 1. Low Fast responses with lighter reasoning - 2. Medium (default) Balances speed and reasoning depth for everyday - tasks - 3. High Greater reasoning depth for complex problems -› 4. Extra high (current) Extra high reasoning depth for complex problems + 1. Low Balances speed with some reasoning; useful for + straightforward queries and short explanations + 2. Medium (default) Provides a solid balance of reasoning depth and + latency for general-purpose tasks + 3. High Maximizes reasoning depth for complex or ambiguous + problems +› 4. Extra high (current) Extra high reasoning for complex problems ⚠ Extra high reasoning effort can quickly consume Plus plan rate limits. 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 d322bf35e..41773729e 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 @@ -1,18 +1,14 @@ --- -source: tui/src/chatwidget/tests.rs +source: tui/src/chatwidget/tests/popups_and_settings.rs expression: popup --- Select Model and Effort Access legacy models by running codex -m or in your config.toml -› 1. gpt-5.3-codex (default) Latest frontier agentic coding model. - 2. gpt-5.4 Latest frontier agentic coding model. - 3. gpt-5.2-codex Frontier agentic coding model. - 4. gpt-5.1-codex-max Codex-optimized flagship for deep and fast - reasoning. - 5. gpt-5.2 Latest frontier model with improvements across - knowledge, reasoning and coding - 6. gpt-5.1-codex-mini Optimized for codex. Cheaper, faster, but less - capable. + 1. gpt-5.4 (default) Latest frontier agentic coding model. + 2. gpt-5.4-mini Smaller frontier agentic coding model. + 3. gpt-5.3-codex Frontier Codex-optimized agentic coding model. +› 4. gpt-5.2 (current) Optimized for professional work and long-running + agents Press enter to select reasoning effort, or esc to dismiss. diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__preamble_keeps_working_status.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__preamble_keeps_working_status.snap index ad7fa5253..3dbbd8f30 100644 --- a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__preamble_keeps_working_status.snap +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__preamble_keeps_working_status.snap @@ -8,4 +8,4 @@ expression: normalized_backend_snapshot(terminal.backend()) " " "› Ask Codex to do anything " " " -" gpt-5.3-codex default · /tmp/project " +" gpt-5.4 default · /tmp/project " 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 e210d1f0a..97ed0c719 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 @@ -3,10 +3,10 @@ source: tui/src/chatwidget/tests.rs expression: popup --- Approaching rate limits - Switch to gpt-5.1-codex-mini for lower credit usage? + Switch to gpt-5.4-mini for lower credit usage? -› 1. Switch to gpt-5.1-codex-mini Optimized for codex. Cheaper, - faster, but less capable. +› 1. Switch to gpt-5.4-mini Smaller frontier agentic coding + model. 2. Keep current model 3. Keep current model (never show again) Hide future rate limit reminders about switching models. diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__review_queues_user_messages_snapshot.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__review_queues_user_messages_snapshot.snap index bb4a8cefe..5148441eb 100644 --- a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__review_queues_user_messages_snapshot.snap +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__review_queues_user_messages_snapshot.snap @@ -9,4 +9,4 @@ expression: normalize_snapshot_paths(term.backend().vt100().screen().contents()) › Ask Codex to do anything - gpt-5.3-codex default · /tmp/project + gpt-5.4 default · /tmp/project diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__side_context_label_preserves_status_line.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__side_context_label_preserves_status_line.snap index db30e31a6..e4d578860 100644 --- a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__side_context_label_preserves_status_line.snap +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__side_context_label_preserves_status_line.snap @@ -6,4 +6,4 @@ expression: terminal.backend() " " "› Check recently modified functions for compatibility " " " -" gpt-5.3-codex Side from main thread · Esc to return " +" gpt-5.4 Side from main thread · Esc to return " diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__side_context_label_shows_parent_status.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__side_context_label_shows_parent_status.snap index 0dd45297b..75e4f53d3 100644 --- a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__side_context_label_shows_parent_status.snap +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__side_context_label_shows_parent_status.snap @@ -6,4 +6,4 @@ expression: terminal.backend() " " "› Check recently modified functions for compatibility " " " -" gpt-5.3-codex defa… Side from main thread · main needs input · Esc to return " +" gpt-5.4 default · … Side from main thread · main needs input · Esc to return " diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__slash_side_requests_forked_side_question_while_task_running.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__slash_side_requests_forked_side_question_while_task_running.snap index 014fb41f1..4ab1cfb6e 100644 --- a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__slash_side_requests_forked_side_question_while_task_running.snap +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__slash_side_requests_forked_side_question_while_task_running.snap @@ -8,4 +8,4 @@ expression: normalized_backend_snapshot(terminal.backend()) " " "› Ask Codex to do anything " " " -" gpt-5.3-codex default Side starting... " +" gpt-5.4 default Side starting... " diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__status_widget_active.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__status_widget_active.snap index fea8a4db0..91d80a1a2 100644 --- a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__status_widget_active.snap +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__status_widget_active.snap @@ -8,4 +8,4 @@ expression: normalized_backend_snapshot(terminal.backend()) " " "› Ask Codex to do anything " " " -" gpt-5.3-codex default · /tmp/project " +" gpt-5.4 default · /tmp/project " diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__unified_exec_begin_restores_working_status.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__unified_exec_begin_restores_working_status.snap index 7a2d0b4b9..43a3188fb 100644 --- a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__unified_exec_begin_restores_working_status.snap +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__unified_exec_begin_restores_working_status.snap @@ -8,4 +8,4 @@ expression: normalized_backend_snapshot(terminal.backend()) " " "› Ask Codex to do anything " " " -" gpt-5.3-codex default · /tmp/project " +" gpt-5.4 default · /tmp/project " diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__unified_exec_wait_status_renders_command_in_single_details_row.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__unified_exec_wait_status_renders_command_in_single_details_row.snap index a5b839e00..0a59dd990 100644 --- a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__unified_exec_wait_status_renders_command_in_single_details_row.snap +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__unified_exec_wait_status_renders_command_in_single_details_row.snap @@ -8,4 +8,4 @@ expression: normalize_snapshot_paths(rendered) › Ask Codex to do anything - gpt-5.3-codex default · /tmp/project + gpt-5.4 default · /tmp/project diff --git a/codex-rs/tui/src/chatwidget/tests/plan_mode.rs b/codex-rs/tui/src/chatwidget/tests/plan_mode.rs index 9f2c81010..8f3de7897 100644 --- a/codex-rs/tui/src/chatwidget/tests/plan_mode.rs +++ b/codex-rs/tui/src/chatwidget/tests/plan_mode.rs @@ -169,7 +169,7 @@ async fn submit_user_message_with_mode_sets_coding_collaboration_mode() { #[tokio::test] async fn reasoning_selection_in_plan_mode_opens_scope_prompt_event() { - let (mut chat, mut rx, _op_rx) = make_chatwidget_manual(Some("gpt-5.1-codex-max")).await; + let (mut chat, mut rx, _op_rx) = make_chatwidget_manual(Some("gpt-5.4")).await; chat.thread_id = Some(ThreadId::new()); chat.set_feature_enabled(Feature::CollaborationModes, /*enabled*/ true); let plan_mask = collaboration_modes::plan_mask(chat.model_catalog.as_ref()) @@ -179,7 +179,7 @@ async fn reasoning_selection_in_plan_mode_opens_scope_prompt_event() { set_chatgpt_auth(&mut chat); chat.set_reasoning_effort(Some(ReasoningEffortConfig::High)); - let preset = get_available_model(&chat, "gpt-5.1-codex-max"); + let preset = get_available_model(&chat, "gpt-5.4"); chat.open_reasoning_popup(preset); chat.handle_key_event(KeyEvent::from(KeyCode::Down)); chat.handle_key_event(KeyEvent::from(KeyCode::Enter)); @@ -190,13 +190,13 @@ async fn reasoning_selection_in_plan_mode_opens_scope_prompt_event() { AppEvent::OpenPlanReasoningScopePrompt { model, effort: Some(_) - } if model == "gpt-5.1-codex-max" + } if model == "gpt-5.4" ); } #[tokio::test] async fn reasoning_selection_in_plan_mode_without_effort_change_does_not_open_scope_prompt_event() { - let (mut chat, mut rx, _op_rx) = make_chatwidget_manual(Some("gpt-5.1-codex-max")).await; + let (mut chat, mut rx, _op_rx) = make_chatwidget_manual(Some("gpt-5.4")).await; chat.thread_id = Some(ThreadId::new()); chat.set_feature_enabled(Feature::CollaborationModes, /*enabled*/ true); let plan_mask = collaboration_modes::plan_mask(chat.model_catalog.as_ref()) @@ -205,10 +205,10 @@ async fn reasoning_selection_in_plan_mode_without_effort_change_does_not_open_sc let _ = drain_insert_history(&mut rx); set_chatgpt_auth(&mut chat); - let current_preset = get_available_model(&chat, "gpt-5.1-codex-max"); + let current_preset = get_available_model(&chat, "gpt-5.4"); chat.set_reasoning_effort(Some(current_preset.default_reasoning_effort)); - let preset = get_available_model(&chat, "gpt-5.1-codex-max"); + let preset = get_available_model(&chat, "gpt-5.4"); chat.open_reasoning_popup(preset); chat.handle_key_event(KeyEvent::from(KeyCode::Enter)); @@ -216,7 +216,7 @@ async fn reasoning_selection_in_plan_mode_without_effort_change_does_not_open_sc assert!( events.iter().any(|event| matches!( event, - AppEvent::UpdateModel(model) if model == "gpt-5.1-codex-max" + AppEvent::UpdateModel(model) if model == "gpt-5.4" )), "expected model update event; events: {events:?}" ); @@ -231,7 +231,7 @@ async fn reasoning_selection_in_plan_mode_without_effort_change_does_not_open_sc #[tokio::test] async fn reasoning_selection_in_plan_mode_matching_plan_effort_but_different_global_opens_scope_prompt() { - let (mut chat, mut rx, _op_rx) = make_chatwidget_manual(Some("gpt-5.1-codex-max")).await; + let (mut chat, mut rx, _op_rx) = make_chatwidget_manual(Some("gpt-5.4")).await; chat.thread_id = Some(ThreadId::new()); chat.set_feature_enabled(Feature::CollaborationModes, /*enabled*/ true); let plan_mask = collaboration_modes::plan_mask(chat.model_catalog.as_ref()) @@ -245,7 +245,7 @@ async fn reasoning_selection_in_plan_mode_matching_plan_effort_but_different_glo // should open the scope prompt rather than silently rewriting the global default. chat.set_reasoning_effort(Some(ReasoningEffortConfig::High)); - let preset = get_available_model(&chat, "gpt-5.1-codex-max"); + let preset = get_available_model(&chat, "gpt-5.4"); chat.open_reasoning_popup(preset); chat.handle_key_event(KeyEvent::from(KeyCode::Enter)); @@ -255,13 +255,13 @@ async fn reasoning_selection_in_plan_mode_matching_plan_effort_but_different_glo AppEvent::OpenPlanReasoningScopePrompt { model, effort: Some(ReasoningEffortConfig::Medium) - } if model == "gpt-5.1-codex-max" + } if model == "gpt-5.4" ); } #[tokio::test] async fn plan_mode_reasoning_override_is_marked_current_in_reasoning_popup() { - let (mut chat, _rx, _op_rx) = make_chatwidget_manual(Some("gpt-5.1-codex-max")).await; + let (mut chat, _rx, _op_rx) = make_chatwidget_manual(Some("gpt-5.4")).await; chat.set_feature_enabled(Feature::CollaborationModes, /*enabled*/ true); set_chatgpt_auth(&mut chat); chat.set_reasoning_effort(Some(ReasoningEffortConfig::High)); @@ -271,7 +271,7 @@ async fn plan_mode_reasoning_override_is_marked_current_in_reasoning_popup() { .expect("expected plan collaboration mode"); chat.set_collaboration_mask(plan_mask); - let preset = get_available_model(&chat, "gpt-5.1-codex-max"); + let preset = get_available_model(&chat, "gpt-5.4"); chat.open_reasoning_popup(preset); let popup = render_bottom_popup(&chat, /*width*/ 100); @@ -284,7 +284,7 @@ async fn plan_mode_reasoning_override_is_marked_current_in_reasoning_popup() { #[tokio::test] async fn reasoning_selection_in_plan_mode_model_switch_does_not_open_scope_prompt_event() { - let (mut chat, mut rx, _op_rx) = make_chatwidget_manual(Some("gpt-5.1-codex-max")).await; + let (mut chat, mut rx, _op_rx) = make_chatwidget_manual(Some("gpt-5.4")).await; chat.thread_id = Some(ThreadId::new()); chat.set_feature_enabled(Feature::CollaborationModes, /*enabled*/ true); let plan_mask = collaboration_modes::plan_mask(chat.model_catalog.as_ref()) @@ -293,7 +293,7 @@ async fn reasoning_selection_in_plan_mode_model_switch_does_not_open_scope_promp let _ = drain_insert_history(&mut rx); set_chatgpt_auth(&mut chat); - let preset = get_available_model(&chat, "gpt-5"); + let preset = get_available_model(&chat, "gpt-5.2"); chat.open_reasoning_popup(preset); chat.handle_key_event(KeyEvent::from(KeyCode::Enter)); @@ -301,7 +301,7 @@ async fn reasoning_selection_in_plan_mode_model_switch_does_not_open_scope_promp assert!( events.iter().any(|event| matches!( event, - AppEvent::UpdateModel(model) if model == "gpt-5" + AppEvent::UpdateModel(model) if model == "gpt-5.2" )), "expected model update event; events: {events:?}" ); @@ -315,11 +315,8 @@ async fn reasoning_selection_in_plan_mode_model_switch_does_not_open_scope_promp #[tokio::test] async fn plan_reasoning_scope_popup_all_modes_persists_global_and_plan_override() { - let (mut chat, mut rx, _op_rx) = make_chatwidget_manual(Some("gpt-5.1-codex-max")).await; - chat.open_plan_reasoning_scope_prompt( - "gpt-5.1-codex-max".to_string(), - Some(ReasoningEffortConfig::High), - ); + let (mut chat, mut rx, _op_rx) = make_chatwidget_manual(Some("gpt-5.4")).await; + chat.open_plan_reasoning_scope_prompt("gpt-5.4".to_string(), Some(ReasoningEffortConfig::High)); chat.handle_key_event(KeyEvent::from(KeyCode::Down)); chat.handle_key_event(KeyEvent::from(KeyCode::Enter)); @@ -343,7 +340,7 @@ async fn plan_reasoning_scope_popup_all_modes_persists_global_and_plan_override( events.iter().any(|event| matches!( event, AppEvent::PersistModelSelection { model, effort: Some(ReasoningEffortConfig::High) } - if model == "gpt-5.1-codex-max" + if model == "gpt-5.4" )), "expected global model reasoning selection persistence; events: {events:?}" ); @@ -369,7 +366,7 @@ fn plan_mode_prompt_notification_uses_dedicated_type_name() { #[tokio::test] async fn open_plan_implementation_prompt_sets_pending_notification() { - let (mut chat, _rx, _op_rx) = make_chatwidget_manual(Some("gpt-5.1-codex-max")).await; + let (mut chat, _rx, _op_rx) = make_chatwidget_manual(Some("gpt-5.4")).await; chat.config.tui_notifications.notifications = Notifications::Custom(vec!["plan-mode-prompt".to_string()]); @@ -383,14 +380,11 @@ async fn open_plan_implementation_prompt_sets_pending_notification() { #[tokio::test] async fn open_plan_reasoning_scope_prompt_sets_pending_notification() { - let (mut chat, _rx, _op_rx) = make_chatwidget_manual(Some("gpt-5.1-codex-max")).await; + let (mut chat, _rx, _op_rx) = make_chatwidget_manual(Some("gpt-5.4")).await; chat.config.tui_notifications.notifications = Notifications::Custom(vec!["plan-mode-prompt".to_string()]); - chat.open_plan_reasoning_scope_prompt( - "gpt-5.1-codex-max".to_string(), - Some(ReasoningEffortConfig::High), - ); + chat.open_plan_reasoning_scope_prompt("gpt-5.4".to_string(), Some(ReasoningEffortConfig::High)); assert_matches!( chat.pending_notification, @@ -400,7 +394,7 @@ async fn open_plan_reasoning_scope_prompt_sets_pending_notification() { #[tokio::test] async fn agent_turn_complete_does_not_override_pending_plan_mode_prompt_notification() { - let (mut chat, _rx, _op_rx) = make_chatwidget_manual(Some("gpt-5.1-codex-max")).await; + let (mut chat, _rx, _op_rx) = make_chatwidget_manual(Some("gpt-5.4")).await; chat.open_plan_implementation_prompt(); chat.notify(Notification::AgentTurnComplete { @@ -415,7 +409,7 @@ async fn agent_turn_complete_does_not_override_pending_plan_mode_prompt_notifica #[tokio::test] async fn request_user_input_notification_overrides_pending_agent_turn_complete_notification() { - let (mut chat, _rx, _op_rx) = make_chatwidget_manual(Some("gpt-5.1-codex-max")).await; + let (mut chat, _rx, _op_rx) = make_chatwidget_manual(Some("gpt-5.4")).await; chat.notify(Notification::AgentTurnComplete { response: "done".to_string(), @@ -444,7 +438,7 @@ async fn request_user_input_notification_overrides_pending_agent_turn_complete_n #[tokio::test] async fn handle_request_user_input_sets_pending_notification() { - let (mut chat, _rx, _op_rx) = make_chatwidget_manual(Some("gpt-5.1-codex-max")).await; + let (mut chat, _rx, _op_rx) = make_chatwidget_manual(Some("gpt-5.4")).await; chat.config.tui_notifications.notifications = Notifications::Custom(vec!["plan-mode-prompt".to_string()]); @@ -472,10 +466,10 @@ async fn handle_request_user_input_sets_pending_notification() { #[tokio::test] async fn plan_reasoning_scope_popup_mentions_selected_reasoning() { - let (mut chat, _rx, _op_rx) = make_chatwidget_manual(Some("gpt-5.1-codex-max")).await; + let (mut chat, _rx, _op_rx) = make_chatwidget_manual(Some("gpt-5.4")).await; chat.set_plan_mode_reasoning_effort(Some(ReasoningEffortConfig::Low)); chat.open_plan_reasoning_scope_prompt( - "gpt-5.1-codex-max".to_string(), + "gpt-5.4".to_string(), Some(ReasoningEffortConfig::Medium), ); @@ -489,9 +483,9 @@ async fn plan_reasoning_scope_popup_mentions_selected_reasoning() { #[tokio::test] async fn plan_reasoning_scope_popup_mentions_built_in_plan_default_when_no_override() { - let (mut chat, _rx, _op_rx) = make_chatwidget_manual(Some("gpt-5.1-codex-max")).await; + let (mut chat, _rx, _op_rx) = make_chatwidget_manual(Some("gpt-5.4")).await; chat.open_plan_reasoning_scope_prompt( - "gpt-5.1-codex-max".to_string(), + "gpt-5.4".to_string(), Some(ReasoningEffortConfig::Medium), ); @@ -501,11 +495,8 @@ async fn plan_reasoning_scope_popup_mentions_built_in_plan_default_when_no_overr #[tokio::test] async fn plan_reasoning_scope_popup_plan_only_does_not_update_all_modes_reasoning() { - let (mut chat, mut rx, _op_rx) = make_chatwidget_manual(Some("gpt-5.1-codex-max")).await; - chat.open_plan_reasoning_scope_prompt( - "gpt-5.1-codex-max".to_string(), - Some(ReasoningEffortConfig::High), - ); + let (mut chat, mut rx, _op_rx) = make_chatwidget_manual(Some("gpt-5.4")).await; + chat.open_plan_reasoning_scope_prompt("gpt-5.4".to_string(), Some(ReasoningEffortConfig::High)); chat.handle_key_event(KeyEvent::from(KeyCode::Enter)); @@ -1123,7 +1114,7 @@ async fn mode_switch_surfaces_model_change_notification_when_effective_model_cha let mut plan_mask = collaboration_modes::mask_for_kind(chat.model_catalog.as_ref(), ModeKind::Plan) .expect("expected plan collaboration mode"); - plan_mask.model = Some("gpt-5.1-codex-mini".to_string()); + plan_mask.model = Some("gpt-5.4-mini".to_string()); chat.set_collaboration_mask(plan_mask); let plan_messages = drain_insert_history(&mut rx) @@ -1132,7 +1123,7 @@ async fn mode_switch_surfaces_model_change_notification_when_effective_model_cha .collect::>() .join("\n"); assert!( - plan_messages.contains("Model changed to gpt-5.1-codex-mini medium for Plan mode."), + plan_messages.contains("Model changed to gpt-5.4-mini medium for Plan mode."), "expected Plan-mode model switch notice, got: {plan_messages:?}" ); @@ -1336,21 +1327,21 @@ async fn collaboration_modes_defaults_to_code_on_startup() { #[tokio::test] async fn set_model_updates_active_collaboration_mask() { - let (mut chat, _rx, _op_rx) = make_chatwidget_manual(Some("gpt-5.1")).await; + let (mut chat, _rx, _op_rx) = make_chatwidget_manual(Some("gpt-5.2")).await; chat.set_feature_enabled(Feature::CollaborationModes, /*enabled*/ true); let plan_mask = collaboration_modes::mask_for_kind(chat.model_catalog.as_ref(), ModeKind::Plan) .expect("expected plan collaboration mask"); chat.set_collaboration_mask(plan_mask); - chat.set_model("gpt-5.1-codex-mini"); + chat.set_model("gpt-5.4-mini"); - assert_eq!(chat.current_model(), "gpt-5.1-codex-mini"); + assert_eq!(chat.current_model(), "gpt-5.4-mini"); assert_eq!(chat.active_collaboration_mode_kind(), ModeKind::Plan); } #[tokio::test] async fn set_reasoning_effort_updates_active_collaboration_mask() { - let (mut chat, _rx, _op_rx) = make_chatwidget_manual(Some("gpt-5.1")).await; + let (mut chat, _rx, _op_rx) = make_chatwidget_manual(Some("gpt-5.2")).await; chat.set_feature_enabled(Feature::CollaborationModes, /*enabled*/ true); let plan_mask = collaboration_modes::mask_for_kind(chat.model_catalog.as_ref(), ModeKind::Plan) .expect("expected plan collaboration mask"); @@ -1367,7 +1358,7 @@ async fn set_reasoning_effort_updates_active_collaboration_mask() { #[tokio::test] async fn set_reasoning_effort_does_not_override_active_plan_override() { - let (mut chat, _rx, _op_rx) = make_chatwidget_manual(Some("gpt-5.1")).await; + let (mut chat, _rx, _op_rx) = make_chatwidget_manual(Some("gpt-5.2")).await; chat.set_feature_enabled(Feature::CollaborationModes, /*enabled*/ true); chat.set_plan_mode_reasoning_effort(Some(ReasoningEffortConfig::High)); let plan_mask = collaboration_modes::mask_for_kind(chat.model_catalog.as_ref(), ModeKind::Plan) @@ -1437,10 +1428,10 @@ async fn collab_mode_applies_default_preset() { #[tokio::test] async fn user_turn_includes_personality_from_config() { - let (mut chat, _rx, mut op_rx) = make_chatwidget_manual(Some("gpt-5.2-codex")).await; + let (mut chat, _rx, mut op_rx) = make_chatwidget_manual(Some("gpt-5.3-codex")).await; chat.set_feature_enabled(Feature::Personality, /*enabled*/ true); chat.thread_id = Some(ThreadId::new()); - chat.set_model("gpt-5.2-codex"); + chat.set_model("gpt-5.3-codex"); chat.set_personality(Personality::Friendly); chat.bottom_pane diff --git a/codex-rs/tui/src/chatwidget/tests/popups_and_settings.rs b/codex-rs/tui/src/chatwidget/tests/popups_and_settings.rs index a3792c31f..e05dcfd5c 100644 --- a/codex-rs/tui/src/chatwidget/tests/popups_and_settings.rs +++ b/codex-rs/tui/src/chatwidget/tests/popups_and_settings.rs @@ -1901,7 +1901,7 @@ async fn memories_reset_confirmation_sends_event_on_confirm() { #[tokio::test] async fn model_selection_popup_snapshot() { - let (mut chat, _rx, _op_rx) = make_chatwidget_manual(Some("gpt-5-codex")).await; + let (mut chat, _rx, _op_rx) = make_chatwidget_manual(Some("gpt-5.2")).await; chat.thread_id = Some(ThreadId::new()); chat.open_model_popup(); @@ -1911,7 +1911,7 @@ async fn model_selection_popup_snapshot() { #[tokio::test] async fn personality_selection_popup_snapshot() { - let (mut chat, _rx, _op_rx) = make_chatwidget_manual(Some("gpt-5.2-codex")).await; + let (mut chat, _rx, _op_rx) = make_chatwidget_manual(Some("gpt-5.3-codex")).await; chat.thread_id = Some(ThreadId::new()); chat.open_personality_popup(); @@ -1922,7 +1922,7 @@ async fn personality_selection_popup_snapshot() { #[cfg(not(target_os = "linux"))] #[tokio::test] async fn realtime_audio_selection_popup_snapshot() { - let (mut chat, _rx, _op_rx) = make_chatwidget_manual(Some("gpt-5.2-codex")).await; + let (mut chat, _rx, _op_rx) = make_chatwidget_manual(Some("gpt-5.3-codex")).await; chat.open_realtime_audio_popup(); let popup = render_bottom_popup(&chat, /*width*/ 80); @@ -1932,7 +1932,7 @@ async fn realtime_audio_selection_popup_snapshot() { #[cfg(not(target_os = "linux"))] #[tokio::test] async fn realtime_audio_selection_popup_narrow_snapshot() { - let (mut chat, _rx, _op_rx) = make_chatwidget_manual(Some("gpt-5.2-codex")).await; + let (mut chat, _rx, _op_rx) = make_chatwidget_manual(Some("gpt-5.3-codex")).await; chat.open_realtime_audio_popup(); let popup = render_bottom_popup(&chat, /*width*/ 56); @@ -1942,7 +1942,7 @@ async fn realtime_audio_selection_popup_narrow_snapshot() { #[cfg(not(target_os = "linux"))] #[tokio::test] async fn realtime_microphone_picker_popup_snapshot() { - let (mut chat, _rx, _op_rx) = make_chatwidget_manual(Some("gpt-5.2-codex")).await; + let (mut chat, _rx, _op_rx) = make_chatwidget_manual(Some("gpt-5.3-codex")).await; chat.config.realtime_audio.microphone = Some("Studio Mic".to_string()); chat.open_realtime_audio_device_selection_with_names( RealtimeAudioDeviceKind::Microphone, @@ -1956,7 +1956,7 @@ async fn realtime_microphone_picker_popup_snapshot() { #[cfg(not(target_os = "linux"))] #[tokio::test] async fn realtime_audio_picker_emits_persist_event() { - let (mut chat, mut rx, _op_rx) = make_chatwidget_manual(Some("gpt-5.2-codex")).await; + let (mut chat, mut rx, _op_rx) = make_chatwidget_manual(Some("gpt-5.3-codex")).await; chat.open_realtime_audio_device_selection_with_names( RealtimeAudioDeviceKind::Speaker, vec!["Desk Speakers".to_string(), "Headphones".to_string()], @@ -2017,8 +2017,8 @@ async fn model_picker_hides_show_in_picker_false_models_from_cache() { #[tokio::test] async fn server_overloaded_error_does_not_switch_models() { - let (mut chat, mut rx, mut op_rx) = make_chatwidget_manual(Some("gpt-5.2-codex")).await; - chat.set_model("gpt-5.2-codex"); + let (mut chat, mut rx, mut op_rx) = make_chatwidget_manual(Some("gpt-5.3-codex")).await; + chat.set_model("gpt-5.3-codex"); while rx.try_recv().is_ok() {} while op_rx.try_recv().is_ok() {} @@ -2033,7 +2033,7 @@ async fn server_overloaded_error_does_not_switch_models() { while let Ok(event) = rx.try_recv() { if let AppEvent::UpdateModel(model) = event { assert_eq!( - model, "gpt-5.2-codex", + model, "gpt-5.3-codex", "did not expect model switch on server-overloaded error" ); } @@ -2051,12 +2051,12 @@ async fn server_overloaded_error_does_not_switch_models() { #[tokio::test] async fn model_reasoning_selection_popup_snapshot() { - let (mut chat, _rx, _op_rx) = make_chatwidget_manual(Some("gpt-5.1-codex-max")).await; + let (mut chat, _rx, _op_rx) = make_chatwidget_manual(Some("gpt-5.4")).await; set_chatgpt_auth(&mut chat); chat.set_reasoning_effort(Some(ReasoningEffortConfig::High)); - let preset = get_available_model(&chat, "gpt-5.1-codex-max"); + let preset = get_available_model(&chat, "gpt-5.4"); chat.open_reasoning_popup(preset); let popup = render_bottom_popup(&chat, /*width*/ 80); @@ -2065,12 +2065,12 @@ async fn model_reasoning_selection_popup_snapshot() { #[tokio::test] async fn model_reasoning_selection_popup_extra_high_warning_snapshot() { - let (mut chat, _rx, _op_rx) = make_chatwidget_manual(Some("gpt-5.1-codex-max")).await; + let (mut chat, _rx, _op_rx) = make_chatwidget_manual(Some("gpt-5.2")).await; set_chatgpt_auth(&mut chat); chat.set_reasoning_effort(Some(ReasoningEffortConfig::XHigh)); - let preset = get_available_model(&chat, "gpt-5.1-codex-max"); + let preset = get_available_model(&chat, "gpt-5.2"); chat.open_reasoning_popup(preset); let popup = render_bottom_popup(&chat, /*width*/ 80); @@ -2079,11 +2079,11 @@ async fn model_reasoning_selection_popup_extra_high_warning_snapshot() { #[tokio::test] async fn reasoning_popup_shows_extra_high_with_space() { - let (mut chat, _rx, _op_rx) = make_chatwidget_manual(Some("gpt-5.1-codex-max")).await; + let (mut chat, _rx, _op_rx) = make_chatwidget_manual(Some("gpt-5.4")).await; set_chatgpt_auth(&mut chat); - let preset = get_available_model(&chat, "gpt-5.1-codex-max"); + let preset = get_available_model(&chat, "gpt-5.4"); chat.open_reasoning_popup(preset); let popup = render_bottom_popup(&chat, /*width*/ 120); @@ -2193,11 +2193,11 @@ async fn feedback_good_result_consent_popup_includes_connectivity_diagnostics_fi #[tokio::test] async fn reasoning_popup_escape_returns_to_model_popup() { - let (mut chat, _rx, _op_rx) = make_chatwidget_manual(Some("gpt-5.1-codex-max")).await; + let (mut chat, _rx, _op_rx) = make_chatwidget_manual(Some("gpt-5.4")).await; chat.thread_id = Some(ThreadId::new()); chat.open_model_popup(); - let preset = get_available_model(&chat, "gpt-5.1-codex-max"); + let preset = get_available_model(&chat, "gpt-5.4"); chat.open_reasoning_popup(preset); let before_escape = render_bottom_popup(&chat, /*width*/ 80); diff --git a/codex-rs/tui/src/chatwidget/tests/slash_commands.rs b/codex-rs/tui/src/chatwidget/tests/slash_commands.rs index 905ae9837..e91a11eca 100644 --- a/codex-rs/tui/src/chatwidget/tests/slash_commands.rs +++ b/codex-rs/tui/src/chatwidget/tests/slash_commands.rs @@ -299,7 +299,7 @@ async fn queued_bang_shell_waits_for_user_shell_completion_before_next_input() { } async fn assert_cancelled_queued_menu_drains_next_input(command: &str, expected_popup_text: &str) { - let (mut chat, _rx, mut op_rx) = make_chatwidget_manual(Some("gpt-5-codex")).await; + let (mut chat, _rx, mut op_rx) = make_chatwidget_manual(Some("gpt-5.2")).await; chat.thread_id = Some(ThreadId::new()); chat.handle_codex_event(Event { id: "turn-start".into(), @@ -351,7 +351,7 @@ async fn queued_slash_menu_cancel_drains_next_input() { #[tokio::test] async fn queued_slash_menu_selection_drains_next_input() { - let (mut chat, _rx, mut op_rx) = make_chatwidget_manual(Some("gpt-5-codex")).await; + let (mut chat, _rx, mut op_rx) = make_chatwidget_manual(Some("gpt-5.2")).await; chat.thread_id = Some(ThreadId::new()); chat.handle_codex_event(Event { id: "turn-start".into(), diff --git a/codex-rs/tui/src/chatwidget/tests/status_command_tests.rs b/codex-rs/tui/src/chatwidget/tests/status_command_tests.rs index a0a32056a..c20631354 100644 --- a/codex-rs/tui/src/chatwidget/tests/status_command_tests.rs +++ b/codex-rs/tui/src/chatwidget/tests/status_command_tests.rs @@ -78,7 +78,7 @@ async fn status_command_renders_immediately_without_rate_limit_refresh() { #[tokio::test] async fn status_command_uses_catalog_default_reasoning_when_config_empty() { - let (mut chat, mut rx, _op_rx) = make_chatwidget_manual(Some("gpt-5.1-codex-max")).await; + let (mut chat, mut rx, _op_rx) = make_chatwidget_manual(Some("gpt-5.4")).await; chat.config.model_reasoning_effort = None; chat.dispatch_command(SlashCommand::Status); @@ -90,7 +90,7 @@ async fn status_command_uses_catalog_default_reasoning_when_config_empty() { other => panic!("expected status output, got {other:?}"), }; assert!( - rendered.contains("gpt-5.1-codex-max (reasoning medium, summaries auto)"), + rendered.contains("gpt-5.4 (reasoning medium, summaries auto)"), "expected /status to render the catalog default reasoning effort, got: {rendered}" ); } diff --git a/codex-rs/tui/src/snapshots/codex_tui__app__tests__model_migration_prompt_shows_for_hidden_model.snap b/codex-rs/tui/src/snapshots/codex_tui__app__tests__model_migration_prompt_shows_for_hidden_model.snap deleted file mode 100644 index 23fb02d56..000000000 --- a/codex-rs/tui/src/snapshots/codex_tui__app__tests__model_migration_prompt_shows_for_hidden_model.snap +++ /dev/null @@ -1,11 +0,0 @@ ---- -source: tui/src/app.rs -expression: model_migration_copy_to_plain_text(©) ---- -**Codex just got an upgrade. Introducing gpt-5.3-codex.** - -Codex is now powered by gpt-5.3-codex, our most capable agentic coding model yet. It's built for long-running, project-scale work, with mid-turn steering + frequent progress updates so you can collaborate while it runs (and it's faster too). - -Learn more: https://openai.com/index/introducing-gpt-5-3-codex/ - -You can keep using gpt-5.1-codex if you prefer.