diff --git a/codex-rs/tui/src/bottom_pane/chat_composer_history.rs b/codex-rs/tui/src/bottom_pane/chat_composer_history.rs index 87bcc438..07e3df7c 100644 --- a/codex-rs/tui/src/bottom_pane/chat_composer_history.rs +++ b/codex-rs/tui/src/bottom_pane/chat_composer_history.rs @@ -59,14 +59,15 @@ impl ChatComposerHistory { return; } + self.history_cursor = None; + self.last_history_text = None; + // Avoid inserting a duplicate if identical to the previous entry. if self.local_history.last().is_some_and(|prev| prev == text) { return; } self.local_history.push(text.to_string()); - self.history_cursor = None; - self.last_history_text = None; } /// Should Up/Down key presses be interpreted as history navigation given diff --git a/codex-rs/tui/src/chatwidget/tests.rs b/codex-rs/tui/src/chatwidget/tests.rs index 0ab31daa..20554450 100644 --- a/codex-rs/tui/src/chatwidget/tests.rs +++ b/codex-rs/tui/src/chatwidget/tests.rs @@ -615,6 +615,35 @@ fn alt_up_edits_most_recent_queued_message() { ); } +/// Pressing Up to recall the most recent history entry and immediately queuing +/// it while a task is running should always enqueue the same text, even when it +/// is queued repeatedly. +#[test] +fn enqueueing_history_prompt_multiple_times_is_stable() { + let (mut chat, _rx, _op_rx) = make_chatwidget_manual(); + + // Submit an initial prompt to seed history. + chat.bottom_pane.set_composer_text("repeat me".to_string()); + chat.handle_key_event(KeyEvent::new(KeyCode::Enter, KeyModifiers::NONE)); + + // Simulate an active task so further submissions are queued. + chat.bottom_pane.set_task_running(true); + + for _ in 0..3 { + // Recall the prompt from history and ensure it is what we expect. + chat.handle_key_event(KeyEvent::new(KeyCode::Up, KeyModifiers::NONE)); + assert_eq!(chat.bottom_pane.composer_text(), "repeat me"); + + // Queue the prompt while the task is running. + chat.handle_key_event(KeyEvent::new(KeyCode::Enter, KeyModifiers::NONE)); + } + + assert_eq!(chat.queued_user_messages.len(), 3); + for message in chat.queued_user_messages.iter() { + assert_eq!(message.text, "repeat me"); + } +} + #[test] fn streaming_final_answer_keeps_task_running_state() { let (mut chat, _rx, mut op_rx) = make_chatwidget_manual();