first commit

This commit is contained in:
2026-03-08 15:40:34 +07:00
commit 8dc496b626
159 changed files with 27932 additions and 0 deletions
+45
View File
@@ -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]
}
+306
View File
@@ -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"},
},
}
}
+156
View File
@@ -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")
}
}