summaryrefslogtreecommitdiffhomepage
path: root/internal/llm/tools/diagnostics.go
diff options
context:
space:
mode:
authorKujtim Hoxha <[email protected]>2025-04-08 19:15:23 +0200
committerKujtim Hoxha <[email protected]>2025-04-08 19:15:23 +0200
commit94923948e1a1525988bf13025a10cc9226652684 (patch)
tree91d6b5b78b6af47a7272e92b54386eee42f21e50 /internal/llm/tools/diagnostics.go
parent5acf0cba6040aaf90acb5dcacd3e4127d6833ac5 (diff)
downloadopencode-94923948e1a1525988bf13025a10cc9226652684.tar.gz
opencode-94923948e1a1525988bf13025a10cc9226652684.zip
structure tools the same
- add some tests - fix some tests - change how we handle permissions
Diffstat (limited to 'internal/llm/tools/diagnostics.go')
-rw-r--r--internal/llm/tools/diagnostics.go73
1 files changed, 30 insertions, 43 deletions
diff --git a/internal/llm/tools/diagnostics.go b/internal/llm/tools/diagnostics.go
index ce76ae12f..1bb02098e 100644
--- a/internal/llm/tools/diagnostics.go
+++ b/internal/llm/tools/diagnostics.go
@@ -13,22 +13,48 @@ import (
"github.com/kujtimiihoxha/termai/internal/lsp/protocol"
)
+type DiagnosticsParams struct {
+ FilePath string `json:"file_path"`
+}
type diagnosticsTool struct {
lspClients map[string]*lsp.Client
}
const (
- DiagnosticsToolName = "diagnostics"
+ DiagnosticsToolName = "diagnostics"
+ diagnosticsDescription = `Get diagnostics for a file and/or project.
+WHEN TO USE THIS TOOL:
+- Use when you need to check for errors or warnings in your code
+- Helpful for debugging and ensuring code quality
+- Good for getting a quick overview of issues in a file or project
+HOW TO USE:
+- Provide a path to a file to get diagnostics for that file
+- Leave the path empty to get diagnostics for the entire project
+- Results are displayed in a structured format with severity levels
+FEATURES:
+- Displays errors, warnings, and hints
+- Groups diagnostics by severity
+- Provides detailed information about each diagnostic
+LIMITATIONS:
+- Results are limited to the diagnostics provided by the LSP clients
+- May not cover all possible issues in the code
+- Does not provide suggestions for fixing issues
+TIPS:
+- Use in conjunction with other tools for a comprehensive code review
+- Combine with the LSP client for real-time diagnostics
+`
)
-type DiagnosticsParams struct {
- FilePath string `json:"file_path"`
+func NewDiagnosticsTool(lspClients map[string]*lsp.Client) BaseTool {
+ return &diagnosticsTool{
+ lspClients,
+ }
}
func (b *diagnosticsTool) Info() ToolInfo {
return ToolInfo{
Name: DiagnosticsToolName,
- Description: "Get diagnostics for a file and/or project.",
+ Description: diagnosticsDescription,
Parameters: map[string]any{
"file_path": map[string]any{
"type": "string",
@@ -63,31 +89,24 @@ func (b *diagnosticsTool) Run(ctx context.Context, call ToolCall) (ToolResponse,
func notifyLspOpenFile(ctx context.Context, filePath string, lsps map[string]*lsp.Client) {
for _, client := range lsps {
- // Open the file
err := client.OpenFile(ctx, filePath)
if err != nil {
- // If there's an error opening the file, continue to the next client
continue
}
}
}
-// waitForLspDiagnostics opens a file in LSP clients and waits for diagnostics to be published
func waitForLspDiagnostics(ctx context.Context, filePath string, lsps map[string]*lsp.Client) {
if len(lsps) == 0 {
return
}
- // Create a channel to receive diagnostic notifications
diagChan := make(chan struct{}, 1)
- // Register a temporary diagnostic handler for each client
for _, client := range lsps {
- // Store the original diagnostics map to detect changes
originalDiags := make(map[protocol.DocumentUri][]protocol.Diagnostic)
maps.Copy(originalDiags, client.GetDiagnostics())
- // Create a notification handler that will signal when diagnostics are received
handler := func(params json.RawMessage) {
lsp.HandleDiagnostics(client, params)
var diagParams protocol.PublishDiagnosticsParams
@@ -95,28 +114,22 @@ func waitForLspDiagnostics(ctx context.Context, filePath string, lsps map[string
return
}
- // If this is for our file or we've received any new diagnostics, signal completion
if diagParams.URI.Path() == filePath || hasDiagnosticsChanged(client.GetDiagnostics(), originalDiags) {
select {
case diagChan <- struct{}{}:
- // Signal sent
default:
- // Channel already has a value, no need to send again
}
}
}
- // Register our temporary handler
client.RegisterNotificationHandler("textDocument/publishDiagnostics", handler)
- // Notify change if the file is already open
if client.IsFileOpen(filePath) {
err := client.NotifyChange(ctx, filePath)
if err != nil {
continue
}
} else {
- // Open the file if it's not already open
err := client.OpenFile(ctx, filePath)
if err != nil {
continue
@@ -124,22 +137,13 @@ func waitForLspDiagnostics(ctx context.Context, filePath string, lsps map[string
}
}
- // Wait for diagnostics with a reasonable timeout
select {
case <-diagChan:
- // Diagnostics received
case <-time.After(5 * time.Second):
- // Timeout after 5 seconds - this is a fallback in case no diagnostics are published
case <-ctx.Done():
- // Context cancelled
}
-
- // Note: We're not unregistering our handler because the Client.RegisterNotificationHandler
- // replaces any existing handler, and we'll be replaced by the original handler when
- // the LSP client is reinitialized or when a new handler is registered.
}
-// hasDiagnosticsChanged checks if there are any new diagnostics compared to the original set
func hasDiagnosticsChanged(current, original map[protocol.DocumentUri][]protocol.Diagnostic) bool {
for uri, diags := range current {
origDiags, exists := original[uri]
@@ -154,9 +158,7 @@ func appendDiagnostics(filePath string, lsps map[string]*lsp.Client) string {
fileDiagnostics := []string{}
projectDiagnostics := []string{}
- // Enhanced format function that includes more diagnostic information
formatDiagnostic := func(pth string, diagnostic protocol.Diagnostic, source string) string {
- // Base components
severity := "Info"
switch diagnostic.Severity {
case protocol.SeverityError:
@@ -167,10 +169,8 @@ func appendDiagnostics(filePath string, lsps map[string]*lsp.Client) string {
severity = "Hint"
}
- // Location information
location := fmt.Sprintf("%s:%d:%d", pth, diagnostic.Range.Start.Line+1, diagnostic.Range.Start.Character+1)
- // Source information (LSP name)
sourceInfo := ""
if diagnostic.Source != "" {
sourceInfo = diagnostic.Source
@@ -178,13 +178,11 @@ func appendDiagnostics(filePath string, lsps map[string]*lsp.Client) string {
sourceInfo = source
}
- // Code information
codeInfo := ""
if diagnostic.Code != nil {
codeInfo = fmt.Sprintf("[%v]", diagnostic.Code)
}
- // Tags information
tagsInfo := ""
if len(diagnostic.Tags) > 0 {
tags := []string{}
@@ -201,7 +199,6 @@ func appendDiagnostics(filePath string, lsps map[string]*lsp.Client) string {
}
}
- // Assemble the full diagnostic message
return fmt.Sprintf("%s: %s [%s]%s%s %s",
severity,
location,
@@ -217,7 +214,6 @@ func appendDiagnostics(filePath string, lsps map[string]*lsp.Client) string {
for location, diags := range diagnostics {
isCurrentFile := location.Path() == filePath
- // Group diagnostics by severity for better organization
for _, diag := range diags {
formattedDiag := formatDiagnostic(location.Path(), diag, lspName)
@@ -231,7 +227,6 @@ func appendDiagnostics(filePath string, lsps map[string]*lsp.Client) string {
}
}
- // Sort diagnostics by severity (errors first) and then by location
sort.Slice(fileDiagnostics, func(i, j int) bool {
iIsError := strings.HasPrefix(fileDiagnostics[i], "Error")
jIsError := strings.HasPrefix(fileDiagnostics[j], "Error")
@@ -274,7 +269,6 @@ func appendDiagnostics(filePath string, lsps map[string]*lsp.Client) string {
output += "\n</project_diagnostics>\n"
}
- // Add summary counts
if len(fileDiagnostics) > 0 || len(projectDiagnostics) > 0 {
fileErrors := countSeverity(fileDiagnostics, "Error")
fileWarnings := countSeverity(fileDiagnostics, "Warn")
@@ -290,7 +284,6 @@ func appendDiagnostics(filePath string, lsps map[string]*lsp.Client) string {
return output
}
-// Helper function to count diagnostics by severity
func countSeverity(diagnostics []string, severity string) int {
count := 0
for _, diag := range diagnostics {
@@ -300,9 +293,3 @@ func countSeverity(diagnostics []string, severity string) int {
}
return count
}
-
-func NewDiagnosticsTool(lspClients map[string]*lsp.Client) BaseTool {
- return &diagnosticsTool{
- lspClients,
- }
-}