fix false "task complete" state during agent message (#4627)

fixes an issue where user messages wouldn't be queued and ctrl + c would
quit the app instead of canceling the stream during the final agent
message.
This commit is contained in:
Jeremy Rose
2025-10-02 15:41:25 -07:00
committed by GitHub
parent 591a8ecc16
commit c0a84473a4
3 changed files with 41 additions and 3 deletions

View File

@@ -339,7 +339,14 @@ impl BottomPane {
self.request_redraw();
} else {
// Hide the status indicator when a task completes, but keep other modal views.
self.status = None;
self.hide_status_indicator();
}
}
/// Hide the status indicator while leaving task-running state untouched.
pub(crate) fn hide_status_indicator(&mut self) {
if self.status.take().is_some() {
self.request_redraw();
}
}

View File

@@ -632,7 +632,7 @@ impl ChatWidget {
if let Some(controller) = self.stream_controller.as_mut() {
let (cell, is_idle) = controller.on_commit_tick();
if let Some(cell) = cell {
self.bottom_pane.set_task_running(false);
self.bottom_pane.hide_status_indicator();
self.add_boxed_history(cell);
}
if is_idle {
@@ -665,7 +665,7 @@ impl ChatWidget {
fn handle_stream_finished(&mut self) {
if self.task_complete_pending {
self.bottom_pane.set_task_running(false);
self.bottom_pane.hide_status_indicator();
self.task_complete_pending = false;
}
// A completed stream indicates non-exec content was just inserted.

View File

@@ -47,6 +47,7 @@ use std::io::BufRead;
use std::io::BufReader;
use std::path::PathBuf;
use tempfile::NamedTempFile;
use tokio::sync::mpsc::error::TryRecvError;
use tokio::sync::mpsc::unbounded_channel;
fn test_config() -> Config {
@@ -612,6 +613,36 @@ fn alt_up_edits_most_recent_queued_message() {
);
}
#[test]
fn streaming_final_answer_keeps_task_running_state() {
let (mut chat, _rx, mut op_rx) = make_chatwidget_manual();
chat.on_task_started();
chat.on_agent_message_delta("Final answer line\n".to_string());
chat.on_commit_tick();
assert!(chat.bottom_pane.is_task_running());
assert!(chat.bottom_pane.status_widget().is_none());
chat.bottom_pane
.set_composer_text("queued submission".to_string());
chat.handle_key_event(KeyEvent::new(KeyCode::Enter, KeyModifiers::NONE));
assert_eq!(chat.queued_user_messages.len(), 1);
assert_eq!(
chat.queued_user_messages.front().unwrap().text,
"queued submission"
);
assert!(matches!(op_rx.try_recv(), Err(TryRecvError::Empty)));
chat.handle_key_event(KeyEvent::new(KeyCode::Char('c'), KeyModifiers::CONTROL));
match op_rx.try_recv() {
Ok(Op::Interrupt) => {}
other => panic!("expected Op::Interrupt, got {other:?}"),
}
assert!(chat.bottom_pane.ctrl_c_quit_hint_visible());
}
#[test]
fn exec_history_cell_shows_working_then_completed() {
let (mut chat, mut rx, _op_rx) = make_chatwidget_manual();