first commit
This commit is contained in:
@@ -0,0 +1,45 @@
|
||||
package tools
|
||||
|
||||
import (
|
||||
"ai-agent/internal/llm"
|
||||
)
|
||||
|
||||
var builtinToolNames = map[string]bool{
|
||||
"grep": true,
|
||||
"read": true,
|
||||
"write": true,
|
||||
"glob": true,
|
||||
"bash": true,
|
||||
"ls": true,
|
||||
"find": true,
|
||||
"diff": true,
|
||||
"edit": true,
|
||||
"mkdir": true,
|
||||
"remove": true,
|
||||
"copy": true,
|
||||
"move": true,
|
||||
"exists": true,
|
||||
}
|
||||
|
||||
func AllToolDefs() []llm.ToolDef {
|
||||
return []llm.ToolDef{
|
||||
GrepToolDef(),
|
||||
ReadToolDef(),
|
||||
WriteToolDef(),
|
||||
GlobToolDef(),
|
||||
BashToolDef(),
|
||||
LsToolDef(),
|
||||
FindToolDef(),
|
||||
DiffToolDef(),
|
||||
EditToolDef(),
|
||||
MkdirToolDef(),
|
||||
RemoveToolDef(),
|
||||
CopyToolDef(),
|
||||
MoveToolDef(),
|
||||
ExistsToolDef(),
|
||||
}
|
||||
}
|
||||
|
||||
func IsBuiltinTool(name string) bool {
|
||||
return builtinToolNames[name]
|
||||
}
|
||||
@@ -0,0 +1,306 @@
|
||||
package tools
|
||||
|
||||
import (
|
||||
"ai-agent/internal/llm"
|
||||
)
|
||||
|
||||
func GrepToolDef() llm.ToolDef {
|
||||
return llm.ToolDef{
|
||||
Name: "grep",
|
||||
Description: "Search for a pattern in files. Use this to find code, text, or values across multiple files.",
|
||||
Parameters: map[string]any{
|
||||
"type": "object",
|
||||
"properties": map[string]any{
|
||||
"pattern": map[string]any{
|
||||
"type": "string",
|
||||
"description": "The regex pattern to search for.",
|
||||
},
|
||||
"path": map[string]any{
|
||||
"type": "string",
|
||||
"description": "Directory path to search in (defaults to current directory).",
|
||||
},
|
||||
"include": map[string]any{
|
||||
"type": "string",
|
||||
"description": "File pattern to include (e.g., '*.go', '*.ts').",
|
||||
},
|
||||
"context": map[string]any{
|
||||
"type": "integer",
|
||||
"description": "Number of lines of context to show around matches (default: 3).",
|
||||
},
|
||||
},
|
||||
"required": []string{"pattern"},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func ReadToolDef() llm.ToolDef {
|
||||
return llm.ToolDef{
|
||||
Name: "read",
|
||||
Description: "Read the contents of a file. Use this to view source code, configuration files, or any text file.",
|
||||
Parameters: map[string]any{
|
||||
"type": "object",
|
||||
"properties": map[string]any{
|
||||
"path": map[string]any{
|
||||
"type": "string",
|
||||
"description": "Path to the file to read.",
|
||||
},
|
||||
"limit": map[string]any{
|
||||
"type": "integer",
|
||||
"description": "Maximum number of lines to read (optional).",
|
||||
},
|
||||
"offset": map[string]any{
|
||||
"type": "integer",
|
||||
"description": "Line number to start reading from (optional, 1-indexed).",
|
||||
},
|
||||
},
|
||||
"required": []string{"path"},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func WriteToolDef() llm.ToolDef {
|
||||
return llm.ToolDef{
|
||||
Name: "write",
|
||||
Description: "Write content to a file. Use this to create new files or overwrite existing ones. Creates parent directories if needed.",
|
||||
Parameters: map[string]any{
|
||||
"type": "object",
|
||||
"properties": map[string]any{
|
||||
"path": map[string]any{
|
||||
"type": "string",
|
||||
"description": "Path to the file to write.",
|
||||
},
|
||||
"content": map[string]any{
|
||||
"type": "string",
|
||||
"description": "Content to write to the file.",
|
||||
},
|
||||
},
|
||||
"required": []string{"path", "content"},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func GlobToolDef() llm.ToolDef {
|
||||
return llm.ToolDef{
|
||||
Name: "glob",
|
||||
Description: "Find files matching a pattern. Use this to discover files by name patterns like '*.go', '**/*.ts', etc.",
|
||||
Parameters: map[string]any{
|
||||
"type": "object",
|
||||
"properties": map[string]any{
|
||||
"pattern": map[string]any{
|
||||
"type": "string",
|
||||
"description": "Glob pattern to match (e.g., '**/*.go', 'src/**/*.ts').",
|
||||
},
|
||||
"path": map[string]any{
|
||||
"type": "string",
|
||||
"description": "Directory to search in (defaults to current directory).",
|
||||
},
|
||||
},
|
||||
"required": []string{"pattern"},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func BashToolDef() llm.ToolDef {
|
||||
return llm.ToolDef{
|
||||
Name: "bash",
|
||||
Description: "Execute a shell command. Use this to run git, npm, go, or other command-line tools. Output is returned after completion.",
|
||||
Parameters: map[string]any{
|
||||
"type": "object",
|
||||
"properties": map[string]any{
|
||||
"command": map[string]any{
|
||||
"type": "string",
|
||||
"description": "The shell command to execute.",
|
||||
},
|
||||
"timeout": map[string]any{
|
||||
"type": "integer",
|
||||
"description": "Timeout in seconds (default: 30, max: 120).",
|
||||
},
|
||||
},
|
||||
"required": []string{"command"},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func LsToolDef() llm.ToolDef {
|
||||
return llm.ToolDef{
|
||||
Name: "ls",
|
||||
Description: "List files and directories. Use this to see what's in a directory.",
|
||||
Parameters: map[string]any{
|
||||
"type": "object",
|
||||
"properties": map[string]any{
|
||||
"path": map[string]any{
|
||||
"type": "string",
|
||||
"description": "Directory path to list (defaults to current directory).",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func FindToolDef() llm.ToolDef {
|
||||
return llm.ToolDef{
|
||||
Name: "find",
|
||||
Description: "Find files or directories by name. Use this to locate specific files when you know all or part of the filename.",
|
||||
Parameters: map[string]any{
|
||||
"type": "object",
|
||||
"properties": map[string]any{
|
||||
"name": map[string]any{
|
||||
"type": "string",
|
||||
"description": "Name or pattern to search for (supports * and ? wildcards).",
|
||||
},
|
||||
"path": map[string]any{
|
||||
"type": "string",
|
||||
"description": "Directory to search in (defaults to current directory).",
|
||||
},
|
||||
"type": map[string]any{
|
||||
"type": "string",
|
||||
"description": "Type to find: 'f' for files, 'd' for directories (default: both).",
|
||||
},
|
||||
},
|
||||
"required": []string{"name"},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func DiffToolDef() llm.ToolDef {
|
||||
return llm.ToolDef{
|
||||
Name: "diff",
|
||||
Description: "Show the differences between the current file content and new content. Use this to preview changes before writing.",
|
||||
Parameters: map[string]any{
|
||||
"type": "object",
|
||||
"properties": map[string]any{
|
||||
"path": map[string]any{
|
||||
"type": "string",
|
||||
"description": "Path to the file to diff.",
|
||||
},
|
||||
"new_content": map[string]any{
|
||||
"type": "string",
|
||||
"description": "The new content to compare against the current file.",
|
||||
},
|
||||
},
|
||||
"required": []string{"path", "new_content"},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func EditToolDef() llm.ToolDef {
|
||||
return llm.ToolDef{
|
||||
Name: "edit",
|
||||
Description: "Apply a patch to a file. Use this to make targeted edits to specific lines without overwriting the entire file. The patch format is: @@ -start,count +new_start,new_count @@\nfollowed by lines starting with - (remove), + (add), or (context).",
|
||||
Parameters: map[string]any{
|
||||
"type": "object",
|
||||
"properties": map[string]any{
|
||||
"path": map[string]any{
|
||||
"type": "string",
|
||||
"description": "Path to the file to edit.",
|
||||
},
|
||||
"patch": map[string]any{
|
||||
"type": "string",
|
||||
"description": "Unified diff patch to apply. Format: @@ -start,count +new_start,new_count @@ followed by -line (remove), +line (add), or context line.",
|
||||
},
|
||||
},
|
||||
"required": []string{"path", "patch"},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func MkdirToolDef() llm.ToolDef {
|
||||
return llm.ToolDef{
|
||||
Name: "mkdir",
|
||||
Description: "Create one or more directories. Creates parent directories as needed.",
|
||||
Parameters: map[string]any{
|
||||
"type": "object",
|
||||
"properties": map[string]any{
|
||||
"path": map[string]any{
|
||||
"type": "string",
|
||||
"description": "Path to the directory to create.",
|
||||
},
|
||||
},
|
||||
"required": []string{"path"},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func RemoveToolDef() llm.ToolDef {
|
||||
return llm.ToolDef{
|
||||
Name: "remove",
|
||||
Description: "Remove files or directories. Use with caution - this permanently deletes files.",
|
||||
Parameters: map[string]any{
|
||||
"type": "object",
|
||||
"properties": map[string]any{
|
||||
"path": map[string]any{
|
||||
"type": "string",
|
||||
"description": "Path to remove (file or directory).",
|
||||
},
|
||||
"recursive": map[string]any{
|
||||
"type": "boolean",
|
||||
"description": "Remove directories recursively (default: false).",
|
||||
},
|
||||
"force": map[string]any{
|
||||
"type": "boolean",
|
||||
"description": "Ignore nonexistent files (default: false).",
|
||||
},
|
||||
},
|
||||
"required": []string{"path"},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func CopyToolDef() llm.ToolDef {
|
||||
return llm.ToolDef{
|
||||
Name: "copy",
|
||||
Description: "Copy a file from source to destination.",
|
||||
Parameters: map[string]any{
|
||||
"type": "object",
|
||||
"properties": map[string]any{
|
||||
"source": map[string]any{
|
||||
"type": "string",
|
||||
"description": "Source path to copy from.",
|
||||
},
|
||||
"destination": map[string]any{
|
||||
"type": "string",
|
||||
"description": "Destination path to copy to.",
|
||||
},
|
||||
},
|
||||
"required": []string{"source", "destination"},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func MoveToolDef() llm.ToolDef {
|
||||
return llm.ToolDef{
|
||||
Name: "move",
|
||||
Description: "Move or rename a file or directory.",
|
||||
Parameters: map[string]any{
|
||||
"type": "object",
|
||||
"properties": map[string]any{
|
||||
"source": map[string]any{
|
||||
"type": "string",
|
||||
"description": "Source path to move from.",
|
||||
},
|
||||
"destination": map[string]any{
|
||||
"type": "string",
|
||||
"description": "Destination path to move to.",
|
||||
},
|
||||
},
|
||||
"required": []string{"source", "destination"},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func ExistsToolDef() llm.ToolDef {
|
||||
return llm.ToolDef{
|
||||
Name: "exists",
|
||||
Description: "Check if a file or directory exists and get information about it.",
|
||||
Parameters: map[string]any{
|
||||
"type": "object",
|
||||
"properties": map[string]any{
|
||||
"path": map[string]any{
|
||||
"type": "string",
|
||||
"description": "Path to check.",
|
||||
},
|
||||
},
|
||||
"required": []string{"path"},
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,156 @@
|
||||
package tools
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestGrepToolDef(t *testing.T) {
|
||||
tool := GrepToolDef()
|
||||
|
||||
if tool.Name != "grep" {
|
||||
t.Errorf("Name = %q, want %q", tool.Name, "grep")
|
||||
}
|
||||
if tool.Description == "" {
|
||||
t.Error("Description should not be empty")
|
||||
}
|
||||
if tool.Parameters == nil {
|
||||
t.Error("Parameters should not be nil")
|
||||
}
|
||||
}
|
||||
|
||||
func TestReadToolDef(t *testing.T) {
|
||||
tool := ReadToolDef()
|
||||
|
||||
if tool.Name != "read" {
|
||||
t.Errorf("Name = %q, want %q", tool.Name, "read")
|
||||
}
|
||||
props := tool.Parameters["properties"].(map[string]any)
|
||||
if _, ok := props["path"]; !ok {
|
||||
t.Error("should have path property")
|
||||
}
|
||||
}
|
||||
|
||||
func TestWriteToolDef(t *testing.T) {
|
||||
tool := WriteToolDef()
|
||||
|
||||
if tool.Name != "write" {
|
||||
t.Errorf("Name = %q, want %q", tool.Name, "write")
|
||||
}
|
||||
props := tool.Parameters["properties"].(map[string]any)
|
||||
if _, ok := props["path"]; !ok {
|
||||
t.Error("should have path property")
|
||||
}
|
||||
if _, ok := props["content"]; !ok {
|
||||
t.Error("should have content property")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGlobToolDef(t *testing.T) {
|
||||
tool := GlobToolDef()
|
||||
|
||||
if tool.Name != "glob" {
|
||||
t.Errorf("Name = %q, want %q", tool.Name, "glob")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBashToolDef(t *testing.T) {
|
||||
tool := BashToolDef()
|
||||
|
||||
if tool.Name != "bash" {
|
||||
t.Errorf("Name = %q, want %q", tool.Name, "bash")
|
||||
}
|
||||
props := tool.Parameters["properties"].(map[string]any)
|
||||
if _, ok := props["command"]; !ok {
|
||||
t.Error("should have command property")
|
||||
}
|
||||
}
|
||||
|
||||
func TestLsToolDef(t *testing.T) {
|
||||
tool := LsToolDef()
|
||||
|
||||
if tool.Name != "ls" {
|
||||
t.Errorf("Name = %q, want %q", tool.Name, "ls")
|
||||
}
|
||||
}
|
||||
|
||||
func TestFindToolDef(t *testing.T) {
|
||||
tool := FindToolDef()
|
||||
|
||||
if tool.Name != "find" {
|
||||
t.Errorf("Name = %q, want %q", tool.Name, "find")
|
||||
}
|
||||
props := tool.Parameters["properties"].(map[string]any)
|
||||
if _, ok := props["name"]; !ok {
|
||||
t.Error("should have name property")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDiffToolDef(t *testing.T) {
|
||||
tool := DiffToolDef()
|
||||
|
||||
if tool.Name != "diff" {
|
||||
t.Errorf("Name = %q, want %q", tool.Name, "diff")
|
||||
}
|
||||
}
|
||||
|
||||
func TestEditToolDef(t *testing.T) {
|
||||
tool := EditToolDef()
|
||||
|
||||
if tool.Name != "edit" {
|
||||
t.Errorf("Name = %q, want %q", tool.Name, "edit")
|
||||
}
|
||||
}
|
||||
|
||||
func TestMkdirToolDef(t *testing.T) {
|
||||
tool := MkdirToolDef()
|
||||
|
||||
if tool.Name != "mkdir" {
|
||||
t.Errorf("Name = %q, want %q", tool.Name, "mkdir")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRemoveToolDef(t *testing.T) {
|
||||
tool := RemoveToolDef()
|
||||
|
||||
if tool.Name != "remove" {
|
||||
t.Errorf("Name = %q, want %q", tool.Name, "remove")
|
||||
}
|
||||
props := tool.Parameters["properties"].(map[string]any)
|
||||
if _, ok := props["recursive"]; !ok {
|
||||
t.Error("should have recursive property")
|
||||
}
|
||||
if _, ok := props["force"]; !ok {
|
||||
t.Error("should have force property")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCopyToolDef(t *testing.T) {
|
||||
tool := CopyToolDef()
|
||||
|
||||
if tool.Name != "copy" {
|
||||
t.Errorf("Name = %q, want %q", tool.Name, "copy")
|
||||
}
|
||||
props := tool.Parameters["properties"].(map[string]any)
|
||||
if _, ok := props["source"]; !ok {
|
||||
t.Error("should have source property")
|
||||
}
|
||||
if _, ok := props["destination"]; !ok {
|
||||
t.Error("should have destination property")
|
||||
}
|
||||
}
|
||||
|
||||
func TestMoveToolDef(t *testing.T) {
|
||||
tool := MoveToolDef()
|
||||
|
||||
if tool.Name != "move" {
|
||||
t.Errorf("Name = %q, want %q", tool.Name, "move")
|
||||
}
|
||||
}
|
||||
|
||||
func TestExistsToolDef(t *testing.T) {
|
||||
tool := ExistsToolDef()
|
||||
|
||||
if tool.Name != "exists" {
|
||||
t.Errorf("Name = %q, want %q", tool.Name, "exists")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user