mirror of
https://github.com/openai/codex.git
synced 2026-10-30 19:18:49 +00:00
tui: reset plan popup state after steer
This commit is contained in:
@@ -624,7 +624,6 @@ pub(crate) struct ChatWidget {
|
|||||||
// corresponding user message item.
|
// corresponding user message item.
|
||||||
pending_steers: VecDeque<RenderedUserMessageEvent>,
|
pending_steers: VecDeque<RenderedUserMessageEvent>,
|
||||||
// Whether a steer was submitted during the current turn.
|
// Whether a steer was submitted during the current turn.
|
||||||
steer_submitted_this_turn: bool,
|
|
||||||
/// Terminal-appropriate keybinding for popping the most-recently queued
|
/// Terminal-appropriate keybinding for popping the most-recently queued
|
||||||
/// message back into the composer. Determined once at construction time via
|
/// message back into the composer. Determined once at construction time via
|
||||||
/// [`queued_message_edit_binding_for_terminal`] and propagated to
|
/// [`queued_message_edit_binding_for_terminal`] and propagated to
|
||||||
@@ -1443,7 +1442,6 @@ impl ChatWidget {
|
|||||||
self.turn_sleep_inhibitor.set_turn_running(true);
|
self.turn_sleep_inhibitor.set_turn_running(true);
|
||||||
self.saw_plan_update_this_turn = false;
|
self.saw_plan_update_this_turn = false;
|
||||||
self.saw_plan_item_this_turn = false;
|
self.saw_plan_item_this_turn = false;
|
||||||
self.steer_submitted_this_turn = false;
|
|
||||||
self.plan_delta_buffer.clear();
|
self.plan_delta_buffer.clear();
|
||||||
self.plan_item_active = false;
|
self.plan_item_active = false;
|
||||||
self.adaptive_chunking.reset();
|
self.adaptive_chunking.reset();
|
||||||
@@ -1530,11 +1528,7 @@ impl ChatWidget {
|
|||||||
}
|
}
|
||||||
self.refresh_pending_input_preview();
|
self.refresh_pending_input_preview();
|
||||||
|
|
||||||
if !from_replay
|
if !from_replay && self.queued_user_messages.is_empty() && !had_pending_steers {
|
||||||
&& self.queued_user_messages.is_empty()
|
|
||||||
&& !self.steer_submitted_this_turn
|
|
||||||
&& !had_pending_steers
|
|
||||||
{
|
|
||||||
self.maybe_prompt_plan_implementation();
|
self.maybe_prompt_plan_implementation();
|
||||||
}
|
}
|
||||||
// Keep this flag for replayed completion events so a subsequent live TurnComplete can
|
// Keep this flag for replayed completion events so a subsequent live TurnComplete can
|
||||||
@@ -3005,7 +2999,6 @@ impl ChatWidget {
|
|||||||
forked_from: None,
|
forked_from: None,
|
||||||
queued_user_messages: VecDeque::new(),
|
queued_user_messages: VecDeque::new(),
|
||||||
pending_steers: VecDeque::new(),
|
pending_steers: VecDeque::new(),
|
||||||
steer_submitted_this_turn: false,
|
|
||||||
queued_message_edit_binding,
|
queued_message_edit_binding,
|
||||||
show_welcome_banner: is_first_run,
|
show_welcome_banner: is_first_run,
|
||||||
startup_tooltip_override,
|
startup_tooltip_override,
|
||||||
@@ -3190,7 +3183,6 @@ impl ChatWidget {
|
|||||||
plan_item_active: false,
|
plan_item_active: false,
|
||||||
queued_user_messages: VecDeque::new(),
|
queued_user_messages: VecDeque::new(),
|
||||||
pending_steers: VecDeque::new(),
|
pending_steers: VecDeque::new(),
|
||||||
steer_submitted_this_turn: false,
|
|
||||||
queued_message_edit_binding,
|
queued_message_edit_binding,
|
||||||
show_welcome_banner: is_first_run,
|
show_welcome_banner: is_first_run,
|
||||||
startup_tooltip_override,
|
startup_tooltip_override,
|
||||||
@@ -3356,7 +3348,6 @@ impl ChatWidget {
|
|||||||
forked_from: None,
|
forked_from: None,
|
||||||
queued_user_messages: VecDeque::new(),
|
queued_user_messages: VecDeque::new(),
|
||||||
pending_steers: VecDeque::new(),
|
pending_steers: VecDeque::new(),
|
||||||
steer_submitted_this_turn: false,
|
|
||||||
queued_message_edit_binding,
|
queued_message_edit_binding,
|
||||||
show_welcome_banner: false,
|
show_welcome_banner: false,
|
||||||
startup_tooltip_override: None,
|
startup_tooltip_override: None,
|
||||||
@@ -4363,7 +4354,7 @@ impl ChatWidget {
|
|||||||
|
|
||||||
if let Some(pending_steer) = pending_steer {
|
if let Some(pending_steer) = pending_steer {
|
||||||
self.pending_steers.push_back(pending_steer);
|
self.pending_steers.push_back(pending_steer);
|
||||||
self.steer_submitted_this_turn = true;
|
self.saw_plan_item_this_turn = false;
|
||||||
self.refresh_pending_input_preview();
|
self.refresh_pending_input_preview();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1710,7 +1710,6 @@ async fn make_chatwidget_manual(
|
|||||||
startup_tooltip_override: None,
|
startup_tooltip_override: None,
|
||||||
queued_user_messages: VecDeque::new(),
|
queued_user_messages: VecDeque::new(),
|
||||||
pending_steers: VecDeque::new(),
|
pending_steers: VecDeque::new(),
|
||||||
steer_submitted_this_turn: false,
|
|
||||||
queued_message_edit_binding: crate::key_hint::alt(KeyCode::Up),
|
queued_message_edit_binding: crate::key_hint::alt(KeyCode::Up),
|
||||||
suppress_session_configured_redraw: false,
|
suppress_session_configured_redraw: false,
|
||||||
pending_notification: None,
|
pending_notification: None,
|
||||||
@@ -2744,6 +2743,94 @@ async fn plan_implementation_popup_shows_after_proposed_plan_output() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn plan_implementation_popup_skips_when_steer_follows_proposed_plan() {
|
||||||
|
let (mut chat, _rx, mut op_rx) = make_chatwidget_manual(Some("gpt-5")).await;
|
||||||
|
chat.set_feature_enabled(Feature::CollaborationModes, true);
|
||||||
|
let plan_mask =
|
||||||
|
collaboration_modes::mask_for_kind(chat.models_manager.as_ref(), ModeKind::Plan)
|
||||||
|
.expect("expected plan collaboration mask");
|
||||||
|
chat.set_collaboration_mask(plan_mask);
|
||||||
|
chat.thread_id = Some(ThreadId::new());
|
||||||
|
|
||||||
|
chat.on_task_started();
|
||||||
|
chat.on_plan_item_completed(
|
||||||
|
"- Step 1
|
||||||
|
- Step 2
|
||||||
|
"
|
||||||
|
.to_string(),
|
||||||
|
);
|
||||||
|
chat.bottom_pane
|
||||||
|
.set_composer_text("Please continue.".to_string(), Vec::new(), Vec::new());
|
||||||
|
chat.handle_key_event(KeyEvent::new(KeyCode::Enter, KeyModifiers::NONE));
|
||||||
|
|
||||||
|
match next_submit_op(&mut op_rx) {
|
||||||
|
Op::UserTurn { items, .. } => assert_eq!(
|
||||||
|
items,
|
||||||
|
vec![UserInput::Text {
|
||||||
|
text: "Please continue.".to_string(),
|
||||||
|
text_elements: Vec::new(),
|
||||||
|
}]
|
||||||
|
),
|
||||||
|
other => panic!("expected Op::UserTurn, got {other:?}"),
|
||||||
|
}
|
||||||
|
|
||||||
|
complete_user_message(&mut chat, "user-1", "Please continue.");
|
||||||
|
chat.on_task_complete(None, false);
|
||||||
|
|
||||||
|
let popup = render_bottom_popup(&chat, 80);
|
||||||
|
assert!(
|
||||||
|
!popup.contains(PLAN_IMPLEMENTATION_TITLE),
|
||||||
|
"expected no plan popup after a steer follows the plan, got {popup:?}"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn plan_implementation_popup_shows_after_new_plan_follows_steer() {
|
||||||
|
let (mut chat, _rx, mut op_rx) = make_chatwidget_manual(Some("gpt-5")).await;
|
||||||
|
chat.set_feature_enabled(Feature::CollaborationModes, true);
|
||||||
|
let plan_mask =
|
||||||
|
collaboration_modes::mask_for_kind(chat.models_manager.as_ref(), ModeKind::Plan)
|
||||||
|
.expect("expected plan collaboration mask");
|
||||||
|
chat.set_collaboration_mask(plan_mask);
|
||||||
|
chat.thread_id = Some(ThreadId::new());
|
||||||
|
|
||||||
|
chat.on_task_started();
|
||||||
|
chat.on_plan_item_completed(
|
||||||
|
"- Initial plan
|
||||||
|
"
|
||||||
|
.to_string(),
|
||||||
|
);
|
||||||
|
chat.bottom_pane
|
||||||
|
.set_composer_text("Please revise.".to_string(), Vec::new(), Vec::new());
|
||||||
|
chat.handle_key_event(KeyEvent::new(KeyCode::Enter, KeyModifiers::NONE));
|
||||||
|
|
||||||
|
match next_submit_op(&mut op_rx) {
|
||||||
|
Op::UserTurn { items, .. } => assert_eq!(
|
||||||
|
items,
|
||||||
|
vec![UserInput::Text {
|
||||||
|
text: "Please revise.".to_string(),
|
||||||
|
text_elements: Vec::new(),
|
||||||
|
}]
|
||||||
|
),
|
||||||
|
other => panic!("expected Op::UserTurn, got {other:?}"),
|
||||||
|
}
|
||||||
|
|
||||||
|
complete_user_message(&mut chat, "user-1", "Please revise.");
|
||||||
|
chat.on_plan_item_completed(
|
||||||
|
"- Revised plan
|
||||||
|
"
|
||||||
|
.to_string(),
|
||||||
|
);
|
||||||
|
chat.on_task_complete(None, false);
|
||||||
|
|
||||||
|
let popup = render_bottom_popup(&chat, 80);
|
||||||
|
assert!(
|
||||||
|
popup.contains(PLAN_IMPLEMENTATION_TITLE),
|
||||||
|
"expected plan popup after a newer plan follows the steer, got {popup:?}"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn plan_implementation_popup_skips_when_rate_limit_prompt_pending() {
|
async fn plan_implementation_popup_skips_when_rate_limit_prompt_pending() {
|
||||||
let (mut chat, _rx, _op_rx) = make_chatwidget_manual(Some("gpt-5")).await;
|
let (mut chat, _rx, _op_rx) = make_chatwidget_manual(Some("gpt-5")).await;
|
||||||
|
|||||||
Reference in New Issue
Block a user