UNPKG

@polybiouslabs/polybious

Version:

Polybius is a next-generation intelligent agent framework built for adaptability across diverse domains. It merges contextual awareness, multi-agent collaboration, and predictive reasoning to deliver dynamic, self-optimizing performance.

267 lines (221 loc) 9.63 kB
import { logger } from '../config/logger.js'; import * as fs from 'fs/promises'; import * as path from 'path'; export class ContextualMemoryMatrix { memories = new Map(); relationships = new Map(); contexts = new Map(); memoryPath; maxMemories; constructor(maxMemories = 2000) { this.memoryPath = path.join('data', 'contextual-memory', 'matrix.json'); this.maxMemories = maxMemories; this.loadMemories(); } async store(type, data, importance = 0.5, tags = []) { const id = `ctx_${Date.now()}_${Math.random().toString(36).substring(7)}`; const entry = { id, timestamp: new Date(), type, data, importance, tags, context: this.extractContext(data), relationships: [] }; this.memories.set(id, entry); await this.buildRelationships(id, entry); await this.consolidateMemories(); await this.saveMemories(); logger.debug('Contextual memory stored', { id, type, importance, tags }); return id; } async recall(query, limit = 10) { const queryTerms = query.toLowerCase().split(' '); const scored = []; for (const entry of this.memories.values()) { let score = 0; const entryText = JSON.stringify(entry.data).toLowerCase(); // Keyword matching for (const term of queryTerms) { if (entryText.includes(term)) score += 1; if (entry.tags.some(tag => tag.toLowerCase().includes(term))) score += 2; if (entry.context && entry.context.toLowerCase().includes(term)) score += 1.5; } // Relationship bonus const relatedMemories = this.getRelatedMemories(entry.id); score += relatedMemories.length * 0.1; // Recency and importance weighting const hoursSince = (Date.now() - entry.timestamp.getTime()) / (1000 * 60 * 60); score += Math.max(0, 1 - hoursSince / 168) * entry.importance; if (score > 0) { scored.push({ entry, score }); } } return scored .sort((a, b) => b.score - a.score) .slice(0, limit) .map(item => item.entry); } async generateInsights() { const insights = []; const allMemories = Array.from(this.memories.values()); // Pattern analysis const tagFrequency = new Map(); const contextPatterns = new Map(); allMemories.forEach(memory => { memory.tags.forEach(tag => { tagFrequency.set(tag, (tagFrequency.get(tag) || 0) + 1); }); if (memory.context) { contextPatterns.set(memory.context, (contextPatterns.get(memory.context) || 0) + 1); } }); // Most frequent tags const topTags = Array.from(tagFrequency.entries()) .sort(([, a], [, b]) => b - a) .slice(0, 5); if (topTags.length > 0) { insights.push(`Most frequent topics: ${topTags.map(([tag]) => tag).join(', ')}`); } // Memory relationship density const totalRelationships = Array.from(this.relationships.values()).reduce((sum, rels) => sum + rels.length, 0); const avgRelationships = totalRelationships / this.memories.size; insights.push(`Average memory connections: ${avgRelationships.toFixed(2)}`); // High importance memories const highImportanceMemories = allMemories.filter(m => m.importance > 0.8); if (highImportanceMemories.length > 0) { insights.push(`${highImportanceMemories.length} high-importance memories stored`); } return insights; } extractContext(data) { if (typeof data === 'string') { return data.slice(0, 100); } if (typeof data === 'object' && data !== null) { if (data.context) return data.context; if (data.topic) return data.topic; if (data.task) return data.task; return JSON.stringify(data).slice(0, 100); } return 'unknown_context'; } async buildRelationships(memoryId, memory) { const relationships = []; for (const [otherId, otherMemory] of this.memories) { if (otherId === memoryId) continue; const similarity = this.calculateSimilarity(memory, otherMemory); if (similarity > 0.3) { relationships.push({ targetId: otherId, strength: similarity, type: this.classifyRelationship(memory, otherMemory) }); } } this.relationships.set(memoryId, relationships); memory.relationships = relationships.map(r => r.targetId); } calculateSimilarity(memory1, memory2) { let similarity = 0; // Tag overlap const tags1 = new Set(memory1.tags); const tags2 = new Set(memory2.tags); const tagOverlap = [...tags1].filter(tag => tags2.has(tag)).length; const tagUnion = new Set([...tags1, ...tags2]).size; similarity += tagOverlap / tagUnion * 0.4; // Context similarity if (memory1.context && memory2.context) { const contextWords1 = memory1.context.toLowerCase().split(' '); const contextWords2 = memory2.context.toLowerCase().split(' '); const wordOverlap = contextWords1.filter(word => contextWords2.includes(word)).length; similarity += wordOverlap / Math.max(contextWords1.length, contextWords2.length) * 0.3; } // Type similarity if (memory1.type === memory2.type) { similarity += 0.2; } // Time proximity const timeDiff = Math.abs(memory1.timestamp.getTime() - memory2.timestamp.getTime()); const daysDiff = timeDiff / (1000 * 60 * 60 * 24); similarity += Math.max(0, (7 - daysDiff) / 7) * 0.1; return Math.min(1, similarity); } classifyRelationship(memory1, memory2) { if (memory1.type === memory2.type) return 'same_type'; if (memory1.tags.some(tag => memory2.tags.includes(tag))) return 'shared_topic'; if (memory1.context === memory2.context) return 'same_context'; return 'general'; } getRelatedMemories(memoryId) { const relationships = this.relationships.get(memoryId) || []; return relationships .sort((a, b) => b.strength - a.strength) .map(rel => this.memories.get(rel.targetId)) .filter(Boolean); } async consolidateMemories() { if (this.memories.size <= this.maxMemories) return; const sorted = Array.from(this.memories.entries()) .sort(([, a], [, b]) => { const scoreA = a.importance + (this.relationships.get(a.id)?.length || 0) * 0.1 + (Date.now() - a.timestamp.getTime()) / (1000 * 60 * 60 * 24 * 30); const scoreB = b.importance + (this.relationships.get(b.id)?.length || 0) * 0.1 + (Date.now() - b.timestamp.getTime()) / (1000 * 60 * 60 * 24 * 30); return scoreB - scoreA; }); this.memories.clear(); this.relationships.clear(); sorted.slice(0, this.maxMemories).forEach(([id, entry]) => { this.memories.set(id, entry); }); // Rebuild relationships for remaining memories for (const [id, memory] of this.memories) { await this.buildRelationships(id, memory); } logger.info(`Consolidated contextual memories: kept ${this.memories.size} out of ${sorted.length}`); } async loadMemories() { try { await fs.mkdir(path.dirname(this.memoryPath), { recursive: true }); const data = await fs.readFile(this.memoryPath, 'utf8'); const parsed = JSON.parse(data); if (parsed.memories) { parsed.memories.forEach(entry => { entry.timestamp = new Date(entry.timestamp); this.memories.set(entry.id, entry); }); } if (parsed.relationships) { parsed.relationships.forEach(([id, rels]) => { this.relationships.set(id, rels); }); } if (parsed.contexts) { parsed.contexts.forEach(([context, data]) => { this.contexts.set(context, data); }); } logger.info(`Loaded ${this.memories.size} contextual memories with ${this.relationships.size} relationship maps`); } catch (error) { logger.debug('No existing contextual memory file found, starting fresh'); } } async saveMemories() { try { const data = { memories: Array.from(this.memories.values()), relationships: Array.from(this.relationships.entries()), contexts: Array.from(this.contexts.entries()), savedAt: new Date().toISOString() }; await fs.writeFile(this.memoryPath, JSON.stringify(data, null, 2)); } catch (error) { logger.error('Failed to save contextual memories', { error }); } } }