Add tui.experimental_mode setting (#9656)

To simplify testing
This commit is contained in:
pakrym-oai 2026-01-21 21:27:57 -08:00 committed by GitHub
parent e520592bcf
commit 836f0343a3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 101 additions and 34 deletions

View file

@ -343,6 +343,16 @@
}
]
},
"ModeKind": {
"description": "Initial collaboration mode to use when the TUI starts.",
"enum": [
"plan",
"pair_programming",
"execute",
"custom"
],
"type": "string"
},
"ModelProviderInfo": {
"additionalProperties": false,
"description": "Serializable representation of a provider definition.",
@ -953,6 +963,15 @@
"description": "Enable animations (welcome screen, shimmer effects, spinners). Defaults to `true`.",
"type": "boolean"
},
"experimental_mode": {
"allOf": [
{
"$ref": "#/definitions/ModeKind"
}
],
"default": null,
"description": "Start the TUI in the specified collaboration mode (plan/execute/etc.). Defaults to unset."
},
"notifications": {
"allOf": [
{

View file

@ -42,6 +42,7 @@ use codex_app_server_protocol::Tools;
use codex_app_server_protocol::UserSavedConfig;
use codex_protocol::config_types::AltScreenMode;
use codex_protocol::config_types::ForcedLoginMethod;
use codex_protocol::config_types::ModeKind;
use codex_protocol::config_types::Personality;
use codex_protocol::config_types::ReasoningSummary;
use codex_protocol::config_types::SandboxMode;
@ -199,6 +200,9 @@ pub struct Config {
/// Show startup tooltips in the TUI welcome screen.
pub show_tooltips: bool,
/// Start the TUI in the specified collaboration mode (plan/execute/etc.).
pub experimental_mode: Option<ModeKind>,
/// Controls whether the TUI uses the terminal's alternate screen buffer.
///
/// This is the same `tui.alternate_screen` value from `config.toml` (see [`Tui`]).
@ -1560,6 +1564,7 @@ impl Config {
.unwrap_or_default(),
animations: cfg.tui.as_ref().map(|t| t.animations).unwrap_or(true),
show_tooltips: cfg.tui.as_ref().map(|t| t.show_tooltips).unwrap_or(true),
experimental_mode: cfg.tui.as_ref().and_then(|t| t.experimental_mode),
tui_alternate_screen: cfg
.tui
.as_ref()
@ -1812,6 +1817,7 @@ persistence = "none"
notifications: Notifications::Enabled(true),
animations: true,
show_tooltips: true,
experimental_mode: None,
alternate_screen: AltScreenMode::Auto,
}
);
@ -3697,6 +3703,7 @@ model_verbosity = "high"
tui_notifications: Default::default(),
animations: true,
show_tooltips: true,
experimental_mode: None,
analytics_enabled: Some(true),
feedback_enabled: true,
tui_alternate_screen: AltScreenMode::Auto,
@ -3777,6 +3784,7 @@ model_verbosity = "high"
tui_notifications: Default::default(),
animations: true,
show_tooltips: true,
experimental_mode: None,
analytics_enabled: Some(true),
feedback_enabled: true,
tui_alternate_screen: AltScreenMode::Auto,
@ -3872,6 +3880,7 @@ model_verbosity = "high"
tui_notifications: Default::default(),
animations: true,
show_tooltips: true,
experimental_mode: None,
analytics_enabled: Some(false),
feedback_enabled: true,
tui_alternate_screen: AltScreenMode::Auto,
@ -3953,6 +3962,7 @@ model_verbosity = "high"
tui_notifications: Default::default(),
animations: true,
show_tooltips: true,
experimental_mode: None,
analytics_enabled: Some(true),
feedback_enabled: true,
tui_alternate_screen: AltScreenMode::Auto,

View file

@ -5,6 +5,7 @@
use crate::config_loader::RequirementSource;
pub use codex_protocol::config_types::AltScreenMode;
pub use codex_protocol::config_types::ModeKind;
pub use codex_protocol::config_types::Personality;
pub use codex_protocol::config_types::WebSearchMode;
use codex_utils_absolute_path::AbsolutePathBuf;
@ -438,6 +439,11 @@ pub struct Tui {
#[serde(default = "default_true")]
pub show_tooltips: bool,
/// Start the TUI in the specified collaboration mode (plan/execute/etc.).
/// Defaults to unset.
#[serde(default)]
pub experimental_mode: Option<ModeKind>,
/// Controls whether the TUI uses the terminal's alternate screen buffer.
///
/// - `auto` (default): Disable alternate screen in Zellij, enable elsewhere.

View file

@ -151,6 +151,16 @@ pub enum AltScreenMode {
Never,
}
/// Initial collaboration mode to use when the TUI starts.
#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq, Hash, JsonSchema, TS)]
#[serde(rename_all = "snake_case")]
pub enum ModeKind {
Plan,
PairProgramming,
Execute,
Custom,
}
/// Collaboration mode for a Codex session.
#[derive(Clone, PartialEq, Eq, Hash, Debug, Serialize, Deserialize, JsonSchema, TS)]
#[serde(tag = "mode", rename_all = "lowercase")]

View file

@ -93,6 +93,7 @@ use codex_protocol::ThreadId;
use codex_protocol::account::PlanType;
use codex_protocol::approvals::ElicitationRequestEvent;
use codex_protocol::config_types::CollaborationMode;
use codex_protocol::config_types::ModeKind;
use codex_protocol::config_types::Settings;
use codex_protocol::models::local_image_label_text;
use codex_protocol::parse_command::ParsedCommand;
@ -1844,20 +1845,19 @@ impl ChatWidget {
let codex_op_tx = spawn_agent(config.clone(), app_event_tx.clone(), thread_manager);
let model_for_header = model.unwrap_or_else(|| DEFAULT_MODEL_DISPLAY_NAME.to_string());
let fallback_custom = Settings {
model: model_for_header.clone(),
reasoning_effort: None,
developer_instructions: None,
};
let stored_collaboration_mode = if config.features.enabled(Feature::CollaborationModes) {
collaboration_modes::default_mode(models_manager.as_ref()).unwrap_or_else(|| {
CollaborationMode::Custom(Settings {
model: model_for_header.clone(),
reasoning_effort: None,
developer_instructions: None,
})
})
initial_collaboration_mode(
models_manager.as_ref(),
fallback_custom,
config.experimental_mode,
)
} else {
CollaborationMode::Custom(Settings {
model: model_for_header.clone(),
reasoning_effort: None,
developer_instructions: None,
})
CollaborationMode::Custom(fallback_custom)
};
let active_cell = Some(Self::placeholder_session_header_cell(
@ -1969,20 +1969,19 @@ impl ChatWidget {
let codex_op_tx =
spawn_agent_from_existing(conversation, session_configured, app_event_tx.clone());
let fallback_custom = Settings {
model: header_model.clone(),
reasoning_effort: None,
developer_instructions: None,
};
let stored_collaboration_mode = if config.features.enabled(Feature::CollaborationModes) {
collaboration_modes::default_mode(models_manager.as_ref()).unwrap_or_else(|| {
CollaborationMode::Custom(Settings {
model: header_model.clone(),
reasoning_effort: None,
developer_instructions: None,
})
})
initial_collaboration_mode(
models_manager.as_ref(),
fallback_custom,
config.experimental_mode,
)
} else {
CollaborationMode::Custom(Settings {
model: header_model.clone(),
reasoning_effort: None,
developer_instructions: None,
})
CollaborationMode::Custom(fallback_custom)
};
let mut widget = Self {
@ -4296,9 +4295,13 @@ impl ChatWidget {
| CollaborationMode::Execute(settings)
| CollaborationMode::Custom(settings) => settings.clone(),
};
let fallback_custom = settings.clone();
self.stored_collaboration_mode = if enabled {
collaboration_modes::default_mode(self.models_manager.as_ref())
.unwrap_or(CollaborationMode::Custom(settings))
initial_collaboration_mode(
self.models_manager.as_ref(),
fallback_custom,
self.config.experimental_mode,
)
} else {
CollaborationMode::Custom(settings)
};
@ -5031,6 +5034,24 @@ fn extract_first_bold(s: &str) -> Option<String> {
None
}
fn initial_collaboration_mode(
models_manager: &ModelsManager,
fallback_custom: Settings,
desired_mode: Option<ModeKind>,
) -> CollaborationMode {
if let Some(kind) = desired_mode {
if kind == ModeKind::Custom {
return CollaborationMode::Custom(fallback_custom);
}
if let Some(mode) = collaboration_modes::mode_for_kind(models_manager, kind) {
return mode;
}
}
collaboration_modes::default_mode(models_manager)
.unwrap_or(CollaborationMode::Custom(fallback_custom))
}
async fn fetch_rate_limits(base_url: String, auth: CodexAuth) -> Option<RateLimitSnapshot> {
match BackendClient::from_auth(base_url, &auth) {
Ok(client) => match client.get_rate_limits().await {

View file

@ -1,13 +1,6 @@
use codex_core::models_manager::manager::ModelsManager;
use codex_protocol::config_types::CollaborationMode;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
enum ModeKind {
Plan,
PairProgramming,
Execute,
Custom,
}
use codex_protocol::config_types::ModeKind;
fn mode_kind(mode: &CollaborationMode) -> ModeKind {
match mode {
@ -27,6 +20,14 @@ pub(crate) fn default_mode(models_manager: &ModelsManager) -> Option<Collaborati
.or_else(|| presets.into_iter().next())
}
pub(crate) fn mode_for_kind(
models_manager: &ModelsManager,
kind: ModeKind,
) -> Option<CollaborationMode> {
let presets = models_manager.list_collaboration_modes();
presets.into_iter().find(|preset| mode_kind(preset) == kind)
}
pub(crate) fn same_variant(a: &CollaborationMode, b: &CollaborationMode) -> bool {
mode_kind(a) == mode_kind(b)
}