87 lines
3.7 KiB
C++
87 lines
3.7 KiB
C++
#include "edit_tool.hpp"
|
|
#include "json_types.hpp"
|
|
#include <fstream>
|
|
#include <sstream>
|
|
|
|
|
|
static int countOccurrences(const std::string& text, const std::string& target) {
|
|
int count = 0;
|
|
size_t pos = text.find(target);
|
|
|
|
while (pos != std::string::npos) {
|
|
++count;
|
|
pos = text.find(target, pos + target.length());
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
Tool make_edit_tool() {
|
|
return Tool{
|
|
.name = "edit",
|
|
.description = ""
|
|
"Performs exact string replacements in files.\n"
|
|
"\n"
|
|
"Usage:\n"
|
|
"- When editing text from Read tool output, ensure you preserve the exact indentation (tabs/spaces) as it appears AFTER the line number prefix. The line number prefix format is: line number + colon + space (e.g., `1: `). Everything after that space is the actual file content to match. Never include any part of the line number prefix in the oldString or newString.\n"
|
|
// "- ALWAYS prefer editing existing files in the codebase. NEVER write new files unless explicitly required.\n"
|
|
"- Only use emojis if the user explicitly requests it. Avoid adding emojis to files unless asked.\n"
|
|
"- The edit will FAIL if `oldString` is not found in the file with an error \"oldString not found in content\".\n"
|
|
"- The edit will FAIL if `oldString` is found multiple times in the file with an error \"Found multiple matches for oldString. Provide more surrounding lines in oldString to identify the correct match.\"",// Either provide a larger string with more surrounding context to make it unique or use `replaceAll` to change every instance of `oldString`. \n"
|
|
// "- Use `replaceAll` for replacing and renaming strings across the file. This parameter is useful if you want to rename a variable for instance.",
|
|
|
|
.parameters_schema = {
|
|
{"type", "object"},
|
|
{"properties", {
|
|
{"filePath", {
|
|
{"type", "string"},
|
|
{"description", "The path to the file to modify (relative or absolute)"}
|
|
}},
|
|
{"oldString", {
|
|
{"type", "string"},
|
|
{"description", "The text to replace"}
|
|
}},
|
|
{"newString", {
|
|
{"type", "string"},
|
|
{"description", "The text to replace it with (must be different from oldString)"}
|
|
}},
|
|
#if 0
|
|
{"replaceAll", {
|
|
{"type", "bool"},
|
|
{"description", "Replace all occurrences of oldString (default false)"}
|
|
}},
|
|
#endif
|
|
}},
|
|
{"required", {"filePath", "oldString", "newString"}}
|
|
},
|
|
.execute = create_tool_execute<EditToolParams>([](const EditToolParams& params) -> std::string {
|
|
|
|
std::ifstream in(params.filePath);
|
|
|
|
if (!in)
|
|
return "Error: Could not open file '" + params.filePath + "'";
|
|
|
|
std::ostringstream sstr;
|
|
sstr << in.rdbuf();
|
|
std::string file_string = sstr.str(); // Contents of the file
|
|
|
|
auto count = countOccurrences(file_string, params.oldString);
|
|
if (count == 0)
|
|
return "Error: oldString not found in content";
|
|
|
|
if (count > 1)
|
|
return "Error: Found multiple matches for oldString. Provide more surrounding lines in oldString to identify the correct match.";
|
|
|
|
file_string = file_string.replace(
|
|
file_string.find(params.oldString),
|
|
params.oldString.length(),
|
|
params.newString);
|
|
|
|
std::ofstream output(params.filePath);
|
|
output << file_string;
|
|
|
|
return "Successfully edited file";
|
|
})
|
|
};
|
|
}
|