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
JavaScript
/**
* 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