Retry safety-buffered turns on a forked thread (#33207)

## Why

Retrying a safety-buffered turn by rolling back the active thread rewrites the
source conversation and requires the TUI to repair its local transcript state.

## What changed

- Interrupt the buffered turn, then fork after the preceding completed turn and
  submit the prompt on the new thread with the faster model and low reasoning
  effort.
- Start a new thread when the buffered request is the conversation's first turn.
- Preserve committed steering input in the retry, leave the source thread
  intact, and restore the prompt alongside any existing draft if branching
  fails.
- Do not offer the retry action for side conversations or stale and in-progress
  turns.

## Testing

Added coverage for retries with prior context, first-turn retries, committed
steering input, branch failures, existing composer drafts and attachments, and
side conversations.

GitOrigin-RevId: adb49da8236e9212ef0082e033e6f715986b5cd9
This commit is contained in:
Felipe Coury authored and copyberry committed 2026-07-15 02:03:46 +00:00
1 parent 77a3f4e80f
commit 9cddda7556
21 files changed
+897 -586

No files matched your search

-6
View File
@@ -475,7 +475,6 @@ const APPROVE_FOR_ME_LABEL: &str = "Approve for me";
const AUTO_REVIEW_DESCRIPTION: &str = "Only ask for actions detected as potentially unsafe.";
const DEFAULT_OPENAI_BASE_URL: &str = "https://api.openai.com/v1";
const DEFAULT_STATUS_LINE_ITEMS: [&str; 2] = ["model-with-reasoning", "current-dir"];
const MAX_AGENT_COPY_HISTORY: usize = 32;
/// Common initialization parameters shared by all `ChatWidget` constructors.
pub(crate) struct ChatWidgetInit {
@@ -965,10 +964,6 @@ impl ChatWidget {
}
}
fn record_visible_user_turn_for_copy(&mut self) {
self.transcript.record_visible_user_turn();
}
pub(crate) fn open_feedback_note(
&mut self,
category: crate::app_event::FeedbackCategory,
@@ -1308,7 +1303,6 @@ impl ChatWidget {
|| !display.local_images.is_empty()
|| !display.remote_image_urls.is_empty()
{
self.record_visible_user_turn_for_copy();
self.add_to_history(history_cell::new_user_prompt(
display.message,
display.text_elements,