diff --git a/codex-rs/tui/src/chatwidget.rs b/codex-rs/tui/src/chatwidget.rs index c15c59f2e..d8f3c90be 100644 --- a/codex-rs/tui/src/chatwidget.rs +++ b/codex-rs/tui/src/chatwidget.rs @@ -7126,7 +7126,22 @@ impl ChatWidget { .map(|ti| &ti.total_token_usage) .unwrap_or(&default_usage); let collaboration_mode = self.collaboration_mode_label(); - let reasoning_effort_override = Some(self.effective_reasoning_effort()); + let model = self.current_model().to_string(); + let model_default_reasoning_effort = + self.model_catalog + .try_list_models() + .ok() + .and_then(|models| { + models + .into_iter() + .find(|preset| preset.model == model) + .map(|preset| preset.default_reasoning_effort) + }); + let reasoning_effort_override = Some( + self.effective_reasoning_effort() + .or(self.config.model_reasoning_effort) + .or(model_default_reasoning_effort), + ); let rate_limit_snapshots: Vec = self .rate_limit_snapshots_by_limit_id .values() 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 51f1c8da4..a0a32056a 100644 --- a/codex-rs/tui/src/chatwidget/tests/status_command_tests.rs +++ b/codex-rs/tui/src/chatwidget/tests/status_command_tests.rs @@ -76,6 +76,25 @@ 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; + chat.config.model_reasoning_effort = None; + + chat.dispatch_command(SlashCommand::Status); + + let rendered = match rx.try_recv() { + Ok(AppEvent::InsertHistoryCell(cell)) => { + lines_to_single_string(&cell.display_lines(/*width*/ 80)) + } + other => panic!("expected status output, got {other:?}"), + }; + assert!( + rendered.contains("gpt-5.1-codex-max (reasoning medium, summaries auto)"), + "expected /status to render the catalog default reasoning effort, got: {rendered}" + ); +} + #[tokio::test] async fn status_command_renders_instruction_sources_from_thread_session() { let (mut chat, mut rx, _op_rx) = make_chatwidget_manual(/*model_override*/ None).await; diff --git a/codex-rs/tui/src/status/card.rs b/codex-rs/tui/src/status/card.rs index 20b4c6ed8..2a05bb888 100644 --- a/codex-rs/tui/src/status/card.rs +++ b/codex-rs/tui/src/status/card.rs @@ -259,7 +259,7 @@ impl StatusHistoryCell { ]; if config.model_provider.wire_api == WireApi::Responses { let effort_value = reasoning_effort_override - .unwrap_or(None) + .unwrap_or(config.model_reasoning_effort) .map(|effort| effort.to_string()) .unwrap_or_else(|| "none".to_string()); config_entries.push(("reasoning effort", effort_value)); diff --git a/codex-rs/tui/src/status/snapshots/codex_tui__status__tests__status_snapshot_uses_default_reasoning_when_config_empty.snap b/codex-rs/tui/src/status/snapshots/codex_tui__status__tests__status_snapshot_uses_default_reasoning_when_config_empty.snap new file mode 100644 index 000000000..de0ea5056 --- /dev/null +++ b/codex-rs/tui/src/status/snapshots/codex_tui__status__tests__status_snapshot_uses_default_reasoning_when_config_empty.snap @@ -0,0 +1,21 @@ +--- +source: tui/src/status/tests.rs +expression: sanitized +--- +/status + +╭─────────────────────────────────────────────────────────────────────────╮ +│ >_ OpenAI Codex (v0.0.0) │ +│ │ +│ Visit https://chatgpt.com/codex/settings/usage for up-to-date │ +│ information on rate limits and credits │ +│ │ +│ Model: gpt-5.1-codex-max (reasoning medium, summaries auto) │ +│ Directory: [[workspace]] │ +│ Permissions: Custom (read-only, on-request) │ +│ Agents.md: │ +│ │ +│ Token usage: 750 total (500 input + 250 output) │ +│ Context window: 100% left (750 used / 272K) │ +│ Limits: data not available yet │ +╰─────────────────────────────────────────────────────────────────────────╯ diff --git a/codex-rs/tui/src/status/tests.rs b/codex-rs/tui/src/status/tests.rs index 12b23a38f..90325332c 100644 --- a/codex-rs/tui/src/status/tests.rs +++ b/codex-rs/tui/src/status/tests.rs @@ -1,5 +1,6 @@ use super::new_status_output; use super::new_status_output_with_rate_limits; +use super::new_status_output_with_rate_limits_handle; use super::rate_limit_snapshot_display; use crate::history_cell::HistoryCell; use crate::legacy_core::config::Config; @@ -702,6 +703,56 @@ async fn status_snapshot_shows_missing_limits_message() { assert_snapshot!(sanitized); } +#[tokio::test] +async fn status_snapshot_uses_default_reasoning_when_config_empty() { + let temp_home = TempDir::new().expect("temp home"); + let mut config = test_config(&temp_home).await; + config.model = Some("gpt-5.1-codex-max".to_string()); + config.cwd = test_path_buf("/workspace/tests").abs(); + + let account_display = test_status_account_display(); + let usage = TokenUsage { + input_tokens: 500, + cached_input_tokens: 0, + output_tokens: 250, + reasoning_output_tokens: 0, + total_tokens: 750, + }; + + let now = chrono::Local + .with_ymd_and_hms(2024, 2, 3, 4, 5, 6) + .single() + .expect("timestamp"); + + let model_slug = crate::legacy_core::test_support::get_model_offline(config.model.as_deref()); + let token_info = token_info_for(&model_slug, &config, &usage); + let (composite, _) = new_status_output_with_rate_limits_handle( + &config, + account_display.as_ref(), + Some(&token_info), + &usage, + &None, + /*thread_name*/ None, + /*forked_from*/ None, + &[], + None, + now, + &model_slug, + /*collaboration_mode*/ None, + /*reasoning_effort_override*/ Some(Some(ReasoningEffort::Medium)), + "".to_string(), + /*refreshing_rate_limits*/ false, + ); + let mut rendered_lines = render_lines(&composite.display_lines(/*width*/ 80)); + if cfg!(windows) { + for line in &mut rendered_lines { + *line = line.replace('\\', "/"); + } + } + let sanitized = sanitize_directory(rendered_lines).join("\n"); + assert_snapshot!(sanitized); +} + #[tokio::test] async fn status_snapshot_shows_refreshing_limits_notice() { let temp_home = TempDir::new().expect("temp home");