mirror of
https://github.com/openai/codex.git
synced 2026-11-02 19:43:24 +00:00
## Why Removes the realtime audio support from TUI. ## What Changed - Removed the TUI `/realtime` and realtime `/settings` command paths. - Deleted TUI voice capture/playback, WebRTC session handling, audio-device selection UI, and recording-meter code. - Removed TUI realtime tests and snapshots that covered the deleted surfaces. - Dropped the TUI-only `cpal` and `codex-realtime-webrtc` dependencies and refreshed the Rust/Bazel locks.
132 lines
5.1 KiB
Rust
132 lines
5.1 KiB
Rust
//! Settings-adjacent popup surfaces for `ChatWidget`.
|
|
//!
|
|
//! This keeps theme, personality, and experimental-feature UI out of the main
|
|
//! orchestration module without changing their event wiring.
|
|
|
|
use super::*;
|
|
|
|
impl ChatWidget {
|
|
pub(super) fn open_theme_picker(&mut self) {
|
|
let codex_home = codex_utils_home_dir::find_codex_home().ok();
|
|
let terminal_width = self
|
|
.last_rendered_width
|
|
.get()
|
|
.and_then(|width| u16::try_from(width).ok());
|
|
let params = crate::theme_picker::build_theme_picker_params(
|
|
self.config.tui_theme.as_deref(),
|
|
codex_home.as_deref(),
|
|
terminal_width,
|
|
);
|
|
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<SelectionItem> = 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<SelectionAction> = 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 features: Vec<ExperimentalFeatureItem> = FEATURES
|
|
.iter()
|
|
.filter_map(|spec| {
|
|
let name = spec.stage.experimental_menu_name()?;
|
|
let description = spec.stage.experimental_menu_description()?;
|
|
Some(ExperimentalFeatureItem {
|
|
feature: spec.id,
|
|
name: name.to_string(),
|
|
description: description.to_string(),
|
|
enabled: self.config.features.enabled(spec.id),
|
|
})
|
|
})
|
|
.collect();
|
|
|
|
let view = ExperimentalFeaturesView::new(
|
|
features,
|
|
self.app_event_tx.clone(),
|
|
self.bottom_pane.list_keymap(),
|
|
);
|
|
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.",
|
|
}
|
|
}
|
|
}
|