Skip to content

Commit 0f1eb57

Browse files
committed
feat: 🤖 simplify file edit tools to single edits
1 parent a5131d3 commit 0f1eb57

File tree

6 files changed

+216
-240
lines changed

6 files changed

+216
-240
lines changed

src/services/streamManager.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -345,7 +345,7 @@ describe("StreamManager - Unavailable Tool Handling", () => {
345345
type: "tool-call",
346346
toolCallId: "test-call-1",
347347
toolName: "file_edit_replace_string",
348-
input: { file_path: "/test", edits: [] },
348+
input: { file_path: "/test", old_string: "foo", new_string: "bar" },
349349
};
350350
// SDK emits tool-error when tool execution fails
351351
yield {

src/services/tools/file_edit_replace_lines.ts

Lines changed: 37 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { executeFileEditOperation } from "./file_edit_operation";
66

77
/**
88
* File edit replace (lines) tool factory for AI assistant
9-
* Applies line-range replacements sequentially with optional content validation.
9+
* Applies a single line-range replacement with optional content validation.
1010
*/
1111
export const createFileEditReplaceLinesTool: ToolFactory = (config: ToolConfiguration) => {
1212
return tool({
@@ -19,59 +19,53 @@ export const createFileEditReplaceLinesTool: ToolFactory = (config: ToolConfigur
1919
config,
2020
filePath: args.file_path,
2121
operation: (originalContent) => {
22-
let lines = originalContent.split("\n");
23-
let linesReplaced = 0;
24-
let totalDelta = 0;
22+
const startIndex = args.start_line - 1;
23+
const endIndex = args.end_line - 1;
2524

26-
for (let i = 0; i < args.edits.length; i++) {
27-
const edit = args.edits[i];
28-
const startIndex = edit.start_line - 1;
29-
const endIndex = edit.end_line - 1;
30-
31-
if (edit.start_line <= 0) {
32-
return {
33-
success: false,
34-
error: `Edit ${i + 1}: start_line must be >= 1 (received ${edit.start_line}).`,
35-
};
36-
}
37-
38-
if (edit.end_line < edit.start_line) {
39-
return {
40-
success: false,
41-
error: `Edit ${i + 1}: end_line must be >= start_line (received start ${edit.start_line}, end ${edit.end_line}).`,
42-
};
43-
}
25+
if (args.start_line <= 0) {
26+
return {
27+
success: false,
28+
error: `start_line must be >= 1 (received ${args.start_line}).`,
29+
};
30+
}
4431

45-
if (startIndex >= lines.length) {
46-
return {
47-
success: false,
48-
error: `Edit ${i + 1}: start_line ${edit.start_line} exceeds current file length (${lines.length}).`,
49-
};
50-
}
32+
if (args.end_line < args.start_line) {
33+
return {
34+
success: false,
35+
error: `end_line must be >= start_line (received start ${args.start_line}, end ${args.end_line}).`,
36+
};
37+
}
5138

52-
const clampedEndIndex = Math.min(endIndex, lines.length - 1);
53-
const currentRange = lines.slice(startIndex, clampedEndIndex + 1);
39+
const lines = originalContent.split("\n");
5440

55-
if (edit.expected_lines && !arraysEqual(currentRange, edit.expected_lines)) {
56-
return {
57-
success: false,
58-
error: `Edit ${i + 1}: expected_lines validation failed. Current lines [${currentRange.join("\n")}] differ from expected [${edit.expected_lines.join("\n")}].`,
59-
};
60-
}
41+
if (startIndex >= lines.length) {
42+
return {
43+
success: false,
44+
error: `start_line ${args.start_line} exceeds current file length (${lines.length}).`,
45+
};
46+
}
6147

62-
const before = lines.slice(0, startIndex);
63-
const after = lines.slice(clampedEndIndex + 1);
64-
lines = [...before, ...edit.new_lines, ...after];
48+
const clampedEndIndex = Math.min(endIndex, lines.length - 1);
49+
const currentRange = lines.slice(startIndex, clampedEndIndex + 1);
6550

66-
linesReplaced += currentRange.length;
67-
totalDelta += edit.new_lines.length - currentRange.length;
51+
if (args.expected_lines && !arraysEqual(currentRange, args.expected_lines)) {
52+
return {
53+
success: false,
54+
error: `expected_lines validation failed. Current lines [${currentRange.join("\n")}] differ from expected [${args.expected_lines.join("\n")}].`,
55+
};
6856
}
6957

58+
const before = lines.slice(0, startIndex);
59+
const after = lines.slice(clampedEndIndex + 1);
60+
const updatedLines = [...before, ...args.new_lines, ...after];
61+
const linesReplaced = currentRange.length;
62+
const totalDelta = args.new_lines.length - currentRange.length;
63+
7064
return {
7165
success: true,
72-
newContent: lines.join("\n"),
66+
newContent: updatedLines.join("\n"),
7367
metadata: {
74-
edits_applied: args.edits.length,
68+
edits_applied: 1,
7569
lines_replaced: linesReplaced,
7670
line_delta: totalDelta,
7771
},

0 commit comments

Comments
 (0)