package hap import ( "bufio" "context" "fmt" "os" "strings" "time" "chorus.services/bzzz/internal/common/runtime" "chorus.services/bzzz/logging" ) // TerminalInterface provides a terminal-based interface for human agents type TerminalInterface struct { services *runtime.RuntimeServices logger logging.Logger running bool scanner *bufio.Scanner } // NewTerminalInterface creates a new terminal interface func NewTerminalInterface(services *runtime.RuntimeServices, logger logging.Logger) *TerminalInterface { return &TerminalInterface{ services: services, logger: logger, running: false, scanner: bufio.NewScanner(os.Stdin), } } // Start begins the terminal interface func (ti *TerminalInterface) Start(ctx context.Context) error { if ti.running { return fmt.Errorf("terminal interface is already running") } ti.logger.Info("πŸ‘€ Starting Human Agent Portal terminal interface") // Display welcome message ti.displayWelcome() // Start command processing in background go ti.processCommands(ctx) ti.running = true ti.logger.Info("βœ… Terminal interface ready for human interaction") return nil } // Stop gracefully stops the terminal interface func (ti *TerminalInterface) Stop(ctx context.Context) error { if !ti.running { return nil } ti.logger.Info("πŸ›‘ Stopping terminal interface") ti.running = false fmt.Println("\nπŸ‘‹ Human Agent Portal shutting down. Goodbye!") return nil } // displayWelcome shows the welcome message and commands func (ti *TerminalInterface) displayWelcome() { fmt.Println("\n" + strings.Repeat("=", 60)) fmt.Println("🎯 BZZZ Human Agent Portal (HAP)") fmt.Println(" Welcome to collaborative AI task coordination") fmt.Println(strings.Repeat("=", 60)) if ti.services.Node != nil { fmt.Printf("πŸ“ Node ID: %s\n", ti.services.Node.ID().ShortString()) } if ti.services.Config != nil { fmt.Printf("πŸ€– Agent ID: %s\n", ti.services.Config.Agent.ID) if ti.services.Config.Agent.Role != "" { fmt.Printf("🎭 Role: %s\n", ti.services.Config.Agent.Role) } } if ti.services.Node != nil { fmt.Printf("🌐 Connected Peers: %d\n", ti.services.Node.ConnectedPeers()) } fmt.Println("\nπŸ“‹ Available Commands:") fmt.Println(" status - Show system status") fmt.Println(" peers - List connected peers") fmt.Println(" send - Send message to coordination channel") fmt.Println(" role - Show role information") fmt.Println(" tasks - Show task information") fmt.Println(" health - Show health status") fmt.Println(" help - Show this help message") fmt.Println(" quit/exit - Exit the interface") fmt.Println(strings.Repeat("-", 60)) fmt.Print("HAP> ") } // processCommands handles user input and commands func (ti *TerminalInterface) processCommands(ctx context.Context) { for ti.running && ti.scanner.Scan() { input := strings.TrimSpace(ti.scanner.Text()) if input == "" { fmt.Print("HAP> ") continue } // Parse command and arguments parts := strings.Fields(input) command := strings.ToLower(parts[0]) switch command { case "quit", "exit": ti.running = false return case "help": ti.showHelp() case "status": ti.showStatus() case "peers": ti.showPeers() case "role": ti.showRole() case "tasks": ti.showTasks() case "health": ti.showHealth() case "send": if len(parts) < 2 { fmt.Println("❌ Usage: send ") } else { message := strings.Join(parts[1:], " ") ti.sendMessage(message) } default: fmt.Printf("❌ Unknown command: %s (type 'help' for available commands)\n", command) } fmt.Print("HAP> ") } } // showHelp displays the help message func (ti *TerminalInterface) showHelp() { fmt.Println("\nπŸ“‹ HAP Commands:") fmt.Println(" status - Show current system status") fmt.Println(" peers - List all connected P2P peers") fmt.Println(" send - Send message to coordination channel") fmt.Println(" role - Display role and capability information") fmt.Println(" tasks - Show active tasks (if any)") fmt.Println(" health - Display system health status") fmt.Println(" help - Show this help message") fmt.Println(" quit/exit - Exit the Human Agent Portal") } // showStatus displays the current system status func (ti *TerminalInterface) showStatus() { fmt.Println("\nπŸ“Š System Status:") fmt.Println(strings.Repeat("-", 40)) if ti.services.Node != nil { fmt.Printf("🌐 P2P Status: Connected (%d peers)\n", ti.services.Node.ConnectedPeers()) fmt.Printf("πŸ“ Node ID: %s\n", ti.services.Node.ID().ShortString()) } if ti.services.Config != nil { fmt.Printf("πŸ€– Agent ID: %s\n", ti.services.Config.Agent.ID) fmt.Printf("🎭 Role: %s\n", ti.services.Config.Agent.Role) fmt.Printf("🎯 Specialization: %s\n", ti.services.Config.Agent.Specialization) } // Service status fmt.Printf("πŸ“‘ PubSub: %s\n", ti.getServiceStatus("PubSub", ti.services.PubSub != nil)) fmt.Printf("πŸ•ΈοΈ DHT: %s\n", ti.getServiceStatus("DHT", ti.services.DHT != nil)) fmt.Printf("πŸ”— UCXI: %s\n", ti.getServiceStatus("UCXI", ti.services.UCXIServer != nil)) fmt.Printf("πŸ—³οΈ Elections: %s\n", ti.getServiceStatus("Elections", ti.services.ElectionManager != nil)) fmt.Printf("❀️ Health: %s\n", ti.getServiceStatus("Health", ti.services.HealthManager != nil)) fmt.Printf("⏰ Uptime: %s\n", time.Since(time.Now().Add(-5*time.Minute)).String()) // Placeholder } // showPeers displays connected peers func (ti *TerminalInterface) showPeers() { fmt.Println("\n🌐 Connected Peers:") fmt.Println(strings.Repeat("-", 40)) if ti.services.Node != nil { peerCount := ti.services.Node.ConnectedPeers() fmt.Printf("Total Connected: %d\n", peerCount) if peerCount == 0 { fmt.Println("No peers currently connected") fmt.Println("πŸ’‘ Tip: Make sure other BZZZ nodes are running on your network") } else { fmt.Println("πŸ” Use P2P tools to see detailed peer information") } } else { fmt.Println("❌ P2P node not available") } } // showRole displays role and capability information func (ti *TerminalInterface) showRole() { fmt.Println("\n🎭 Role Information:") fmt.Println(strings.Repeat("-", 40)) if ti.services.Config != nil { cfg := ti.services.Config fmt.Printf("Role: %s\n", cfg.Agent.Role) fmt.Printf("Expertise: %v\n", cfg.Agent.Expertise) fmt.Printf("Reports To: %v\n", cfg.Agent.ReportsTo) fmt.Printf("Deliverables: %v\n", cfg.Agent.Deliverables) fmt.Printf("Capabilities: %v\n", cfg.Agent.Capabilities) fmt.Printf("Specialization: %s\n", cfg.Agent.Specialization) // Authority level if authority, err := cfg.GetRoleAuthority(cfg.Agent.Role); err == nil { fmt.Printf("Authority Level: %s\n", authority) } } else { fmt.Println("❌ Configuration not available") } } // showTasks displays task information func (ti *TerminalInterface) showTasks() { fmt.Println("\nπŸ“‹ Task Information:") fmt.Println(strings.Repeat("-", 40)) // HAP doesn't execute tasks like agents, but can show coordination status fmt.Println("πŸ“ HAP Role: Human interaction facilitator") fmt.Println("🎯 Purpose: Coordinate with autonomous agents") fmt.Println("πŸ’Ό Current Mode: Interactive terminal") if ti.services.TaskCoordinator != nil { fmt.Println("βœ… Task coordination system is active") } else { fmt.Println("❌ Task coordination system not available") } } // showHealth displays health status func (ti *TerminalInterface) showHealth() { fmt.Println("\n❀️ Health Status:") fmt.Println(strings.Repeat("-", 40)) if ti.services.HealthManager != nil { status := ti.services.HealthManager.GetOverallStatus() healthIcon := "βœ…" if !status.Healthy { healthIcon = "❌" } fmt.Printf("%s Overall Health: %s\n", healthIcon, ti.boolToStatus(status.Healthy)) fmt.Printf("πŸ“‹ Details: %s\n", status.Message) fmt.Printf("⏰ Last Check: %s\n", status.Timestamp.Format(time.RFC3339)) } else { fmt.Println("❌ Health manager not available") } } // sendMessage sends a message to the coordination channel func (ti *TerminalInterface) sendMessage(message string) { if ti.services.PubSub == nil { fmt.Println("❌ PubSub not available - cannot send message") return } // Create a human-authored message messageData := map[string]interface{}{ "type": "human_message", "author": "human", "node_id": ti.services.Node.ID().ShortString(), "agent_id": ti.services.Config.Agent.ID, "role": ti.services.Config.Agent.Role, "message": message, "timestamp": time.Now().Unix(), } // Send to coordination channel if err := ti.services.PubSub.PublishBzzzMessage("coordination", messageData); err != nil { fmt.Printf("❌ Failed to send message: %v\n", err) } else { fmt.Printf("πŸ“€ Message sent to coordination channel\n") fmt.Printf("πŸ’¬ \"%s\"\n", message) } } // Helper functions func (ti *TerminalInterface) getServiceStatus(serviceName string, available bool) string { if available { return "βœ… Active" } return "❌ Inactive" } func (ti *TerminalInterface) boolToStatus(b bool) string { if b { return "Healthy" } return "Unhealthy" } // IsRunning returns whether the terminal interface is running func (ti *TerminalInterface) IsRunning() bool { return ti.running } // GetServices returns the runtime services func (ti *TerminalInterface) GetServices() *runtime.RuntimeServices { return ti.services }