From c59af48565816a23316c7436401bda28196d09e6 Mon Sep 17 00:00:00 2001 From: Bennet Bo Fenner Date: Tue, 17 Mar 2026 12:05:11 +0100 Subject: [PATCH] agent: Fix issue where created file is not deleted after rejecting (#51745) Release Notes: - N/A --- .../src/tools/streaming_edit_file_tool.rs | 63 ++++++++++++++++--- 1 file changed, 56 insertions(+), 7 deletions(-) diff --git a/crates/agent/src/tools/streaming_edit_file_tool.rs b/crates/agent/src/tools/streaming_edit_file_tool.rs index 574fe078063b0b8e66ceb6cf0503ad139c23cdc4..ccfde2dd5ba0772f51210526f35896c9bb53b559 100644 --- a/crates/agent/src/tools/streaming_edit_file_tool.rs +++ b/crates/agent/src/tools/streaming_edit_file_tool.rs @@ -528,8 +528,10 @@ impl EditSession { } }) as Box); - tool.action_log - .update(cx, |log, cx| log.buffer_read(buffer.clone(), cx)); + tool.action_log.update(cx, |log, cx| match mode { + StreamingEditFileMode::Write => log.buffer_created(buffer.clone(), cx), + StreamingEditFileMode::Edit => log.buffer_read(buffer.clone(), cx), + }); let old_snapshot = buffer.read_with(cx, |buffer, _cx| buffer.snapshot()); let old_text = cx @@ -568,10 +570,6 @@ impl EditSession { let events = self.parser.finalize_content(&content); self.process_events(&events, tool, event_stream, cx)?; - - tool.action_log.update(cx, |log, cx| { - log.buffer_created(self.buffer.clone(), cx); - }); } StreamingEditFileMode::Edit => { let edits = input.edits.ok_or_else(|| { @@ -3711,7 +3709,7 @@ mod tests { assert!( !changed.is_empty(), "action_log.changed_buffers() should be non-empty after streaming edit, - but no changed buffers were found \u{2014} Accept All / Reject All will not appear" + but no changed buffers were found - Accept All / Reject All will not appear" ); } @@ -3856,6 +3854,57 @@ mod tests { assert_eq!(new_text, "new_content"); } + #[gpui::test] + async fn test_streaming_reject_created_file_deletes_it(cx: &mut TestAppContext) { + let (tool, _project, action_log, fs, _thread) = setup_test(cx, json!({"dir": {}})).await; + cx.update(|cx| { + let mut settings = agent_settings::AgentSettings::get_global(cx).clone(); + settings.tool_permissions.default = settings::ToolPermissionMode::Allow; + agent_settings::AgentSettings::override_global(settings, cx); + }); + + // Create a new file via the streaming edit file tool + let (event_stream, _rx) = ToolCallEventStream::test(); + let task = cx.update(|cx| { + tool.clone().run( + ToolInput::resolved(StreamingEditFileToolInput { + display_description: "Create new file".into(), + path: "root/dir/new_file.txt".into(), + mode: StreamingEditFileMode::Write, + content: Some("Hello, World!".into()), + edits: None, + }), + event_stream, + cx, + ) + }); + let result = task.await; + assert!(result.is_ok(), "create should succeed: {:?}", result.err()); + cx.run_until_parked(); + + assert!( + fs.is_file(path!("/root/dir/new_file.txt").as_ref()).await, + "file should exist after creation" + ); + + // Reject all edits — this should delete the newly created file + let changed = action_log.read_with(cx, |log, cx| log.changed_buffers(cx)); + assert!( + !changed.is_empty(), + "action_log should track the created file as changed" + ); + + action_log + .update(cx, |log, cx| log.reject_all_edits(None, cx)) + .await; + cx.run_until_parked(); + + assert!( + !fs.is_file(path!("/root/dir/new_file.txt").as_ref()).await, + "file should be deleted after rejecting creation, but an empty file was left behind" + ); + } + async fn setup_test_with_fs( cx: &mut TestAppContext, fs: Arc,