mirror of
https://github.com/openai/codex.git
synced 2026-10-30 19:18:49 +00:00
tui: reject repeated model modifiers
Track whether /model effort and scope modifiers were provided so repeated sentinel values like default and global are rejected consistently. Validation: cargo test -p codex-tui; just fix -p codex-tui; just fmt Co-authored-by: Codex <noreply@openai.com>
This commit is contained in:
co-authored by
Codex
parent
8c45c1acfc
commit
bcb3555e70
@@ -881,6 +881,7 @@ impl App {
|
||||
resume_config.clone(),
|
||||
target_session.path.clone(),
|
||||
self.auth_manager.clone(),
|
||||
None,
|
||||
)
|
||||
.await
|
||||
{
|
||||
|
||||
@@ -5671,41 +5671,34 @@ impl ChatWidget {
|
||||
fn parse_model_selection_args(
|
||||
args: &str,
|
||||
) -> Result<(String, Option<ReasoningEffortConfig>, ModelSelectionScope), String> {
|
||||
const MODEL_USAGE: &str = "Usage: /model <model> [default|none|minimal|low|medium|high|xhigh] [plan-only|all-modes]";
|
||||
let mut tokens = args.split_whitespace();
|
||||
let Some(model) = tokens.next() else {
|
||||
return Err(
|
||||
"Usage: /model <model> [default|none|minimal|low|medium|high|xhigh] [plan-only|all-modes]"
|
||||
.to_string(),
|
||||
);
|
||||
return Err(MODEL_USAGE.to_string());
|
||||
};
|
||||
|
||||
let mut effort = None;
|
||||
let mut saw_effort = false;
|
||||
let mut scope = ModelSelectionScope::Global;
|
||||
let mut saw_scope = false;
|
||||
for token in tokens {
|
||||
if let Some(parsed_effort) = Self::parse_model_reasoning_effort_token(token) {
|
||||
if effort.is_some() {
|
||||
return Err(
|
||||
"Usage: /model <model> [default|none|minimal|low|medium|high|xhigh] [plan-only|all-modes]"
|
||||
.to_string(),
|
||||
);
|
||||
if saw_effort {
|
||||
return Err(MODEL_USAGE.to_string());
|
||||
}
|
||||
saw_effort = true;
|
||||
effort = parsed_effort;
|
||||
continue;
|
||||
}
|
||||
if let Some(parsed_scope) = Self::parse_model_scope_token(token) {
|
||||
if scope != ModelSelectionScope::Global {
|
||||
return Err(
|
||||
"Usage: /model <model> [default|none|minimal|low|medium|high|xhigh] [plan-only|all-modes]"
|
||||
.to_string(),
|
||||
);
|
||||
if saw_scope {
|
||||
return Err(MODEL_USAGE.to_string());
|
||||
}
|
||||
saw_scope = true;
|
||||
scope = parsed_scope;
|
||||
continue;
|
||||
}
|
||||
return Err(
|
||||
"Usage: /model <model> [default|none|minimal|low|medium|high|xhigh] [plan-only|all-modes]"
|
||||
.to_string(),
|
||||
);
|
||||
return Err(MODEL_USAGE.to_string());
|
||||
}
|
||||
|
||||
Ok((model.to_string(), effort, scope))
|
||||
|
||||
@@ -8089,6 +8089,32 @@ async fn single_reasoning_option_skips_selection() {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn model_parser_rejects_repeated_effort_when_first_token_is_default() {
|
||||
let parsed = ChatWidget::parse_model_selection_args("gpt-5 default high");
|
||||
|
||||
assert_eq!(
|
||||
parsed,
|
||||
Err(
|
||||
"Usage: /model <model> [default|none|minimal|low|medium|high|xhigh] [plan-only|all-modes]"
|
||||
.to_string(),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn model_parser_rejects_repeated_scope_when_first_token_is_global() {
|
||||
let parsed = ChatWidget::parse_model_selection_args("gpt-5 global plan-only");
|
||||
|
||||
assert_eq!(
|
||||
parsed,
|
||||
Err(
|
||||
"Usage: /model <model> [default|none|minimal|low|medium|high|xhigh] [plan-only|all-modes]"
|
||||
.to_string(),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn feedback_selection_popup_snapshot() {
|
||||
let (mut chat, _rx, _op_rx) = make_chatwidget_manual(None).await;
|
||||
|
||||
Reference in New Issue
Block a user