From 5827290ece952e9a631cf969d92fc02768c854a2 Mon Sep 17 00:00:00 2001 From: Lukasz Raczylo Date: Fri, 19 Jun 2026 19:28:43 +0100 Subject: [PATCH] fix(edit): point empty-replace error at operation=delete A replace with empty new_content failed with a bare 'new_content is required' message, leaving the model to guess. Append a hint to use operation=delete when the intent is removal. Adds TestValidateReplaceEmptySuggestsDelete. --- internal/edit/edit.go | 6 +++++- internal/edit/edit_test.go | 16 ++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/internal/edit/edit.go b/internal/edit/edit.go index aabe663..8f45734 100644 --- a/internal/edit/edit.go +++ b/internal/edit/edit.go @@ -270,7 +270,11 @@ func (e *Engine) validateBaseEdit(edit *ASTEdit) error { switch edit.Operation { case EditReplace, EditInsertBefore, EditInsertAfter: if edit.NewContent == "" { - return errors.NewInvalidEditError(fmt.Sprintf("new_content is required for %s operation", edit.Operation)) + msg := fmt.Sprintf("new_content is required for %s operation", edit.Operation) + if edit.Operation == EditReplace { + msg += " (to remove content instead, use operation=delete)" + } + return errors.NewInvalidEditError(msg) } case EditDelete: // new_content not required diff --git a/internal/edit/edit_test.go b/internal/edit/edit_test.go index f7abcf1..cf400ca 100644 --- a/internal/edit/edit_test.go +++ b/internal/edit/edit_test.go @@ -101,6 +101,22 @@ func TestValidateEdit(t *testing.T) { } } +// A replace with empty new_content should point the caller at operation=delete. +func TestValidateReplaceEmptySuggestsDelete(t *testing.T) { + e := NewEngine(parser.NewRegistry()) + err := e.validateASTEdit(&ASTEdit{ + File: "test.go", + Operation: EditReplace, + Selector: ASTSelector{Kind: "function_declaration"}, + }) + if err == nil { + t.Fatal("expected error for replace with empty new_content") + } + if !strings.Contains(err.Error(), "operation=delete") { + t.Errorf("error should suggest operation=delete, got: %v", err) + } +} + func TestResolveSelector(t *testing.T) { registry := parser.NewRegistry() defer registry.Close()