Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/types/src/tool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export const toolNames = [
"apply_diff",
"search_and_replace",
"search_replace",
"edit_file",
"apply_patch",
"search_files",
"list_files",
Expand Down
30 changes: 30 additions & 0 deletions src/core/assistant-message/NativeToolCallParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -525,6 +525,21 @@ export class NativeToolCallParser {
}
break

case "edit_file":
if (
partialArgs.file_path !== undefined ||
partialArgs.old_string !== undefined ||
partialArgs.new_string !== undefined
) {
nativeArgs = {
file_path: partialArgs.file_path,
old_string: partialArgs.old_string,
new_string: partialArgs.new_string,
expected_replacements: partialArgs.expected_replacements,
}
}
break

default:
break
}
Expand Down Expand Up @@ -785,6 +800,21 @@ export class NativeToolCallParser {
}
break

case "edit_file":
if (
args.file_path !== undefined &&
args.old_string !== undefined &&
args.new_string !== undefined
) {
nativeArgs = {
file_path: args.file_path,
old_string: args.old_string,
new_string: args.new_string,
expected_replacements: args.expected_replacements,
} as NativeArgsFor<TName>
}
break

default:
break
}
Expand Down
13 changes: 13 additions & 0 deletions src/core/assistant-message/presentAssistantMessage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import { writeToFileTool } from "../tools/WriteToFileTool"
import { applyDiffTool } from "../tools/MultiApplyDiffTool"
import { searchAndReplaceTool } from "../tools/SearchAndReplaceTool"
import { searchReplaceTool } from "../tools/SearchReplaceTool"
import { editFileTool } from "../tools/EditFileTool"
import { applyPatchTool } from "../tools/ApplyPatchTool"
import { searchFilesTool } from "../tools/SearchFilesTool"
import { browserActionTool } from "../tools/BrowserActionTool"
Expand Down Expand Up @@ -403,6 +404,8 @@ export async function presentAssistantMessage(cline: Task) {
return `[${block.name} for '${block.params.path}']`
case "search_replace":
return `[${block.name} for '${block.params.file_path}']`
case "edit_file":
return `[${block.name} for '${block.params.file_path}']`
case "apply_patch":
return `[${block.name}]`
case "list_files":
Expand Down Expand Up @@ -872,6 +875,16 @@ export async function presentAssistantMessage(cline: Task) {
toolProtocol,
})
break
case "edit_file":
await checkpointSaveAndMark(cline)
await editFileTool.handle(cline, block as ToolUse<"edit_file">, {
askApproval,
handleError,
pushToolResult,
removeClosingTag,
toolProtocol,
})
break
case "apply_patch":
await checkpointSaveAndMark(cline)
await applyPatchTool.handle(cline, block as ToolUse<"apply_patch">, {
Expand Down
70 changes: 70 additions & 0 deletions src/core/prompts/tools/native-tools/edit_file.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import type OpenAI from "openai"

const EDIT_FILE_DESCRIPTION = `Use this tool to replace text in an existing file, or create a new file.

This tool performs literal string replacement with support for multiple occurrences.

USAGE PATTERNS:

1. MODIFY EXISTING FILE (default):
- Provide file_path, old_string (text to find), and new_string (replacement)
- By default, expects exactly 1 occurrence of old_string
- Use expected_replacements to replace multiple occurrences

2. CREATE NEW FILE:
- Set old_string to empty string ""
- new_string becomes the entire file content
- File must not already exist

CRITICAL REQUIREMENTS:

1. EXACT MATCHING: The old_string must match the file contents EXACTLY, including:
- All whitespace (spaces, tabs, newlines)
- All indentation
- All punctuation and special characters

2. CONTEXT FOR UNIQUENESS: For single replacements (default), include at least 3 lines of context BEFORE and AFTER the target text to ensure uniqueness.

3. MULTIPLE REPLACEMENTS: If you need to replace multiple identical occurrences:
- Set expected_replacements to the exact count you expect to replace
- ALL occurrences will be replaced

4. NO ESCAPING: Provide the literal text - do not escape special characters.`

const edit_file = {
type: "function",
function: {
name: "edit_file",
description: EDIT_FILE_DESCRIPTION,
parameters: {
type: "object",
properties: {
file_path: {
type: "string",
description:
"The path to the file to modify or create. You can use either a relative path in the workspace or an absolute path. If an absolute path is provided, it will be preserved as is.",
},
old_string: {
type: "string",
description:
"The exact literal text to replace (must match the file contents exactly, including all whitespace and indentation). For single replacements (default), include at least 3 lines of context BEFORE and AFTER the target text. Use empty string to create a new file.",
},
new_string: {
type: "string",
description:
"The exact literal text to replace old_string with. When creating a new file (old_string is empty), this becomes the file content.",
},
expected_replacements: {
type: "number",
description:
"Number of replacements expected. Defaults to 1 if not specified. Use when you want to replace multiple occurrences of the same text.",
minimum: 1,
},
},
required: ["file_path", "old_string", "new_string"],
additionalProperties: false,
},
},
} satisfies OpenAI.Chat.ChatCompletionTool

export default edit_file
2 changes: 2 additions & 0 deletions src/core/prompts/tools/native-tools/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { createReadFileTool } from "./read_file"
import runSlashCommand from "./run_slash_command"
import searchAndReplace from "./search_and_replace"
import searchReplace from "./search_replace"
import edit_file from "./edit_file"
import searchFiles from "./search_files"
import switchMode from "./switch_mode"
import updateTodoList from "./update_todo_list"
Expand Down Expand Up @@ -47,6 +48,7 @@ export function getNativeTools(partialReadsEnabled: boolean = true): OpenAI.Chat
runSlashCommand,
searchAndReplace,
searchReplace,
edit_file,
searchFiles,
switchMode,
updateTodoList,
Expand Down
Loading
Loading