a431d1ec95
Add OpenAI-compatible providers, TUI, slash commands, and model switching. Add local file tools plus optional yolo shell execution. Document config, usage, and development workflow.
81 lines
2.0 KiB
Go
81 lines
2.0 KiB
Go
package tools
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"os"
|
|
"os/exec"
|
|
"strings"
|
|
|
|
"agentu/internal/llm"
|
|
)
|
|
|
|
type ShellRunTool struct {
|
|
workingDir string
|
|
}
|
|
|
|
func NewShellRunTool(workingDir string) *ShellRunTool {
|
|
return &ShellRunTool{workingDir: workingDir}
|
|
}
|
|
|
|
func (t *ShellRunTool) Definition() llm.Tool {
|
|
return llm.Tool{
|
|
Type: "function",
|
|
Function: llm.ToolFunction{
|
|
Name: "shell_run",
|
|
Description: "Run a non-interactive shell command on the local machine. Use for builds, tests, local status inspection, and local automation. Avoid commands that require an interactive TTY, credentials, or open long-running sessions.",
|
|
Parameters: JSONSchema(`{
|
|
"type": "object",
|
|
"properties": {
|
|
"command": {"type": "string", "description": "Command to execute."},
|
|
"workdir": {"type": "string", "description": "Optional working directory. Relative paths are resolved from the configured agent working directory."}
|
|
},
|
|
"required": ["command"],
|
|
"additionalProperties": false
|
|
}`),
|
|
},
|
|
}
|
|
}
|
|
|
|
type shellRunArgs struct {
|
|
Command string `json:"command"`
|
|
Workdir string `json:"workdir"`
|
|
}
|
|
|
|
func (t *ShellRunTool) Execute(ctx context.Context, raw json.RawMessage) (string, error) {
|
|
var args shellRunArgs
|
|
if err := json.Unmarshal(raw, &args); err != nil {
|
|
return "", fmt.Errorf("parse arguments: %w", err)
|
|
}
|
|
if strings.TrimSpace(args.Command) == "" {
|
|
return "", errors.New("command is required")
|
|
}
|
|
|
|
workdir, err := resolvePath(t.workingDir, args.Workdir)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
shell := os.Getenv("SHELL")
|
|
if shell == "" {
|
|
shell = "/bin/sh"
|
|
}
|
|
cmd := exec.CommandContext(ctx, shell, "-lc", args.Command)
|
|
cmd.Dir = workdir
|
|
|
|
output, err := cmd.CombinedOutput()
|
|
text := FormatResult(string(output))
|
|
if errors.Is(ctx.Err(), context.DeadlineExceeded) {
|
|
return text, fmt.Errorf("command timed out: %w", ctx.Err())
|
|
}
|
|
if err != nil {
|
|
if text != "" {
|
|
return text, fmt.Errorf("command failed: %w", err)
|
|
}
|
|
return "", fmt.Errorf("command failed: %w", err)
|
|
}
|
|
return text, nil
|
|
}
|