summaryrefslogtreecommitdiffhomepage
path: root/internal/llm/tools/write.go
diff options
context:
space:
mode:
authorKujtim Hoxha <[email protected]>2025-04-08 19:42:59 +0200
committerGitHub <[email protected]>2025-04-08 19:42:59 +0200
commit124bd57c507fdcbb56ab27137cbe892f12e1b48f (patch)
tree894d335a5f2f6587a19e94f139f681b91b01e877 /internal/llm/tools/write.go
parent5acf0cba6040aaf90acb5dcacd3e4127d6833ac5 (diff)
parentc571283ac26cdf03be5a1d5c1e36051e3b7ea7be (diff)
downloadopencode-124bd57c507fdcbb56ab27137cbe892f12e1b48f.tar.gz
opencode-124bd57c507fdcbb56ab27137cbe892f12e1b48f.zip
Merge pull request #24 from kujtimiihoxha/cleanup-tools
Cleanup tools
Diffstat (limited to 'internal/llm/tools/write.go')
-rw-r--r--internal/llm/tools/write.go105
1 files changed, 47 insertions, 58 deletions
diff --git a/internal/llm/tools/write.go b/internal/llm/tools/write.go
index 86c9be37e..7b698d2d8 100644
--- a/internal/llm/tools/write.go
+++ b/internal/llm/tools/write.go
@@ -13,14 +13,6 @@ import (
"github.com/kujtimiihoxha/termai/internal/permission"
)
-type writeTool struct {
- lspClients map[string]*lsp.Client
-}
-
-const (
- WriteToolName = "write"
-)
-
type WriteParams struct {
FilePath string `json:"file_path"`
Content string `json:"content"`
@@ -31,10 +23,54 @@ type WritePermissionsParams struct {
Content string `json:"content"`
}
+type writeTool struct {
+ lspClients map[string]*lsp.Client
+ permissions permission.Service
+}
+
+const (
+ WriteToolName = "write"
+ writeDescription = `File writing tool that creates or updates files in the filesystem, allowing you to save or modify text content.
+
+WHEN TO USE THIS TOOL:
+- Use when you need to create a new file
+- Helpful for updating existing files with modified content
+- Perfect for saving generated code, configurations, or text data
+
+HOW TO USE:
+- Provide the path to the file you want to write
+- Include the content to be written to the file
+- The tool will create any necessary parent directories
+
+FEATURES:
+- Can create new files or overwrite existing ones
+- Creates parent directories automatically if they don't exist
+- Checks if the file has been modified since last read for safety
+- Avoids unnecessary writes when content hasn't changed
+
+LIMITATIONS:
+- You should read a file before writing to it to avoid conflicts
+- Cannot append to files (rewrites the entire file)
+
+
+TIPS:
+- Use the View tool first to examine existing files before modifying them
+- Use the LS tool to verify the correct location when creating new files
+- Combine with Glob and Grep tools to find and modify multiple files
+- Always include descriptive comments when making changes to existing code`
+)
+
+func NewWriteTool(lspClients map[string]*lsp.Client, permissions permission.Service) BaseTool {
+ return &writeTool{
+ lspClients: lspClients,
+ permissions: permissions,
+ }
+}
+
func (w *writeTool) Info() ToolInfo {
return ToolInfo{
Name: WriteToolName,
- Description: writeDescription(),
+ Description: writeDescription,
Parameters: map[string]any{
"file_path": map[string]any{
"type": "string",
@@ -49,7 +85,6 @@ func (w *writeTool) Info() ToolInfo {
}
}
-// Run implements Tool.
func (w *writeTool) Run(ctx context.Context, call ToolCall) (ToolResponse, error) {
var params WriteParams
if err := json.Unmarshal([]byte(call.Input), &params); err != nil {
@@ -64,20 +99,17 @@ func (w *writeTool) Run(ctx context.Context, call ToolCall) (ToolResponse, error
return NewTextErrorResponse("content is required"), nil
}
- // Handle relative paths
filePath := params.FilePath
if !filepath.IsAbs(filePath) {
filePath = filepath.Join(config.WorkingDirectory(), filePath)
}
- // Check if file exists and is a directory
fileInfo, err := os.Stat(filePath)
if err == nil {
if fileInfo.IsDir() {
return NewTextErrorResponse(fmt.Sprintf("Path is a directory, not a file: %s", filePath)), nil
}
- // Check if file was modified since last read
modTime := fileInfo.ModTime()
lastRead := getLastReadTime(filePath)
if modTime.After(lastRead) {
@@ -85,7 +117,6 @@ func (w *writeTool) Run(ctx context.Context, call ToolCall) (ToolResponse, error
filePath, modTime.Format(time.RFC3339), lastRead.Format(time.RFC3339))), nil
}
- // Optional: Get old content for diff
oldContent, readErr := os.ReadFile(filePath)
if readErr == nil && string(oldContent) == params.Content {
return NewTextErrorResponse(fmt.Sprintf("File %s already contains the exact content. No changes made.", filePath)), nil
@@ -94,13 +125,11 @@ func (w *writeTool) Run(ctx context.Context, call ToolCall) (ToolResponse, error
return NewTextErrorResponse(fmt.Sprintf("Failed to access file: %s", err)), nil
}
- // Create parent directories if needed
dir := filepath.Dir(filePath)
if err = os.MkdirAll(dir, 0o755); err != nil {
return NewTextErrorResponse(fmt.Sprintf("Failed to create parent directories: %s", err)), nil
}
- // Get old content for diff if file exists
oldContent := ""
if fileInfo != nil && !fileInfo.IsDir() {
oldBytes, readErr := os.ReadFile(filePath)
@@ -108,8 +137,8 @@ func (w *writeTool) Run(ctx context.Context, call ToolCall) (ToolResponse, error
oldContent = string(oldBytes)
}
}
-
- p := permission.Default.Request(
+
+ p := w.permissions.Request(
permission.CreatePermissionRequest{
Path: filePath,
ToolName: WriteToolName,
@@ -125,16 +154,13 @@ func (w *writeTool) Run(ctx context.Context, call ToolCall) (ToolResponse, error
return NewTextErrorResponse(fmt.Sprintf("Permission denied to create file: %s", filePath)), nil
}
- // Write the file
err = os.WriteFile(filePath, []byte(params.Content), 0o644)
if err != nil {
return NewTextErrorResponse(fmt.Sprintf("Failed to write file: %s", err)), nil
}
- // Record the file write
recordFileWrite(filePath)
recordFileRead(filePath)
- // Wait for LSP diagnostics after writing the file
waitForLspDiagnostics(ctx, filePath, w.lspClients)
result := fmt.Sprintf("File successfully written: %s", filePath)
@@ -142,40 +168,3 @@ func (w *writeTool) Run(ctx context.Context, call ToolCall) (ToolResponse, error
result += appendDiagnostics(filePath, w.lspClients)
return NewTextResponse(result), nil
}
-
-func writeDescription() string {
- return `File writing tool that creates or updates files in the filesystem, allowing you to save or modify text content.
-
-WHEN TO USE THIS TOOL:
-- Use when you need to create a new file
-- Helpful for updating existing files with modified content
-- Perfect for saving generated code, configurations, or text data
-
-HOW TO USE:
-- Provide the path to the file you want to write
-- Include the content to be written to the file
-- The tool will create any necessary parent directories
-
-FEATURES:
-- Can create new files or overwrite existing ones
-- Creates parent directories automatically if they don't exist
-- Checks if the file has been modified since last read for safety
-- Avoids unnecessary writes when content hasn't changed
-
-LIMITATIONS:
-- You should read a file before writing to it to avoid conflicts
-- Cannot append to files (rewrites the entire file)
-
-
-TIPS:
-- Use the View tool first to examine existing files before modifying them
-- Use the LS tool to verify the correct location when creating new files
-- Combine with Glob and Grep tools to find and modify multiple files
-- Always include descriptive comments when making changes to existing code`
-}
-
-func NewWriteTool(lspClients map[string]*lsp.Client) BaseTool {
- return &writeTool{
- lspClients,
- }
-}