Add modify_file tool
This commit is contained in:
parent
b89cecf89e
commit
5c1f7e2594
@ -156,6 +156,102 @@ Result is returned as JSON in the following format:
|
||||
return WriteFile(path, content), nil
|
||||
},
|
||||
},
|
||||
"modify_file": {
|
||||
Tool: openai.Tool{Type: "function", Function: openai.FunctionDefinition{
|
||||
Name: "modify_file",
|
||||
Description: `Perform complex line-based modifications to a file.
|
||||
|
||||
Line ranges are inclusive. If 'start_line' is specified but 'end_line' is not,
|
||||
'end_line' gets set to the last line of the file.
|
||||
|
||||
To replace or remove a single line, *set start_line and end_line to the same value*
|
||||
|
||||
Examples:
|
||||
* Insert the lines "hello<new line>world" at line 10, preserving other content:
|
||||
{"path": "myfile", "operation": "insert", "start_line": 10, "content": "hello\nworld"}
|
||||
|
||||
* Remove lines 45 up to and including 54:
|
||||
{"path": "myfile", "operation": "remove", "start_line": 45, "end_line": 54}
|
||||
|
||||
* Replace content from line 10 to 25:
|
||||
{"path": "myfile", "operation": "replace", "start_line": 10, "end_line": 25, "content": "i\nwas\nhere"}
|
||||
|
||||
* Replace contents of entire the file:
|
||||
{"path": "myfile", "operation": "replace", "start_line": 0, "content": "i\nwas\nhere"}`,
|
||||
Parameters: FunctionParameters{
|
||||
Type: "object",
|
||||
Properties: map[string]FunctionParameter{
|
||||
"path": {
|
||||
Type: "string",
|
||||
Description: "Path of the file to be modified, relative to the current working directory.",
|
||||
},
|
||||
"operation": {
|
||||
Type: "string",
|
||||
Description: `The the type of modification to make to the file. One of: insert, remove, replace`,
|
||||
},
|
||||
"start_line": {
|
||||
Type: "integer",
|
||||
Description: `(Optional) Where to start making a modification (insert, remove, and replace).`,
|
||||
},
|
||||
"end_line": {
|
||||
Type: "integer",
|
||||
Description: `(Optional) Where to stop making a modification (remove or replace, end of file if omitted).`,
|
||||
},
|
||||
"content": {
|
||||
Type: "string",
|
||||
Description: `(Optional) The content to insert, or replace with.`,
|
||||
},
|
||||
},
|
||||
Required: []string{"path", "operation"},
|
||||
},
|
||||
}},
|
||||
Impl: func(args map[string]interface{}) (string, error) {
|
||||
tmp, ok := args["path"]
|
||||
if !ok {
|
||||
return "", fmt.Errorf("path parameter to write_file was not included.")
|
||||
}
|
||||
path, ok := tmp.(string)
|
||||
if !ok {
|
||||
return "", fmt.Errorf("Invalid path in function arguments: %v", tmp)
|
||||
}
|
||||
tmp, ok = args["operation"]
|
||||
if !ok {
|
||||
return "", fmt.Errorf("operation parameter to modify_file was not included.")
|
||||
}
|
||||
operation, ok := tmp.(string)
|
||||
if !ok {
|
||||
return "", fmt.Errorf("Invalid operation in function arguments: %v", tmp)
|
||||
}
|
||||
var start_line int
|
||||
tmp, ok = args["start_line"]
|
||||
if ok {
|
||||
tmp, ok := tmp.(float64)
|
||||
if !ok {
|
||||
return "", fmt.Errorf("Invalid start_line in function arguments: %v", tmp)
|
||||
}
|
||||
start_line = int(tmp)
|
||||
}
|
||||
var end_line int
|
||||
tmp, ok = args["end_line"]
|
||||
if ok {
|
||||
tmp, ok := tmp.(float64)
|
||||
if !ok {
|
||||
return "", fmt.Errorf("Invalid end_line in function arguments: %v", tmp)
|
||||
}
|
||||
end_line = int(tmp)
|
||||
}
|
||||
var content string
|
||||
tmp, ok = args["content"]
|
||||
if ok {
|
||||
content, ok = tmp.(string)
|
||||
if !ok {
|
||||
return "", fmt.Errorf("Invalid content in function arguments: %v", tmp)
|
||||
}
|
||||
}
|
||||
|
||||
return ModifyFile(path, operation, content, start_line, end_line), nil
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func resultToJson(result FunctionResult) string {
|
||||
@ -353,3 +449,70 @@ func WriteFile(path string, content string) string {
|
||||
}
|
||||
return resultToJson(FunctionResult{})
|
||||
}
|
||||
|
||||
func ModifyFile(path string, operation string, content string, startLine int, endLine int) string {
|
||||
ok, res := isPathWithinCWD(path)
|
||||
if !ok {
|
||||
return resultToJson(*res)
|
||||
}
|
||||
|
||||
// Read the existing file's content
|
||||
data, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
if !os.IsNotExist(err) {
|
||||
return resultToJson(FunctionResult{Message: fmt.Sprintf("Could not read path: %s", err.Error())})
|
||||
}
|
||||
_, err = os.Create(path)
|
||||
if err != nil {
|
||||
return resultToJson(FunctionResult{Message: fmt.Sprintf("Could not create new file: %s", err.Error())})
|
||||
}
|
||||
data = []byte{}
|
||||
}
|
||||
|
||||
if startLine < 0 {
|
||||
return resultToJson(FunctionResult{Message: "start_line cannot be less than 0"})
|
||||
}
|
||||
|
||||
// Split the content by newline to process lines
|
||||
lines := strings.Split(string(data), "\n")
|
||||
contentLines := strings.Split(strings.Trim(content, "\n"), "\n")
|
||||
|
||||
switch operation {
|
||||
case "insert":
|
||||
// Insert new lines
|
||||
before := lines[:startLine-1]
|
||||
after := append(contentLines, lines[startLine-1:]...)
|
||||
lines = append(before, after...)
|
||||
case "remove":
|
||||
// Remove lines
|
||||
if endLine == 0 || endLine > len(lines) {
|
||||
endLine = len(lines)
|
||||
}
|
||||
|
||||
lines = append(lines[:startLine-1], lines[endLine:]...)
|
||||
case "replace":
|
||||
// Replace the lines between start_line and end_line
|
||||
if endLine == 0 || endLine > len(lines) {
|
||||
endLine = len(lines)
|
||||
}
|
||||
if startLine == 0 {
|
||||
// model likely trying to replace contents, must start at line 1
|
||||
startLine = 1
|
||||
}
|
||||
before := lines[:startLine-1]
|
||||
after := lines[endLine:]
|
||||
lines = append(before, append(contentLines, after...)...)
|
||||
default:
|
||||
return resultToJson(FunctionResult{Message: fmt.Sprintf("Invalid operation: %s", operation)})
|
||||
}
|
||||
|
||||
newContent := strings.Join(lines, "\n")
|
||||
|
||||
// Join the lines and write back to the file
|
||||
err = os.WriteFile(path, []byte(newContent), 0644)
|
||||
if err != nil {
|
||||
return resultToJson(FunctionResult{Message: fmt.Sprintf("Could not write to path: %s", err.Error())})
|
||||
}
|
||||
|
||||
return resultToJson(FunctionResult{Result: newContent})
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user