From f00a168cdb4889f5571e2c1126d9f4067836f69a Mon Sep 17 00:00:00 2001 From: Danny Zei Date: Sat, 12 Sep 2026 09:30:57 -0700 Subject: [PATCH] fix(tool): swap inverted file_read line range instead of erroring --- internal/tool/file_read.go | 11 +++++++---- internal/tool/file_read_test.go | 15 ++++++++++----- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/internal/tool/file_read.go b/internal/tool/file_read.go index e474365ed..90f33c304 100644 --- a/internal/tool/file_read.go +++ b/internal/tool/file_read.go @@ -37,11 +37,14 @@ func (p *FileReadProvider) Execute(ctx context.Context, args map[string]any) (st maxLines := fileReadMaxLines if endLine > 0 { - requested := int(endLine) - int(startLine) + 1 - if requested <= 0 { - return "", fmt.Errorf("invalid line range: start_line %d is greater than end_line %d", int(startLine), int(endLine)) + if int(endLine) < int(startLine) { + // Models sometimes derive start_line from the old side of a diff + // hunk while end_line comes from the new file, or simply swap the + // two. Serve the swapped range instead of failing the call; the + // total-line count in the response lets the caller recover. + startLine, endLine = endLine, startLine } - if requested < maxLines { + if requested := int(endLine) - int(startLine) + 1; requested < maxLines { maxLines = requested } } diff --git a/internal/tool/file_read_test.go b/internal/tool/file_read_test.go index 7a192d681..970f29236 100644 --- a/internal/tool/file_read_test.go +++ b/internal/tool/file_read_test.go @@ -353,20 +353,25 @@ func TestExecute_EmptyFilePath(t *testing.T) { } } -func TestExecute_InvalidLineRange(t *testing.T) { +func TestExecute_SwappedLineRange(t *testing.T) { dir := t.TempDir() writeTestFile(t, dir, "test.txt", "a\nb\nc\n") fr := &FileReader{RepoDir: dir, Mode: ModeWorkspace} p := NewFileRead(fr) - _, err := p.Execute(context.Background(), map[string]any{ + // An inverted range is a common model slip (start from the old hunk side, + // end from the new file). The tool swaps it instead of erroring. + got, err := p.Execute(context.Background(), map[string]any{ "file_path": "test.txt", - "start_line": float64(5), + "start_line": float64(3), "end_line": float64(2), }) - if err == nil { - t.Error("expected error for invalid line range") + if err != nil { + t.Fatal(err) + } + if !strings.Contains(got, "2|b\n3|c\n") { + t.Errorf("Execute() = %q, want swapped range 2-3", got) } }