From 6cc04f43022e08ce2344d58fae271c4784cf7571 Mon Sep 17 00:00:00 2001 From: Grail Finder Date: Tue, 25 Nov 2025 20:01:18 +0300 Subject: Feat: more shell tools --- tools.go | 544 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 540 insertions(+), 4 deletions(-) (limited to 'tools.go') diff --git a/tools.go b/tools.go index 72b065c..751a4a4 100644 --- a/tools.go +++ b/tools.go @@ -10,6 +10,9 @@ import ( "strconv" "strings" "time" + "os" + "io" + "os/exec" ) var ( @@ -171,13 +174,370 @@ func recallTopics(args map[string]string) []byte { return []byte(joinedS) } +// File Manipulation Tools + +func fileCreate(args map[string]string) []byte { + path, ok := args["path"] + if !ok || path == "" { + msg := "path not provided to file_create tool" + logger.Error(msg) + return []byte(msg) + } + + content, ok := args["content"] + if !ok { + content = "" + } + + if err := writeStringToFile(path, content); err != nil { + msg := "failed to create file; error: " + err.Error() + logger.Error(msg) + return []byte(msg) + } + + msg := "file created successfully at " + path + return []byte(msg) +} + +func fileRead(args map[string]string) []byte { + path, ok := args["path"] + if !ok || path == "" { + msg := "path not provided to file_read tool" + logger.Error(msg) + return []byte(msg) + } + + content, err := readStringFromFile(path) + if err != nil { + msg := "failed to read file; error: " + err.Error() + logger.Error(msg) + return []byte(msg) + } + + result := map[string]string{ + "content": content, + "path": path, + } + jsonResult, err := json.Marshal(result) + if err != nil { + msg := "failed to marshal result; error: " + err.Error() + logger.Error(msg) + return []byte(msg) + } + + return jsonResult +} + +func fileUpdate(args map[string]string) []byte { + path, ok := args["path"] + if !ok || path == "" { + msg := "path not provided to file_update tool" + logger.Error(msg) + return []byte(msg) + } + + content, ok := args["content"] + if !ok { + content = "" + } + + mode, ok := args["mode"] + if !ok || mode == "" { + mode = "overwrite" + } + + switch mode { + case "overwrite": + if err := writeStringToFile(path, content); err != nil { + msg := "failed to update file; error: " + err.Error() + logger.Error(msg) + return []byte(msg) + } + case "append": + if err := appendStringToFile(path, content); err != nil { + msg := "failed to append to file; error: " + err.Error() + logger.Error(msg) + return []byte(msg) + } + default: + msg := "invalid mode; use 'overwrite' or 'append'" + logger.Error(msg) + return []byte(msg) + } + + msg := "file updated successfully at " + path + return []byte(msg) +} + +func fileDelete(args map[string]string) []byte { + path, ok := args["path"] + if !ok || path == "" { + msg := "path not provided to file_delete tool" + logger.Error(msg) + return []byte(msg) + } + + if err := removeFile(path); err != nil { + msg := "failed to delete file; error: " + err.Error() + logger.Error(msg) + return []byte(msg) + } + + msg := "file deleted successfully at " + path + return []byte(msg) +} + +func fileMove(args map[string]string) []byte { + src, ok := args["src"] + if !ok || src == "" { + msg := "source path not provided to file_move tool" + logger.Error(msg) + return []byte(msg) + } + + dst, ok := args["dst"] + if !ok || dst == "" { + msg := "destination path not provided to file_move tool" + logger.Error(msg) + return []byte(msg) + } + + if err := moveFile(src, dst); err != nil { + msg := "failed to move file; error: " + err.Error() + logger.Error(msg) + return []byte(msg) + } + + msg := fmt.Sprintf("file moved successfully from %s to %s", src, dst) + return []byte(msg) +} + +func fileCopy(args map[string]string) []byte { + src, ok := args["src"] + if !ok || src == "" { + msg := "source path not provided to file_copy tool" + logger.Error(msg) + return []byte(msg) + } + + dst, ok := args["dst"] + if !ok || dst == "" { + msg := "destination path not provided to file_copy tool" + logger.Error(msg) + return []byte(msg) + } + + if err := copyFile(src, dst); err != nil { + msg := "failed to copy file; error: " + err.Error() + logger.Error(msg) + return []byte(msg) + } + + msg := fmt.Sprintf("file copied successfully from %s to %s", src, dst) + return []byte(msg) +} + +func fileList(args map[string]string) []byte { + path, ok := args["path"] + if !ok || path == "" { + path = "." // default to current directory + } + + files, err := listDirectory(path) + if err != nil { + msg := "failed to list directory; error: " + err.Error() + logger.Error(msg) + return []byte(msg) + } + + result := map[string]interface{}{ + "directory": path, + "files": files, + } + jsonResult, err := json.Marshal(result) + if err != nil { + msg := "failed to marshal result; error: " + err.Error() + logger.Error(msg) + return []byte(msg) + } + + return jsonResult +} + +// Helper functions for file operations + +func readStringFromFile(filename string) (string, error) { + data, err := os.ReadFile(filename) + if err != nil { + return "", err + } + return string(data), nil +} + +func writeStringToFile(filename string, data string) error { + return os.WriteFile(filename, []byte(data), 0644) +} + +func appendStringToFile(filename string, data string) error { + file, err := os.OpenFile(filename, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) + if err != nil { + return err + } + defer file.Close() + + _, err = file.WriteString(data) + return err +} + +func removeFile(filename string) error { + return os.Remove(filename) +} + +func moveFile(src, dst string) error { + // First try with os.Rename (works within same filesystem) + if err := os.Rename(src, dst); err == nil { + return nil + } + // If that fails (e.g., cross-filesystem), copy and delete + return copyAndRemove(src, dst) +} + +func copyFile(src, dst string) error { + srcFile, err := os.Open(src) + if err != nil { + return err + } + defer srcFile.Close() + + dstFile, err := os.Create(dst) + if err != nil { + return err + } + defer dstFile.Close() + + _, err = io.Copy(dstFile, srcFile) + return err +} + +func copyAndRemove(src, dst string) error { + // Copy the file + if err := copyFile(src, dst); err != nil { + return err + } + // Remove the source file + return os.Remove(src) +} + +func listDirectory(path string) ([]string, error) { + entries, err := os.ReadDir(path) + if err != nil { + return nil, err + } + + var files []string + for _, entry := range entries { + if entry.IsDir() { + files = append(files, entry.Name()+"/") // Add "/" to indicate directory + } else { + files = append(files, entry.Name()) + } + } + + return files, nil +} + +// Command Execution Tool + +func executeCommand(args map[string]string) []byte { + command, ok := args["command"] + if !ok || command == "" { + msg := "command not provided to execute_command tool" + logger.Error(msg) + return []byte(msg) + } + + if !isCommandAllowed(command) { + msg := fmt.Sprintf("command '%s' is not allowed", command) + logger.Error(msg) + return []byte(msg) + } + + // Get arguments - handle both single arg and multiple args + var cmdArgs []string + if args["args"] != "" { + // If args is provided as a single string, split by spaces + cmdArgs = strings.Fields(args["args"]) + } else { + // If individual args are provided, collect them + argNum := 1 + for { + argKey := fmt.Sprintf("arg%d", argNum) + if argValue, exists := args[argKey]; exists && argValue != "" { + cmdArgs = append(cmdArgs, argValue) + } else { + break + } + argNum++ + } + } + + // Execute with timeout for safety + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + defer cancel() + cmd := exec.CommandContext(ctx, command, cmdArgs...) + + output, err := cmd.CombinedOutput() + if err != nil { + msg := fmt.Sprintf("command '%s' failed; error: %v; output: %s", command, err, string(output)) + logger.Error(msg) + return []byte(msg) + } + + return output +} + +// Helper functions for command execution + +func isCommandAllowed(command string) bool { + allowedCommands := map[string]bool{ + "grep": true, + "sed": true, + "awk": true, + "find": true, + "cat": true, + "head": true, + "tail": true, + "sort": true, + "uniq": true, + "wc": true, + "ls": true, + "echo": true, + "cut": true, + "tr": true, + "cp": true, + "mv": true, + "rm": true, + "mkdir": true, + "rmdir": true, + } + return allowedCommands[command] +} + type fnSig func(map[string]string) []byte var fnMap = map[string]fnSig{ - "recall": recall, - "recall_topics": recallTopics, - "memorise": memorise, - "websearch": websearch, + "recall": recall, + "recall_topics": recallTopics, + "memorise": memorise, + "websearch": websearch, + "file_create": fileCreate, + "file_read": fileRead, + "file_update": fileUpdate, + "file_delete": fileDelete, + "file_move": fileMove, + "file_copy": fileCopy, + "file_list": fileList, + "execute_command": executeCommand, } // openai style def @@ -257,4 +617,180 @@ var baseTools = []models.Tool{ }, }, }, + + // file_create + models.Tool{ + Type: "function", + Function: models.ToolFunc{ + Name: "file_create", + Description: "Create a new file with specified content. Use when you need to create a new file.", + Parameters: models.ToolFuncParams{ + Type: "object", + Required: []string{"path"}, + Properties: map[string]models.ToolArgProps{ + "path": models.ToolArgProps{ + Type: "string", + Description: "path where the file should be created", + }, + "content": models.ToolArgProps{ + Type: "string", + Description: "content to write to the file (optional, defaults to empty string)", + }, + }, + }, + }, + }, + + // file_read + models.Tool{ + Type: "function", + Function: models.ToolFunc{ + Name: "file_read", + Description: "Read the content of a file. Use when you need to see the content of a file.", + Parameters: models.ToolFuncParams{ + Type: "object", + Required: []string{"path"}, + Properties: map[string]models.ToolArgProps{ + "path": models.ToolArgProps{ + Type: "string", + Description: "path of the file to read", + }, + }, + }, + }, + }, + + // file_update + models.Tool{ + Type: "function", + Function: models.ToolFunc{ + Name: "file_update", + Description: "Update a file with new content. Use when you want to modify an existing file (overwrite or append).", + Parameters: models.ToolFuncParams{ + Type: "object", + Required: []string{"path", "content"}, + Properties: map[string]models.ToolArgProps{ + "path": models.ToolArgProps{ + Type: "string", + Description: "path of the file to update", + }, + "content": models.ToolArgProps{ + Type: "string", + Description: "content to write to the file", + }, + "mode": models.ToolArgProps{ + Type: "string", + Description: "update mode: 'overwrite' to replace entire file content, 'append' to add to the end (defaults to 'overwrite')", + }, + }, + }, + }, + }, + + // file_delete + models.Tool{ + Type: "function", + Function: models.ToolFunc{ + Name: "file_delete", + Description: "Delete a file. Use when you need to remove a file.", + Parameters: models.ToolFuncParams{ + Type: "object", + Required: []string{"path"}, + Properties: map[string]models.ToolArgProps{ + "path": models.ToolArgProps{ + Type: "string", + Description: "path of the file to delete", + }, + }, + }, + }, + }, + + // file_move + models.Tool{ + Type: "function", + Function: models.ToolFunc{ + Name: "file_move", + Description: "Move a file from one location to another. Use when you need to relocate a file.", + Parameters: models.ToolFuncParams{ + Type: "object", + Required: []string{"src", "dst"}, + Properties: map[string]models.ToolArgProps{ + "src": models.ToolArgProps{ + Type: "string", + Description: "source path of the file to move", + }, + "dst": models.ToolArgProps{ + Type: "string", + Description: "destination path where the file should be moved", + }, + }, + }, + }, + }, + + // file_copy + models.Tool{ + Type: "function", + Function: models.ToolFunc{ + Name: "file_copy", + Description: "Copy a file from one location to another. Use when you need to duplicate a file.", + Parameters: models.ToolFuncParams{ + Type: "object", + Required: []string{"src", "dst"}, + Properties: map[string]models.ToolArgProps{ + "src": models.ToolArgProps{ + Type: "string", + Description: "source path of the file to copy", + }, + "dst": models.ToolArgProps{ + Type: "string", + Description: "destination path where the file should be copied", + }, + }, + }, + }, + }, + + // file_list + models.Tool{ + Type: "function", + Function: models.ToolFunc{ + Name: "file_list", + Description: "List files and directories in a directory. Use when you need to see what files are in a directory.", + Parameters: models.ToolFuncParams{ + Type: "object", + Required: []string{}, + Properties: map[string]models.ToolArgProps{ + "path": models.ToolArgProps{ + Type: "string", + Description: "path of the directory to list (optional, defaults to current directory)", + }, + }, + }, + }, + }, + + // execute_command + models.Tool{ + Type: "function", + Function: models.ToolFunc{ + Name: "execute_command", + Description: "Execute a shell command safely. Use when you need to run system commands like grep, sed, awk, cat, head, tail, find, etc.", + Parameters: models.ToolFuncParams{ + Type: "object", + Required: []string{"command"}, + Properties: map[string]models.ToolArgProps{ + "command": models.ToolArgProps{ + Type: "string", + Description: "command to execute (only commands from whitelist are allowed: grep, sed, awk, cat, head, tail, find, etc.)", + }, + "args": models.ToolArgProps{ + Type: "string", + Description: "command arguments as a single string (e.g., 'pattern file.txt')", + }, + }, + }, + }, + }, } -- cgit v1.2.3 From 05cf4b87497273b6a4c984d6ea4a9fb9a407924a Mon Sep 17 00:00:00 2001 From: Grail Finder Date: Wed, 26 Nov 2025 21:28:50 +0300 Subject: Chore: tool description update --- tools.go | 256 +++++++++++++++++++++++++++++++-------------------------------- 1 file changed, 128 insertions(+), 128 deletions(-) (limited to 'tools.go') diff --git a/tools.go b/tools.go index 751a4a4..37c874b 100644 --- a/tools.go +++ b/tools.go @@ -6,13 +6,13 @@ import ( "fmt" "gf-lt/extra" "gf-lt/models" + "io" + "os" + "os/exec" "regexp" "strconv" "strings" "time" - "os" - "io" - "os/exec" ) var ( @@ -367,160 +367,160 @@ func fileList(args map[string]string) []byte { // Helper functions for file operations func readStringFromFile(filename string) (string, error) { - data, err := os.ReadFile(filename) - if err != nil { - return "", err - } - return string(data), nil + data, err := os.ReadFile(filename) + if err != nil { + return "", err + } + return string(data), nil } func writeStringToFile(filename string, data string) error { - return os.WriteFile(filename, []byte(data), 0644) + return os.WriteFile(filename, []byte(data), 0644) } func appendStringToFile(filename string, data string) error { - file, err := os.OpenFile(filename, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) - if err != nil { - return err - } - defer file.Close() - - _, err = file.WriteString(data) - return err + file, err := os.OpenFile(filename, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) + if err != nil { + return err + } + defer file.Close() + + _, err = file.WriteString(data) + return err } func removeFile(filename string) error { - return os.Remove(filename) + return os.Remove(filename) } func moveFile(src, dst string) error { - // First try with os.Rename (works within same filesystem) - if err := os.Rename(src, dst); err == nil { - return nil - } - // If that fails (e.g., cross-filesystem), copy and delete - return copyAndRemove(src, dst) + // First try with os.Rename (works within same filesystem) + if err := os.Rename(src, dst); err == nil { + return nil + } + // If that fails (e.g., cross-filesystem), copy and delete + return copyAndRemove(src, dst) } func copyFile(src, dst string) error { - srcFile, err := os.Open(src) - if err != nil { - return err - } - defer srcFile.Close() - - dstFile, err := os.Create(dst) - if err != nil { - return err - } - defer dstFile.Close() - - _, err = io.Copy(dstFile, srcFile) - return err + srcFile, err := os.Open(src) + if err != nil { + return err + } + defer srcFile.Close() + + dstFile, err := os.Create(dst) + if err != nil { + return err + } + defer dstFile.Close() + + _, err = io.Copy(dstFile, srcFile) + return err } func copyAndRemove(src, dst string) error { - // Copy the file - if err := copyFile(src, dst); err != nil { - return err - } - // Remove the source file - return os.Remove(src) + // Copy the file + if err := copyFile(src, dst); err != nil { + return err + } + // Remove the source file + return os.Remove(src) } func listDirectory(path string) ([]string, error) { - entries, err := os.ReadDir(path) - if err != nil { - return nil, err - } - - var files []string - for _, entry := range entries { - if entry.IsDir() { - files = append(files, entry.Name()+"/") // Add "/" to indicate directory - } else { - files = append(files, entry.Name()) - } - } - - return files, nil + entries, err := os.ReadDir(path) + if err != nil { + return nil, err + } + + var files []string + for _, entry := range entries { + if entry.IsDir() { + files = append(files, entry.Name()+"/") // Add "/" to indicate directory + } else { + files = append(files, entry.Name()) + } + } + + return files, nil } // Command Execution Tool func executeCommand(args map[string]string) []byte { - command, ok := args["command"] - if !ok || command == "" { - msg := "command not provided to execute_command tool" - logger.Error(msg) - return []byte(msg) - } - - if !isCommandAllowed(command) { - msg := fmt.Sprintf("command '%s' is not allowed", command) - logger.Error(msg) - return []byte(msg) - } - - // Get arguments - handle both single arg and multiple args - var cmdArgs []string - if args["args"] != "" { - // If args is provided as a single string, split by spaces - cmdArgs = strings.Fields(args["args"]) - } else { - // If individual args are provided, collect them - argNum := 1 - for { - argKey := fmt.Sprintf("arg%d", argNum) - if argValue, exists := args[argKey]; exists && argValue != "" { - cmdArgs = append(cmdArgs, argValue) - } else { - break - } - argNum++ - } - } - - // Execute with timeout for safety - ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) - defer cancel() - cmd := exec.CommandContext(ctx, command, cmdArgs...) - - output, err := cmd.CombinedOutput() - if err != nil { - msg := fmt.Sprintf("command '%s' failed; error: %v; output: %s", command, err, string(output)) - logger.Error(msg) - return []byte(msg) - } - - return output + command, ok := args["command"] + if !ok || command == "" { + msg := "command not provided to execute_command tool" + logger.Error(msg) + return []byte(msg) + } + + if !isCommandAllowed(command) { + msg := fmt.Sprintf("command '%s' is not allowed", command) + logger.Error(msg) + return []byte(msg) + } + + // Get arguments - handle both single arg and multiple args + var cmdArgs []string + if args["args"] != "" { + // If args is provided as a single string, split by spaces + cmdArgs = strings.Fields(args["args"]) + } else { + // If individual args are provided, collect them + argNum := 1 + for { + argKey := fmt.Sprintf("arg%d", argNum) + if argValue, exists := args[argKey]; exists && argValue != "" { + cmdArgs = append(cmdArgs, argValue) + } else { + break + } + argNum++ + } + } + + // Execute with timeout for safety + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + defer cancel() + cmd := exec.CommandContext(ctx, command, cmdArgs...) + + output, err := cmd.CombinedOutput() + if err != nil { + msg := fmt.Sprintf("command '%s' failed; error: %v; output: %s", command, err, string(output)) + logger.Error(msg) + return []byte(msg) + } + + return output } // Helper functions for command execution func isCommandAllowed(command string) bool { - allowedCommands := map[string]bool{ - "grep": true, - "sed": true, - "awk": true, - "find": true, - "cat": true, - "head": true, - "tail": true, - "sort": true, - "uniq": true, - "wc": true, - "ls": true, - "echo": true, - "cut": true, - "tr": true, - "cp": true, - "mv": true, - "rm": true, - "mkdir": true, - "rmdir": true, - } - return allowedCommands[command] + allowedCommands := map[string]bool{ + "grep": true, + "sed": true, + "awk": true, + "find": true, + "cat": true, + "head": true, + "tail": true, + "sort": true, + "uniq": true, + "wc": true, + "ls": true, + "echo": true, + "cut": true, + "tr": true, + "cp": true, + "mv": true, + "rm": true, + "mkdir": true, + "rmdir": true, + } + return allowedCommands[command] } type fnSig func(map[string]string) []byte @@ -776,14 +776,14 @@ var baseTools = []models.Tool{ Type: "function", Function: models.ToolFunc{ Name: "execute_command", - Description: "Execute a shell command safely. Use when you need to run system commands like grep, sed, awk, cat, head, tail, find, etc.", + Description: "Execute a shell command safely. Use when you need to run system commands like grep sed awk find cat head tail sort uniq wc ls echo cut tr cp mv rm mkdir rmdir", Parameters: models.ToolFuncParams{ Type: "object", Required: []string{"command"}, Properties: map[string]models.ToolArgProps{ "command": models.ToolArgProps{ Type: "string", - Description: "command to execute (only commands from whitelist are allowed: grep, sed, awk, cat, head, tail, find, etc.)", + Description: "command to execute (only commands from whitelist are allowed: grep sed awk find cat head tail sort uniq wc ls echo cut tr cp mv rm mkdir rmdir", }, "args": models.ToolArgProps{ Type: "string", -- cgit v1.2.3 From 4d3935c28b578f747941f8742365864c6b09ba7f Mon Sep 17 00:00:00 2001 From: Grail Finder Date: Thu, 27 Nov 2025 12:22:32 +0300 Subject: Enha: more shell tools --- tools.go | 46 ++++++++++++++++++++++++---------------------- 1 file changed, 24 insertions(+), 22 deletions(-) (limited to 'tools.go') diff --git a/tools.go b/tools.go index 37c874b..fd422f5 100644 --- a/tools.go +++ b/tools.go @@ -500,25 +500,27 @@ func executeCommand(args map[string]string) []byte { func isCommandAllowed(command string) bool { allowedCommands := map[string]bool{ - "grep": true, - "sed": true, - "awk": true, - "find": true, - "cat": true, - "head": true, - "tail": true, - "sort": true, - "uniq": true, - "wc": true, - "ls": true, - "echo": true, - "cut": true, - "tr": true, - "cp": true, - "mv": true, - "rm": true, - "mkdir": true, - "rmdir": true, + "grep": true, + "sed": true, + "awk": true, + "find": true, + "cat": true, + "head": true, + "tail": true, + "sort": true, + "uniq": true, + "wc": true, + "ls": true, + "echo": true, + "cut": true, + "tr": true, + "cp": true, + "mv": true, + "rm": true, + "mkdir": true, + "rmdir": true, + "pwd": true, + "realpath": true, } return allowedCommands[command] } @@ -776,18 +778,18 @@ var baseTools = []models.Tool{ Type: "function", Function: models.ToolFunc{ Name: "execute_command", - Description: "Execute a shell command safely. Use when you need to run system commands like grep sed awk find cat head tail sort uniq wc ls echo cut tr cp mv rm mkdir rmdir", + Description: "Execute a shell command safely. Use when you need to run system commands like grep sed awk find cat head tail sort uniq wc ls echo cut tr cp mv rm mkdir rmdir pwd realpath", Parameters: models.ToolFuncParams{ Type: "object", Required: []string{"command"}, Properties: map[string]models.ToolArgProps{ "command": models.ToolArgProps{ Type: "string", - Description: "command to execute (only commands from whitelist are allowed: grep sed awk find cat head tail sort uniq wc ls echo cut tr cp mv rm mkdir rmdir", + Description: "command to execute (only commands from whitelist are allowed: grep sed awk find cat head tail sort uniq wc ls echo cut tr cp mv rm mkdir rmdir pwd realpath", }, "args": models.ToolArgProps{ Type: "string", - Description: "command arguments as a single string (e.g., 'pattern file.txt')", + Description: "command arguments as a single string (e.g., '-la {path}')", }, }, }, -- cgit v1.2.3 From 7bca1e3f2883f8f9da8c8bd93c95d1dbfbf4b26b Mon Sep 17 00:00:00 2001 From: Grail Finder Date: Thu, 27 Nov 2025 12:39:41 +0300 Subject: Enha: remove non POSIX command 'realpath' --- tools.go | 45 ++++++++++++++++++++++----------------------- 1 file changed, 22 insertions(+), 23 deletions(-) (limited to 'tools.go') diff --git a/tools.go b/tools.go index fd422f5..eb9713e 100644 --- a/tools.go +++ b/tools.go @@ -500,27 +500,26 @@ func executeCommand(args map[string]string) []byte { func isCommandAllowed(command string) bool { allowedCommands := map[string]bool{ - "grep": true, - "sed": true, - "awk": true, - "find": true, - "cat": true, - "head": true, - "tail": true, - "sort": true, - "uniq": true, - "wc": true, - "ls": true, - "echo": true, - "cut": true, - "tr": true, - "cp": true, - "mv": true, - "rm": true, - "mkdir": true, - "rmdir": true, - "pwd": true, - "realpath": true, + "grep": true, + "sed": true, + "awk": true, + "find": true, + "cat": true, + "head": true, + "tail": true, + "sort": true, + "uniq": true, + "wc": true, + "ls": true, + "echo": true, + "cut": true, + "tr": true, + "cp": true, + "mv": true, + "rm": true, + "mkdir": true, + "rmdir": true, + "pwd": true, } return allowedCommands[command] } @@ -778,14 +777,14 @@ var baseTools = []models.Tool{ Type: "function", Function: models.ToolFunc{ Name: "execute_command", - Description: "Execute a shell command safely. Use when you need to run system commands like grep sed awk find cat head tail sort uniq wc ls echo cut tr cp mv rm mkdir rmdir pwd realpath", + Description: "Execute a shell command safely. Use when you need to run system commands like grep sed awk find cat head tail sort uniq wc ls echo cut tr cp mv rm mkdir rmdir pwd", Parameters: models.ToolFuncParams{ Type: "object", Required: []string{"command"}, Properties: map[string]models.ToolArgProps{ "command": models.ToolArgProps{ Type: "string", - Description: "command to execute (only commands from whitelist are allowed: grep sed awk find cat head tail sort uniq wc ls echo cut tr cp mv rm mkdir rmdir pwd realpath", + Description: "command to execute (only commands from whitelist are allowed: grep sed awk find cat head tail sort uniq wc ls echo cut tr cp mv rm mkdir rmdir pwd", }, "args": models.ToolArgProps{ Type: "string", -- cgit v1.2.3 From 2ff954f7c9895458768c3d6b776d4eb888d54f70 Mon Sep 17 00:00:00 2001 From: Grail Finder Date: Thu, 27 Nov 2025 20:54:51 +0300 Subject: Feat: failed tool call is send to llm --- tools.go | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'tools.go') diff --git a/tools.go b/tools.go index eb9713e..a9c03da 100644 --- a/tools.go +++ b/tools.go @@ -228,10 +228,10 @@ func fileRead(args map[string]string) []byte { return jsonResult } -func fileUpdate(args map[string]string) []byte { +func fileWrite(args map[string]string) []byte { path, ok := args["path"] if !ok || path == "" { - msg := "path not provided to file_update tool" + msg := "path not provided to file_write tool" logger.Error(msg) return []byte(msg) } @@ -249,7 +249,7 @@ func fileUpdate(args map[string]string) []byte { switch mode { case "overwrite": if err := writeStringToFile(path, content); err != nil { - msg := "failed to update file; error: " + err.Error() + msg := "failed to write to file; error: " + err.Error() logger.Error(msg) return []byte(msg) } @@ -265,7 +265,7 @@ func fileUpdate(args map[string]string) []byte { return []byte(msg) } - msg := "file updated successfully at " + path + msg := "file written successfully at " + path return []byte(msg) } @@ -533,7 +533,7 @@ var fnMap = map[string]fnSig{ "websearch": websearch, "file_create": fileCreate, "file_read": fileRead, - "file_update": fileUpdate, + "file_write": fileWrite, "file_delete": fileDelete, "file_move": fileMove, "file_copy": fileCopy, @@ -661,19 +661,19 @@ var baseTools = []models.Tool{ }, }, - // file_update + // file_write models.Tool{ Type: "function", Function: models.ToolFunc{ - Name: "file_update", - Description: "Update a file with new content. Use when you want to modify an existing file (overwrite or append).", + Name: "file_write", + Description: "Write content to a file. Use when you want to create or modify a file (overwrite or append).", Parameters: models.ToolFuncParams{ Type: "object", Required: []string{"path", "content"}, Properties: map[string]models.ToolArgProps{ "path": models.ToolArgProps{ Type: "string", - Description: "path of the file to update", + Description: "path of the file to write to", }, "content": models.ToolArgProps{ Type: "string", @@ -681,7 +681,7 @@ var baseTools = []models.Tool{ }, "mode": models.ToolArgProps{ Type: "string", - Description: "update mode: 'overwrite' to replace entire file content, 'append' to add to the end (defaults to 'overwrite')", + Description: "write mode: 'overwrite' to replace entire file content, 'append' to add to the end (defaults to 'overwrite')", }, }, }, -- cgit v1.2.3 From f5aab322afbf337d797a62f24cf85ef7766a96bb Mon Sep 17 00:00:00 2001 From: Grail Finder Date: Fri, 28 Nov 2025 12:39:59 +0300 Subject: Feat: /completion tools update --- tools.go | 49 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 47 insertions(+), 2 deletions(-) (limited to 'tools.go') diff --git a/tools.go b/tools.go index a9c03da..fda8750 100644 --- a/tools.go +++ b/tools.go @@ -39,13 +39,58 @@ Your current tools: }, { "name":"memorise", -"args": ["topic", "info"], -"when_to_use": "when asked to memorise something" +"args": ["topic", "data"], +"when_to_use": "when asked to memorise information under a topic" }, { "name":"recall_topics", "args": [], "when_to_use": "to see what topics are saved in memory" +}, +{ +"name":"websearch", +"args": ["query", "limit"], +"when_to_use": "when asked to search the web for information; limit is optional (default 3)" +}, +{ +"name":"file_create", +"args": ["path", "content"], +"when_to_use": "when asked to create a new file with optional content" +}, +{ +"name":"file_read", +"args": ["path"], +"when_to_use": "when asked to read the content of a file" +}, +{ +"name":"file_write", +"args": ["path", "content", "mode"], +"when_to_use": "when asked to write content to a file; mode is optional (overwrite or append, default: overwrite)" +}, +{ +"name":"file_delete", +"args": ["path"], +"when_to_use": "when asked to delete a file" +}, +{ +"name":"file_move", +"args": ["src", "dst"], +"when_to_use": "when asked to move a file from source to destination" +}, +{ +"name":"file_copy", +"args": ["src", "dst"], +"when_to_use": "when asked to copy a file from source to destination" +}, +{ +"name":"file_list", +"args": ["path"], +"when_to_use": "when asked to list files in a directory; path is optional (default: current directory)" +}, +{ +"name":"execute_command", +"args": ["command", "args"], +"when_to_use": "when asked to execute a system command; args is optional" } ] -- cgit v1.2.3