Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 14 additions & 35 deletions codex-rs/tui/src/chatwidget.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4554,10 +4554,14 @@ impl ChatWidget {

pub(crate) fn handle_request_user_input_now(&mut self, ev: RequestUserInputEvent) {
self.flush_answer_stream_with_separator();
self.notify(Notification::UserInputRequested {
question_count: ev.questions.len(),
summary: Notification::user_input_request_summary(&ev.questions),
});
let question_count = ev.questions.len();
let summary = Notification::user_input_request_summary(&ev.questions);
let title = match (question_count, summary.as_deref()) {
(1, Some(summary)) => summary.to_string(),
(1, None) => "Question requested".to_string(),
(count, _) => format!("{count} questions requested"),
};
self.notify(Notification::PlanModePrompt { title });
self.bottom_pane.push_user_input_request(ev);
self.request_redraw();
}
Expand Down Expand Up @@ -11143,26 +11147,11 @@ impl Renderable for ChatWidget {

#[derive(Debug)]
enum Notification {
AgentTurnComplete {
response: String,
},
ExecApprovalRequested {
command: String,
},
EditApprovalRequested {
cwd: PathBuf,
changes: Vec<PathBuf>,
},
ElicitationRequested {
server_name: String,
},
PlanModePrompt {
title: String,
},
UserInputRequested {
question_count: usize,
summary: Option<String>,
},
AgentTurnComplete { response: String },
ExecApprovalRequested { command: String },
EditApprovalRequested { cwd: PathBuf, changes: Vec<PathBuf> },
ElicitationRequested { server_name: String },
PlanModePrompt { title: String },
}

impl Notification {
Expand Down Expand Up @@ -11195,14 +11184,6 @@ impl Notification {
Notification::PlanModePrompt { title } => {
format!("Plan mode prompt: {title}")
}
Notification::UserInputRequested {
question_count,
summary,
} => match (*question_count, summary.as_deref()) {
(1, Some(summary)) => format!("Question requested: {summary}"),
(1, None) => "Question requested".to_string(),
(count, _) => format!("Questions requested: {count}"),
},
}
}

Expand All @@ -11213,7 +11194,6 @@ impl Notification {
| Notification::EditApprovalRequested { .. }
| Notification::ElicitationRequested { .. } => "approval-requested",
Notification::PlanModePrompt { .. } => "plan-mode-prompt",
Notification::UserInputRequested { .. } => "user-input-requested",
}
}

Expand All @@ -11223,8 +11203,7 @@ impl Notification {
Notification::ExecApprovalRequested { .. }
| Notification::EditApprovalRequested { .. }
| Notification::ElicitationRequested { .. }
| Notification::PlanModePrompt { .. }
| Notification::UserInputRequested { .. } => 1,
| Notification::PlanModePrompt { .. } => 1,
}
}

Expand Down
33 changes: 4 additions & 29 deletions codex-rs/tui/src/chatwidget/tests/plan_mode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -265,25 +265,6 @@ fn plan_mode_prompt_notification_uses_dedicated_type_name() {
);
}

#[test]
fn user_input_requested_notification_uses_dedicated_type_name() {
let notification = Notification::UserInputRequested {
question_count: 1,
summary: Some("Reasoning scope".to_string()),
};

assert!(notification.allowed_for(&Notifications::Custom(vec![
"user-input-requested".to_string(),
])));
assert!(!notification.allowed_for(&Notifications::Custom(vec![
"approval-requested".to_string(),
])));
assert_eq!(
notification.display(),
"Question requested: Reasoning scope"
);
}

#[tokio::test]
async fn open_plan_implementation_prompt_sets_pending_notification() {
let (mut chat, _rx, _op_rx) = make_chatwidget_manual(Some("gpt-5.1-codex-max")).await;
Expand Down Expand Up @@ -331,7 +312,7 @@ async fn agent_turn_complete_does_not_override_pending_plan_mode_prompt_notifica
}

#[tokio::test]
async fn user_input_notification_overrides_pending_agent_turn_complete_notification() {
async fn request_user_input_notification_overrides_pending_agent_turn_complete_notification() {
let (mut chat, _rx, _op_rx) = make_chatwidget_manual(Some("gpt-5.1-codex-max")).await;

chat.notify(Notification::AgentTurnComplete {
Expand All @@ -355,18 +336,15 @@ async fn user_input_notification_overrides_pending_agent_turn_complete_notificat

assert_matches!(
chat.pending_notification,
Some(Notification::UserInputRequested {
question_count: 1,
summary: Some(ref summary),
}) if summary == "Reasoning scope"
Some(Notification::PlanModePrompt { ref title }) if title == "Reasoning scope"
);
}

#[tokio::test]
async fn handle_request_user_input_sets_pending_notification() {
let (mut chat, _rx, _op_rx) = make_chatwidget_manual(Some("gpt-5.1-codex-max")).await;
chat.config.tui_notifications.notifications =
Notifications::Custom(vec!["user-input-requested".to_string()]);
Notifications::Custom(vec!["plan-mode-prompt".to_string()]);

chat.handle_request_user_input_now(RequestUserInputEvent {
call_id: "call-1".to_string(),
Expand All @@ -386,10 +364,7 @@ async fn handle_request_user_input_sets_pending_notification() {

assert_matches!(
chat.pending_notification,
Some(Notification::UserInputRequested {
question_count: 1,
summary: Some(ref summary),
}) if summary == "Reasoning scope"
Some(Notification::PlanModePrompt { ref title }) if title == "Reasoning scope"
);
}

Expand Down
Loading