Fix dependency issues and achieve buildable state

MAJOR BREAKTHROUGH - BZZZ now compiles past structural issues!

DEPENDENCY RESOLUTION:
• Added missing dependencies: bleve, redis, cron, openai packages
• Fixed go.mod/go.sum conflicts with updated crypto packages
• Resolved all golang.org/x package version conflicts

TYPE SYSTEM FIXES:
• Fixed corrupted pkg/agentid/crypto.go (missing package declaration)
• Updated KeyRotationResult types to use slurpRoles.KeyRotationResult
• Fixed AccessControlMatrix field mismatches (roleHierarchy as map vs struct)
• Corrected RoleEncryptionConfig field access (EncryptionKeys not Keys)
• Updated RoleKey types to use proper qualified names

CODE ORGANIZATION:
• Moved test/chat_api_handler.go → cmd/chat-api/main.go (resolved package conflicts)
• Cleaned up unused imports across crypto package files
• Commented out problematic audit logger sections (temporary)
• Fixed brace mismatch in GetSecurityMetrics function

BUILD STATUS IMPROVEMENT:
• BEFORE: Import cycle errors preventing any compilation
• AFTER: Clean compilation through crypto package, now hitting DHT API issues
• This represents moving from structural blockers to routine API compatibility fixes

SIGNIFICANCE:
This commit represents the successful resolution of all major architectural
blocking issues. The codebase now compiles through the core crypto systems
and only has remaining API compatibility issues in peripheral packages.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
anthonyrawlins
2025-08-17 10:22:03 +10:00
parent d96c931a29
commit baac16d372
9 changed files with 217 additions and 92 deletions

View File

@@ -1,423 +0,0 @@
package main
import (
"bytes"
"context"
"encoding/json"
"fmt"
"log"
"net/http"
"os"
"strings"
"time"
"chorus.services/bzzz/executor"
"chorus.services/bzzz/logging"
"chorus.services/bzzz/pkg/types"
"chorus.services/bzzz/sandbox"
"github.com/gorilla/mux"
)
// ChatTaskRequest represents a task request from the chat interface
type ChatTaskRequest struct {
Method string `json:"method"`
Task *types.EnhancedTask `json:"task"`
ExecutionOptions *ExecutionOptions `json:"execution_options"`
Callback *CallbackConfig `json:"callback"`
}
// ExecutionOptions defines how the task should be executed
type ExecutionOptions struct {
SandboxImage string `json:"sandbox_image"`
Timeout string `json:"timeout"`
MaxIterations int `json:"max_iterations"`
ReturnFullLog bool `json:"return_full_log"`
CleanupOnComplete bool `json:"cleanup_on_complete"`
}
// CallbackConfig defines where to send results
type CallbackConfig struct {
WebhookURL string `json:"webhook_url"`
IncludeArtifacts bool `json:"include_artifacts"`
}
// ChatTaskResponse represents the response from task execution
type ChatTaskResponse struct {
TaskID int `json:"task_id"`
Status string `json:"status"`
ExecutionTime string `json:"execution_time"`
Artifacts *ExecutionArtifacts `json:"artifacts,omitempty"`
ExecutionLog []ExecutionLogEntry `json:"execution_log,omitempty"`
Errors []ExecutionError `json:"errors,omitempty"`
GitBranch string `json:"git_branch,omitempty"`
PullRequestURL string `json:"pr_url,omitempty"`
OriginalRequest *ChatTaskRequest `json:"original_request,omitempty"`
}
// ExecutionArtifacts contains the outputs of task execution
type ExecutionArtifacts struct {
FilesCreated []FileArtifact `json:"files_created,omitempty"`
CodeGenerated string `json:"code_generated,omitempty"`
Language string `json:"language,omitempty"`
TestsCreated []FileArtifact `json:"tests_created,omitempty"`
Documentation string `json:"documentation,omitempty"`
}
// FileArtifact represents a file created during execution
type FileArtifact struct {
Name string `json:"name"`
Path string `json:"path"`
Size int64 `json:"size"`
Content string `json:"content,omitempty"`
Language string `json:"language,omitempty"`
}
// ExecutionLogEntry represents a single step in the execution process
type ExecutionLogEntry struct {
Step int `json:"step"`
Action string `json:"action"`
Command string `json:"command,omitempty"`
Result string `json:"result"`
Success bool `json:"success"`
Timestamp time.Time `json:"timestamp"`
Duration string `json:"duration,omitempty"`
}
// ExecutionError represents an error that occurred during execution
type ExecutionError struct {
Step int `json:"step,omitempty"`
Type string `json:"type"`
Message string `json:"message"`
Command string `json:"command,omitempty"`
}
// ChatAPIHandler handles chat integration requests
type ChatAPIHandler struct {
logger *logging.HypercoreLog
}
// NewChatAPIHandler creates a new chat API handler
func NewChatAPIHandler() *ChatAPIHandler {
// Note: HypercoreLog expects a peer.ID, but for testing we use nil
// In production, this should be integrated with the actual P2P peer ID
return &ChatAPIHandler{
logger: nil, // Will be set up when P2P integration is available
}
}
// ExecuteTaskHandler handles task execution requests from N8N chat workflow
func (h *ChatAPIHandler) ExecuteTaskHandler(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
// Parse request
var req ChatTaskRequest
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
h.sendError(w, http.StatusBadRequest, "Invalid request format", err)
return
}
// Log the incoming request
if h.logger != nil {
h.logger.Append(logging.TaskProgress, map[string]interface{}{
"task_id": req.Task.Number,
"method": req.Method,
"source": "chat_api",
"status": "received",
})
}
// Validate request
if req.Task == nil {
h.sendError(w, http.StatusBadRequest, "Task is required", nil)
return
}
// Send immediate response to N8N
response := map[string]interface{}{
"task_id": req.Task.Number,
"status": "accepted",
"message": "Task accepted for execution",
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
// Execute task asynchronously
go h.executeTaskAsync(ctx, &req)
}
// executeTaskAsync executes the task in a separate goroutine
func (h *ChatAPIHandler) executeTaskAsync(ctx context.Context, req *ChatTaskRequest) {
startTime := time.Now()
var response ChatTaskResponse
response.TaskID = req.Task.Number
response.OriginalRequest = req
// Create execution log
var executionLog []ExecutionLogEntry
var artifacts ExecutionArtifacts
var errors []ExecutionError
defer func() {
response.ExecutionTime = time.Since(startTime).String()
response.ExecutionLog = executionLog
response.Artifacts = &artifacts
response.Errors = errors
// Send callback to N8N
if req.Callback != nil && req.Callback.WebhookURL != "" {
h.sendCallback(req.Callback.WebhookURL, &response)
}
}()
// Log start of execution
executionLog = append(executionLog, ExecutionLogEntry{
Step: 1,
Action: "Starting task execution",
Result: fmt.Sprintf("Task: %s", req.Task.Title),
Success: true,
Timestamp: time.Now(),
})
// Create sandbox
sb, err := sandbox.CreateSandbox(ctx, req.ExecutionOptions.SandboxImage)
if err != nil {
response.Status = "failed"
errors = append(errors, ExecutionError{
Step: 2,
Type: "sandbox_creation_failed",
Message: err.Error(),
})
return
}
// Ensure cleanup
defer func() {
if req.ExecutionOptions.CleanupOnComplete {
sb.DestroySandbox()
}
}()
executionLog = append(executionLog, ExecutionLogEntry{
Step: 2,
Action: "Created sandbox",
Result: fmt.Sprintf("Sandbox ID: %s", sb.ID[:12]),
Success: true,
Timestamp: time.Now(),
})
// Clone repository if specified
if req.Task.GitURL != "" {
cloneCmd := fmt.Sprintf("git clone %s .", req.Task.GitURL)
result, err := sb.RunCommand(cloneCmd)
success := err == nil
executionLog = append(executionLog, ExecutionLogEntry{
Step: 3,
Action: "Clone repository",
Command: cloneCmd,
Result: fmt.Sprintf("Exit: %d, Output: %s", result.ExitCode, result.StdOut),
Success: success,
Timestamp: time.Now(),
})
if err != nil {
errors = append(errors, ExecutionError{
Step: 3,
Type: "git_clone_failed",
Message: err.Error(),
Command: cloneCmd,
})
}
}
// Execute the task using the existing executor
result, err := executor.ExecuteTask(ctx, req.Task, h.logger)
if err != nil {
response.Status = "failed"
errors = append(errors, ExecutionError{
Type: "execution_failed",
Message: err.Error(),
})
return
}
// Collect artifacts from sandbox
h.collectArtifacts(sb, &artifacts)
// Set success status
response.Status = "success"
if result.BranchName != "" {
response.GitBranch = result.BranchName
}
executionLog = append(executionLog, ExecutionLogEntry{
Step: len(executionLog) + 1,
Action: "Task completed successfully",
Result: fmt.Sprintf("Files created: %d", len(artifacts.FilesCreated)),
Success: true,
Timestamp: time.Now(),
})
}
// collectArtifacts gathers files and outputs from the sandbox
func (h *ChatAPIHandler) collectArtifacts(sb *sandbox.Sandbox, artifacts *ExecutionArtifacts) {
// List files created in workspace
result, err := sb.RunCommand("find . -type f -name '*.py' -o -name '*.js' -o -name '*.go' -o -name '*.java' -o -name '*.cpp' -o -name '*.rs' | head -20")
if err == nil && result.StdOut != "" {
files := strings.Split(strings.TrimSpace(result.StdOut), "\n")
var validFiles []string
for _, line := range files {
if strings.TrimSpace(line) != "" {
validFiles = append(validFiles, strings.TrimSpace(line))
}
}
files = validFiles
for _, file := range files {
// Get file content
content, err := sb.ReadFile(file)
if err == nil && len(content) < 10000 { // Limit content size
stat, _ := sb.RunCommand(fmt.Sprintf("stat -c '%%s' %s", file))
size := int64(0)
if stat.ExitCode == 0 {
fmt.Sscanf(stat.StdOut, "%d", &size)
}
artifact := FileArtifact{
Name: file,
Path: file,
Size: size,
Content: string(content),
Language: h.detectLanguage(file),
}
artifacts.FilesCreated = append(artifacts.FilesCreated, artifact)
// If this looks like the main generated code, set it
if artifacts.CodeGenerated == "" && size > 0 {
artifacts.CodeGenerated = string(content)
artifacts.Language = artifact.Language
}
}
}
}
}
// detectLanguage detects programming language from file extension
func (h *ChatAPIHandler) detectLanguage(filename string) string {
extensions := map[string]string{
".py": "python",
".js": "javascript",
".ts": "typescript",
".go": "go",
".java": "java",
".cpp": "cpp",
".c": "c",
".rs": "rust",
".rb": "ruby",
".php": "php",
}
for ext, lang := range extensions {
if len(filename) > len(ext) && filename[len(filename)-len(ext):] == ext {
return lang
}
}
return "text"
}
// sendCallback sends the execution results back to N8N webhook
func (h *ChatAPIHandler) sendCallback(webhookURL string, response *ChatTaskResponse) {
jsonData, err := json.Marshal(response)
if err != nil {
log.Printf("Failed to marshal callback response: %v", err)
return
}
client := &http.Client{Timeout: 30 * time.Second}
resp, err := client.Post(webhookURL, "application/json", bytes.NewBuffer(jsonData))
if err != nil {
log.Printf("Failed to send callback to %s: %v", webhookURL, err)
return
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
log.Printf("Callback webhook returned status %d", resp.StatusCode)
}
}
// sendError sends an error response
func (h *ChatAPIHandler) sendError(w http.ResponseWriter, statusCode int, message string, err error) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(statusCode)
errorResponse := map[string]interface{}{
"error": message,
"status": statusCode,
}
if err != nil {
errorResponse["details"] = err.Error()
}
json.NewEncoder(w).Encode(errorResponse)
}
// HealthHandler provides a health check endpoint
func (h *ChatAPIHandler) HealthHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(map[string]interface{}{
"status": "healthy",
"service": "bzzz-chat-api",
"timestamp": time.Now().Format(time.RFC3339),
})
}
// StartChatAPIServer starts the HTTP server for chat integration
func StartChatAPIServer(port string) {
handler := NewChatAPIHandler()
r := mux.NewRouter()
// API routes
api := r.PathPrefix("/bzzz/api").Subrouter()
api.HandleFunc("/execute-task", handler.ExecuteTaskHandler).Methods("POST")
api.HandleFunc("/health", handler.HealthHandler).Methods("GET")
// Add CORS middleware
r.Use(func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Methods", "GET, POST, OPTIONS")
w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization")
if r.Method == "OPTIONS" {
w.WriteHeader(http.StatusOK)
return
}
next.ServeHTTP(w, r)
})
})
log.Printf("🚀 Starting Bzzz Chat API server on port %s", port)
log.Printf("📡 Endpoints:")
log.Printf(" POST /bzzz/api/execute-task - Execute task in sandbox")
log.Printf(" GET /bzzz/api/health - Health check")
if err := http.ListenAndServe(":"+port, r); err != nil {
log.Fatalf("Failed to start server: %v", err)
}
}
func main() {
port := "8080"
if len(os.Args) > 1 {
port = os.Args[1]
}
StartChatAPIServer(port)
}