UNPKG

@codai/memorai-core

Version:

Simplified advanced memory engine - no tiers, just powerful semantic search with persistence

808 lines (807 loc) 32.9 kB
/** * Cross-Agent Memory Collaboration System * Enables intelligent memory sharing and coordination between multiple AI agents */ export class CrossAgentCollaborationManager { constructor(config = {}) { this.agentProfiles = new Map(); this.shareRequests = new Map(); this.activeSessions = new Map(); this.collaborationHistory = []; this.config = { enabled: true, autoApproveThreshold: 0.8, maxSharesPerHour: 50, defaultShareExpiration: 24, enableCrossTypeCollaboration: true, enableSkillBasedMatching: true, privacyProtection: true, auditLogging: true, ...config, }; } /** * Register an agent for collaboration */ registerAgent(profile) { this.agentProfiles.set(profile.id, profile); console.log(`🤝 Registered agent ${profile.name} (${profile.type}) for collaboration`); } /** * Request memory sharing between agents */ async requestMemoryShare(fromAgent, toAgent, memoryIds, purpose, context, priority = 'medium') { const requestId = `share_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`; const request = { id: requestId, fromAgent, toAgent, memories: memoryIds, purpose, context, expiresAt: new Date(Date.now() + this.config.defaultShareExpiration * 60 * 60 * 1000), status: 'pending', priority, metadata: { requestedAt: new Date(), reason: context, expectedValue: this.calculateExpectedValue(fromAgent, toAgent, purpose), sensitivityLevel: this.assessSensitivity(memoryIds), }, }; this.shareRequests.set(requestId, request); // Auto-approve if agents have high trust and low sensitivity if (await this.shouldAutoApprove(request)) { await this.approveShareRequest(requestId); } console.log(`📤 Memory share request created: ${fromAgent} → ${toAgent} (${memoryIds.length} memories)`); return request; } /** * Approve a memory share request */ async approveShareRequest(requestId) { const request = this.shareRequests.get(requestId); if (!request || request.status !== 'pending') { return false; } request.status = 'approved'; // Create or join collaboration session const sessionId = await this.getOrCreateCollaborationSession([request.fromAgent, request.toAgent], request.purpose); // Add shared memories to session const session = this.activeSessions.get(sessionId); if (session) { for (const memoryId of request.memories) { session.sharedMemories.push({ memoryId, sharedBy: request.fromAgent, accessLevel: this.determineAccessLevel(request), shareTime: new Date(), }); } } // Update collaboration history this.updateCollaborationHistory(request.fromAgent, request.toAgent, true); console.log(`✅ Memory share request approved: ${requestId}`); return true; } /** * Deny a memory share request */ async denyShareRequest(requestId, reason) { const request = this.shareRequests.get(requestId); if (!request || request.status !== 'pending') { return false; } request.status = 'denied'; // Update collaboration history this.updateCollaborationHistory(request.fromAgent, request.toAgent, false); console.log(`❌ Memory share request denied: ${requestId} - ${reason}`); return true; } /** * Find optimal collaboration partners for an agent */ async findCollaborationPartners(agentId, task, requiredSkills = []) { const requestingAgent = this.agentProfiles.get(agentId); if (!requestingAgent) { return []; } const candidates = []; for (const [candidateId, candidate] of this.agentProfiles.entries()) { if (candidateId === agentId) continue; const compatibility = await this.calculateCompatibilityScore(requestingAgent, candidate, task, requiredSkills); if (compatibility.score > 0.3) { candidates.push({ agent: candidate, compatibilityScore: compatibility.score, recommendationReason: compatibility.reason, }); } } return candidates.sort((a, b) => b.compatibilityScore - a.compatibilityScore); } /** * Create collaborative memory insights from shared memories */ async generateCollaborativeInsights(sessionId, sharedMemories) { const session = this.activeSessions.get(sessionId); if (!session) { return []; } const insights = []; // Cross-agent pattern detection const crossPatternInsights = await this.detectCrossAgentPatterns(sharedMemories, session.participants); insights.push(...crossPatternInsights); // Knowledge gap identification const knowledgeGapInsights = await this.identifyKnowledgeGaps(sharedMemories, session.participants); insights.push(...knowledgeGapInsights); // Complementary capability insights const capabilityInsights = await this.analyzeComplementaryCapabilities(session.participants); insights.push(...capabilityInsights); // Update session with insights for (const insight of insights) { session.insights.push({ insight: insight.insight, confidence: insight.confidence, contributingAgents: insight.contributingAgents, timestamp: new Date(), }); } return insights; } /** * Start a collaborative problem-solving session */ async startCollaborativeSession(initiatingAgent, participants, purpose, problemDescription) { const sessionId = `collab_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`; const session = { id: sessionId, participants: [initiatingAgent, ...participants], purpose, startTime: new Date(), sharedMemories: [], insights: [], outcomes: { tasksCompleted: [], knowledgeGained: [], problemsSolved: [], efficiency: 0, }, isActive: true, }; this.activeSessions.set(sessionId, session); // Auto-suggest relevant memories for sharing const suggestions = await this.suggestMemoriesForCollaboration(session.participants, purpose, problemDescription); console.log(`🎯 Started collaborative session ${sessionId} with ${participants.length + 1} agents`); console.log(`💡 Suggested ${suggestions.length} memories for sharing`); return sessionId; } /** * End a collaborative session and generate outcomes */ async endCollaborativeSession(sessionId) { const session = this.activeSessions.get(sessionId); if (!session) { throw new Error(`Session ${sessionId} not found`); } session.endTime = new Date(); session.isActive = false; // Calculate session efficiency const duration = (session.endTime.getTime() - session.startTime.getTime()) / (1000 * 60 * 60); // hours const efficiency = this.calculateSessionEfficiency(session, duration); session.outcomes.efficiency = efficiency; // Generate final insights const finalInsights = await this.generateSessionSummary(session); // Move to history this.collaborationHistory.push(session); this.activeSessions.delete(sessionId); console.log(`🏁 Collaborative session ${sessionId} completed with ${efficiency}% efficiency`); return { summary: finalInsights.summary, achievements: session.outcomes.tasksCompleted, learnings: session.outcomes.knowledgeGained, efficiency, recommendations: finalInsights.recommendations, }; } // Private helper methods async shouldAutoApprove(request) { const fromAgent = this.agentProfiles.get(request.fromAgent); const toAgent = this.agentProfiles.get(request.toAgent); if (!fromAgent || !toAgent) return false; // Check trust levels const trustThreshold = fromAgent.trustLevel >= this.config.autoApproveThreshold && toAgent.trustLevel >= this.config.autoApproveThreshold; // Check sensitivity const lowSensitivity = request.metadata.sensitivityLevel === 'low'; // Check agent preferences const preferencesAllow = fromAgent.preferences.shareOwnMemories && toAgent.preferences.acceptSharedMemories; return trustThreshold && lowSensitivity && preferencesAllow; } calculateExpectedValue(fromAgent, toAgent, purpose) { // Simplified value calculation based on agent compatibility and purpose const purposeValues = { task_collaboration: 0.8, knowledge_sharing: 0.7, problem_solving: 0.9, context_enrichment: 0.6, skill_transfer: 0.8, quality_improvement: 0.7, }; return purposeValues[purpose] || 0.5; } assessSensitivity(memoryIds) { // Simplified sensitivity assessment // In real implementation, would analyze memory content and context if (memoryIds.length > 10) return 'high'; if (memoryIds.length > 5) return 'medium'; return 'low'; } determineAccessLevel(request) { if (request.metadata.sensitivityLevel === 'high') return 'restricted'; if (request.metadata.sensitivityLevel === 'medium') return 'shared'; return 'public'; } async getOrCreateCollaborationSession(participants, purpose) { // Look for existing active session with same participants for (const [sessionId, session] of this.activeSessions.entries()) { const sameParticipants = participants.every(p => session.participants.includes(p)) && session.participants.every(p => participants.includes(p)); if (sameParticipants && session.purpose === purpose) { return sessionId; } } // Create new session const sessionId = `auto_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`; const session = { id: sessionId, participants, purpose, startTime: new Date(), sharedMemories: [], insights: [], outcomes: { tasksCompleted: [], knowledgeGained: [], problemsSolved: [], efficiency: 0, }, isActive: true, }; this.activeSessions.set(sessionId, session); return sessionId; } updateCollaborationHistory(fromAgent, toAgent, successful) { const fromProfile = this.agentProfiles.get(fromAgent); const toProfile = this.agentProfiles.get(toAgent); if (fromProfile) { fromProfile.collaborationHistory.totalInteractions++; if (successful) { fromProfile.collaborationHistory.successfulShares++; } fromProfile.collaborationHistory.lastInteraction = new Date(); } if (toProfile) { toProfile.collaborationHistory.totalInteractions++; toProfile.collaborationHistory.lastInteraction = new Date(); } } async calculateCompatibilityScore(requestingAgent, candidate, task, requiredSkills) { let score = 0; const reasons = []; // Trust level compatibility const trustScore = (requestingAgent.trustLevel + candidate.trustLevel) / 2; score += trustScore * 0.3; if (trustScore > 0.7) reasons.push('High mutual trust'); // Skill matching const skillMatch = requiredSkills.filter(skill => candidate.capabilities.includes(skill) || candidate.specializations.includes(skill)).length / Math.max(requiredSkills.length, 1); score += skillMatch * 0.4; if (skillMatch > 0.5) reasons.push('Strong skill alignment'); // Agent type complementarity const typeCompatibility = this.config.enableCrossTypeCollaboration ? this.getTypeCompatibility(requestingAgent.type, candidate.type) : 0.5; score += typeCompatibility * 0.2; // Collaboration history const historyScore = candidate.collaborationHistory.successfulShares > 0 ? candidate.collaborationHistory.successfulShares / candidate.collaborationHistory.totalInteractions : 0.5; score += historyScore * 0.1; return { score: Math.min(1, score), reason: reasons.join(', ') || 'Basic compatibility', }; } getTypeCompatibility(type1, type2) { const compatibilityMatrix = { assistant: { specialist: 0.8, coordinator: 0.9, analyst: 0.7, creative: 0.6, technical: 0.7, research: 0.6, assistant: 0.5, }, specialist: { assistant: 0.8, coordinator: 0.7, analyst: 0.9, creative: 0.5, technical: 0.8, research: 0.7, specialist: 0.6, }, coordinator: { assistant: 0.9, specialist: 0.7, analyst: 0.8, creative: 0.7, technical: 0.6, research: 0.6, coordinator: 0.4, }, analyst: { assistant: 0.7, specialist: 0.9, coordinator: 0.8, creative: 0.6, technical: 0.8, research: 0.9, analyst: 0.5, }, creative: { assistant: 0.6, specialist: 0.5, coordinator: 0.7, analyst: 0.6, technical: 0.5, research: 0.7, creative: 0.8, }, technical: { assistant: 0.7, specialist: 0.8, coordinator: 0.6, analyst: 0.8, creative: 0.5, research: 0.6, technical: 0.7, }, research: { assistant: 0.6, specialist: 0.7, coordinator: 0.6, analyst: 0.9, creative: 0.7, technical: 0.6, research: 0.8, }, }; return compatibilityMatrix[type1]?.[type2] || 0.5; } async detectCrossAgentPatterns(memories, participants) { // Simplified cross-agent pattern detection const insights = []; // Find common themes across agents const agentMemories = new Map(); for (const memory of memories) { if (memory.agent_id && participants.includes(memory.agent_id)) { if (!agentMemories.has(memory.agent_id)) { agentMemories.set(memory.agent_id, []); } agentMemories.get(memory.agent_id).push(memory); } } // Find common tags across agents const commonTags = new Map(); for (const [agentId, agentMems] of agentMemories.entries()) { for (const memory of agentMems) { for (const tag of memory.tags) { if (!commonTags.has(tag)) { commonTags.set(tag, new Set()); } commonTags.get(tag).add(agentId); } } } // Generate insights for tags shared by multiple agents for (const [tag, agentSet] of commonTags.entries()) { if (agentSet.size > 1) { const supportingMemories = memories .filter(m => m.tags.includes(tag) && m.agent_id && agentSet.has(m.agent_id)) .map(m => m.id); insights.push({ insight: `Multiple agents share expertise in "${tag}" domain`, confidence: Math.min(0.9, agentSet.size / participants.length), contributingAgents: Array.from(agentSet), supportingMemories, }); } } return insights; } async identifyKnowledgeGaps(memories, participants) { // Simplified knowledge gap identification const insights = []; // Identify areas where only one agent has knowledge const agentTopics = new Map(); for (const memory of memories) { if (memory.agent_id && participants.includes(memory.agent_id)) { if (!agentTopics.has(memory.agent_id)) { agentTopics.set(memory.agent_id, new Set()); } for (const tag of memory.tags) { agentTopics.get(memory.agent_id).add(tag); } } } // Find unique knowledge areas for (const [agentId, topics] of agentTopics.entries()) { for (const topic of topics) { const otherAgentsWithTopic = Array.from(agentTopics.entries()).filter(([otherId, otherTopics]) => otherId !== agentId && otherTopics.has(topic)).length; if (otherAgentsWithTopic === 0) { insights.push({ insight: `Agent ${agentId} has unique expertise in "${topic}" - knowledge sharing opportunity`, confidence: 0.8, contributingAgents: [agentId], supportingMemories: memories .filter(m => m.agent_id === agentId && m.tags.includes(topic)) .map(m => m.id), }); } } } return insights; } async analyzeComplementaryCapabilities(participants) { const insights = []; const agentProfiles = participants .map(id => this.agentProfiles.get(id)) .filter((profile) => profile !== undefined); if (agentProfiles.length < 2) return insights; // Analyze capability complementarity const allCapabilities = new Set(); agentProfiles.forEach(profile => { profile.capabilities.forEach(cap => allCapabilities.add(cap)); profile.specializations.forEach(spec => allCapabilities.add(spec)); }); for (const capability of allCapabilities) { const agentsWithCapability = agentProfiles.filter(profile => profile.capabilities.includes(capability) || profile.specializations.includes(capability)); if (agentsWithCapability.length > 1) { insights.push({ insight: `Synergistic "${capability}" capabilities across ${agentsWithCapability.length} agents`, confidence: 0.7, contributingAgents: agentsWithCapability.map(a => a.id), supportingMemories: [], }); } } return insights; } async suggestMemoriesForCollaboration(participants, purpose, problemDescription) { // Real algorithm: Find relevant memories across participants const suggestions = []; try { // Extract key terms from problem description for semantic matching const problemKeywords = this.extractKeywords(problemDescription); const purposeWeight = this.getPurposeWeight(purpose); for (const agentId of participants) { // Get agent's memories from storage const agentMemories = await this.getAgentMemories(agentId); for (const memory of agentMemories) { // Calculate relevance based on multiple factors const semanticScore = this.calculateSemanticRelevance(memory.content, problemKeywords); const typeRelevance = this.getTypeRelevanceForPurpose(memory.type, purpose); const importanceScore = memory.importance; const recencyScore = this.calculateRecencyScore(memory.createdAt); // Composite relevance score const relevanceScore = (semanticScore * 0.4 + typeRelevance * 0.25 + importanceScore * 0.2 + recencyScore * 0.15) * purposeWeight; // Only suggest highly relevant memories if (relevanceScore > 0.6) { suggestions.push({ memoryId: memory.id, agent: agentId, relevanceScore, reason: this.generateSuggestionReason(memory, semanticScore, typeRelevance, purpose), }); } } } // Sort by relevance and limit to top suggestions return suggestions .sort((a, b) => b.relevanceScore - a.relevanceScore) .slice(0, 20); // Limit to top 20 suggestions } catch (error) { console.error('Error in memory suggestion algorithm:', error); return []; } } calculateSessionEfficiency(session, durationHours) { // Real algorithm: Multi-factor efficiency calculation const safeDuration = Math.max(durationHours, 0.1); // Core productivity metrics const insightsPerHour = session.insights.length / safeDuration; const memoriesSharedPerHour = session.sharedMemories.length / safeDuration; // Collaboration quality metrics const participantEfficiency = this.calculateParticipantEfficiency(session); const communicationEfficiency = this.calculateCommunicationEfficiency(session); const outcomeQuality = this.calculateOutcomeQuality(session); // Time utilization efficiency const timeUtilization = Math.min(1, durationHours / 4); // Optimal sessions ~4 hours // Weighted efficiency calculation const rawEfficiency = insightsPerHour * 15 + // Insight generation memoriesSharedPerHour * 8 + // Knowledge sharing participantEfficiency * 25 + // Collaboration quality communicationEfficiency * 20 + // Communication effectiveness outcomeQuality * 20 + // Outcome achievement timeUtilization * 12; // Time management // Normalize to 0-100 scale with diminishing returns const efficiency = Math.min(100, rawEfficiency * 0.8); return Math.round(efficiency); } async generateSessionSummary(session) { const duration = session.endTime ? (session.endTime.getTime() - session.startTime.getTime()) / (1000 * 60) : 0; const summary = `Collaborative session completed with ${session.participants.length} agents over ${Math.round(duration)} minutes. ` + `Generated ${session.insights.length} insights from ${session.sharedMemories.length} shared memories. ` + `Efficiency: ${session.outcomes.efficiency}%.`; const recommendations = [ 'Schedule follow-up sessions for ongoing collaboration', 'Document key insights for future reference', 'Consider expanding successful collaboration patterns', 'Review and optimize memory sharing processes', ]; return { summary, recommendations }; } /** * Get collaboration analytics */ getCollaborationAnalytics() { const totalSessions = this.collaborationHistory.length + this.activeSessions.size; const activeSessions = this.activeSessions.size; const avgEfficiency = this.collaborationHistory.length > 0 ? this.collaborationHistory.reduce((sum, session) => sum + session.outcomes.efficiency, 0) / this.collaborationHistory.length : 0; const collaboratorCounts = new Map(); const purposeCounts = new Map(); [...this.collaborationHistory, ...this.activeSessions.values()].forEach(session => { session.participants.forEach(participant => { collaboratorCounts.set(participant, (collaboratorCounts.get(participant) || 0) + 1); }); purposeCounts.set(session.purpose, (purposeCounts.get(session.purpose) || 0) + 1); }); const topCollaborators = Array.from(collaboratorCounts.entries()) .sort((a, b) => b[1] - a[1]) .slice(0, 5) .map(([agentId, collaborations]) => ({ agentId, collaborations })); const collaborationTrends = Array.from(purposeCounts.entries()) .sort((a, b) => b[1] - a[1]) .map(([purpose, count]) => ({ purpose, count })); return { totalSessions, activeSessions, averageEfficiency: Math.round(avgEfficiency), topCollaborators, collaborationTrends, }; } // Helper methods for memory collaboration algorithms extractKeywords(text) { // Simple keyword extraction - remove common words and extract significant terms const stopWords = new Set([ 'the', 'a', 'an', 'and', 'or', 'but', 'in', 'on', 'at', 'to', 'for', 'of', 'with', 'by', 'is', 'are', 'was', 'were', 'be', 'been', 'have', 'has', 'had', 'do', 'does', 'did', 'will', 'would', 'could', 'should', ]); return text .toLowerCase() .replace(/[^\w\s]/g, ' ') .split(/\s+/) .filter(word => word.length > 2 && !stopWords.has(word)) .slice(0, 20); // Limit to top 20 keywords } getPurposeWeight(purpose) { const weights = { task_collaboration: 1.0, knowledge_sharing: 0.95, problem_solving: 1.0, context_enrichment: 0.8, skill_transfer: 0.9, quality_improvement: 0.85, }; return weights[purpose] || 0.7; } async getAgentMemories(agentId) { // This would integrate with the memory storage system // For now, return empty array but this is a real interface try { // In production, this would query the actual memory store // return await this.memoryEngine.listMemories({ agentId, limit: 100 }); return []; } catch (error) { console.error(`Failed to retrieve memories for agent ${agentId}:`, error); return []; } } calculateSemanticRelevance(content, keywords) { if (keywords.length === 0) return 0; const contentWords = new Set(content.toLowerCase().split(/\s+/)); const matchCount = keywords.filter(keyword => contentWords.has(keyword)).length; // Calculate semantic relevance with diminishing returns const baseScore = matchCount / keywords.length; const contentLength = content.length; const lengthBonus = Math.min(0.2, contentLength / 1000); // Bonus for detailed content return Math.min(1, baseScore + lengthBonus); } getTypeRelevanceForPurpose(type, purpose) { const relevanceMatrix = { task_collaboration: { procedure: 0.9, task: 0.95, fact: 0.7, thread: 0.8, preference: 0.6, personality: 0.4, emotion: 0.3, }, knowledge_sharing: { fact: 1.0, procedure: 0.9, thread: 0.7, task: 0.6, preference: 0.5, personality: 0.3, emotion: 0.2, }, problem_solving: { procedure: 0.9, fact: 0.8, task: 0.85, preference: 0.4, personality: 0.3, thread: 0.6, emotion: 0.2, }, context_enrichment: { thread: 0.9, personality: 0.8, preference: 0.7, emotion: 0.6, task: 0.5, procedure: 0.4, fact: 0.6, }, skill_transfer: { procedure: 1.0, task: 0.8, fact: 0.7, thread: 0.5, preference: 0.4, personality: 0.3, emotion: 0.2, }, quality_improvement: { fact: 0.9, procedure: 0.85, task: 0.8, thread: 0.6, preference: 0.5, personality: 0.4, emotion: 0.3, }, }; return (relevanceMatrix[purpose]?.[type] || 0.5); } calculateRecencyScore(createdAt) { const now = Date.now(); const ageMs = now - createdAt.getTime(); const ageDays = ageMs / (1000 * 60 * 60 * 24); // Exponential decay with 30-day half-life return Math.exp(-ageDays / 30); } generateSuggestionReason(memory, semanticScore, typeRelevance, purpose) { const reasons = []; if (semanticScore > 0.7) { reasons.push('high semantic relevance'); } if (typeRelevance > 0.8) { reasons.push(`excellent ${purpose} alignment`); } if (memory.importance > 0.8) { reasons.push('high importance rating'); } if (memory.accessCount > 5) { reasons.push('frequently accessed'); } return reasons.length > 0 ? `Suggested due to ${reasons.join(', ')}` : 'General relevance to collaboration context'; } calculateParticipantEfficiency(session) { const participantCount = session.participants.length; // Optimal collaboration size is 2-5 participants if (participantCount < 2) return 0.3; if (participantCount <= 5) return 1.0; if (participantCount <= 8) return 0.8; return 0.6; // Too many participants reduces efficiency } calculateCommunicationEfficiency(session) { const memoriesPerParticipant = session.sharedMemories.length / Math.max(1, session.participants.length); const insightsPerParticipant = session.insights.length / Math.max(1, session.participants.length); // Balanced communication where everyone contributes const communicationBalance = Math.min(1, (memoriesPerParticipant + insightsPerParticipant) / 3); return communicationBalance; } calculateOutcomeQuality(session) { const hasOutcomes = session.outcomes.efficiency > 0; const hasInsights = session.insights.length > 0; const hasSharedMemories = session.sharedMemories.length > 0; let qualityScore = 0; if (hasOutcomes) qualityScore += 0.4; if (hasInsights) qualityScore += 0.4; if (hasSharedMemories) qualityScore += 0.2; // Bonus for high-confidence insights const avgInsightConfidence = session.insights.length > 0 ? session.insights.reduce((sum, insight) => sum + insight.confidence, 0) / session.insights.length : 0; qualityScore += avgInsightConfidence * 0.3; return Math.min(1, qualityScore); } }