Fix: view_img, exec commands
This commit is contained in:
27
tools.go
27
tools.go
@@ -518,9 +518,18 @@ func runCmd(args map[string]string) []byte {
|
||||
case "capture_and_view", "screenshot_and_view":
|
||||
// capture and view screenshot
|
||||
return captureWindowAndView(args)
|
||||
case "view_img":
|
||||
// view_img <file> - view image for multimodal
|
||||
return []byte(tools.FsViewImg(rest, ""))
|
||||
case "browser":
|
||||
// browser <action> [args...] - Playwright browser automation
|
||||
return runBrowserCommand(rest, args)
|
||||
case "mkdir", "ls", "cat", "pwd", "cd", "cp", "mv", "rm", "sed", "grep", "head", "tail", "wc", "sort", "uniq", "echo", "time", "stat", "go", "find", "file":
|
||||
// File operations and shell commands - use ExecChain which has whitelist
|
||||
return executeCommand(args)
|
||||
case "git":
|
||||
// git has its own whitelist in FsGit
|
||||
return []byte(tools.FsGit(rest, ""))
|
||||
default:
|
||||
// Unknown subcommand - return help to remind user of available commands
|
||||
return []byte(getHelp(nil))
|
||||
@@ -667,13 +676,13 @@ func getHelp(args []string) string {
|
||||
# File operations
|
||||
ls [path] - list files in directory
|
||||
cat <file> - read file content
|
||||
see <file> - view image file
|
||||
view_img <file> - view image file
|
||||
write <file> - write content to file
|
||||
stat <file> - get file info
|
||||
rm <file> - delete file
|
||||
cp <src> <dst> - copy file
|
||||
mv <src> <dst> - move/rename file
|
||||
mkdir <dir> - create directory
|
||||
mkdir [-p] <dir> - create directory (use full path)
|
||||
pwd - print working directory
|
||||
cd <dir> - change directory
|
||||
sed 's/old/new/[g]' [file] - text replacement
|
||||
@@ -747,12 +756,12 @@ Use: run "command" to execute.`
|
||||
Examples:
|
||||
run "cat readme.md"
|
||||
run "cat -b image.png" (base64 output)`
|
||||
case "see":
|
||||
return `see <image-file>
|
||||
case "view_img":
|
||||
return `view_img <image-file>
|
||||
View an image file for multimodal analysis.
|
||||
Supports: png, jpg, jpeg, gif, webp, svg
|
||||
Example:
|
||||
run "see screenshot.png"`
|
||||
run "view_img screenshot.png"`
|
||||
case "write":
|
||||
return `write <file> [content]
|
||||
Write content to a file.
|
||||
@@ -812,6 +821,14 @@ Use: run "command" to execute.`
|
||||
Print working directory.
|
||||
Example:
|
||||
run "pwd"`
|
||||
case "mkdir":
|
||||
return `mkdir [-p] <directory>
|
||||
Create a directory (use full path).
|
||||
Options:
|
||||
-p, --parents create parent directories as needed
|
||||
Examples:
|
||||
run "mkdir /full/path/myfolder"
|
||||
run "mkdir -p /full/path/to/nested/folder"`
|
||||
case "sed":
|
||||
return `sed 's/old/new/[g]' [file]
|
||||
Stream editor for text replacement.
|
||||
|
||||
@@ -239,7 +239,12 @@ func execBuiltin(name string, args []string, stdin string) string {
|
||||
}
|
||||
return ""
|
||||
}
|
||||
data, err := os.ReadFile(args[0])
|
||||
path := args[0]
|
||||
abs := path
|
||||
if !filepath.IsAbs(path) {
|
||||
abs = filepath.Join(fsRootDir, path)
|
||||
}
|
||||
data, err := os.ReadFile(abs)
|
||||
if err != nil {
|
||||
return fmt.Sprintf("[error] cat: %v", err)
|
||||
}
|
||||
@@ -266,6 +271,76 @@ func execBuiltin(name string, args []string, stdin string) string {
|
||||
}
|
||||
fsRootDir = abs
|
||||
return fmt.Sprintf("Changed directory to: %s", fsRootDir)
|
||||
case "mkdir":
|
||||
if len(args) == 0 {
|
||||
return "[error] usage: mkdir [-p] <dir>"
|
||||
}
|
||||
createParents := false
|
||||
var dirPath string
|
||||
for _, a := range args {
|
||||
if a == "-p" || a == "--parents" {
|
||||
createParents = true
|
||||
} else if dirPath == "" {
|
||||
dirPath = a
|
||||
}
|
||||
}
|
||||
if dirPath == "" {
|
||||
return "[error] usage: mkdir [-p] <dir>"
|
||||
}
|
||||
abs := dirPath
|
||||
if !filepath.IsAbs(dirPath) {
|
||||
abs = filepath.Join(fsRootDir, dirPath)
|
||||
}
|
||||
abs = filepath.Clean(abs)
|
||||
var mkdirFunc func(string, os.FileMode) error
|
||||
if createParents {
|
||||
mkdirFunc = os.MkdirAll
|
||||
} else {
|
||||
mkdirFunc = os.Mkdir
|
||||
}
|
||||
if err := mkdirFunc(abs, 0o755); err != nil {
|
||||
return fmt.Sprintf("[error] mkdir: %v", err)
|
||||
}
|
||||
if createParents {
|
||||
return fmt.Sprintf("Created %s (with parents)", dirPath)
|
||||
}
|
||||
return fmt.Sprintf("Created %s", dirPath)
|
||||
case "ls":
|
||||
dir := "."
|
||||
for _, a := range args {
|
||||
if !strings.HasPrefix(a, "-") {
|
||||
dir = a
|
||||
break
|
||||
}
|
||||
}
|
||||
abs := dir
|
||||
if !filepath.IsAbs(dir) {
|
||||
abs = filepath.Join(fsRootDir, dir)
|
||||
}
|
||||
entries, err := os.ReadDir(abs)
|
||||
if err != nil {
|
||||
return fmt.Sprintf("[error] ls: %v", err)
|
||||
}
|
||||
var out strings.Builder
|
||||
for _, e := range entries {
|
||||
info, _ := e.Info()
|
||||
if e.IsDir() {
|
||||
fmt.Fprintf(&out, "d %-8s %s/\n", "-", e.Name())
|
||||
} else if info != nil {
|
||||
size := info.Size()
|
||||
sizeStr := fmt.Sprintf("%d", size)
|
||||
if size > 1024 {
|
||||
sizeStr = fmt.Sprintf("%.1fKB", float64(size)/1024)
|
||||
}
|
||||
fmt.Fprintf(&out, "f %-8s %s\n", sizeStr, e.Name())
|
||||
} else {
|
||||
fmt.Fprintf(&out, "f %-8s %s\n", "?", e.Name())
|
||||
}
|
||||
}
|
||||
if out.Len() == 0 {
|
||||
return "(empty directory)"
|
||||
}
|
||||
return strings.TrimRight(out.String(), "\n")
|
||||
case "go":
|
||||
// Allow all go subcommands
|
||||
if len(args) == 0 {
|
||||
|
||||
76
tools/fs.go
76
tools/fs.go
@@ -2,7 +2,9 @@ package tools
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"gf-lt/models"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
@@ -155,27 +157,53 @@ func FsCat(args []string, stdin string) string {
|
||||
return string(data)
|
||||
}
|
||||
|
||||
func FsSee(args []string, stdin string) string {
|
||||
func FsViewImg(args []string, stdin string) string {
|
||||
if len(args) == 0 {
|
||||
return "[error] usage: see <image-path>"
|
||||
return "[error] usage: view_img <image-path>"
|
||||
}
|
||||
path := args[0]
|
||||
|
||||
abs, err := resolvePath(path)
|
||||
var abs string
|
||||
if filepath.IsAbs(path) {
|
||||
abs = path
|
||||
} else {
|
||||
var err error
|
||||
abs, err = resolvePath(path)
|
||||
if err != nil {
|
||||
return fmt.Sprintf("[error] %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
info, err := os.Stat(abs)
|
||||
if err != nil {
|
||||
return fmt.Sprintf("[error] see: %v", err)
|
||||
if _, err := os.Stat(abs); err != nil {
|
||||
return fmt.Sprintf("[error] view_img: %v", err)
|
||||
}
|
||||
|
||||
if !IsImageFile(path) {
|
||||
return fmt.Sprintf("[error] not an image file: %s (use cat to read text files)", path)
|
||||
}
|
||||
|
||||
return fmt.Sprintf("Image: %s (%s)\n", path, humanSize(info.Size()), abs)
|
||||
dataURL, err := models.CreateImageURLFromPath(abs)
|
||||
if err != nil {
|
||||
return fmt.Sprintf("[error] view_img: %v", err)
|
||||
}
|
||||
|
||||
result := models.MultimodalToolResp{
|
||||
Type: "multimodal_content",
|
||||
Parts: []map[string]string{
|
||||
{"type": "text", "text": "Image: " + path},
|
||||
{"type": "image_url", "url": dataURL},
|
||||
},
|
||||
}
|
||||
jsonResult, err := json.Marshal(result)
|
||||
if err != nil {
|
||||
return fmt.Sprintf("[error] view_img: %v", err)
|
||||
}
|
||||
return string(jsonResult)
|
||||
}
|
||||
|
||||
// FsSee is deprecated, use FsViewImg
|
||||
func FsSee(args []string, stdin string) string {
|
||||
return FsViewImg(args, stdin)
|
||||
}
|
||||
|
||||
func FsWrite(args []string, stdin string) string {
|
||||
@@ -352,18 +380,44 @@ func FsMv(args []string, stdin string) string {
|
||||
|
||||
func FsMkdir(args []string, stdin string) string {
|
||||
if len(args) == 0 {
|
||||
return "[error] usage: mkdir <dir>"
|
||||
return "[error] usage: mkdir [-p] <dir>"
|
||||
}
|
||||
|
||||
abs, err := resolvePath(args[0])
|
||||
createParents := false
|
||||
var dirPath string
|
||||
|
||||
for _, a := range args {
|
||||
if a == "-p" || a == "--parents" {
|
||||
createParents = true
|
||||
} else if dirPath == "" {
|
||||
dirPath = a
|
||||
}
|
||||
}
|
||||
|
||||
if dirPath == "" {
|
||||
return "[error] usage: mkdir [-p] <dir>"
|
||||
}
|
||||
|
||||
abs, err := resolvePath(dirPath)
|
||||
if err != nil {
|
||||
return fmt.Sprintf("[error] %v", err)
|
||||
}
|
||||
|
||||
if err := os.MkdirAll(abs, 0o755); err != nil {
|
||||
var mkdirFunc func(string, os.FileMode) error
|
||||
if createParents {
|
||||
mkdirFunc = os.MkdirAll
|
||||
} else {
|
||||
mkdirFunc = os.Mkdir
|
||||
}
|
||||
|
||||
if err := mkdirFunc(abs, 0o755); err != nil {
|
||||
return fmt.Sprintf("[error] mkdir: %v", err)
|
||||
}
|
||||
return fmt.Sprintf("Created %s", args[0])
|
||||
|
||||
if createParents {
|
||||
return fmt.Sprintf("Created %s (with parents)", dirPath)
|
||||
}
|
||||
return fmt.Sprintf("Created %s", dirPath)
|
||||
}
|
||||
|
||||
// Text processing commands
|
||||
|
||||
Reference in New Issue
Block a user