UNPKG

claude-flow-multilang

Version:

Revolutionary multilingual AI orchestration framework with cultural awareness and DDD architecture

495 lines (423 loc) 12.9 kB
/** * Communication Class * * Manages inter-agent messaging, broadcasts, and communication protocols * within the Hive Mind swarm. */ import { EventEmitter } from 'events'; import { DatabaseManager } from './DatabaseManager.js'; import { Agent } from './Agent.js'; import { Message, MessageType, MessagePriority, CommunicationStats, CommunicationChannel, } from '../types.js'; export class Communication extends EventEmitter { private swarmId: string; private db: DatabaseManager; private agents: Map<string, Agent>; private channels: Map<string, CommunicationChannel>; private messageQueue: Map<MessagePriority, Message[]>; private stats: CommunicationStats; private isActive: boolean = false; constructor(swarmId: string) { super(); this.swarmId = swarmId; this.agents = new Map(); this.channels = new Map(); this.messageQueue = new Map([ ['urgent', []], ['high', []], ['normal', []], ['low', []], ]); this.stats = { totalMessages: 0, avgLatency: 0, activeChannels: 0, messagesByType: {}, throughput: 0, }; } /** * Initialize communication system */ async initialize(): Promise<void> { this.db = await DatabaseManager.getInstance(); // Set up default channels this.setupDefaultChannels(); // Start message processing this.startMessageProcessor(); this.startLatencyMonitor(); this.startStatsCollector(); this.isActive = true; this.emit('initialized'); } /** * Add an agent to the communication network */ addAgent(agent: Agent): void { this.agents.set(agent.id, agent); // Create agent-specific channels this.createAgentChannels(agent); // Subscribe agent to relevant channels this.subscribeAgentToChannels(agent); this.emit('agentAdded', { agentId: agent.id }); } /** * Remove an agent from the communication network */ removeAgent(agentId: string): void { this.agents.delete(agentId); // Remove agent from channels this.channels.forEach((channel) => { channel.subscribers = channel.subscribers.filter((id) => id !== agentId); }); this.emit('agentRemoved', { agentId }); } /** * Send a message */ async sendMessage(message: Message): Promise<void> { // Store in database await this.db.createCommunication({ from_agent_id: message.fromAgentId, to_agent_id: message.toAgentId, swarm_id: this.swarmId, message_type: message.type, content: JSON.stringify(message.content), priority: message.priority || 'normal', requires_response: message.requiresResponse || false, }); // Add to queue const priority = message.priority || 'normal'; this.messageQueue.get(priority)!.push(message); // Update stats this.stats.totalMessages++; this.stats.messagesByType[message.type] = (this.stats.messagesByType[message.type] || 0) + 1; this.emit('messageSent', message); } /** * Broadcast a message to all agents */ async broadcast( fromAgentId: string, type: MessageType, content: any, priority: MessagePriority = 'normal', ): Promise<void> { const message: Message = { id: this.generateMessageId(), fromAgentId, toAgentId: null, // null indicates broadcast swarmId: this.swarmId, type, content, priority, timestamp: new Date(), requiresResponse: false, }; await this.sendMessage(message); } /** * Send a message to a specific channel */ async sendToChannel( channelName: string, fromAgentId: string, content: any, priority: MessagePriority = 'normal', ): Promise<void> { const channel = this.channels.get(channelName); if (!channel) { throw new Error(`Channel ${channelName} not found`); } // Send to all subscribers for (const subscriberId of channel.subscribers) { if (subscriberId !== fromAgentId) { const message: Message = { id: this.generateMessageId(), fromAgentId, toAgentId: subscriberId, swarmId: this.swarmId, type: 'channel', content: { channel: channelName, data: content, }, priority, timestamp: new Date(), requiresResponse: false, }; await this.sendMessage(message); } } } /** * Request response from an agent */ async requestResponse( fromAgentId: string, toAgentId: string, query: any, timeout: number = 5000, ): Promise<any> { const message: Message = { id: this.generateMessageId(), fromAgentId, toAgentId, swarmId: this.swarmId, type: 'query', content: query, priority: 'high', timestamp: new Date(), requiresResponse: true, }; await this.sendMessage(message); // Wait for response return new Promise((resolve, reject) => { const timer = setTimeout(() => { reject(new Error('Response timeout')); }, timeout); const responseHandler = (response: Message) => { if (response.content.queryId === message.id) { clearTimeout(timer); this.off('messageReceived', responseHandler); resolve(response.content.response); } }; this.on('messageReceived', responseHandler); }); } /** * Create a new communication channel */ createChannel(name: string, description: string, type: 'public' | 'private' = 'public'): void { if (this.channels.has(name)) { throw new Error(`Channel ${name} already exists`); } const channel: CommunicationChannel = { name, description, type, subscribers: [], createdAt: new Date(), }; this.channels.set(name, channel); this.stats.activeChannels++; this.emit('channelCreated', { channel }); } /** * Subscribe an agent to a channel */ subscribeToChannel(agentId: string, channelName: string): void { const channel = this.channels.get(channelName); if (!channel) { throw new Error(`Channel ${channelName} not found`); } if (!channel.subscribers.includes(agentId)) { channel.subscribers.push(agentId); this.emit('channelSubscribed', { agentId, channelName }); } } /** * Unsubscribe an agent from a channel */ unsubscribeFromChannel(agentId: string, channelName: string): void { const channel = this.channels.get(channelName); if (!channel) { return; } channel.subscribers = channel.subscribers.filter((id) => id !== agentId); this.emit('channelUnsubscribed', { agentId, channelName }); } /** * Get communication statistics */ async getStats(): Promise<CommunicationStats> { // Calculate throughput const recentMessages = await this.db.getRecentMessages(this.swarmId, 60000); // Last minute this.stats.throughput = recentMessages.length; return { ...this.stats }; } /** * Get pending messages for an agent */ async getPendingMessages(agentId: string): Promise<Message[]> { const messages = await this.db.getPendingMessages(agentId); return messages.map((msg) => ({ id: msg.id.toString(), fromAgentId: msg.from_agent_id, toAgentId: msg.to_agent_id, swarmId: msg.swarm_id, type: msg.message_type as MessageType, content: JSON.parse(msg.content), priority: msg.priority as MessagePriority, timestamp: new Date(msg.timestamp), requiresResponse: msg.requires_response, })); } /** * Mark message as delivered */ async markDelivered(messageId: string): Promise<void> { await this.db.markMessageDelivered(messageId); } /** * Mark message as read */ async markRead(messageId: string): Promise<void> { await this.db.markMessageRead(messageId); } /** * Setup default communication channels */ private setupDefaultChannels(): void { // System channels this.createChannel('system', 'System-wide notifications and alerts'); this.createChannel('coordination', 'Task coordination messages'); this.createChannel('consensus', 'Consensus voting and decisions'); this.createChannel('monitoring', 'Performance and health monitoring'); // Agent type channels this.createChannel('coordinators', 'Coordinator agent communications'); this.createChannel('researchers', 'Researcher agent communications'); this.createChannel('coders', 'Coder agent communications'); this.createChannel('analysts', 'Analyst agent communications'); } /** * Create channels for a specific agent */ private createAgentChannels(agent: Agent): void { // Direct message channel this.createChannel(`agent-${agent.id}`, `Direct messages for ${agent.name}`, 'private'); // Team channel if agent is coordinator if (agent.type === 'coordinator') { this.createChannel(`team-${agent.id}`, `Team channel led by ${agent.name}`); } } /** * Subscribe agent to relevant channels */ private subscribeAgentToChannels(agent: Agent): void { // Subscribe to system channels this.subscribeToChannel(agent.id, 'system'); this.subscribeToChannel(agent.id, 'coordination'); // Subscribe to type-specific channel const typeChannel = `${agent.type}s`; if (this.channels.has(typeChannel)) { this.subscribeToChannel(agent.id, typeChannel); } // Subscribe to own direct channel this.subscribeToChannel(agent.id, `agent-${agent.id}`); // Special subscriptions based on capabilities if (agent.capabilities.includes('consensus_building')) { this.subscribeToChannel(agent.id, 'consensus'); } if (agent.capabilities.includes('system_monitoring')) { this.subscribeToChannel(agent.id, 'monitoring'); } } /** * Start message processor */ private startMessageProcessor(): void { setInterval(async () => { if (!this.isActive) return; // Process messages by priority for (const [priority, messages] of this.messageQueue) { if (messages.length === 0) continue; // Process batch of messages const batch = messages.splice(0, 10); // Process up to 10 messages for (const message of batch) { await this.processMessage(message); } } }, 100); // Every 100ms } /** * Process a single message */ private async processMessage(message: Message): Promise<void> { const startTime = Date.now(); try { if (message.toAgentId) { // Direct message const agent = this.agents.get(message.toAgentId); if (agent) { await agent.receiveMessage(message); await this.markDelivered(message.id); } } else { // Broadcast message for (const agent of this.agents.values()) { if (agent.id !== message.fromAgentId) { await agent.receiveMessage(message); } } } // Update latency stats const latency = Date.now() - startTime; this.updateLatencyStats(latency); this.emit('messageProcessed', { message, latency }); } catch (error) { this.emit('messageError', { message, error }); } } /** * Update latency statistics */ private updateLatencyStats(latency: number): void { // Simple moving average this.stats.avgLatency = this.stats.avgLatency * 0.9 + latency * 0.1; } /** * Start latency monitor */ private startLatencyMonitor(): void { setInterval(async () => { if (!this.isActive) return; // Check for high latency if (this.stats.avgLatency > 1000) { this.emit('highLatency', { avgLatency: this.stats.avgLatency }); } }, 5000); // Every 5 seconds } /** * Start statistics collector */ private startStatsCollector(): void { setInterval(async () => { if (!this.isActive) return; // Store stats in database await this.db.storePerformanceMetric({ swarm_id: this.swarmId, metric_type: 'communication_throughput', metric_value: this.stats.throughput, }); await this.db.storePerformanceMetric({ swarm_id: this.swarmId, metric_type: 'communication_latency', metric_value: this.stats.avgLatency, }); }, 60000); // Every minute } /** * Generate unique message ID */ private generateMessageId(): string { return `msg-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`; } /** * Shutdown communication system */ async shutdown(): Promise<void> { this.isActive = false; // Clear queues this.messageQueue.forEach((queue) => (queue.length = 0)); // Clear channels this.channels.clear(); this.emit('shutdown'); } }