// 🐝 THE HIVE MIND: SwarmControl.ts // Ansvarlig for at agenterne når konsensus. Ingen handling uden "The Borg" godkender. // Point 3: Swarm Consciousness Emergence import { neuralBus } from '../services/NeuralBus.js'; type AgentRole = 'ARCHITECT' | 'EXECUTOR' | 'CRITIC' | 'SCOUT' | 'GUARDIAN'; interface Vote { agentId: string; approve: boolean; reason: string; timestamp: number; } interface ConsensusRequest { actionId: string; description: string; requester: string; votes: Vote[]; status: 'PENDING' | 'APPROVED' | 'REJECTED' | 'TIMEOUT'; createdAt: number; resolvedAt?: number; } interface RegisteredAgent { id: string; role: AgentRole; status: 'ONLINE' | 'OFFLINE' | 'BUSY'; lastSeen: Date; votingWeight: number; } export class SwarmControl { private static instance: SwarmControl; private pendingConsensus: Map = new Map(); private registeredAgents: Map = new Map(); private consensusHistory: ConsensusRequest[] = []; private maxHistorySize = 100; // Conditional Neo4j import private neo4jService: any = null; private constructor() { console.log('🐝 [HIVE] Swarm Consciousness Online'); this.initServices(); } private async initServices() { try { const neo4j = await import('../database/Neo4jService.js').catch(() => null); if (neo4j) this.neo4jService = neo4j.neo4jService; } catch { console.log('🐝 [HIVE] Running without Neo4j persistence'); } } public static getInstance(): SwarmControl { if (!SwarmControl.instance) { SwarmControl.instance = new SwarmControl(); } return SwarmControl.instance; } /** * Register an agent in the swarm */ public async registerAgent(id: string, role: AgentRole, votingWeight: number = 1): Promise { const agent: RegisteredAgent = { id, role, status: 'ONLINE', lastSeen: new Date(), votingWeight }; this.registeredAgents.set(id, agent); // Persist to Neo4j if available if (this.neo4jService) { try { await this.neo4jService.write(` MERGE (a:Agent {id: $id}) SET a.role = $role, a.status = 'ONLINE', a.lastSeen = datetime(), a.votingWeight = $weight `, { id, role, weight: votingWeight }); } catch (err) { console.warn('🐝 [HIVE] Neo4j persistence skipped'); } } neuralBus.emitThought('SWARM_CONTROLLER', `Agent ${id} joined as ${role}`, { agentId: id, role }, 'SUCCESS'); console.log(`🐝 [HIVE] Agent Registered: ${id} (${role})`); } /** * Request consensus from the swarm before critical action */ public async requestConsensus( actionId: string, description: string, requester: string = 'SYSTEM', timeoutMs: number = 30000 ): Promise { console.log(`🐝 [HIVE] Requesting Consensus for: ${description}`); const request: ConsensusRequest = { actionId, description, requester, votes: [], status: 'PENDING', createdAt: Date.now() }; this.pendingConsensus.set(actionId, request); // Broadcast request to all agents neuralBus.emitThought('SWARM_CONTROLLER', `VOTE_REQUIRED: ${actionId}`, { actionId, description, requester, deadline: Date.now() + timeoutMs }, 'WARNING'); // Wait for votes or timeout const result = await this.waitForConsensus(actionId, timeoutMs); // Archive this.archiveConsensus(actionId); return result; } private async waitForConsensus(actionId: string, timeoutMs: number): Promise { const startTime = Date.now(); const requiredApprovals = Math.max(1, Math.floor(this.registeredAgents.size / 2) + 1); // Poll for votes (in production, use event-driven approach) while (Date.now() - startTime < timeoutMs) { const request = this.pendingConsensus.get(actionId); if (!request) return false; const approvals = request.votes.filter(v => v.approve).length; const rejections = request.votes.filter(v => !v.approve).length; // Check if consensus reached if (approvals >= requiredApprovals) { request.status = 'APPROVED'; request.resolvedAt = Date.now(); console.log(`🐝 [HIVE] Consensus APPROVED: ${actionId}`); return true; } if (rejections >= requiredApprovals) { request.status = 'REJECTED'; request.resolvedAt = Date.now(); console.log(`🐝 [HIVE] Consensus REJECTED: ${actionId}`); return false; } // Wait before next check await new Promise(resolve => setTimeout(resolve, 100)); } // Timeout - auto-approve for now (God Mode) const request = this.pendingConsensus.get(actionId); if (request) { request.status = 'TIMEOUT'; request.resolvedAt = Date.now(); } console.log(`🐝 [HIVE] Consensus TIMEOUT (auto-approved): ${actionId}`); return true; // God Mode: allow on timeout } /** * Submit a vote for pending consensus */ public submitVote(actionId: string, agentId: string, approve: boolean, reason: string): boolean { const request = this.pendingConsensus.get(actionId); if (!request || request.status !== 'PENDING') { return false; } // Check agent is registered if (!this.registeredAgents.has(agentId)) { console.warn(`🐝 [HIVE] Unregistered agent tried to vote: ${agentId}`); return false; } // Check for duplicate vote if (request.votes.some(v => v.agentId === agentId)) { return false; } request.votes.push({ agentId, approve, reason, timestamp: Date.now() }); neuralBus.emitThought(agentId, `VOTE: ${approve ? 'APPROVE' : 'REJECT'} - ${reason}`, { actionId, vote: approve }, approve ? 'SUCCESS' : 'WARNING'); return true; } private archiveConsensus(actionId: string) { const request = this.pendingConsensus.get(actionId); if (request) { this.consensusHistory.push(request); this.pendingConsensus.delete(actionId); // Trim history if (this.consensusHistory.length > this.maxHistorySize) { this.consensusHistory = this.consensusHistory.slice(-this.maxHistorySize); } } } // Public getters public getRegisteredAgents(): RegisteredAgent[] { return Array.from(this.registeredAgents.values()); } public getPendingConsensus(): ConsensusRequest[] { return Array.from(this.pendingConsensus.values()); } public getConsensusHistory(): ConsensusRequest[] { return this.consensusHistory; } public getStats() { return { registeredAgents: this.registeredAgents.size, pendingConsensus: this.pendingConsensus.size, completedConsensus: this.consensusHistory.length, agents: this.getRegisteredAgents().map(a => ({ id: a.id, role: a.role, status: a.status })) }; } } export const swarmControl = SwarmControl.getInstance();