UNPKG

codecrucible-synth

Version:

Production-Ready AI Development Platform with Multi-Voice Synthesis, Smithery MCP Integration, Enterprise Security, and Zero-Timeout Reliability

621 lines 23.8 kB
/** * Agent Communication Protocol - Semantic Kernel & AutoGen Inspired * Implements modern agent-to-agent communication patterns for CodeCrucible Synth * * Features: * - Agent lifecycle management and discovery * - Message passing and subscription patterns * - Orchestration strategies (Sequential, Parallel, Democratic, Hierarchical) * - Event-driven communication with telemetry integration * - Agent conversation management and memory * - Capability negotiation and task delegation * - Multi-agent coordination and consensus building */ import { EventEmitter } from 'events'; import { logger } from '../logger.js'; import { getTelemetryProvider } from '../observability/observability-system.js'; /** * Agent Communication Protocol Implementation */ export class AgentCommunicationProtocol extends EventEmitter { registry; conversationManager; orchestrationStrategies; activeConversations; messageQueue; telemetry = getTelemetryProvider(); constructor(registry, conversationManager) { super(); this.registry = registry; this.conversationManager = conversationManager; this.orchestrationStrategies = new Map(); this.activeConversations = new Map(); this.messageQueue = []; this.initializeOrchestrationStrategies(); this.setupEventHandlers(); } /** * Initialize built-in orchestration strategies */ initializeOrchestrationStrategies() { // Sequential strategy this.orchestrationStrategies.set('sequential', new SequentialOrchestrationStrategy()); // Parallel strategy this.orchestrationStrategies.set('parallel', new ParallelOrchestrationStrategy()); // Democratic strategy this.orchestrationStrategies.set('democratic', new DemocraticOrchestrationStrategy()); // Hierarchical strategy this.orchestrationStrategies.set('hierarchical', new HierarchicalOrchestrationStrategy()); // Consensus strategy this.orchestrationStrategies.set('consensus', new ConsensusOrchestrationStrategy()); logger.info('🤝 Orchestration strategies initialized', { strategies: Array.from(this.orchestrationStrategies.keys()), }); } /** * Setup event handlers for telemetry and monitoring */ setupEventHandlers() { this.on('message-sent', (message) => { logger.debug('Agent message sent', { messageId: message.id, sender: message.sender, recipient: message.recipient, type: message.type, }); }); this.on('orchestration-started', (strategy, agents) => { logger.info('Orchestration started', { strategy, agentCount: agents }); }); this.on('orchestration-completed', (result) => { logger.info('Orchestration completed', { success: result.success, agentCount: result.results.length, totalTime: result.totalTime, }); }); } /** * Orchestrate a task across multiple agents */ async orchestrateTask(task, strategyName = 'sequential', agentCriteria) { return await this.telemetry.traceAgentCommunication({ 'codecrucible.agent.source_id': 'orchestrator', 'codecrucible.agent.target_id': 'multiple', 'codecrucible.agent.message_type': 'orchestration', 'codecrucible.agent.orchestration_strategy': strategyName, }, async () => { logger.info('Starting task orchestration', { taskId: task.id, taskType: task.type, strategy: strategyName, }); // Find suitable agents const agents = agentCriteria ? await this.registry.findAgents(agentCriteria) : await this.registry.findAgents({ capabilities: [task.type] }); if (agents.length === 0) { throw new Error(`No agents found capable of handling task type: ${task.type}`); } // Get orchestration strategy const strategy = this.orchestrationStrategies.get(strategyName); if (!strategy) { throw new Error(`Unknown orchestration strategy: ${strategyName}`); } this.emit('orchestration-started', strategyName, agents.length); // Execute orchestration const result = await strategy.orchestrate(agents, task); this.emit('orchestration-completed', result); return result; }); } /** * Send message between agents */ async sendMessage(senderId, recipientId, content, type = 'task-request', metadata = {}) { const message = { id: this.generateMessageId(), type, sender: senderId, recipient: recipientId, content, metadata: { priority: 'medium', expectsResponse: true, ...metadata, }, timestamp: new Date(), }; // Add to message queue for processing this.messageQueue.push(message); // Process message immediately (could be async queue in production) await this.processMessage(message); this.emit('message-sent', message); return message; } /** * Start a multi-agent conversation */ async startConversation(participants, topic, orchestrationStrategy = 'democratic') { const conversationId = await this.conversationManager.startConversation(participants, topic); const context = { id: conversationId, participants, topic, strategy: orchestrationStrategy, startTime: new Date(), active: true, messageCount: 0, }; this.activeConversations.set(conversationId, context); logger.info('Multi-agent conversation started', { conversationId, participants: participants.length, topic, strategy: orchestrationStrategy, }); return conversationId; } /** * Facilitate agent capability negotiation */ async negotiateCapabilities(task, candidateAgents) { const negotiations = []; for (const agentId of candidateAgents) { const agent = await this.registry.getAgent(agentId); if (!agent) continue; const canHandle = agent.canHandle(task); const relevantCapabilities = agent.capabilities.filter(cap => task.requirements.some(req => req.value === cap.name)); negotiations.push({ agentId, canHandle, capabilities: relevantCapabilities, confidence: this.calculateCapabilityConfidence(relevantCapabilities, task), estimatedTime: agent.metadata.averageResponseTime, resourceRequirements: this.estimateResourceRequirements(task, agent), }); } // Sort by capability match and confidence negotiations.sort((a, b) => { if (a.canHandle && !b.canHandle) return -1; if (!a.canHandle && b.canHandle) return 1; return b.confidence - a.confidence; }); return { task, negotiations, bestMatch: negotiations[0] || null, alternatives: negotiations.slice(1), totalCandidates: candidateAgents.length, }; } /** * Get orchestration strategies */ getOrchestrationStrategies() { return Array.from(this.orchestrationStrategies.keys()); } /** * Get active conversations */ getActiveConversations() { return Array.from(this.activeConversations.values()); } /** * Private: Process individual message */ async processMessage(message) { try { const recipient = await this.registry.getAgent(message.recipient); if (!recipient) { logger.warn('Recipient agent not found', { messageId: message.id, recipient: message.recipient, }); return; } // Handle different message types switch (message.type) { case 'task-request': await this.handleTaskRequest(message, recipient); break; case 'capability-inquiry': await this.handleCapabilityInquiry(message, recipient); break; case 'coordination-request': await this.handleCoordinationRequest(message, recipient); break; default: logger.debug('Unhandled message type', { type: message.type }); } } catch (error) { logger.error('Error processing message', { messageId: message.id, error: error instanceof Error ? error.message : String(error), }); } } /** * Handle task request messages */ async handleTaskRequest(message, recipient) { if (recipient.status !== 'active' && recipient.status !== 'idle') { logger.warn('Agent not available for task', { agentId: recipient.id, status: recipient.status, }); return; } try { const response = await recipient.invoke([message]); // Send response back to sender if expected if (message.metadata.expectsResponse) { await this.sendMessage(recipient.id, message.sender, response, 'task-response', { expectsResponse: false, }); } } catch (error) { logger.error('Task execution failed', { agentId: recipient.id, taskId: message.id, error: error instanceof Error ? error.message : String(error), }); } } /** * Handle capability inquiry messages */ async handleCapabilityInquiry(message, recipient) { const capabilities = { capabilities: recipient.capabilities, status: recipient.status, metadata: recipient.metadata, }; await this.sendMessage(recipient.id, message.sender, capabilities, 'capability-response', { expectsResponse: false, }); } /** * Handle coordination request messages */ async handleCoordinationRequest(message, recipient) { // Implementation would coordinate with other agents based on request logger.debug('Coordination request received', { from: message.sender, to: recipient.id, content: message.content, }); } /** * Calculate capability confidence for a task */ calculateCapabilityConfidence(capabilities, task) { if (capabilities.length === 0) return 0; const relevantCaps = capabilities.filter(cap => task.requirements.some(req => req.value === cap.name)); if (relevantCaps.length === 0) return 0; const avgConfidence = relevantCaps.reduce((sum, cap) => sum + cap.confidence, 0) / relevantCaps.length; const coverageRatio = relevantCaps.length / task.requirements.length; return avgConfidence * coverageRatio; } /** * Estimate resource requirements */ estimateResourceRequirements(task, agent) { // Simplified estimation - would be more sophisticated in production const baseMemory = 50; const baseCpu = 30; const complexity = task.constraints.length + task.requirements.length; const multiplier = Math.min(complexity / 5, 3); return { memory: baseMemory * multiplier, cpu: baseCpu * multiplier, network: 10, tokens: task.description.length * 4, // Rough token estimate }; } /** * Generate unique message ID */ generateMessageId() { return `msg_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`; } } // Orchestration strategy implementations class SequentialOrchestrationStrategy { name = 'sequential'; type = 'sequential'; async orchestrate(agents, task) { const results = []; const executionPlan = []; const errors = []; const startTime = Date.now(); for (let i = 0; i < agents.length; i++) { const agent = agents[i]; const step = { step: i + 1, agentId: agent.id, task, startTime: new Date(), }; try { const response = await agent.invoke([ { id: `task_${Date.now()}`, type: 'task-request', sender: 'orchestrator', recipient: agent.id, content: task, metadata: { priority: 'medium', expectsResponse: true }, timestamp: new Date(), }, ]); step.endTime = new Date(); step.result = response; results.push(response); } catch (error) { errors.push(`Agent ${agent.id}: ${error instanceof Error ? error.message : String(error)}`); step.endTime = new Date(); } executionPlan.push(step); } return { success: errors.length === 0, results, executionPlan, totalTime: Date.now() - startTime, errors, }; } } class ParallelOrchestrationStrategy { name = 'parallel'; type = 'parallel'; async orchestrate(agents, task) { const startTime = Date.now(); const executionPlan = []; const errors = []; // Execute all agents in parallel const promises = agents.map(async (agent, index) => { const step = { step: index + 1, agentId: agent.id, task, startTime: new Date(), }; try { const response = await agent.invoke([ { id: `task_${Date.now()}_${index}`, type: 'task-request', sender: 'orchestrator', recipient: agent.id, content: task, metadata: { priority: 'medium', expectsResponse: true }, timestamp: new Date(), }, ]); step.endTime = new Date(); step.result = response; return { step, response, error: null }; } catch (error) { const errorMsg = `Agent ${agent.id}: ${error instanceof Error ? error.message : String(error)}`; step.endTime = new Date(); return { step, response: null, error: errorMsg }; } }); const settledResults = await Promise.allSettled(promises); const results = []; settledResults.forEach((settled, index) => { if (settled.status === 'fulfilled') { const { step, response, error } = settled.value; executionPlan.push(step); if (response) { results.push(response); } if (error) { errors.push(error); } } else { errors.push(`Agent ${agents[index].id}: Promise rejected`); } }); return { success: errors.length === 0, results, executionPlan, totalTime: Date.now() - startTime, errors, }; } } class DemocraticOrchestrationStrategy { name = 'democratic'; type = 'democratic'; async orchestrate(agents, task) { // Execute in parallel then combine results democratically const parallelStrategy = new ParallelOrchestrationStrategy(); const parallelResult = await parallelStrategy.orchestrate(agents, task); // Simple democratic consensus - average confidence scores if (parallelResult.results.length > 0) { const averageConfidence = parallelResult.results.reduce((sum, result) => sum + result.metadata.confidence, 0) / parallelResult.results.length; const consensus = { agreement: averageConfidence > 0.7, confidence: averageConfidence, dissenting: parallelResult.results .filter(r => r.metadata.confidence < 0.5) .map((_, i) => agents[i].id), finalDecision: parallelResult.results[0].content, votingResults: parallelResult.results.map((result, i) => ({ agentId: agents[i].id, vote: result.metadata.confidence > 0.5 ? 'yes' : 'no', confidence: result.metadata.confidence, })), }; return { ...parallelResult, consensus, }; } return parallelResult; } } class HierarchicalOrchestrationStrategy { name = 'hierarchical'; type = 'hierarchical'; async orchestrate(agents, task) { // Sort agents by capability confidence for the task const sortedAgents = [...agents].sort((a, b) => { const aConf = this.getAgentConfidenceForTask(a, task); const bConf = this.getAgentConfidenceForTask(b, task); return bConf - aConf; }); // Execute sequentially in order of capability const sequentialStrategy = new SequentialOrchestrationStrategy(); return await sequentialStrategy.orchestrate(sortedAgents, task); } getAgentConfidenceForTask(agent, task) { const relevantCaps = agent.capabilities.filter(cap => task.requirements.some(req => req.value === cap.name)); return relevantCaps.length > 0 ? relevantCaps.reduce((sum, cap) => sum + cap.confidence, 0) / relevantCaps.length : 0; } } class ConsensusOrchestrationStrategy { name = 'consensus'; type = 'consensus'; async orchestrate(agents, task) { const startTime = Date.now(); const maxRounds = 3; let round = 0; const results = []; const executionPlan = []; const errors = []; // Multi-round consensus building while (round < maxRounds) { round++; // Get responses from all agents const roundResults = await this.executeRound(agents, task, round, executionPlan); results.push(...roundResults.responses); errors.push(...roundResults.errors); // Check for consensus const consensus = this.evaluateConsensus(roundResults.responses); if (consensus.agreement) { return { success: true, results, consensus, executionPlan, totalTime: Date.now() - startTime, errors, }; } // If not final round, adjust task based on feedback if (round < maxRounds) { task = this.refineTaskBasedOnFeedback(task, roundResults.responses); } } // Final consensus attempt const finalConsensus = this.evaluateConsensus(results); return { success: finalConsensus.agreement, results, consensus: finalConsensus, executionPlan, totalTime: Date.now() - startTime, errors, }; } async executeRound(agents, task, round, executionPlan) { const responses = []; const errors = []; for (let i = 0; i < agents.length; i++) { const agent = agents[i]; const step = { step: executionPlan.length + 1, agentId: agent.id, task: { ...task, description: `${task.description} (Consensus Round ${round})` }, startTime: new Date(), }; try { const response = await agent.invoke([ { id: `consensus_${round}_${Date.now()}_${i}`, type: 'task-request', sender: 'consensus-orchestrator', recipient: agent.id, content: step.task, metadata: { priority: 'high', expectsResponse: true }, timestamp: new Date(), }, ]); step.endTime = new Date(); step.result = response; responses.push(response); } catch (error) { errors.push(`Round ${round} Agent ${agent.id}: ${error instanceof Error ? error.message : String(error)}`); step.endTime = new Date(); } executionPlan.push(step); } return { responses, errors }; } evaluateConsensus(responses) { if (responses.length === 0) { return { agreement: false, confidence: 0, dissenting: [], finalDecision: null, votingResults: [], }; } const avgConfidence = responses.reduce((sum, r) => sum + r.metadata.confidence, 0) / responses.length; const highConfidenceResponses = responses.filter(r => r.metadata.confidence > 0.7); const agreement = highConfidenceResponses.length / responses.length > 0.6; return { agreement, confidence: avgConfidence, dissenting: responses .map((r, i) => ({ response: r, index: i })) .filter(({ response }) => response.metadata.confidence < 0.5) .map(({ index }) => `agent_${index}`), finalDecision: agreement ? highConfidenceResponses[0].content : null, votingResults: responses.map((response, i) => ({ agentId: `agent_${i}`, vote: response.metadata.confidence > 0.5 ? 'yes' : 'no', confidence: response.metadata.confidence, })), }; } refineTaskBasedOnFeedback(task, responses) { // Simple refinement - in practice would be more sophisticated const lowConfidenceCount = responses.filter(r => r.metadata.confidence < 0.5).length; if (lowConfidenceCount > responses.length / 2) { return { ...task, description: `${task.description} (Please provide more specific guidance)`, priority: Math.min(task.priority + 1, 10), }; } return task; } } // Factory functions export function createAgentCommunicationProtocol(registry, conversationManager) { return new AgentCommunicationProtocol(registry, conversationManager); } // Default export export default AgentCommunicationProtocol; //# sourceMappingURL=agent-communication-protocol.js.map