package agent import ( "fmt" "os" "path/filepath" "strings" ) // Tool-Ergebnis das dem LLM zurückgegeben wird type ToolResult struct { Success bool Output string } // Parst Tool-Calls aus der LLM-Antwort // Erwartetes Format: // TOOL:READ_FILE:path/to/file // TOOL:WRITE_FILE:path/to/file:<<>> // TOOL:LIST_FILES:. func ExecuteTools(response string, workDir string) (string, bool) { lines := strings.Split(response, "\n") var toolOutputs []string hasToolCall := false for _, line := range lines { line = strings.TrimSpace(line) if !strings.HasPrefix(line, "TOOL:") { continue } hasToolCall = true result := executeTool(line, workDir) toolOutputs = append(toolOutputs, result) } return strings.Join(toolOutputs, "\n"), hasToolCall } func executeTool(toolCall string, workDir string) string { parts := strings.SplitN(toolCall, ":", 4) if len(parts) < 3 { return "ERROR: Ungültiger Tool-Call" } toolName := parts[1] arg1 := parts[2] switch toolName { case "READ_FILE": path := filepath.Join(workDir, arg1) content, err := os.ReadFile(path) if err != nil { return fmt.Sprintf("READ_FILE ERROR: %v", err) } return fmt.Sprintf("READ_FILE %s:\n%s", arg1, string(content)) case "WRITE_FILE": if len(parts) < 4 { return "ERROR: WRITE_FILE braucht Inhalt" } content := parts[3] path := filepath.Join(workDir, arg1) // Verzeichnis anlegen falls nötig if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil { return fmt.Sprintf("WRITE_FILE ERROR: %v", err) } if err := os.WriteFile(path, []byte(content), 0644); err != nil { return fmt.Sprintf("WRITE_FILE ERROR: %v", err) } return fmt.Sprintf("WRITE_FILE OK: %s geschrieben", arg1) case "LIST_FILES": path := filepath.Join(workDir, arg1) entries, err := os.ReadDir(path) if err != nil { return fmt.Sprintf("LIST_FILES ERROR: %v", err) } var files []string for _, e := range entries { files = append(files, e.Name()) } return fmt.Sprintf("LIST_FILES %s:\n%s", arg1, strings.Join(files, "\n")) } return fmt.Sprintf("ERROR: Unbekanntes Tool: %s", toolName) }