diff --git a/codex-rs/tui/assets/tooltips.txt b/codex-rs/tui/assets/tooltips.txt index 58cc948290..029e9e7bd4 100644 --- a/codex-rs/tui/assets/tooltips.txt +++ b/codex-rs/tui/assets/tooltips.txt @@ -11,7 +11,6 @@ Use /fork to branch the current chat into a new thread. Use /side to start a side conversation in a temporary fork without polluting the main thread. Use /init to create an AGENTS.md with project-specific guidance. Use /mcp to list configured MCP tools. -Use /personality to customize how Codex communicates. Use /rename to rename your threads for easier thread resuming. Use the OpenAI docs MCP for API questions; enable it with `codex mcp add openaiDeveloperDocs --url https://developers.openai.com/mcp`. Join the OpenAI community Discord: http://discord.gg/openai diff --git a/codex-rs/tui/src/app.rs b/codex-rs/tui/src/app.rs index 331d379dc7..75bb355cf8 100644 --- a/codex-rs/tui/src/app.rs +++ b/codex-rs/tui/src/app.rs @@ -152,7 +152,6 @@ use codex_models_manager::model_presets::HIDE_GPT5_1_MIGRATION_PROMPT_CONFIG; use codex_otel::SessionTelemetry; use codex_otel::TelemetryAuthMode; use codex_protocol::ThreadId; -use codex_protocol::config_types::Personality; use codex_protocol::models::ActivePermissionProfile; use codex_protocol::models::BUILT_IN_PERMISSION_PROFILE_WORKSPACE; use codex_protocol::models::PermissionProfile; diff --git a/codex-rs/tui/src/app/config_persistence.rs b/codex-rs/tui/src/app/config_persistence.rs index f6749fc2a6..e2a1f8c220 100644 --- a/codex-rs/tui/src/app/config_persistence.rs +++ b/codex-rs/tui/src/app/config_persistence.rs @@ -1083,11 +1083,6 @@ impl App { false } - pub(super) fn on_update_personality(&mut self, personality: Personality) { - self.config.personality = Some(personality); - self.chat_widget.set_personality(personality); - } - pub(super) fn sync_tui_theme_selection(&mut self, name: String) { self.local_settings.tui.theme = Some(name.clone()); self.chat_widget.set_tui_theme(Some(name)); @@ -1125,14 +1120,6 @@ impl App { } } - pub(super) fn personality_label(personality: Personality) -> &'static str { - match personality { - Personality::None => "None", - Personality::Friendly => "Friendly", - Personality::Pragmatic => "Pragmatic", - } - } - fn sync_feature_state_from_effective_config( &mut self, effective_config: &ConfigReadResponse, diff --git a/codex-rs/tui/src/app/event_dispatch.rs b/codex-rs/tui/src/app/event_dispatch.rs index 30ced383a0..9b49e67fb6 100644 --- a/codex-rs/tui/src/app/event_dispatch.rs +++ b/codex-rs/tui/src/app/event_dispatch.rs @@ -1732,11 +1732,6 @@ impl App { .await; } } - AppEvent::UpdatePersonality(personality) => { - self.on_update_personality(personality); - self.sync_active_thread_personality_setting(app_server, personality) - .await; - } AppEvent::RealtimeWebrtcOfferCreated { thread_id, attempt_id, @@ -2367,32 +2362,6 @@ impl App { AppEvent::PersistRealtimeVoiceSelection { voice } => { self.persist_realtime_voice(app_server, voice).await; } - AppEvent::PersistPersonalitySelection { personality } => { - match crate::config_update::write_config_batch( - app_server.request_handle(), - vec![crate::config_update::replace_config_value( - "personality", - serde_json::json!(personality.to_string()), - )], - ) - .await - { - Ok(_) => { - let label = Self::personality_label(personality); - let message = format!("Personality set to {label}"); - self.chat_widget.add_info_message(message, /*hint*/ None); - } - Err(err) => { - tracing::error!( - error = %err, - "failed to persist personality selection" - ); - self.chat_widget.add_error_message(format!( - "Failed to save default personality: {err}" - )); - } - } - } AppEvent::PersistServiceTierSelection { service_tier } => { self.refresh_status_line(); self.config.service_tier = service_tier.clone(); diff --git a/codex-rs/tui/src/app/thread_settings.rs b/codex-rs/tui/src/app/thread_settings.rs index 66abceebef..94c8955468 100644 --- a/codex-rs/tui/src/app/thread_settings.rs +++ b/codex-rs/tui/src/app/thread_settings.rs @@ -144,22 +144,6 @@ impl App { self.send_thread_settings_update(app_server, params).await; } - pub(super) async fn sync_active_thread_personality_setting( - &mut self, - app_server: &mut AppServerSession, - personality: codex_protocol::config_types::Personality, - ) { - let Some(thread_id) = self.active_thread_id else { - return; - }; - let params = ThreadSettingsUpdateParams { - thread_id: thread_id.to_string(), - personality: Some(personality), - ..ThreadSettingsUpdateParams::default() - }; - self.send_thread_settings_update(app_server, params).await; - } - pub(super) async fn sync_override_turn_context_settings( &mut self, app_server: &mut AppServerSession, diff --git a/codex-rs/tui/src/app_event.rs b/codex-rs/tui/src/app_event.rs index 575ff2d8eb..8e00ef9c3c 100644 --- a/codex-rs/tui/src/app_event.rs +++ b/codex-rs/tui/src/app_event.rs @@ -61,7 +61,6 @@ use codex_config::types::ApprovalsReviewer; use codex_features::Feature; use codex_plugin::PluginCapabilitySummary; use codex_protocol::config_types::CollaborationModeMask; -use codex_protocol::config_types::Personality; use codex_protocol::models::ActivePermissionProfile; use codex_realtime_webrtc::StartedRealtimeWebrtcSession; @@ -1106,9 +1105,6 @@ pub(crate) enum AppEvent { /// Update the current model slug in the running app and widget. UpdateModel(String), - /// Update the current personality in the running app and widget. - UpdatePersonality(Personality), - /// Result of creating a TUI-owned WebRTC offer for an active thread. RealtimeWebrtcOfferCreated { thread_id: ThreadId, @@ -1150,11 +1146,6 @@ pub(crate) enum AppEvent { voice: codex_protocol::protocol::RealtimeVoice, }, - /// Persist the selected personality to the appropriate config. - PersistPersonalitySelection { - personality: Personality, - }, - /// Persist the selected service tier to the appropriate config. PersistServiceTierSelection { service_tier: Option, diff --git a/codex-rs/tui/src/bottom_pane/chat_composer.rs b/codex-rs/tui/src/bottom_pane/chat_composer.rs index ff2dc80f39..54775ca6c6 100644 --- a/codex-rs/tui/src/bottom_pane/chat_composer.rs +++ b/codex-rs/tui/src/bottom_pane/chat_composer.rs @@ -568,7 +568,6 @@ pub(crate) struct ChatComposer { service_tier_commands: Vec, mentions_v2_enabled: bool, goal_command_enabled: bool, - personality_command_enabled: bool, voice_command_enabled: bool, worktrees_enabled: bool, windows_degraded_sandbox_active: bool, @@ -734,7 +733,6 @@ impl ChatComposer { service_tier_commands: Vec::new(), mentions_v2_enabled: false, goal_command_enabled: false, - personality_command_enabled: false, voice_command_enabled: false, worktrees_enabled: false, windows_degraded_sandbox_active: false, @@ -1015,10 +1013,6 @@ impl ChatComposer { self.footer.ide_context_active = active; } - pub fn set_personality_command_enabled(&mut self, enabled: bool) { - self.personality_command_enabled = enabled; - } - pub fn set_side_conversation_active(&mut self, active: bool) { self.side_conversation_active = active; } @@ -5181,39 +5175,6 @@ mod tests { ); } - #[test] - fn parent_owned_thread_allows_bare_navigation_commands() { - for (command, expected) in [ - ("/agents", SlashCommand::Agents), - ("/subagents", SlashCommand::MultiAgents), - ("/side", SlashCommand::Side), - ("/btw", SlashCommand::Btw), - ("/diff ", SlashCommand::Diff), - ] { - let (mut composer, _rx) = new_test_composer(); - composer.set_parent_owned_thread(); - composer.set_text_content(command.to_string(), Vec::new(), Vec::new()); - - assert_eq!( - composer.handle_submission(/*should_queue*/ false).0, - InputResult::Command(expected) - ); - } - } - - #[test] - fn parent_owned_thread_allows_safe_command_selected_from_prefix() { - let (mut composer, _rx) = new_test_composer(); - composer.set_parent_owned_thread(); - type_chars_humanlike(&mut composer, &['/', 'a', 'g']); - - let result = composer - .handle_key_event(KeyEvent::new(KeyCode::Enter, KeyModifiers::NONE)) - .0; - - assert_eq!(result, InputResult::Command(SlashCommand::Agents)); - } - #[test] fn parent_owned_thread_placeholder_snapshot() { snapshot_composer_state( diff --git a/codex-rs/tui/src/bottom_pane/chat_composer/agents_navigation_tests.rs b/codex-rs/tui/src/bottom_pane/chat_composer/agents_navigation_tests.rs index 59bc80a59e..7796587ff3 100644 --- a/codex-rs/tui/src/bottom_pane/chat_composer/agents_navigation_tests.rs +++ b/codex-rs/tui/src/bottom_pane/chat_composer/agents_navigation_tests.rs @@ -1,9 +1,43 @@ use super::tests::new_test_composer; use super::tests::snapshot_composer_state_with_width; +use super::tests::type_chars_humanlike; use super::*; use assert_matches::assert_matches; use pretty_assertions::assert_eq; +#[test] +fn parent_owned_thread_allows_bare_navigation_commands() { + for (command, expected) in [ + ("/agents", SlashCommand::Agents), + ("/subagents", SlashCommand::MultiAgents), + ("/side", SlashCommand::Side), + ("/btw", SlashCommand::Btw), + ("/diff ", SlashCommand::Diff), + ] { + let (mut composer, _rx) = new_test_composer(); + composer.set_parent_owned_thread(); + composer.set_text_content(command.to_string(), Vec::new(), Vec::new()); + + assert_eq!( + composer.handle_submission(/*should_queue*/ false).0, + InputResult::Command(expected) + ); + } +} + +#[test] +fn parent_owned_thread_allows_safe_command_selected_from_prefix() { + let (mut composer, _rx) = new_test_composer(); + composer.set_parent_owned_thread(); + type_chars_humanlike(&mut composer, &['/', 'a', 'g']); + + let result = composer + .handle_key_event(KeyEvent::new(KeyCode::Enter, KeyModifiers::NONE)) + .0; + + assert_eq!(result, InputResult::Command(SlashCommand::Agents)); +} + #[test] fn left_navigates_only_from_an_empty_prompt() { let (mut composer, mut events) = new_test_composer(); diff --git a/codex-rs/tui/src/bottom_pane/chat_composer/slash_input.rs b/codex-rs/tui/src/bottom_pane/chat_composer/slash_input.rs index 8e4ff2f87b..0a1604e5e3 100644 --- a/codex-rs/tui/src/bottom_pane/chat_composer/slash_input.rs +++ b/codex-rs/tui/src/bottom_pane/chat_composer/slash_input.rs @@ -177,7 +177,6 @@ impl<'a> SlashInput<'a> { token_activity_command_enabled: self.command_flags.token_activity_command_enabled, service_tier_commands_enabled: self.command_flags.service_tier_commands_enabled, goal_command_enabled: self.command_flags.goal_command_enabled, - personality_command_enabled: self.command_flags.personality_command_enabled, voice_command_enabled: self.command_flags.voice_command_enabled, worktrees_enabled: self.command_flags.worktrees_enabled, windows_degraded_sandbox_active: self.command_flags.allow_elevate_sandbox, @@ -216,7 +215,6 @@ impl ChatComposer { token_activity_command_enabled: self.token_activity_command_enabled, service_tier_commands_enabled: self.service_tier_commands_enabled, goal_command_enabled: self.goal_command_enabled, - personality_command_enabled: self.personality_command_enabled, voice_command_enabled: self.voice_command_enabled, worktrees_enabled: self.worktrees_enabled, allow_elevate_sandbox: self.windows_degraded_sandbox_active, diff --git a/codex-rs/tui/src/bottom_pane/command_popup.rs b/codex-rs/tui/src/bottom_pane/command_popup.rs index 65d3976f12..26050f7300 100644 --- a/codex-rs/tui/src/bottom_pane/command_popup.rs +++ b/codex-rs/tui/src/bottom_pane/command_popup.rs @@ -47,7 +47,6 @@ pub(crate) struct CommandPopupFlags { pub(crate) token_activity_command_enabled: bool, pub(crate) service_tier_commands_enabled: bool, pub(crate) goal_command_enabled: bool, - pub(crate) personality_command_enabled: bool, pub(crate) voice_command_enabled: bool, pub(crate) worktrees_enabled: bool, pub(crate) windows_degraded_sandbox_active: bool, @@ -63,7 +62,6 @@ impl From for BuiltinCommandFlags { token_activity_command_enabled: value.token_activity_command_enabled, service_tier_commands_enabled: value.service_tier_commands_enabled, goal_command_enabled: value.goal_command_enabled, - personality_command_enabled: value.personality_command_enabled, voice_command_enabled: value.voice_command_enabled, worktrees_enabled: value.worktrees_enabled, allow_elevate_sandbox: value.windows_degraded_sandbox_active, @@ -563,7 +561,6 @@ mod tests { token_activity_command_enabled: false, service_tier_commands_enabled: false, goal_command_enabled: false, - personality_command_enabled: true, voice_command_enabled: false, worktrees_enabled: true, windows_degraded_sandbox_active: false, @@ -582,69 +579,6 @@ mod tests { } } - #[test] - fn personality_command_hidden_when_disabled() { - let mut popup = CommandPopup::new( - CommandPopupFlags { - collaboration_modes_enabled: true, - connectors_enabled: false, - plugins_command_enabled: false, - token_activity_command_enabled: false, - service_tier_commands_enabled: false, - goal_command_enabled: false, - personality_command_enabled: false, - voice_command_enabled: false, - worktrees_enabled: false, - windows_degraded_sandbox_active: false, - side_conversation_active: false, - }, - Vec::new(), - ); - popup.on_composer_text_change("/pers".to_string()); - - let cmds: Vec = popup - .filtered_items() - .into_iter() - .map(|item| match item { - CommandItem::Builtin(cmd) => cmd.command().to_string(), - CommandItem::ServiceTier(command) => command.name, - }) - .collect(); - assert!( - !cmds.iter().any(|cmd| cmd == "personality"), - "expected '/personality' to be hidden when disabled, got {cmds:?}" - ); - } - - #[test] - fn personality_command_visible_when_enabled() { - let mut popup = CommandPopup::new( - CommandPopupFlags { - collaboration_modes_enabled: true, - connectors_enabled: false, - plugins_command_enabled: false, - token_activity_command_enabled: false, - service_tier_commands_enabled: false, - goal_command_enabled: false, - personality_command_enabled: true, - voice_command_enabled: false, - worktrees_enabled: true, - windows_degraded_sandbox_active: false, - side_conversation_active: false, - }, - Vec::new(), - ); - popup.on_composer_text_change("/personality".to_string()); - - match popup.selected_item() { - Some(CommandItem::Builtin(cmd)) => assert_eq!(cmd.command(), "personality"), - Some(CommandItem::ServiceTier(command)) => { - panic!("expected personality command, got service tier {command:?}") - } - other => panic!("expected personality to be selected for exact match, got {other:?}"), - } - } - #[test] fn debug_commands_are_hidden_from_popup() { let popup = CommandPopup::new(CommandPopupFlags::default(), Vec::new()); diff --git a/codex-rs/tui/src/bottom_pane/mod.rs b/codex-rs/tui/src/bottom_pane/mod.rs index 7cabd7d126..fb24219149 100644 --- a/codex-rs/tui/src/bottom_pane/mod.rs +++ b/codex-rs/tui/src/bottom_pane/mod.rs @@ -531,11 +531,6 @@ impl BottomPane { self.request_redraw(); } - pub fn set_personality_command_enabled(&mut self, enabled: bool) { - self.composer.set_personality_command_enabled(enabled); - self.request_redraw(); - } - pub fn set_service_tier_commands_enabled(&mut self, enabled: bool) { self.composer.set_service_tier_commands_enabled(enabled); self.request_redraw(); diff --git a/codex-rs/tui/src/bottom_pane/slash_commands.rs b/codex-rs/tui/src/bottom_pane/slash_commands.rs index 8c478b3e31..184985eb43 100644 --- a/codex-rs/tui/src/bottom_pane/slash_commands.rs +++ b/codex-rs/tui/src/bottom_pane/slash_commands.rs @@ -61,7 +61,6 @@ pub(crate) struct BuiltinCommandFlags { pub(crate) token_activity_command_enabled: bool, pub(crate) service_tier_commands_enabled: bool, pub(crate) goal_command_enabled: bool, - pub(crate) personality_command_enabled: bool, pub(crate) voice_command_enabled: bool, pub(crate) worktrees_enabled: bool, pub(crate) allow_elevate_sandbox: bool, @@ -79,7 +78,6 @@ pub(crate) fn builtins_for_input(flags: BuiltinCommandFlags) -> Vec<(&'static st .filter(|(_, cmd)| flags.token_activity_command_enabled || *cmd != SlashCommand::Usage) .filter(|(_, cmd)| flags.goal_command_enabled || *cmd != SlashCommand::Goal) .filter(|(_, cmd)| flags.worktrees_enabled || *cmd != SlashCommand::Worktree) - .filter(|(_, cmd)| flags.personality_command_enabled || *cmd != SlashCommand::Personality) .filter(|(_, cmd)| flags.voice_command_enabled || *cmd != SlashCommand::Voice) .filter(|(_, cmd)| !flags.side_conversation_active || cmd.available_in_side_conversation()) .collect() @@ -174,7 +172,6 @@ mod tests { token_activity_command_enabled: true, service_tier_commands_enabled: true, goal_command_enabled: true, - personality_command_enabled: true, voice_command_enabled: true, worktrees_enabled: true, allow_elevate_sandbox: true, diff --git a/codex-rs/tui/src/chatwidget.rs b/codex-rs/tui/src/chatwidget.rs index 0ea8de2f64..4e6a7dfbcd 100644 --- a/codex-rs/tui/src/chatwidget.rs +++ b/codex-rs/tui/src/chatwidget.rs @@ -141,7 +141,6 @@ use codex_protocol::approvals::GuardianAssessmentStatus; use codex_protocol::config_types::CollaborationMode; use codex_protocol::config_types::CollaborationModeMask; use codex_protocol::config_types::ModeKind; -use codex_protocol::config_types::Personality; use codex_protocol::config_types::Settings; #[cfg(any(target_os = "windows", test))] use codex_protocol::config_types::WindowsSandboxLevel; diff --git a/codex-rs/tui/src/chatwidget/constructor.rs b/codex-rs/tui/src/chatwidget/constructor.rs index e0be308b80..5eaa8d7715 100644 --- a/codex-rs/tui/src/chatwidget/constructor.rs +++ b/codex-rs/tui/src/chatwidget/constructor.rs @@ -290,7 +290,6 @@ impl ChatWidget { .bottom_pane .set_collaboration_modes_enabled(/*enabled*/ true); widget.sync_service_tier_commands(); - widget.sync_personality_command_enabled(); widget.sync_worktrees_enabled(); widget.sync_plugins_command_enabled(); widget.sync_goal_command_enabled(); diff --git a/codex-rs/tui/src/chatwidget/input_submission.rs b/codex-rs/tui/src/chatwidget/input_submission.rs index fdfe3f6ab6..1421279e3c 100644 --- a/codex-rs/tui/src/chatwidget/input_submission.rs +++ b/codex-rs/tui/src/chatwidget/input_submission.rs @@ -382,11 +382,6 @@ impl ChatWidget { source, compare_key: Self::pending_steer_compare_key_from_items(&items), }); - let personality = self - .config - .personality - .filter(|_| self.config.features.enabled(Feature::Personality)) - .filter(|_| self.current_model_supports_personality()); let service_tier = self.service_tier_update_for_core(); let active_permission_profile = self.config.permissions.active_permission_profile(); let op = AppCommand::user_turn( @@ -401,7 +396,7 @@ impl ChatWidget { service_tier, /*final_output_json_schema*/ None, collaboration_mode, - personality, + /*personality*/ None, ); let submitted_message = UserMessage { text, diff --git a/codex-rs/tui/src/chatwidget/session_flow.rs b/codex-rs/tui/src/chatwidget/session_flow.rs index a24e3695f0..3f3f2aa615 100644 --- a/codex-rs/tui/src/chatwidget/session_flow.rs +++ b/codex-rs/tui/src/chatwidget/session_flow.rs @@ -137,7 +137,6 @@ impl ChatWidget { }); } self.sync_service_tier_commands(); - self.sync_personality_command_enabled(); self.sync_worktrees_enabled(); self.sync_plugins_command_enabled(); self.sync_goal_command_enabled(); diff --git a/codex-rs/tui/src/chatwidget/settings.rs b/codex-rs/tui/src/chatwidget/settings.rs index edda2fdba3..683ad9e52d 100644 --- a/codex-rs/tui/src/chatwidget/settings.rs +++ b/codex-rs/tui/src/chatwidget/settings.rs @@ -83,9 +83,6 @@ impl ChatWidget { if feature == Feature::Worktrees { self.sync_worktrees_enabled(); } - if feature == Feature::Personality { - self.sync_personality_command_enabled(); - } if feature == Feature::Plugins { self.sync_plugins_command_enabled(); self.refresh_plugin_mentions(); @@ -183,11 +180,6 @@ impl ChatWidget { self.refresh_model_dependent_surfaces(); } - /// Set the personality in the widget's config copy. - pub(crate) fn set_personality(&mut self, personality: Personality) { - self.config.personality = Some(personality); - } - pub(crate) fn status_account_display(&self) -> Option<&StatusAccountDisplay> { self.status_account_display.as_ref() } @@ -309,11 +301,6 @@ impl ChatWidget { ); } - pub(super) fn sync_personality_command_enabled(&mut self) { - self.bottom_pane - .set_personality_command_enabled(self.config.features.enabled(Feature::Personality)); - } - pub(super) fn sync_plugins_command_enabled(&mut self) { self.bottom_pane .set_plugins_command_enabled(self.config.features.enabled(Feature::Plugins)); @@ -329,20 +316,6 @@ impl ChatWidget { .set_mentions_v2_enabled(self.config.features.enabled(Feature::MentionsV2)); } - pub(super) fn current_model_supports_personality(&self) -> bool { - let model = self.current_model(); - self.model_catalog - .try_list_models() - .ok() - .and_then(|models| { - models - .into_iter() - .find(|preset| preset.model == model) - .map(|preset| preset.supports_personality) - }) - .unwrap_or(false) - } - /// Return whether the effective model currently advertises image-input support. /// /// We intentionally default to `true` when model metadata cannot be read so transient catalog @@ -527,7 +500,6 @@ impl ChatWidget { self.refresh_effective_service_tier(); self.refresh_status_surfaces(); self.sync_service_tier_commands(); - self.sync_personality_command_enabled(); if cwd_changed { self.invalidate_connector_scope(); self.refresh_skills_for_current_cwd(/*force_reload*/ true); diff --git a/codex-rs/tui/src/chatwidget/settings_popups.rs b/codex-rs/tui/src/chatwidget/settings_popups.rs index 1c8cefdd16..3e6132652d 100644 --- a/codex-rs/tui/src/chatwidget/settings_popups.rs +++ b/codex-rs/tui/src/chatwidget/settings_popups.rs @@ -1,6 +1,6 @@ //! Settings-adjacent popup surfaces for `ChatWidget`. //! -//! This keeps theme, personality, and experimental-feature UI out of the main +//! This keeps theme and experimental-feature UI out of the main //! orchestration module without changing their event wiring. use super::*; @@ -16,76 +16,6 @@ impl ChatWidget { self.bottom_pane.show_selection_view(params); } - pub(crate) fn open_personality_popup(&mut self) { - if !self.is_session_configured() { - self.add_info_message( - "Personality selection is disabled until startup completes.".to_string(), - /*hint*/ None, - ); - return; - } - if !self.current_model_supports_personality() { - let current_model = self.current_model(); - self.add_error_message(format!( - "Current model ({current_model}) doesn't support personalities. Try /model to pick a different model." - )); - return; - } - self.open_personality_popup_for_current_model(); - } - - fn open_personality_popup_for_current_model(&mut self) { - let current_personality = self.config.personality.unwrap_or(Personality::Friendly); - let personalities = [Personality::Friendly, Personality::Pragmatic]; - let supports_personality = self.current_model_supports_personality(); - - let items: Vec = personalities - .into_iter() - .map(|personality| { - let name = Self::personality_label(personality).to_string(); - let description = Some(Self::personality_description(personality).to_string()); - let actions: Vec = vec![Box::new(move |tx| { - tx.send(AppEvent::CodexOp(AppCommand::override_turn_context( - /*cwd*/ None, - /*approval_policy*/ None, - /*approvals_reviewer*/ None, - /*permission_profile*/ None, - /*active_permission_profile*/ None, - /*windows_sandbox_level*/ None, - /*model*/ None, - /*effort*/ None, - /*summary*/ None, - /*service_tier*/ None, - /*collaboration_mode*/ None, - Some(personality), - ))); - tx.send(AppEvent::UpdatePersonality(personality)); - tx.send(AppEvent::PersistPersonalitySelection { personality }); - })]; - SelectionItem { - name, - description, - is_current: current_personality == personality, - is_disabled: !supports_personality, - actions, - dismiss_on_select: true, - ..Default::default() - } - }) - .collect(); - - let mut header = ColumnRenderable::new(); - header.push(Line::from("Select Personality".bold())); - header.push(Line::from("Choose a communication style for Codex.".dim())); - - self.bottom_pane.show_selection_view(SelectionViewParams { - header: Box::new(header), - footer_hint: Some(standard_popup_hint_line()), - items, - ..Default::default() - }); - } - pub(crate) fn open_experimental_popup(&mut self) { let Some(thread_id) = self.thread_id() else { self.add_info_message( @@ -108,20 +38,4 @@ impl ChatWidget { ); self.bottom_pane.show_view(Box::new(view)); } - - fn personality_label(personality: Personality) -> &'static str { - match personality { - Personality::None => "None", - Personality::Friendly => "Friendly", - Personality::Pragmatic => "Pragmatic", - } - } - - fn personality_description(personality: Personality) -> &'static str { - match personality { - Personality::None => "No personality instructions.", - Personality::Friendly => "Warm, collaborative, and helpful.", - Personality::Pragmatic => "Concise, task-focused, and direct.", - } - } } diff --git a/codex-rs/tui/src/chatwidget/slash_dispatch.rs b/codex-rs/tui/src/chatwidget/slash_dispatch.rs index 333f435998..e18a0c50cf 100644 --- a/codex-rs/tui/src/chatwidget/slash_dispatch.rs +++ b/codex-rs/tui/src/chatwidget/slash_dispatch.rs @@ -315,10 +315,6 @@ impl ChatWidget { self.open_model_popup(); self.defer_input_until_settings_applied(); } - SlashCommand::Personality => { - self.open_personality_popup(); - self.defer_input_until_settings_applied(); - } SlashCommand::Plan => { self.apply_plan_slash_command(); } @@ -1147,7 +1143,6 @@ impl ChatWidget { token_activity_command_enabled: self.has_codex_backend_auth, goal_command_enabled: self.config.features.enabled(Feature::Goals), service_tier_commands_enabled: self.fast_mode_enabled(), - personality_command_enabled: self.config.features.enabled(Feature::Personality), voice_command_enabled: self.realtime_conversation_available_for_thread, worktrees_enabled: self.config.features.enabled(Feature::Worktrees) && self.local_worktree_operations, @@ -1214,7 +1209,6 @@ impl ChatWidget { | SlashCommand::Compact | SlashCommand::Review | SlashCommand::Model - | SlashCommand::Personality | SlashCommand::Plan | SlashCommand::Goal | SlashCommand::Side diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__personality_selection_popup.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__personality_selection_popup.snap deleted file mode 100644 index 8613d66814..0000000000 --- a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__personality_selection_popup.snap +++ /dev/null @@ -1,11 +0,0 @@ ---- -source: tui/src/chatwidget/tests/popups_and_settings.rs -expression: popup ---- - Select Personality - Choose a communication style for Codex. - - 1. Friendly Warm, collaborative, and helpful. -› 2. Pragmatic (current) Concise, task-focused, and direct. - - Press enter to confirm or esc to go back diff --git a/codex-rs/tui/src/chatwidget/tests/plan_mode.rs b/codex-rs/tui/src/chatwidget/tests/plan_mode.rs index ffef407828..bb4904c913 100644 --- a/codex-rs/tui/src/chatwidget/tests/plan_mode.rs +++ b/codex-rs/tui/src/chatwidget/tests/plan_mode.rs @@ -1751,54 +1751,6 @@ async fn collab_mode_applies_default_preset() { assert_eq!(chat.current_collaboration_mode().mode, ModeKind::Default); } -#[tokio::test] -async fn user_turn_includes_personality_from_config() { - for configured_personality in [ - Personality::Friendly, - Personality::Pragmatic, - Personality::None, - ] { - let preset = crate::test_support::legacy_personality_model_preset(); - let (mut chat, _rx, mut op_rx) = make_chatwidget_manual(Some(&preset.model)).await; - Arc::make_mut(&mut chat.model_catalog).models = vec![preset]; - chat.set_feature_enabled(Feature::Personality, /*enabled*/ true); - chat.thread_id = Some(ThreadId::new()); - chat.set_personality(configured_personality); - - chat.bottom_pane - .set_composer_text("hello".to_string(), Vec::new(), Vec::new()); - chat.handle_key_event(KeyEvent::from(KeyCode::Enter)); - let Op::UserTurn { personality, .. } = next_submit_op(&mut op_rx) else { - panic!("expected Op::UserTurn"); - }; - assert_eq!(personality, Some(configured_personality)); - } -} - -#[tokio::test] -async fn user_turn_omits_personality_for_fixed_personality_models() { - for model in ["gpt-5.4", "gpt-5.5"] { - for configured_personality in [ - Personality::Friendly, - Personality::Pragmatic, - Personality::None, - ] { - let (mut chat, _rx, mut op_rx) = make_chatwidget_manual(Some(model)).await; - chat.set_feature_enabled(Feature::Personality, /*enabled*/ true); - chat.thread_id = Some(ThreadId::new()); - chat.set_personality(configured_personality); - - chat.bottom_pane - .set_composer_text("hello".to_string(), Vec::new(), Vec::new()); - chat.handle_key_event(KeyEvent::from(KeyCode::Enter)); - let Op::UserTurn { personality, .. } = next_submit_op(&mut op_rx) else { - panic!("expected Op::UserTurn"); - }; - assert_eq!(personality, None, "model: {model}"); - } - } -} - #[tokio::test] async fn plan_update_renders_history_cell() { let (mut chat, mut rx, _op_rx) = make_chatwidget_manual(/*model_override*/ None).await; 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 39a1e2e007..f9a9c44616 100644 --- a/codex-rs/tui/src/chatwidget/tests/popups_and_settings.rs +++ b/codex-rs/tui/src/chatwidget/tests/popups_and_settings.rs @@ -3589,37 +3589,6 @@ async fn model_picker_refresh_dismisses_empty_choices() { } } -#[tokio::test] -async fn personality_selection_popup_snapshot() { - let preset = crate::test_support::legacy_personality_model_preset(); - let (mut chat, _rx, _op_rx) = make_chatwidget_manual(Some(&preset.model)).await; - Arc::make_mut(&mut chat.model_catalog).models = vec![preset]; - chat.thread_id = Some(ThreadId::new()); - chat.set_personality(Personality::Pragmatic); - chat.open_personality_popup(); - - let popup = render_bottom_popup(&chat, /*width*/ 80); - assert_chatwidget_snapshot!("personality_selection_popup", popup); -} - -#[tokio::test] -async fn personality_selection_is_unavailable_for_fixed_personality_models() { - for model in ["gpt-5.4", "gpt-5.5"] { - let (mut chat, mut rx, _op_rx) = make_chatwidget_manual(Some(model)).await; - chat.thread_id = Some(ThreadId::new()); - while rx.try_recv().is_ok() {} - - chat.open_personality_popup(); - - assert!(!chat.bottom_pane.has_active_view()); - let cell = assert_matches!(rx.try_recv(), Ok(AppEvent::InsertHistoryCell(cell)) => cell); - let message = lines_to_single_string(&cell.display_lines(/*width*/ 120)); - assert!(message.contains(&format!( - "Current model ({model}) doesn't support personalities." - ))); - } -} - #[tokio::test] async fn skills_menu_default_mentions_shortcut_snapshot() { let (mut chat, _rx, _op_rx) = make_chatwidget_manual(/*model_override*/ None).await; diff --git a/codex-rs/tui/src/slash_command.rs b/codex-rs/tui/src/slash_command.rs index 0a3e107b88..dd0c1e41a3 100644 --- a/codex-rs/tui/src/slash_command.rs +++ b/codex-rs/tui/src/slash_command.rs @@ -72,7 +72,6 @@ pub enum SlashCommand { #[strum(to_string = "stop", serialize = "clean")] Stop, Clear, - Personality, TestApproval, #[strum(serialize = "subagents")] MultiAgents, @@ -127,7 +126,6 @@ impl SlashCommand { SlashCommand::Ide => { "include current selection, open files, and other context from your IDE" } - SlashCommand::Personality => "choose a communication style for Codex", SlashCommand::Plan => "switch to Plan mode", SlashCommand::Voice => "start or stop voice; use /voice settings to choose a voice", SlashCommand::Goal => "set or view the goal for a long-running task", @@ -230,7 +228,6 @@ impl SlashCommand { SlashCommand::Diff | SlashCommand::Resume | SlashCommand::Model - | SlashCommand::Personality | SlashCommand::Permissions | SlashCommand::Copy | SlashCommand::Raw diff --git a/codex-rs/tui/src/test_support.rs b/codex-rs/tui/src/test_support.rs index f2db0b2cb1..44e9899379 100644 --- a/codex-rs/tui/src/test_support.rs +++ b/codex-rs/tui/src/test_support.rs @@ -4,9 +4,6 @@ use std::sync::LazyLock; use codex_models_manager::bundled_models_response; use codex_protocol::openai_models::ModelPreset; -use codex_protocol::openai_models::ReasoningEffort; -use codex_protocol::openai_models::ReasoningEffortPreset; -use codex_protocol::openai_models::default_input_modalities; pub(crate) use codex_utils_absolute_path::test_support::PathBufExt; pub(crate) use codex_utils_absolute_path::test_support::test_path_buf; use serde::Serialize; @@ -21,34 +18,6 @@ pub(crate) static TEST_MODEL_PRESETS: LazyLock> = LazyLock::new presets }); -/// A legacy catalog entry whose personality remains selectable, independent of bundled models. -pub(crate) fn legacy_personality_model_preset() -> ModelPreset { - ModelPreset { - id: "legacy-personality-model".to_string(), - model: "legacy-personality-model".to_string(), - display_name: "Legacy personality model".to_string(), - description: "Test model with selectable personalities.".to_string(), - model_specialty: None, - default_reasoning_effort: ReasoningEffort::Medium, - supported_reasoning_efforts: vec![ReasoningEffortPreset { - effort: ReasoningEffort::Medium, - description: "medium".to_string(), - }], - supports_personality: true, - additional_speed_tiers: Vec::new(), - service_tiers: Vec::new(), - default_service_tier: None, - available_access_programs: None, - is_default: false, - upgrade: None, - show_in_picker: true, - multi_agent_version: None, - availability_nux: None, - supported_in_api: true, - input_modalities: default_input_modalities(), - } -} - pub(crate) fn test_path_display(path: &str) -> String { test_path_buf(path).display().to_string() }