From 6d2944b001fcdd6588d570c75fd78d031fb6737a Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Mon, 13 Apr 2026 23:15:53 -0600 Subject: [PATCH] Stop automatically deleting agent drafts (#53862) This was leftover from trying to hold the invariant of one empty draft, which was dropped in #53852. Removes all automatic draft deletion: - `retain_running_thread` discarded empty drafts when navigating away - `remove_empty_draft` cleaned up all retained drafts when loading from history - `open_external_thread_with_server` removed empty drafts when opening external threads Release Notes: - Fixed agent drafts being silently discarded when navigating between threads --- crates/agent_ui/src/agent_panel.rs | 94 ------------------------------ 1 file changed, 94 deletions(-) diff --git a/crates/agent_ui/src/agent_panel.rs b/crates/agent_ui/src/agent_panel.rs index b2c8eae7d62358aff0acbc1784cdd17e52c19a3c..8c89b1acc999b6b6c76cc6da2c8c087b4724a636 100644 --- a/crates/agent_ui/src/agent_panel.rs +++ b/crates/agent_ui/src/agent_panel.rs @@ -2153,65 +2153,10 @@ impl AgentPanel { return; } - let is_empty_draft = match conversation_view.read(cx).root_thread(cx) { - Some(tv) => tv.read(cx).is_draft(cx), - None => conversation_view.read(cx).is_new_draft(), - }; - if is_empty_draft { - ThreadMetadataStore::global(cx).update(cx, |store, cx| { - store.delete(thread_id, cx); - }); - return; - } - self.retained_threads.insert(thread_id, conversation_view); self.cleanup_retained_threads(cx); } - fn remove_empty_draft(&mut self, cx: &mut Context) { - let draft_ids: Vec = self - .retained_threads - .iter() - .filter(|(_, cv)| match cv.read(cx).root_thread(cx) { - Some(tv) => tv.read(cx).is_draft(cx), - None => cv.read(cx).is_new_draft(), - }) - .map(|(id, _)| *id) - .collect(); - for id in draft_ids { - self.retained_threads.remove(&id); - ThreadMetadataStore::global(cx).update(cx, |store, cx| { - store.delete(id, cx); - }); - } - - // Also clean up orphaned draft metadata in the store for this - // panel's worktree paths (e.g. from a previously removed workspace). - let path_list = { - let project = self.project.read(cx); - let worktree_paths = project.worktree_paths(cx); - worktree_paths.main_worktree_path_list().clone() - }; - if let Some(store) = ThreadMetadataStore::try_global(cx) { - let orphaned: Vec = { - let store = store.read(cx); - store - .entries_for_path(&path_list) - .chain(store.entries_for_main_worktree_path(&path_list)) - .filter(|entry| entry.is_draft()) - .map(|entry| entry.thread_id) - .collect() - }; - if !orphaned.is_empty() { - store.update(cx, |store, cx| { - for id in orphaned { - store.delete(id, cx); - } - }); - } - } - } - fn cleanup_retained_threads(&mut self, cx: &App) { let mut potential_removals = self .retained_threads @@ -2808,7 +2753,6 @@ impl AgentPanel { window, cx, ); - self.remove_empty_draft(cx); return; } } @@ -2823,7 +2767,6 @@ impl AgentPanel { window, cx, ); - self.remove_empty_draft(cx); } pub(crate) fn create_agent_thread( @@ -5234,16 +5177,6 @@ impl AgentPanel { window: &mut Window, cx: &mut Context, ) { - let active_id = self.active_thread_id(cx); - let empty_draft_ids: Vec = self - .draft_thread_ids(cx) - .into_iter() - .filter(|id| Some(*id) != active_id && self.editor_text(*id, cx).is_none()) - .collect(); - for id in empty_draft_ids { - self.remove_thread(id, cx); - } - let ext_agent = Agent::Custom { id: server.agent_id(), }; @@ -5882,33 +5815,6 @@ mod tests { (panel, cx) } - #[gpui::test] - async fn test_empty_draft_discarded_when_navigating_away(cx: &mut TestAppContext) { - let (panel, mut cx) = setup_panel(cx).await; - - let connection_a = StubAgentConnection::new(); - open_thread_with_connection(&panel, connection_a, &mut cx); - - panel.read_with(&cx, |panel, cx| { - let thread = panel.active_agent_thread(cx).unwrap(); - assert!( - thread.read(cx).entries().is_empty(), - "newly opened draft thread should have no entries" - ); - assert!(panel.retained_threads.is_empty()); - }); - - let connection_b = StubAgentConnection::new(); - open_thread_with_connection(&panel, connection_b, &mut cx); - - panel.read_with(&cx, |panel, _cx| { - assert!( - panel.retained_threads.is_empty(), - "empty draft should be discarded, not retained" - ); - }); - } - #[gpui::test] async fn test_running_thread_retained_when_navigating_away(cx: &mut TestAppContext) { let (panel, mut cx) = setup_panel(cx).await;