Preserve TUI question state and integrate history and queue navigation (#42903)

## What changed

- Retain question drafts, selections, expanded state, and handled message IDs across thread input restoration and reconnects. Preserve buffered live questions during session refresh without replaying their message text.
- Enable history recall and search in question answers, honoring updated key bindings and stripping image attachments and placeholders from recalled entries. Preserve Vim mode when an answer is not accepted.
- Let forward navigation past the last question restore the latest queued message as an editable main composer draft. Keep working status and queued messages visible alongside questions.
- Show a countdown for newly arrived collapsed questions and clear it when the question editor is opened or used.
- Disable question submission and skipping while the thread is unavailable.

## Testing

Add regression tests and snapshots for draft restoration and replay deduplication, history search and key bindings, queued-message editing, countdown rendering, and question layout with working status.

GitOrigin-RevId: de016120a979db860fd0d4b8098b322b312b7d84
This commit is contained in:
Ian MacLeod authored and copyberry committed 2026-09-05 01:13:54 +00:00
1 parent d05e6d5f46
commit be2684ede0
35 files changed
+700 -87

No files matched your search

+10
View File
@@ -440,6 +440,16 @@ impl ChatWidget {
notification: ItemCompletedNotification,
replay_kind: Option<ReplayKind>,
) {
// Buffered live notifications can introduce questions; historical turn replay cannot.
if replay_kind == Some(ReplayKind::ThreadSnapshot)
&& let ThreadItem::AgentMessage {
id,
questions: Some(questions),
..
} = &notification.item
{
self.add_async_questions(id, questions);
}
match notification.item {
item @ ThreadItem::CommandExecution { .. } => self.on_command_execution_completed(item),
item => self.handle_thread_item(