From 2ad6a37192315ca008eec53dbf9dcb20e070976c Mon Sep 17 00:00:00 2001 From: Ahmed Ibrahim Date: Sun, 14 Sep 2025 21:32:18 -0400 Subject: [PATCH] Don't show the model for apikey (#3607) --- codex-rs/common/src/model_presets.rs | 120 ++++++++++++++------------- codex-rs/tui/src/app.rs | 9 ++ codex-rs/tui/src/app_backtrack.rs | 1 + codex-rs/tui/src/chatwidget.rs | 10 ++- codex-rs/tui/src/chatwidget/tests.rs | 5 ++ 5 files changed, 87 insertions(+), 58 deletions(-) diff --git a/codex-rs/common/src/model_presets.rs b/codex-rs/common/src/model_presets.rs index 2e04d81b..09d92777 100644 --- a/codex-rs/common/src/model_presets.rs +++ b/codex-rs/common/src/model_presets.rs @@ -1,4 +1,6 @@ +use codex_core::config::SWIFTFOX_MEDIUM_MODEL; use codex_core::protocol_config_types::ReasoningEffort; +use codex_protocol::mcp_protocol::AuthMode; /// A simple preset pairing a model slug with a reasoning effort. #[derive(Debug, Clone, Copy)] @@ -15,61 +17,65 @@ pub struct ModelPreset { pub effort: Option, } -/// Built-in list of model presets that pair a model with a reasoning effort. -/// -/// Keep this UI-agnostic so it can be reused by both TUI and MCP server. -pub fn builtin_model_presets() -> &'static [ModelPreset] { - // Order groups swiftfox variants before gpt-5 presets, each from minimal to high. - const PRESETS: &[ModelPreset] = &[ - ModelPreset { - id: "swiftfox-low", - label: "swiftfox low", - description: "", - model: "swiftfox", - effort: Some(ReasoningEffort::Low), - }, - ModelPreset { - id: "swiftfox-medium", - label: "swiftfox medium", - description: "", - model: "swiftfox", - effort: None, - }, - ModelPreset { - id: "swiftfox-high", - label: "swiftfox high", - description: "", - model: "swiftfox", - effort: Some(ReasoningEffort::High), - }, - ModelPreset { - id: "gpt-5-minimal", - label: "gpt-5 minimal", - description: "— fastest responses with limited reasoning; ideal for coding, instructions, or lightweight tasks", - model: "gpt-5", - effort: Some(ReasoningEffort::Minimal), - }, - ModelPreset { - id: "gpt-5-low", - label: "gpt-5 low", - description: "— balances speed with some reasoning; useful for straightforward queries and short explanations", - model: "gpt-5", - effort: Some(ReasoningEffort::Low), - }, - ModelPreset { - id: "gpt-5-medium", - label: "gpt-5 medium", - description: "— default setting; provides a solid balance of reasoning depth and latency for general-purpose tasks", - model: "gpt-5", - effort: Some(ReasoningEffort::Medium), - }, - ModelPreset { - id: "gpt-5-high", - label: "gpt-5 high", - description: "— maximizes reasoning depth for complex or ambiguous problems", - model: "gpt-5", - effort: Some(ReasoningEffort::High), - }, - ]; - PRESETS +const PRESETS: &[ModelPreset] = &[ + ModelPreset { + id: "swiftfox-low", + label: "swiftfox low", + description: "", + model: "swiftfox", + effort: Some(ReasoningEffort::Low), + }, + ModelPreset { + id: "swiftfox-medium", + label: "swiftfox medium", + description: "", + model: "swiftfox", + effort: None, + }, + ModelPreset { + id: "swiftfox-high", + label: "swiftfox high", + description: "", + model: "swiftfox", + effort: Some(ReasoningEffort::High), + }, + ModelPreset { + id: "gpt-5-minimal", + label: "gpt-5 minimal", + description: "— fastest responses with limited reasoning; ideal for coding, instructions, or lightweight tasks", + model: "gpt-5", + effort: Some(ReasoningEffort::Minimal), + }, + ModelPreset { + id: "gpt-5-low", + label: "gpt-5 low", + description: "— balances speed with some reasoning; useful for straightforward queries and short explanations", + model: "gpt-5", + effort: Some(ReasoningEffort::Low), + }, + ModelPreset { + id: "gpt-5-medium", + label: "gpt-5 medium", + description: "— default setting; provides a solid balance of reasoning depth and latency for general-purpose tasks", + model: "gpt-5", + effort: Some(ReasoningEffort::Medium), + }, + ModelPreset { + id: "gpt-5-high", + label: "gpt-5 high", + description: "— maximizes reasoning depth for complex or ambiguous problems", + model: "gpt-5", + effort: Some(ReasoningEffort::High), + }, +]; + +pub fn builtin_model_presets(auth_mode: Option) -> Vec { + match auth_mode { + Some(AuthMode::ApiKey) => PRESETS + .iter() + .copied() + .filter(|p| !p.model.contains(SWIFTFOX_MEDIUM_MODEL)) + .collect(), + _ => PRESETS.to_vec(), + } } diff --git a/codex-rs/tui/src/app.rs b/codex-rs/tui/src/app.rs index 7abf5eed..40e3bd1c 100644 --- a/codex-rs/tui/src/app.rs +++ b/codex-rs/tui/src/app.rs @@ -38,6 +38,7 @@ pub(crate) struct App { pub(crate) server: Arc, pub(crate) app_event_tx: AppEventSender, pub(crate) chat_widget: ChatWidget, + pub(crate) auth_manager: Arc, /// Config is stored here so we can recreate ChatWidgets as needed. pub(crate) config: Config, @@ -88,6 +89,7 @@ impl App { initial_prompt: initial_prompt.clone(), initial_images: initial_images.clone(), enhanced_keys_supported, + auth_manager: auth_manager.clone(), }; ChatWidget::new(init, conversation_manager.clone()) } @@ -109,6 +111,7 @@ impl App { initial_prompt: initial_prompt.clone(), initial_images: initial_images.clone(), enhanced_keys_supported, + auth_manager: auth_manager.clone(), }; ChatWidget::new_from_existing( init, @@ -124,6 +127,7 @@ impl App { server: conversation_manager, app_event_tx, chat_widget, + auth_manager: auth_manager.clone(), config, active_profile, file_search, @@ -205,6 +209,7 @@ impl App { initial_prompt: None, initial_images: Vec::new(), enhanced_keys_supported: self.enhanced_keys_supported, + auth_manager: self.auth_manager.clone(), }; self.chat_widget = ChatWidget::new(init, self.server.clone()); tui.frame_requester().schedule_frame(); @@ -418,6 +423,7 @@ mod tests { use crate::app_backtrack::BacktrackState; use crate::chatwidget::tests::make_chatwidget_manual_with_sender; use crate::file_search::FileSearchManager; + use codex_core::AuthManager; use codex_core::CodexAuth; use codex_core::ConversationManager; use std::sync::Arc; @@ -430,12 +436,15 @@ mod tests { let server = Arc::new(ConversationManager::with_auth(CodexAuth::from_api_key( "Test API Key", ))); + let auth_manager = + AuthManager::from_auth_for_testing(CodexAuth::from_api_key("Test API Key")); let file_search = FileSearchManager::new(config.cwd.clone(), app_event_tx.clone()); App { server, app_event_tx, chat_widget, + auth_manager, config, active_profile: None, file_search, diff --git a/codex-rs/tui/src/app_backtrack.rs b/codex-rs/tui/src/app_backtrack.rs index b3ca171c..0da2760f 100644 --- a/codex-rs/tui/src/app_backtrack.rs +++ b/codex-rs/tui/src/app_backtrack.rs @@ -335,6 +335,7 @@ impl App { initial_prompt: None, initial_images: Vec::new(), enhanced_keys_supported: self.enhanced_keys_supported, + auth_manager: self.auth_manager.clone(), }; self.chat_widget = crate::chatwidget::ChatWidget::new_from_existing(init, conv, session_configured); diff --git a/codex-rs/tui/src/chatwidget.rs b/codex-rs/tui/src/chatwidget.rs index e39dc8d6..21eb3585 100644 --- a/codex-rs/tui/src/chatwidget.rs +++ b/codex-rs/tui/src/chatwidget.rs @@ -82,6 +82,7 @@ use codex_common::approval_presets::ApprovalPreset; use codex_common::approval_presets::builtin_approval_presets; use codex_common::model_presets::ModelPreset; use codex_common::model_presets::builtin_model_presets; +use codex_core::AuthManager; use codex_core::ConversationManager; use codex_core::protocol::AskForApproval; use codex_core::protocol::SandboxPolicy; @@ -103,6 +104,7 @@ pub(crate) struct ChatWidgetInit { pub(crate) initial_prompt: Option, pub(crate) initial_images: Vec, pub(crate) enhanced_keys_supported: bool, + pub(crate) auth_manager: Arc, } pub(crate) struct ChatWidget { @@ -111,6 +113,7 @@ pub(crate) struct ChatWidget { bottom_pane: BottomPane, active_exec_cell: Option, config: Config, + auth_manager: Arc, session_header: SessionHeader, initial_user_message: Option, token_info: Option, @@ -646,6 +649,7 @@ impl ChatWidget { initial_prompt, initial_images, enhanced_keys_supported, + auth_manager, } = common; let mut rng = rand::rng(); let placeholder = EXAMPLE_PROMPTS[rng.random_range(0..EXAMPLE_PROMPTS.len())].to_string(); @@ -665,6 +669,7 @@ impl ChatWidget { }), active_exec_cell: None, config: config.clone(), + auth_manager, session_header: SessionHeader::new(config.model.clone()), initial_user_message: create_initial_user_message( initial_prompt.unwrap_or_default(), @@ -697,6 +702,7 @@ impl ChatWidget { initial_prompt, initial_images, enhanced_keys_supported, + auth_manager, } = common; let mut rng = rand::rng(); let placeholder = EXAMPLE_PROMPTS[rng.random_range(0..EXAMPLE_PROMPTS.len())].to_string(); @@ -718,6 +724,7 @@ impl ChatWidget { }), active_exec_cell: None, config: config.clone(), + auth_manager, session_header: SessionHeader::new(config.model.clone()), initial_user_message: create_initial_user_message( initial_prompt.unwrap_or_default(), @@ -1188,7 +1195,8 @@ impl ChatWidget { pub(crate) fn open_model_popup(&mut self) { let current_model = self.config.model.clone(); let current_effort = self.config.model_reasoning_effort; - let presets: &[ModelPreset] = builtin_model_presets(); + let auth_mode = self.auth_manager.auth().map(|auth| auth.mode); + let presets: Vec = builtin_model_presets(auth_mode); let mut items: Vec = Vec::new(); for preset in presets.iter() { diff --git a/codex-rs/tui/src/chatwidget/tests.rs b/codex-rs/tui/src/chatwidget/tests.rs index 9d49c9ed..ebd97c81 100644 --- a/codex-rs/tui/src/chatwidget/tests.rs +++ b/codex-rs/tui/src/chatwidget/tests.rs @@ -1,6 +1,7 @@ use super::*; use crate::app_event::AppEvent; use crate::app_event_sender::AppEventSender; +use codex_core::AuthManager; use codex_core::CodexAuth; use codex_core::config::Config; use codex_core::config::ConfigOverrides; @@ -195,6 +196,7 @@ async fn helpers_are_available_and_do_not_panic() { let conversation_manager = Arc::new(ConversationManager::with_auth(CodexAuth::from_api_key( "test", ))); + let auth_manager = AuthManager::from_auth_for_testing(CodexAuth::from_api_key("test")); let init = ChatWidgetInit { config: cfg, frame_requester: FrameRequester::test_dummy(), @@ -202,6 +204,7 @@ async fn helpers_are_available_and_do_not_panic() { initial_prompt: None, initial_images: Vec::new(), enhanced_keys_supported: false, + auth_manager, }; let mut w = ChatWidget::new(init, conversation_manager); // Basic construction sanity. @@ -226,12 +229,14 @@ fn make_chatwidget_manual() -> ( placeholder_text: "Ask Codex to do anything".to_string(), disable_paste_burst: false, }); + let auth_manager = AuthManager::from_auth_for_testing(CodexAuth::from_api_key("test")); let widget = ChatWidget { app_event_tx, codex_op_tx: op_tx, bottom_pane: bottom, active_exec_cell: None, config: cfg.clone(), + auth_manager, session_header: SessionHeader::new(cfg.model.clone()), initial_user_message: None, token_info: None,