UNPKG

claude-flow-multilang

Version:

Revolutionary multilingual AI orchestration framework with cultural awareness and DDD architecture

741 lines (620 loc) 18.1 kB
/** * Swarm Communication System for Hive Mind * Handles inter-agent messaging and coordination */ import EventEmitter from 'events'; import crypto from 'crypto'; /** * Message types and their priorities */ const MESSAGE_TYPES = { command: { priority: 1, reliable: true, encrypted: true }, query: { priority: 2, reliable: true, encrypted: false }, response: { priority: 2, reliable: true, encrypted: false }, broadcast: { priority: 3, reliable: false, encrypted: false }, heartbeat: { priority: 4, reliable: false, encrypted: false }, consensus: { priority: 1, reliable: true, encrypted: true }, task: { priority: 2, reliable: true, encrypted: false }, result: { priority: 2, reliable: true, encrypted: false }, error: { priority: 1, reliable: true, encrypted: false }, sync: { priority: 3, reliable: true, encrypted: false }, }; /** * Communication protocols */ const PROTOCOLS = { direct: 'direct', // Point-to-point broadcast: 'broadcast', // One-to-all multicast: 'multicast', // One-to-many gossip: 'gossip', // Epidemic spread consensus: 'consensus', // Byzantine agreement }; /** * SwarmCommunication class */ export class SwarmCommunication extends EventEmitter { constructor(config = {}) { super(); this.config = { swarmId: config.swarmId, encryption: config.encryption || false, maxRetries: config.maxRetries || 3, timeout: config.timeout || 5000, bufferSize: config.bufferSize || 1000, gossipFanout: config.gossipFanout || 3, consensusQuorum: config.consensusQuorum || 0.67, ...config, }; this.state = { agents: new Map(), // Connected agents channels: new Map(), // Communication channels messageBuffer: [], // Message queue messageHistory: new Map(), // Sent messages metrics: { sent: 0, received: 0, failed: 0, encrypted: 0, latency: [], }, }; this.encryptionKey = this.config.encryption ? crypto.randomBytes(32) : null; this._initialize(); } /** * Initialize communication system */ _initialize() { // Set up message processing this.messageProcessor = setInterval(() => { this._processMessageBuffer(); }, 100); // Set up heartbeat this.heartbeatTimer = setInterval(() => { this._sendHeartbeats(); }, 10000); this.emit('communication:initialized', { swarmId: this.config.swarmId }); } /** * Register agent in communication network */ registerAgent(agentId, metadata = {}) { const agent = { id: agentId, status: 'online', lastSeen: Date.now(), metadata, messageCount: 0, channel: this._createChannel(agentId), }; this.state.agents.set(agentId, agent); // Announce new agent to swarm this.broadcast( { type: 'agent_joined', agentId, metadata, }, 'sync', ); this.emit('agent:registered', agent); return agent; } /** * Unregister agent from network */ unregisterAgent(agentId) { const agent = this.state.agents.get(agentId); if (!agent) return; // Close channel const channel = this.state.channels.get(agentId); if (channel) { channel.close(); this.state.channels.delete(agentId); } this.state.agents.delete(agentId); // Announce agent departure this.broadcast( { type: 'agent_left', agentId, }, 'sync', ); this.emit('agent:unregistered', { agentId }); } /** * Send direct message to agent */ async send(toAgentId, message, type = 'query') { const messageId = this._generateMessageId(); const timestamp = Date.now(); const envelope = { id: messageId, from: 'system', // Will be set by sender to: toAgentId, type, timestamp, message, protocol: PROTOCOLS.direct, }; // Encrypt if needed if (this.config.encryption && MESSAGE_TYPES[type]?.encrypted) { envelope.message = this._encrypt(message); envelope.encrypted = true; this.state.metrics.encrypted++; } // Add to buffer this._addToBuffer(envelope); // Track message this.state.messageHistory.set(messageId, { ...envelope, status: 'pending', attempts: 0, }); this.state.metrics.sent++; // Return promise that resolves when message is acknowledged return new Promise((resolve, reject) => { const timeout = setTimeout(() => { reject(new Error(`Message timeout: ${messageId}`)); }, this.config.timeout); this.once(`ack:${messageId}`, () => { clearTimeout(timeout); resolve({ messageId, delivered: true }); }); this.once(`nack:${messageId}`, (error) => { clearTimeout(timeout); reject(error); }); }); } /** * Broadcast message to all agents */ broadcast(message, type = 'broadcast') { const messageId = this._generateMessageId(); const timestamp = Date.now(); const envelope = { id: messageId, from: 'system', to: '*', type, timestamp, message, protocol: PROTOCOLS.broadcast, }; // Broadcasts are typically not encrypted this._addToBuffer(envelope); this.state.metrics.sent++; this.emit('message:broadcast', envelope); return { messageId, recipients: this.state.agents.size }; } /** * Multicast message to specific agents */ multicast(agentIds, message, type = 'query') { const messageId = this._generateMessageId(); const timestamp = Date.now(); const envelopes = agentIds.map((agentId) => ({ id: `${messageId}-${agentId}`, from: 'system', to: agentId, type, timestamp, message, protocol: PROTOCOLS.multicast, groupId: messageId, })); envelopes.forEach((envelope) => this._addToBuffer(envelope)); this.state.metrics.sent += envelopes.length; return { messageId, recipients: agentIds.length }; } /** * Gossip protocol for epidemic spread */ gossip(message, type = 'sync') { const messageId = this._generateMessageId(); const timestamp = Date.now(); // Select random agents for initial spread const agents = Array.from(this.state.agents.keys()); const selected = this._selectRandomAgents(agents, this.config.gossipFanout); selected.forEach((agentId) => { const envelope = { id: `${messageId}-${agentId}`, from: 'system', to: agentId, type, timestamp, message: { ...message, _gossip: { originalId: messageId, hops: 0, seen: [], }, }, protocol: PROTOCOLS.gossip, }; this._addToBuffer(envelope); }); this.state.metrics.sent += selected.length; return { messageId, initialTargets: selected }; } /** * Byzantine consensus protocol */ async consensus(proposal, validators = []) { const consensusId = this._generateMessageId(); const timestamp = Date.now(); // If no validators specified, use all online agents if (validators.length === 0) { validators = Array.from(this.state.agents.keys()).filter( (id) => this.state.agents.get(id).status === 'online', ); } const votes = new Map(); const votePromises = []; // Phase 1: Proposal validators.forEach((agentId) => { const envelope = { id: `${consensusId}-propose-${agentId}`, from: 'system', to: agentId, type: 'consensus', timestamp, message: { phase: 'propose', consensusId, proposal, }, protocol: PROTOCOLS.consensus, }; this._addToBuffer(envelope); // Create promise for vote const votePromise = new Promise((resolve) => { this.once(`vote:${consensusId}:${agentId}`, (vote) => { votes.set(agentId, vote); resolve({ agentId, vote }); }); // Timeout for vote setTimeout(() => { if (!votes.has(agentId)) { votes.set(agentId, null); resolve({ agentId, vote: null }); } }, this.config.timeout); }); votePromises.push(votePromise); }); // Wait for all votes await Promise.all(votePromises); // Phase 2: Tally and decide const voteCount = {}; let totalVotes = 0; votes.forEach((vote) => { if (vote !== null) { voteCount[vote] = (voteCount[vote] || 0) + 1; totalVotes++; } }); // Check if consensus reached const sortedVotes = Object.entries(voteCount).sort((a, b) => b[1] - a[1]); const winner = sortedVotes[0]; const consensusReached = winner && winner[1] / validators.length >= this.config.consensusQuorum; const result = { consensusId, proposal, validators: validators.length, votes: Object.fromEntries(votes), voteCount, winner: consensusReached ? winner[0] : null, consensusReached, quorum: this.config.consensusQuorum, timestamp: Date.now(), }; // Phase 3: Announce result this.broadcast( { phase: 'result', consensusId, result, }, 'consensus', ); this.emit('consensus:completed', result); return result; } /** * Handle incoming message */ handleMessage(envelope) { this.state.metrics.received++; // Update agent last seen const agent = this.state.agents.get(envelope.from); if (agent) { agent.lastSeen = Date.now(); agent.messageCount++; } // Decrypt if needed if (envelope.encrypted && this.config.encryption) { try { envelope.message = this._decrypt(envelope.message); } catch (error) { this.emit('error', { type: 'decryption_failed', envelope, error }); return; } } // Process based on protocol switch (envelope.protocol) { case PROTOCOLS.direct: this._handleDirectMessage(envelope); break; case PROTOCOLS.broadcast: this._handleBroadcastMessage(envelope); break; case PROTOCOLS.multicast: this._handleMulticastMessage(envelope); break; case PROTOCOLS.gossip: this._handleGossipMessage(envelope); break; case PROTOCOLS.consensus: this._handleConsensusMessage(envelope); break; default: this.emit('error', { type: 'unknown_protocol', envelope }); } // Emit general message event this.emit('message:received', envelope); } /** * Handle direct message */ _handleDirectMessage(envelope) { // Send acknowledgment this._sendAck(envelope.id, envelope.from); // Emit specific event for message type this.emit(`message:${envelope.type}`, envelope); } /** * Handle broadcast message */ _handleBroadcastMessage(envelope) { // No ack for broadcasts this.emit(`broadcast:${envelope.type}`, envelope); } /** * Handle multicast message */ _handleMulticastMessage(envelope) { // Send ack to original sender this._sendAck(envelope.groupId, envelope.from); this.emit(`multicast:${envelope.type}`, envelope); } /** * Handle gossip message */ _handleGossipMessage(envelope) { const gossipData = envelope.message._gossip; // Check if we've seen this message if (gossipData.seen.includes(this.config.swarmId)) { return; } // Mark as seen gossipData.seen.push(this.config.swarmId); gossipData.hops++; // Process the message this.emit(`gossip:${envelope.type}`, envelope); // Continue spreading if hop count is low if (gossipData.hops < 3) { const agents = Array.from(this.state.agents.keys()).filter( (id) => !gossipData.seen.includes(id), ); const selected = this._selectRandomAgents(agents, this.config.gossipFanout); selected.forEach((agentId) => { const newEnvelope = { ...envelope, id: `${gossipData.originalId}-${agentId}-hop${gossipData.hops}`, to: agentId, from: this.config.swarmId, }; this._addToBuffer(newEnvelope); }); } } /** * Handle consensus message */ _handleConsensusMessage(envelope) { const { phase, consensusId } = envelope.message; switch (phase) { case 'propose': // Agent should vote on proposal this.emit('consensus:proposal', envelope); break; case 'vote': // Collect vote this.emit(`vote:${consensusId}:${envelope.from}`, envelope.message.vote); break; case 'result': // Consensus result announced this.emit('consensus:result', envelope.message.result); break; } } /** * Send acknowledgment */ _sendAck(messageId, toAgent) { const ack = { id: `ack-${messageId}`, from: this.config.swarmId, to: toAgent, type: 'ack', timestamp: Date.now(), message: { originalId: messageId }, protocol: PROTOCOLS.direct, }; this._addToBuffer(ack); } /** * Create communication channel */ _createChannel(agentId) { // In production, this would create actual network channels // For now, we simulate with event emitters const channel = new EventEmitter(); channel.send = (message) => { this.emit(`channel:${agentId}`, message); }; channel.close = () => { channel.removeAllListeners(); }; this.state.channels.set(agentId, channel); return channel; } /** * Add message to buffer */ _addToBuffer(envelope) { this.state.messageBuffer.push(envelope); // Limit buffer size if (this.state.messageBuffer.length > this.config.bufferSize) { const dropped = this.state.messageBuffer.shift(); this.emit('message:dropped', dropped); } } /** * Process message buffer */ _processMessageBuffer() { const toProcess = this.state.messageBuffer.splice(0, 10); toProcess.forEach((envelope) => { // Simulate network delay setTimeout(() => { if (envelope.to === '*') { // Broadcast to all agents this.state.agents.forEach((agent) => { this.emit(`deliver:${agent.id}`, envelope); }); } else { // Direct delivery this.emit(`deliver:${envelope.to}`, envelope); } // Update message history const history = this.state.messageHistory.get(envelope.id); if (history) { history.status = 'sent'; history.sentAt = Date.now(); } }, Math.random() * 100); }); } /** * Send heartbeats to all agents */ _sendHeartbeats() { const now = Date.now(); this.state.agents.forEach((agent, agentId) => { // Check if agent is still responsive if (now - agent.lastSeen > 30000) { agent.status = 'offline'; this.emit('agent:offline', { agentId }); } // Send heartbeat const heartbeat = { id: `heartbeat-${now}-${agentId}`, from: 'system', to: agentId, type: 'heartbeat', timestamp: now, message: { timestamp: now }, protocol: PROTOCOLS.direct, }; this._addToBuffer(heartbeat); }); } /** * Select random agents */ _selectRandomAgents(agents, count) { const shuffled = [...agents].sort(() => Math.random() - 0.5); return shuffled.slice(0, Math.min(count, agents.length)); } /** * Generate unique message ID */ _generateMessageId() { return `msg-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`; } /** * Encrypt message */ _encrypt(data) { if (!this.encryptionKey) return data; const iv = crypto.randomBytes(16); const cipher = crypto.createCipheriv('aes-256-cbc', this.encryptionKey, iv); let encrypted = cipher.update(JSON.stringify(data), 'utf8', 'hex'); encrypted += cipher.final('hex'); return { iv: iv.toString('hex'), data: encrypted, }; } /** * Decrypt message */ _decrypt(encrypted) { if (!this.encryptionKey) return encrypted; const iv = Buffer.from(encrypted.iv, 'hex'); const decipher = crypto.createDecipheriv('aes-256-cbc', this.encryptionKey, iv); let decrypted = decipher.update(encrypted.data, 'hex', 'utf8'); decrypted += decipher.final('utf8'); return JSON.parse(decrypted); } /** * Get communication statistics */ getStatistics() { const avgLatency = this.state.metrics.latency.length > 0 ? this.state.metrics.latency.reduce((a, b) => a + b, 0) / this.state.metrics.latency.length : 0; return { agents: { total: this.state.agents.size, online: Array.from(this.state.agents.values()).filter((a) => a.status === 'online').length, offline: Array.from(this.state.agents.values()).filter((a) => a.status === 'offline') .length, }, messages: { sent: this.state.metrics.sent, received: this.state.metrics.received, failed: this.state.metrics.failed, encrypted: this.state.metrics.encrypted, buffered: this.state.messageBuffer.length, }, performance: { avgLatency: avgLatency.toFixed(2), successRate: this.state.metrics.sent > 0 ? ( ((this.state.metrics.sent - this.state.metrics.failed) / this.state.metrics.sent) * 100 ).toFixed(2) : 100, }, }; } /** * Close communication system */ close() { // Clear timers if (this.messageProcessor) clearInterval(this.messageProcessor); if (this.heartbeatTimer) clearInterval(this.heartbeatTimer); // Close all channels this.state.channels.forEach((channel) => channel.close()); this.emit('communication:closed'); } }