UNPKG

stellar-cyber-mcp-agents

Version:

Model Context Protocol (MCP) server for Stellar Cyber security operations with specialized multi-agent analysis capabilities

188 lines 6.91 kB
import { EventEmitter } from 'eventemitter3'; export class InMemoryCommunicationChannel extends EventEmitter { requestHandlers = new Map(); pendingRequests = new Map(); requestQueue = new Map(); // Queue per agent defaultTimeout = 30000; // 30 seconds constructor() { super(); } async sendRequest(request) { const targetKey = this.getAgentKey(request.targetAgentId); const handler = this.requestHandlers.get(targetKey); if (!handler) { throw new Error(`No handler registered for agent ${targetKey}`); } // Add to queue if agent is busy (simple queue implementation) const queue = this.requestQueue.get(targetKey) || []; if (queue.length > 0) { queue.push(request); this.requestQueue.set(targetKey, queue); } return new Promise((resolve, reject) => { const timeout = setTimeout(() => { this.pendingRequests.delete(request.id); reject(new Error(`Request ${request.id} timed out after ${request.timeout}ms`)); }, request.timeout || this.defaultTimeout); this.pendingRequests.set(request.id, { resolve, reject, timeout }); // Process request immediately if no queue if (queue.length === 0) { this.processRequest(request, handler); } }); } async processRequest(request, handler) { try { const response = await handler(request); this.resolveRequest(request.id, response); } catch (error) { const errorResponse = { requestId: request.id, sourceAgentId: request.targetAgentId, success: false, error: { code: 'PROCESSING_ERROR', message: error instanceof Error ? error.message : 'Unknown error', details: error }, timestamp: new Date(), processingTime: Date.now() - request.timestamp.getTime() }; this.resolveRequest(request.id, errorResponse); } // Process next request in queue const targetKey = this.getAgentKey(request.targetAgentId); const queue = this.requestQueue.get(targetKey) || []; if (queue.length > 0) { const nextRequest = queue.shift(); this.requestQueue.set(targetKey, queue); this.processRequest(nextRequest, handler); } } resolveRequest(requestId, response) { const pending = this.pendingRequests.get(requestId); if (pending) { clearTimeout(pending.timeout); this.pendingRequests.delete(requestId); pending.resolve(response); } } subscribeToRequests(agentId, callback) { const agentKey = this.getAgentKey(agentId); this.requestHandlers.set(agentKey, callback); } unsubscribeFromRequests(agentId) { const agentKey = this.getAgentKey(agentId); this.requestHandlers.delete(agentKey); this.requestQueue.delete(agentKey); } async broadcastEvent(event) { // Emit to all listeners this.emit('agent_event', event); // Could also implement specific event routing here this.emit(`event_${event.type}`, event); } subscribeToEvents(callback) { this.on('agent_event', callback); } unsubscribeFromEvents(callback) { this.off('agent_event', callback); } async close() { // Clear all pending requests for (const [requestId, pending] of this.pendingRequests) { clearTimeout(pending.timeout); pending.reject(new Error('Communication channel closed')); } this.pendingRequests.clear(); // Clear handlers and queues this.requestHandlers.clear(); this.requestQueue.clear(); // Remove all listeners this.removeAllListeners(); } /** * Get channel statistics */ getChannelStats() { const queuedRequests = Array.from(this.requestQueue.values()) .reduce((sum, queue) => sum + queue.length, 0); return { activeHandlers: this.requestHandlers.size, pendingRequests: this.pendingRequests.size, queuedRequests, totalQueues: this.requestQueue.size }; } /** * Get queue status for an agent */ getAgentQueueStatus(agentId) { const agentKey = this.getAgentKey(agentId); const queue = this.requestQueue.get(agentKey) || []; return { queueSize: queue.length, hasHandler: this.requestHandlers.has(agentKey) }; } /** * Priority-based request sending */ async sendPriorityRequest(request) { const targetKey = this.getAgentKey(request.targetAgentId); const queue = this.requestQueue.get(targetKey) || []; // Insert request based on priority if (queue.length > 0) { let insertIndex = 0; for (let i = 0; i < queue.length; i++) { if (request.priority > queue[i].priority) { insertIndex = i; break; } insertIndex = i + 1; } queue.splice(insertIndex, 0, request); this.requestQueue.set(targetKey, queue); } return this.sendRequest(request); } /** * Batch request sending */ async sendBatchRequests(requests) { const promises = requests.map(request => this.sendRequest(request)); return Promise.all(promises); } /** * Request with retry logic */ async sendRequestWithRetry(request, maxRetries = 3, retryDelay = 1000) { let lastError = null; for (let attempt = 0; attempt <= maxRetries; attempt++) { try { return await this.sendRequest(request); } catch (error) { lastError = error instanceof Error ? error : new Error('Unknown error'); if (attempt < maxRetries) { await new Promise(resolve => setTimeout(resolve, retryDelay * (attempt + 1))); } } } throw lastError; } getAgentKey(agentId) { return `${agentId.type}:${agentId.instance}:${agentId.uuid}`; } } export class NetworkCommunicationChannel extends InMemoryCommunicationChannel { // TODO: Implement network-based communication for distributed agents // This would use HTTP/WebSocket/gRPC for inter-agent communication // For now, we'll use the in-memory implementation constructor() { super(); // Future: Add network transport configuration } } //# sourceMappingURL=communication-channel.js.map