claude-flow-multilang
Version:
Revolutionary multilingual AI orchestration framework with cultural awareness and DDD architecture
495 lines (423 loc) • 12.9 kB
text/typescript
/**
* 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');
}
}