Adding edit tool basically cloned from opencode
This commit is contained in:
@@ -14,6 +14,7 @@ add_library(drharness_lib
|
||||
src/harness.cpp
|
||||
tools/shell_tool.cpp
|
||||
tools/agent_tool.cpp
|
||||
tools/edit_tool.cpp
|
||||
)
|
||||
target_include_directories(drharness_lib PUBLIC include tools)
|
||||
target_link_libraries(drharness_lib
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "agent_profile.hpp"
|
||||
#include "shell_tool.hpp"
|
||||
#include "agent_tool.hpp"
|
||||
#include "edit_tool.hpp"
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
@@ -24,6 +25,7 @@ static const std::vector<AgentProfile> profiles = {
|
||||
static const std::vector<std::string> default_tools =
|
||||
{
|
||||
"run_shell",
|
||||
"edit",
|
||||
};
|
||||
|
||||
|
||||
@@ -36,6 +38,7 @@ int main(int argc, char** argv) {
|
||||
ToolRegistry master_registery;
|
||||
ToolRegistry agent_tools;
|
||||
master_registery.register_tool(make_shell_tool());
|
||||
master_registery.register_tool(make_edit_tool());
|
||||
// Add more base tools here:
|
||||
// registry.register_tool(make_file_read_tool());
|
||||
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
#include "edit_tool.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 absolute path to the file to modify"}
|
||||
}},
|
||||
{"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 = [](const nlohmann::json& args) -> std::string {
|
||||
if (!args.contains("filePath") || !args["filePath"].is_string())
|
||||
return "Error: missing required parameter 'filePath'";
|
||||
|
||||
if (!args.contains("oldString") || !args["oldString"].is_string())
|
||||
return "Error: missing required parameter 'oldString'";
|
||||
|
||||
if (!args.contains("newString") || !args["newString"].is_string())
|
||||
return "Error: missing required parameter 'newString'";
|
||||
|
||||
std::string oldString = args["oldString"];
|
||||
|
||||
std::ifstream in(args["filePath"]);
|
||||
|
||||
if (!in)
|
||||
return "Error: Could not open file '" + std::string(args["filePath"]) + "'";
|
||||
|
||||
std::ostringstream sstr;
|
||||
sstr << in.rdbuf();
|
||||
std::string file_string = sstr.str(); // Contents of the file
|
||||
|
||||
auto count = countOccurrences(file_string, 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(oldString),
|
||||
oldString.length(),
|
||||
(std::string)args["newString"]);
|
||||
|
||||
std::ofstream output(args["filePath"]);
|
||||
output << file_string;
|
||||
|
||||
return "Successfully edited file";
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
#pragma once
|
||||
#include "tool.hpp"
|
||||
|
||||
Tool make_edit_tool();
|
||||
Reference in New Issue
Block a user