diff options
| author | Kujtim Hoxha <[email protected]> | 2025-04-21 19:59:35 +0200 |
|---|---|---|
| committer | GitHub <[email protected]> | 2025-04-21 19:59:35 +0200 |
| commit | f33dff87725764af0b675b5e5b2e011b21c14c90 (patch) | |
| tree | 4fe2c022305f13775f2cab3cdd80cd808259765b /internal/llm/tools/write.go | |
| parent | 6b1c64bcc75b89c530294b6a2d4404682b435d56 (diff) | |
| parent | 3a6a26981a8074b6ab0eaadb520db986e04799ff (diff) | |
| download | opencode-f33dff87725764af0b675b5e5b2e011b21c14c90.tar.gz opencode-f33dff87725764af0b675b5e5b2e011b21c14c90.zip | |
Merge pull request #27 from kujtimiihoxha/opencode
OpenCode - Initial Implementation
Diffstat (limited to 'internal/llm/tools/write.go')
| -rw-r--r-- | internal/llm/tools/write.go | 85 |
1 files changed, 71 insertions, 14 deletions
diff --git a/internal/llm/tools/write.go b/internal/llm/tools/write.go index 7b698d2d8..ec6fc1dc4 100644 --- a/internal/llm/tools/write.go +++ b/internal/llm/tools/write.go @@ -6,11 +6,15 @@ import ( "fmt" "os" "path/filepath" + "strings" "time" - "github.com/kujtimiihoxha/termai/internal/config" - "github.com/kujtimiihoxha/termai/internal/lsp" - "github.com/kujtimiihoxha/termai/internal/permission" + "github.com/kujtimiihoxha/opencode/internal/config" + "github.com/kujtimiihoxha/opencode/internal/diff" + "github.com/kujtimiihoxha/opencode/internal/history" + "github.com/kujtimiihoxha/opencode/internal/logging" + "github.com/kujtimiihoxha/opencode/internal/lsp" + "github.com/kujtimiihoxha/opencode/internal/permission" ) type WriteParams struct { @@ -20,12 +24,19 @@ type WriteParams struct { type WritePermissionsParams struct { FilePath string `json:"file_path"` - Content string `json:"content"` + Diff string `json:"diff"` } type writeTool struct { lspClients map[string]*lsp.Client permissions permission.Service + files history.Service +} + +type WriteResponseMetadata struct { + Diff string `json:"diff"` + Additions int `json:"additions"` + Removals int `json:"removals"` } const ( @@ -60,10 +71,11 @@ TIPS: - Always include descriptive comments when making changes to existing code` ) -func NewWriteTool(lspClients map[string]*lsp.Client, permissions permission.Service) BaseTool { +func NewWriteTool(lspClients map[string]*lsp.Client, permissions permission.Service, files history.Service) BaseTool { return &writeTool{ lspClients: lspClients, permissions: permissions, + files: files, } } @@ -122,12 +134,12 @@ func (w *writeTool) Run(ctx context.Context, call ToolCall) (ToolResponse, error return NewTextErrorResponse(fmt.Sprintf("File %s already contains the exact content. No changes made.", filePath)), nil } } else if !os.IsNotExist(err) { - return NewTextErrorResponse(fmt.Sprintf("Failed to access file: %s", err)), nil + return ToolResponse{}, fmt.Errorf("error checking file: %w", err) } dir := filepath.Dir(filePath) if err = os.MkdirAll(dir, 0o755); err != nil { - return NewTextErrorResponse(fmt.Sprintf("Failed to create parent directories: %s", err)), nil + return ToolResponse{}, fmt.Errorf("error creating directory: %w", err) } oldContent := "" @@ -138,25 +150,64 @@ func (w *writeTool) Run(ctx context.Context, call ToolCall) (ToolResponse, error } } + sessionID, messageID := GetContextValues(ctx) + if sessionID == "" || messageID == "" { + return ToolResponse{}, fmt.Errorf("session_id and message_id are required") + } + + diff, additions, removals := diff.GenerateDiff( + oldContent, + params.Content, + filePath, + ) + + rootDir := config.WorkingDirectory() + permissionPath := filepath.Dir(filePath) + if strings.HasPrefix(filePath, rootDir) { + permissionPath = rootDir + } p := w.permissions.Request( permission.CreatePermissionRequest{ - Path: filePath, + SessionID: sessionID, + Path: permissionPath, ToolName: WriteToolName, - Action: "create", + Action: "write", Description: fmt.Sprintf("Create file %s", filePath), Params: WritePermissionsParams{ FilePath: filePath, - Content: GenerateDiff(oldContent, params.Content), + Diff: diff, }, }, ) if !p { - return NewTextErrorResponse(fmt.Sprintf("Permission denied to create file: %s", filePath)), nil + return ToolResponse{}, permission.ErrorPermissionDenied } err = os.WriteFile(filePath, []byte(params.Content), 0o644) if err != nil { - return NewTextErrorResponse(fmt.Sprintf("Failed to write file: %s", err)), nil + return ToolResponse{}, fmt.Errorf("error writing file: %w", err) + } + + // Check if file exists in history + file, err := w.files.GetByPathAndSession(ctx, filePath, sessionID) + if err != nil { + _, err = w.files.Create(ctx, sessionID, filePath, oldContent) + if err != nil { + // Log error but don't fail the operation + return ToolResponse{}, fmt.Errorf("error creating file history: %w", err) + } + } + if file.Content != oldContent { + // User Manually changed the content store an intermediate version + _, err = w.files.CreateVersion(ctx, sessionID, filePath, oldContent) + if err != nil { + logging.Debug("Error creating file history version", "error", err) + } + } + // Store the new version + _, err = w.files.CreateVersion(ctx, sessionID, filePath, params.Content) + if err != nil { + logging.Debug("Error creating file history version", "error", err) } recordFileWrite(filePath) @@ -165,6 +216,12 @@ func (w *writeTool) Run(ctx context.Context, call ToolCall) (ToolResponse, error result := fmt.Sprintf("File successfully written: %s", filePath) result = fmt.Sprintf("<result>\n%s\n</result>", result) - result += appendDiagnostics(filePath, w.lspClients) - return NewTextResponse(result), nil + result += getDiagnostics(filePath, w.lspClients) + return WithResponseMetadata(NewTextResponse(result), + WriteResponseMetadata{ + Diff: diff, + Additions: additions, + Removals: removals, + }, + ), nil } |
