From 2e8c0ff244baf2dc71d7ba68cfd057a92d67b6e2 Mon Sep 17 00:00:00 2001 From: Agus Zubiaga Date: Thu, 20 Mar 2025 10:42:10 -0300 Subject: [PATCH] assistant edit tool: Report when file is empty or doesn't exist (#27190) Instead of just reporting a search match failure, we'll now indicate whether the file is empty or exists to help the model recover better from bad edits. Release Notes: - N/A --- crates/assistant_tools/src/edit_files_tool.rs | 65 ++++++++++++++++--- 1 file changed, 55 insertions(+), 10 deletions(-) diff --git a/crates/assistant_tools/src/edit_files_tool.rs b/crates/assistant_tools/src/edit_files_tool.rs index d0a36b4379..f75add9ebc 100644 --- a/crates/assistant_tools/src/edit_files_tool.rs +++ b/crates/assistant_tools/src/edit_files_tool.rs @@ -160,9 +160,16 @@ enum DiffResult { } #[derive(Debug)] -struct BadSearch { - file_path: String, - search: String, +enum BadSearch { + NoMatch { + file_path: String, + search: String, + }, + EmptyBuffer { + file_path: String, + search: String, + exists: bool, + }, } impl EditToolRequest { @@ -309,6 +316,18 @@ impl EditToolRequest { file_path: std::path::PathBuf, snapshot: language::BufferSnapshot, ) -> Result { + if snapshot.is_empty() { + let exists = snapshot + .file() + .map_or(false, |file| file.disk_state().exists()); + + return Ok(DiffResult::BadSearch(BadSearch::EmptyBuffer { + file_path: file_path.display().to_string(), + exists, + search: old, + })); + } + let result = // Try to match exactly replace_exact(&old, &new, &snapshot) @@ -317,7 +336,7 @@ impl EditToolRequest { .or_else(|| replace_with_flexible_indent(&old, &new, &snapshot)); let Some(diff) = result else { - return anyhow::Ok(DiffResult::BadSearch(BadSearch { + return anyhow::Ok(DiffResult::BadSearch(BadSearch::NoMatch { search: old, file_path: file_path.display().to_string(), })); @@ -377,12 +396,38 @@ impl EditToolRequest { self.bad_searches.len() )?; - for replace in self.bad_searches { - writeln!( - &mut output, - "## No exact match in: {}\n```\n{}\n```\n", - replace.file_path, replace.search, - )?; + for bad_search in self.bad_searches { + match bad_search { + BadSearch::NoMatch { file_path, search } => { + writeln!( + &mut output, + "## No exact match in: `{}`\n```\n{}\n```\n", + file_path, search, + )?; + } + BadSearch::EmptyBuffer { + file_path, + exists: true, + search, + } => { + writeln!( + &mut output, + "## No match because `{}` is empty:\n```\n{}\n```\n", + file_path, search, + )?; + } + BadSearch::EmptyBuffer { + file_path, + exists: false, + search, + } => { + writeln!( + &mut output, + "## No match because `{}` does not exist:\n```\n{}\n```\n", + file_path, search, + )?; + } + } } write!(&mut output,