Avoid panicking when edit agent emits an empty old_text tag (#30030)

Antonio Scandurra and Nathan created

Release Notes:

- Fixed a panic that could sometimes occur when the agent applies edits.

Co-authored-by: Nathan <nathan@zed.dev>

Change summary

crates/assistant_tools/src/edit_agent.rs | 42 ++++++++++++++++++++++++++
1 file changed, 42 insertions(+)

Detailed changes

crates/assistant_tools/src/edit_agent.rs 🔗

@@ -269,6 +269,12 @@ impl EditAgent {
             let EditParserEvent::OldText(old_text_query) = edit_event? else {
                 continue;
             };
+
+            // Skip edits with an empty old text.
+            if old_text_query.is_empty() {
+                continue;
+            }
+
             let old_text_query = SharedString::from(old_text_query);
 
             let (edits_tx, edits_rx) = mpsc::unbounded();
@@ -742,6 +748,42 @@ mod tests {
     use unindent::Unindent;
     use util::test::{generate_marked_text, marked_text_ranges};
 
+    #[gpui::test(iterations = 100)]
+    async fn test_empty_old_text(cx: &mut TestAppContext, mut rng: StdRng) {
+        let agent = init_test(cx).await;
+        let buffer = cx.new(|cx| {
+            Buffer::local(
+                indoc! {"
+                    abc
+                    def
+                    ghi
+                "},
+                cx,
+            )
+        });
+        let raw_edits = simulate_llm_output(
+            indoc! {"
+                <old_text></old_text>
+                <new_text>jkl</new_text>
+                <old_text>def</old_text>
+                <new_text>DEF</new_text>
+            "},
+            &mut rng,
+            cx,
+        );
+        let (apply, _events) =
+            agent.apply_edit_chunks(buffer.clone(), raw_edits, &mut cx.to_async());
+        apply.await.unwrap();
+        pretty_assertions::assert_eq!(
+            buffer.read_with(cx, |buffer, _| buffer.snapshot().text()),
+            indoc! {"
+                abc
+                DEF
+                ghi
+            "}
+        );
+    }
+
     #[gpui::test(iterations = 100)]
     async fn test_indentation(cx: &mut TestAppContext, mut rng: StdRng) {
         let agent = init_test(cx).await;