chore(config) personality as a feature (#10116)

## Summary
Sets up an explicit Feature flag for `/personality`, so users can now
opt in to it via `/experimental`. #10114 also updates the config

## Testing
- [x] Tested locally
This commit is contained in:
Dylan Hurd
2026-01-28 17:58:28 -07:00
committed by GitHub
parent 26590d7927
commit ce3d764ae1
7 changed files with 51 additions and 18 deletions

View File

@@ -180,6 +180,9 @@
"include_apply_patch_tool": {
"type": "boolean"
},
"personality": {
"type": "boolean"
},
"powershell_utf8": {
"type": "boolean"
},
@@ -1198,6 +1201,9 @@
"include_apply_patch_tool": {
"type": "boolean"
},
"personality": {
"type": "boolean"
},
"powershell_utf8": {
"type": "boolean"
},

View File

@@ -119,6 +119,8 @@ pub enum Feature {
Steer,
/// Enable collaboration modes (Plan, Code, Pair Programming, Execute).
CollaborationModes,
/// Enable personality selection in the TUI.
Personality,
/// Use the Responses API WebSocket transport for OpenAI by default.
ResponsesWebsockets,
}
@@ -543,6 +545,16 @@ pub const FEATURES: &[FeatureSpec] = &[
stage: Stage::UnderDevelopment,
default_enabled: false,
},
FeatureSpec {
id: Feature::Personality,
key: "personality",
stage: Stage::Experimental {
name: "Personality",
menu_description: "Choose a communication style for Codex.",
announcement: "NEW! Update codex's communication style with /personality. Enable in /experimental!",
},
default_enabled: false,
},
FeatureSpec {
id: Feature::ResponsesWebsockets,
key: "responses_websockets",

View File

@@ -213,6 +213,16 @@ pub(crate) fn find_model_info_for_slug(slug: &str) -> ModelInfo {
truncation_policy: TruncationPolicyConfig::tokens(10_000),
context_window: Some(CONTEXT_WINDOW_272K),
supported_reasoning_levels: supported_reasoning_level_low_medium_high_xhigh(),
model_instructions_template: Some(ModelInstructionsTemplate {
template: GPT_5_2_CODEX_INSTRUCTIONS_TEMPLATE.to_string(),
personality_messages: Some(PersonalityMessages(BTreeMap::from([(
Personality::Friendly,
PERSONALITY_FRIENDLY.to_string(),
), (
Personality::Pragmatic,
PERSONALITY_PRAGMATIC.to_string(),
)]))),
}),
)
} else if slug.starts_with("gpt-5.1-codex-max") {
model_info!(

View File

@@ -2892,6 +2892,7 @@ impl ChatWidget {
let personality = self
.config
.model_personality
.filter(|_| self.config.features.enabled(Feature::Personality))
.filter(|_| self.current_model_supports_personality());
let op = Op::UserTurn {
items,
@@ -3455,19 +3456,23 @@ impl ChatWidget {
);
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_model = self.current_model();
let current_personality = self.config.model_personality;
let current_personality = self
.config
.model_personality
.unwrap_or(Personality::Friendly);
let personalities = [Personality::Friendly, Personality::Pragmatic];
let supports_personality = self.current_model_supports_personality();
let disabled_message = (!supports_personality).then(|| {
format!(
"Current model ({current_model}) doesn't support personalities. Try /model to switch to a newer model."
)
});
let items: Vec<SelectionItem> = personalities
.into_iter()
@@ -3492,7 +3497,7 @@ impl ChatWidget {
SelectionItem {
name,
description,
is_current: current_personality == Some(personality),
is_current: current_personality == personality,
is_disabled: !supports_personality,
actions,
dismiss_on_select: true,
@@ -3504,11 +3509,8 @@ impl ChatWidget {
let mut header = ColumnRenderable::new();
header.push(Line::from("Select Personality".bold()));
header.push(Line::from(
"Choose a communication style for future responses.".dim(),
"Choose a communication style for Codex. Disable in /experimental.".dim(),
));
if let Some(message) = disabled_message {
header.push(Line::from(message.red()));
}
self.bottom_pane.show_selection_view(SelectionViewParams {
header: Box::new(header),
@@ -4714,6 +4716,9 @@ impl ChatWidget {
self.refresh_model_display();
self.request_redraw();
}
if feature == Feature::Personality {
self.sync_personality_command_enabled();
}
#[cfg(target_os = "windows")]
if matches!(
feature,
@@ -4780,7 +4785,6 @@ impl ChatWidget {
mask.model = Some(model.to_string());
}
self.refresh_model_display();
self.sync_personality_command_enabled();
}
pub(crate) fn current_model(&self) -> &str {
@@ -4795,7 +4799,7 @@ impl ChatWidget {
fn sync_personality_command_enabled(&mut self) {
self.bottom_pane
.set_personality_command_enabled(self.current_model_supports_personality());
.set_personality_command_enabled(self.config.features.enabled(Feature::Personality));
}
fn current_model_supports_personality(&self) -> bool {

View File

@@ -3,9 +3,9 @@ source: tui/src/chatwidget/tests.rs
expression: popup
---
Select Personality
Choose a communication style for future responses.
Choose a communication style for Codex. Disable in /experimental.
1. Friendly Warm, collaborative, and helpful.
2. Pragmatic Concise, task-focused, and direct.
1. Friendly (current) Warm, collaborative, and helpful.
2. Pragmatic Concise, task-focused, and direct.
Press enter to confirm or esc to go back

View File

@@ -2408,6 +2408,7 @@ async fn collab_mode_enabling_keeps_custom_until_selected() {
#[tokio::test]
async fn user_turn_includes_personality_from_config() {
let (mut chat, _rx, mut op_rx) = make_chatwidget_manual(Some("bengalfox")).await;
chat.set_feature_enabled(Feature::Personality, true);
chat.thread_id = Some(ThreadId::new());
chat.set_model("bengalfox");
chat.set_personality(Personality::Friendly);

View File

@@ -61,7 +61,7 @@ impl SlashCommand {
SlashCommand::Status => "show current session configuration and token usage",
SlashCommand::Ps => "list background terminals",
SlashCommand::Model => "choose what model and reasoning effort to use",
SlashCommand::Personality => "choose a communication style for responses",
SlashCommand::Personality => "choose a communication style for Codex",
SlashCommand::Collab => "change collaboration mode (experimental)",
SlashCommand::Agent => "switch the active agent thread",
SlashCommand::Approvals => "choose what Codex can do without approval",