fix(tui): avoid committing transient stream tail cells

This commit is contained in:
Felipe Coury
2026-04-06 13:16:56 -03:00
committed by Felipe Coury
parent d9035a61b0
commit ed087e1fa4
2 changed files with 57 additions and 5 deletions
+10 -5
View File
@@ -5567,12 +5567,17 @@ impl ChatWidget {
}
fn flush_active_cell(&mut self) {
if self.stream_controller.is_some()
&& self
.active_cell
.as_ref()
.is_some_and(|cell| cell.as_any().is::<history_cell::StreamingAgentTailCell>())
if self
.active_cell
.as_ref()
.is_some_and(|cell| cell.as_any().is::<history_cell::StreamingAgentTailCell>())
{
if self.stream_controller.is_some() {
return;
}
// If stream cleanup already cleared the controller, drop the transient tail instead
// of committing preview-only content to transcript history.
self.active_cell.take();
return;
}
@@ -126,6 +126,53 @@ async fn current_stream_width_returns_none_when_reserved_columns_exhaust_width()
assert_eq!(chat.current_stream_width(4), Some(1));
}
#[tokio::test]
async fn add_to_history_does_not_commit_transient_stream_tail_after_controller_clear() {
let (mut chat, mut rx, _op_rx) = make_chatwidget_manual(None).await;
chat.active_cell = Some(Box::new(
crate::history_cell::StreamingAgentTailCell::new(
vec![ratatui::text::Line::from("transient table tail preview")],
true,
),
));
// Interrupt/error cleanup paths clear the controller before appending history.
chat.stream_controller = None;
chat.add_to_history(crate::history_cell::new_error_event(
"stream interrupted".to_string(),
));
let mut inserted_count = 0usize;
let mut saw_transient_tail = false;
let mut saw_error = false;
while let Ok(event) = rx.try_recv() {
if let AppEvent::InsertHistoryCell(cell) = event {
inserted_count += 1;
if cell
.as_any()
.is::<crate::history_cell::StreamingAgentTailCell>()
{
saw_transient_tail = true;
}
let rendered = lines_to_single_string(&cell.display_lines(80));
if rendered.contains("stream interrupted") {
saw_error = true;
}
}
}
assert!(saw_error, "expected error history cell to be emitted");
assert!(
!saw_transient_tail,
"did not expect transient stream-tail cell to be committed",
);
assert_eq!(
inserted_count, 1,
"expected only one committed history cell after cleanup"
);
}
#[tokio::test]
async fn helpers_are_available_and_do_not_panic() {
let (tx_raw, _rx) = unbounded_channel::<AppEvent>();