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.

208 lines (207 loc) 8.49 kB
import { logger } from '../config/logger'; import * as fs from 'fs/promises'; import * as path from 'path'; export class MemorySystem { memories = new Map(); patterns = new Map(); memoryPath; maxMemories; constructor(agentName, maxMemories = 1000) { this.memoryPath = path.join('data', 'memory', `${agentName}.json`); this.maxMemories = maxMemories; this.loadMemories(); } async store(type, data, importance = 0.5, tags = []) { const id = `mem_${Date.now()}_${Math.random().toString(36).substring(7)}`; const entry = { id, timestamp: new Date(), type, data, importance, tags }; this.memories.set(id, entry); // Extract patterns from the data if (type === 'content' && data.performance) { await this.extractPatterns(data); } // Manage memory size await this.consolidateMemories(); await this.saveMemories(); logger.debug('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; } // Recency bonus const hoursSince = (Date.now() - entry.timestamp.getTime()) / (1000 * 60 * 60); score += Math.max(0, 1 - hoursSince / 168); // Decay over a week // Importance weighting score *= 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 getPatterns() { return Array.from(this.patterns.values()) .sort((a, b) => b.confidence - a.confidence); } async getInsights() { const insights = []; const patterns = await this.getPatterns(); // High-performing content patterns const contentPatterns = patterns.filter(p => p.pattern.includes('high_performance')); if (contentPatterns.length > 0) { insights.push(`${contentPatterns[0].pattern.replace('high_performance_', '').replace('_', ' ')} content performs ${Math.round(contentPatterns[0].confidence * 100)}% better`); } // Engagement timing patterns const timingPatterns = patterns.filter(p => p.pattern.includes('timing')); if (timingPatterns.length > 0) { insights.push(`Best posting times: ${timingPatterns.slice(0, 3).map(p => p.pattern.split('_')[1]).join(', ')}`); } // Content length patterns const lengthPatterns = patterns.filter(p => p.pattern.includes('length')); if (lengthPatterns.length > 0) { const avgLength = lengthPatterns.reduce((sum, p) => sum + parseInt(p.pattern.split('_')[1] || '0'), 0) / lengthPatterns.length; insights.push(`Optimal content length: ~${Math.round(avgLength)} characters`); } return insights; } async extractPatterns(contentData) { const { content, performance } = contentData; if (!performance) return; const engagementScore = this.calculateEngagementScore(performance); // Pattern: High-performing content length if (engagementScore > 0.7) { const lengthPattern = `high_performance_length_${Math.round(content.length / 50) * 50}`; this.updatePattern(lengthPattern, engagementScore, content); } // Pattern: Time-based performance const hour = new Date().getHours(); const timePattern = `timing_${hour}h`; this.updatePattern(timePattern, engagementScore, `Posted at ${hour}:00`); // Pattern: Content type performance const contentType = this.inferContentType(content); if (contentType) { const typePattern = `high_performance_${contentType}`; this.updatePattern(typePattern, engagementScore, content); } // Pattern: Hashtag effectiveness const hashtags = content.match(/#\w+/g) || []; if (hashtags.length > 0 && engagementScore > 0.6) { hashtags.forEach((hashtag) => { const hashtagPattern = `effective_hashtag_${hashtag.toLowerCase()}`; this.updatePattern(hashtagPattern, engagementScore, content); }); } } updatePattern(patternName, confidence, example) { const existing = this.patterns.get(patternName); if (existing) { existing.confidence = (existing.confidence + confidence) / 2; existing.frequency++; existing.lastSeen = new Date(); if (existing.examples.length < 5) { existing.examples.push(example); } } else { this.patterns.set(patternName, { pattern: patternName, confidence, examples: [example], lastSeen: new Date(), frequency: 1 }); } } calculateEngagementScore(performance) { const { likes, shares, comments, views } = performance; const total = likes + shares * 2 + comments * 3; // Weight interactions return Math.min(1, total / Math.max(1, views) * 100); } inferContentType(content) { if (content.includes('?')) return 'question'; if (content.match(/https?:\/\/\S+/)) return 'link_share'; if ((content.match(/#\w+/g)?.length || 0) > 2) return 'hashtag_heavy'; if (content.length < 50) return 'short_form'; if (content.length > 200) return 'long_form'; return 'standard'; } async consolidateMemories() { if (this.memories.size <= this.maxMemories) return; // Sort by importance and recency const sorted = Array.from(this.memories.entries()) .sort(([, a], [, b]) => { const scoreA = a.importance + (Date.now() - a.timestamp.getTime()) / (1000 * 60 * 60 * 24 * 7); const scoreB = b.importance + (Date.now() - b.timestamp.getTime()) / (1000 * 60 * 60 * 24 * 7); return scoreB - scoreA; }); // Keep top memories this.memories.clear(); sorted.slice(0, this.maxMemories).forEach(([id, entry]) => { this.memories.set(id, entry); }); logger.info(`Consolidated 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.patterns) { parsed.patterns.forEach((pattern) => { pattern.lastSeen = new Date(pattern.lastSeen); this.patterns.set(pattern.pattern, pattern); }); } logger.info(`Loaded ${this.memories.size} memories and ${this.patterns.size} patterns`); } catch (error) { logger.debug('No existing memory file found, starting fresh'); } } async saveMemories() { try { const data = { memories: Array.from(this.memories.values()), patterns: Array.from(this.patterns.values()), savedAt: new Date().toISOString() }; await fs.writeFile(this.memoryPath, JSON.stringify(data, null, 2)); } catch (error) { logger.error('Failed to save memories', { error }); } } }