From 0702ebed4d6878c40bb90e01ef33039b21c6e1fc Mon Sep 17 00:00:00 2001 From: Benjamin Carlsson Date: Thu, 12 Nov 2026 02:03:18 +0000 Subject: [PATCH] Lowercase service tier names in the model status line (#60972) ## What changed Render service tier names in lowercase for the `model-with-reasoning` status line item, while preserving their display casing in terminal titles. ## Testing Extend footer snapshots to cover Fast and Ultrafast, verify terminal title casing, and check lowercase Flex and multiword tier labels. GitOrigin-RevId: 16227735d4aae55463df537b91ff7e81c436a66e --- ...model_with_reasoning_ultrafast_footer.snap | 10 +++ .../tui/src/chatwidget/status_surfaces.rs | 12 +-- .../src/chatwidget/tests/status_and_layout.rs | 78 ++++++++++++++----- 3 files changed, 76 insertions(+), 24 deletions(-) create mode 100644 codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__status_line_model_with_reasoning_ultrafast_footer.snap diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__status_line_model_with_reasoning_ultrafast_footer.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__status_line_model_with_reasoning_ultrafast_footer.snap new file mode 100644 index 0000000000..dc2f47ea0f --- /dev/null +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__status_line_model_with_reasoning_ultrafast_footer.snap @@ -0,0 +1,10 @@ +--- +source: tui/src/chatwidget/tests/status_and_layout.rs +expression: normalized_backend_snapshot(terminal.backend()) +--- +" " +" " +"› Ask Codex to do anything " +" " +" gpt-5.4 xhigh ultrafast · Context 0% used · /tmp/project " +" ? for shortcuts " diff --git a/codex-rs/tui/src/chatwidget/status_surfaces.rs b/codex-rs/tui/src/chatwidget/status_surfaces.rs index c7109c6e3d..df1c67bf3b 100644 --- a/codex-rs/tui/src/chatwidget/status_surfaces.rs +++ b/codex-rs/tui/src/chatwidget/status_surfaces.rs @@ -723,7 +723,10 @@ impl ChatWidget { pub(super) fn status_line_value_for_item(&mut self, item: StatusLineItem) -> Option { match item { StatusLineItem::ModelName => Some(self.model_display_name().to_string()), - StatusLineItem::ModelWithReasoning => Some(self.model_with_reasoning_display_name()), + StatusLineItem::ModelWithReasoning => { + let service_tier = self.processing_tier_display_name().map(str::to_lowercase); + Some(self.model_with_reasoning_display_name(service_tier.as_deref())) + } StatusLineItem::Reasoning => Some(self.reasoning_display_name()), StatusLineItem::Profile => { let layer = self.config.config_layer_stack.get_active_user_layer()?; @@ -970,7 +973,7 @@ impl ChatWidget { /*max_chars*/ 32, )), TerminalTitleItem::ModelWithReasoning => Some(Self::truncate_terminal_title_part( - self.model_with_reasoning_display_name(), + self.model_with_reasoning_display_name(self.processing_tier_display_name()), /*max_chars*/ 32, )), TerminalTitleItem::Reasoning => Some(Self::truncate_terminal_title_part( @@ -986,10 +989,9 @@ impl ChatWidget { Self::status_line_reasoning_effort_label(effort.as_ref()) } - fn model_with_reasoning_display_name(&self) -> String { + fn model_with_reasoning_display_name(&self, service_tier: Option<&str>) -> String { let label = self.reasoning_display_name(); - let service_tier_label = self - .processing_tier_display_name() + let service_tier_label = service_tier .map(|tier| format!(" {tier}")) .unwrap_or_default(); format!("{} {label}{service_tier_label}", self.model_display_name()) diff --git a/codex-rs/tui/src/chatwidget/tests/status_and_layout.rs b/codex-rs/tui/src/chatwidget/tests/status_and_layout.rs index 3491d386b4..2b56756645 100644 --- a/codex-rs/tui/src/chatwidget/tests/status_and_layout.rs +++ b/codex-rs/tui/src/chatwidget/tests/status_and_layout.rs @@ -4506,13 +4506,8 @@ async fn renamed_thread_footer_title_snapshot() { } #[tokio::test] -async fn status_line_model_with_reasoning_fast_footer_snapshot() { - use ratatui::Terminal; - use ratatui::backend::TestBackend; - +async fn status_line_model_with_reasoning_speed_footer_snapshots() { let (mut chat, _rx, _op_rx) = make_chatwidget_manual(Some("gpt-5.4")).await; - set_fast_mode_test_catalog(&mut chat); - assert!(get_available_model(&chat, "gpt-5.4").supports_fast_mode()); chat.show_welcome_banner = false; chat.config.cwd = test_project_path().abs(); chat.local_settings.tui.status_line = Some(vec![ @@ -4520,23 +4515,68 @@ async fn status_line_model_with_reasoning_fast_footer_snapshot() { "context-used".to_string(), "current-dir".to_string(), ]); + chat.local_settings.tui.terminal_title = Some(vec!["model-with-reasoning".to_string()]); chat.set_reasoning_effort(Some(ReasoningEffortConfig::XHigh)); - chat.set_service_tier(Some(ServiceTier::Fast.request_value().to_string())); set_chatgpt_auth(&mut chat); set_fast_mode_test_catalog(&mut chat); - assert!(get_available_model(&chat, "gpt-5.4").supports_fast_mode()); - chat.refresh_status_line(); + chat.set_feature_enabled(Feature::UltrafastMode, /*enabled*/ true); - let width = 80; - let height = chat.desired_height(width); - let mut terminal = Terminal::new(TestBackend::new(width, height)).expect("create terminal"); - terminal - .draw(|f| chat.render(f.area(), f.buffer_mut())) - .expect("draw model-with-reasoning footer"); - assert_chatwidget_snapshot!( - "status_line_model_with_reasoning_fast_footer", - normalized_backend_snapshot(terminal.backend()) - ); + let mut preset = get_available_model(&chat, "gpt-5.4"); + let fast_tier = preset + .service_tiers + .iter_mut() + .find(|tier| tier.id == ServiceTier::Fast.request_value()) + .expect("fast tier"); + fast_tier.name = "Fast".to_string(); + preset.service_tiers.extend([ + codex_protocol::openai_models::ModelServiceTier { + id: "ultrafast".to_string(), + name: "Ultrafast".to_string(), + description: "Ultrafast processing".to_string(), + }, + codex_protocol::openai_models::ModelServiceTier { + id: "low_latency".to_string(), + name: "Low Latency".to_string(), + description: String::new(), + }, + ]); + chat.model_catalog = Arc::new(ModelCatalog::new(vec![preset])); + + for (tier_id, tier_name, snapshot) in [ + ( + ServiceTier::Fast.request_value(), + "Fast", + "status_line_model_with_reasoning_fast_footer", + ), + ( + "ultrafast", + "Ultrafast", + "status_line_model_with_reasoning_ultrafast_footer", + ), + ] { + chat.set_service_tier(Some(tier_id.to_string())); + chat.refresh_status_line(); + chat.refresh_terminal_title(); + assert_eq!( + chat.last_terminal_title.as_deref(), + Some(format!("gpt-5.4 xhigh {tier_name}").as_str()) + ); + + let width = 80; + let height = chat.desired_height(width); + let mut terminal = Terminal::new(TestBackend::new(width, height)).expect("create terminal"); + terminal + .draw(|f| chat.render(f.area(), f.buffer_mut())) + .expect("draw model-with-reasoning footer"); + assert_chatwidget_snapshot!(snapshot, normalized_backend_snapshot(terminal.backend())); + } + + chat.local_settings.tui.status_line = Some(vec!["model-with-reasoning".to_string()]); + chat.set_service_tier(Some(ServiceTier::Flex.request_value().to_string())); + insta::assert_snapshot!(status_line_text(&chat).expect("status line"), @"gpt-5.4 xhigh flex"); + + chat.set_service_tier(Some("low_latency".to_string())); + insta::assert_snapshot!(status_line_text(&chat).expect("status line"), @"gpt-5.4 xhigh low latency"); } #[tokio::test]