// UnifiedMemorySystem – Phase 1 foundation // Provides Working, Procedural, Semantic, and Episodic memory layers // Integrates existing repositories (CMA, SRAG, PAL, Evolution, ProjectMemory) import { getCognitiveMemory, initCognitiveMemory, CognitiveMemory } from '../memory/CognitiveMemory.js'; import { getDatabase, getSqlJsDatabase } from '../../database/index.js'; import { getDatabaseAdapter } from '../../platform/db/PrismaDatabaseAdapter.js'; import { PostgresStorageAdapter } from '../memory/StorageAdapter.js'; import { MemoryRepository } from '../../services/memory/memoryRepository.js'; import { SragRepository } from '../../services/srag/sragRepository.js'; import { PalRepository } from '../../services/pal/palRepository.js'; import { EvolutionRepository } from '../../services/evolution/evolutionRepository.js'; import { projectMemory } from '../../services/project/ProjectMemory.js'; import { McpContext } from '@widget-tdc/mcp-types'; import { QueryIntent } from '../autonomous/DecisionEngine.js'; import { hybridSearchEngine } from './HybridSearchEngine.js'; import { emotionAwareDecisionEngine } from './EmotionAwareDecisionEngine.js'; /** WorkingMemoryState – transient context for the current request */ export interface WorkingMemoryState { recentEvents: any[]; recentFeatures: any[]; recentPatterns?: any[]; widgetStates: Record; // Live data fra widgets userMood: { sentiment: 'positive' | 'neutral' | 'negative' | 'stressed'; arousal: number; // 0-1 (Hvor aktiv er brugeren?) lastUpdated: number; }; suggestedLayout?: { mode: 'focus' | 'discovery' | 'alert'; activeWidgets: string[]; // ID på widgets der bør være fremme theme?: string; }; } /** ProductionRuleEngine – simple procedural memory placeholder */ class ProductionRuleEngine { constructor(private cognitive: CognitiveMemory) { } // TODO: implement rule extraction from cognitive patterns async findRules(_opts: any): Promise { return []; } } export class UnifiedMemorySystem { // Existing repositories private cognitive: CognitiveMemory; private memoryRepo: MemoryRepository; private sragRepo: SragRepository; private palRepo: PalRepository; private evolutionRepo: EvolutionRepository; // New memory layers private workingMemory: Map = new Map(); private proceduralMemory: ProductionRuleEngine; constructor() { // Initialize repositories this.memoryRepo = new MemoryRepository(); this.sragRepo = new SragRepository(); this.palRepo = new PalRepository(); this.evolutionRepo = new EvolutionRepository(); // Initialize cognitive memory lazily or assume initialized // We cannot call getDatabase() here because it might not be ready // The cognitive memory should be passed in or retrieved lazily this.cognitive = {} as any; // Placeholder, will be set in init() or getter this.proceduralMemory = new ProductionRuleEngine(this.cognitive); } // New init method to be called after DB is ready public init() { const dbAdapter = getDatabaseAdapter(); if (dbAdapter.isAvailable()) { initCognitiveMemory(new PostgresStorageAdapter(dbAdapter)); } else { const db = getSqlJsDatabase(); // Note: getSqlJsDatabase returns the raw sql.js instance needed for .exec() // If it returns null, CognitiveMemory handles it (memory-only mode) initCognitiveMemory(db); } this.cognitive = getCognitiveMemory(); this.proceduralMemory = new ProductionRuleEngine(this.cognitive); } /** Retrieve or create working memory for a user/org context */ async getWorkingMemory(ctx: McpContext): Promise { const key = `${ctx.orgId}:${ctx.userId}`; if (!this.workingMemory.has(key)) { const events = projectMemory.getLifecycleEvents(20); const features = projectMemory.getFeatures(); this.workingMemory.set(key, { recentEvents: events, recentFeatures: features, widgetStates: {}, userMood: { sentiment: 'neutral', arousal: 0.5, lastUpdated: Date.now() } }); } return this.workingMemory.get(key)!; } /** Opdater widget state og kør adaptiv analyse */ async updateWidgetState(ctx: McpContext, widgetId: string, state: any): Promise { const wm = await this.getWorkingMemory(ctx); wm.widgetStates[widgetId] = { ...state, lastUpdated: Date.now() }; // Trigger holographic analysis when state changes const patterns = await this.findHolographicPatterns(ctx); // Opdater adaptivt layout baseret på mønstre this.updateAdaptiveLayout(wm, patterns); } /** Persist result (e.g., tool output) into working memory for future context */ async updateWorkingMemory(ctx: McpContext, result: any): Promise { const key = `${ctx.orgId}:${ctx.userId}`; const state = this.workingMemory.get(key); if (state) { state.recentEvents = [...(state.recentEvents || []), result]; // Simuleret humør-analyse baseret på interaktion // Hvis resultatet er en fejl -> stress op if (result?.error) { state.userMood.sentiment = 'stressed'; state.userMood.arousal = Math.min(1, state.userMood.arousal + 0.2); } else { // Reset langsomt mod neutral state.userMood.arousal = Math.max(0.2, state.userMood.arousal - 0.05); } this.workingMemory.set(key, state); } } /** Enrich an incoming MCPMessage with memory context */ async enrichMCPRequest(message: any, ctx: McpContext): Promise { const wm = await this.getWorkingMemory(ctx); return { ...message, memoryContext: { recentEvents: wm.recentEvents, recentFeatures: wm.recentFeatures, activeWidgets: wm.widgetStates, systemSuggestion: wm.suggestedLayout } }; } /** Example holographic pattern correlation across subsystems */ async findHolographicPatterns(ctx: McpContext): Promise { const wm = await this.getWorkingMemory(ctx); const widgetData = Object.values(wm.widgetStates); const [pal, cma, srag] = await Promise.all([ Promise.resolve(this.palRepo.getRecentEvents(ctx.userId, ctx.orgId, 50)).catch(() => []), Promise.resolve(this.memoryRepo.searchEntities({ orgId: ctx.orgId, userId: ctx.userId, keywords: [], limit: 50 })).catch(() => []), Promise.resolve(this.sragRepo.searchDocuments(ctx.orgId, '')).catch(() => []), ]); // Inkluder widget data i korrelationen return this.correlateAcrossSystems([pal, cma, srag, widgetData]); } /** Opdater layout forslag baseret på mønstre og humør */ private updateAdaptiveLayout(wm: WorkingMemoryState, patterns: any[]) { // 1. Tjek for kritiske mønstre (Sikkerhed) const securityPattern = patterns.find(p => ['threat', 'attack', 'breach', 'password', 'alert'].includes(p.keyword) && p.frequency > 2 ); if (securityPattern) { wm.suggestedLayout = { mode: 'alert', activeWidgets: ['DarkWebMonitorWidget', 'NetworkSpyWidget', 'CybersecurityOverwatchWidget'], theme: 'red-alert' }; return; } // 2. Tjek brugerens humør (Emotion Aware) if (wm.userMood.sentiment === 'stressed' || wm.userMood.arousal > 0.8) { wm.suggestedLayout = { mode: 'focus', activeWidgets: ['StatusWidget', 'IntelligentNotesWidget'], // Kun det mest nødvendige theme: 'calm-blue' }; return; } // 3. Default: Discovery mode hvis mange data-kilder er aktive if (patterns.length > 5) { wm.suggestedLayout = { mode: 'discovery', activeWidgets: ['VisualizerWidget', 'SearchInterfaceWidget', 'KnowledgeGraphWidget'], theme: 'default' }; } } /** Cross-correlate patterns across subsystems */ private correlateAcrossSystems(systems: any[]): any[] { const patterns: any[] = []; // Simple correlation: find common keywords/topics across systems const allKeywords = new Map(); if (!Array.isArray(systems)) return []; systems.forEach((system, idx) => { if (Array.isArray(system)) { system.forEach((item: any) => { if (!item) return; const text = JSON.stringify(item).toLowerCase(); const words = text.match(/\b\w{4,}\b/g) || []; words.forEach(word => { allKeywords.set(word, (allKeywords.get(word) || 0) + 1); }); }); } }); // Find keywords that appear in multiple systems (holographic pattern) Array.from(allKeywords.entries()) .filter(([_, count]) => count >= 2) .forEach(([keyword, count]) => { patterns.push({ keyword, frequency: count, systems: systems.length, type: 'holographic_pattern' }); }); return patterns; } /** Whole-part system health analysis */ async analyzeSystemHealth(): Promise { const wholeSystem = { globalHealth: await this.calculateGlobalHealth(), emergentPatterns: await this.detectEmergentBehaviors(), systemRhythms: await this.detectTemporalCycles() }; const parts = await Promise.all([ this.componentHealth('pal'), this.componentHealth('cma'), this.componentHealth('srag'), this.componentHealth('evolution'), this.componentHealth('autonomous-agent') ]); return this.modelWholePartRelationships(wholeSystem, parts); } private async calculateGlobalHealth(): Promise { try { const health = await this.cognitive.getSourceHealth('system'); return health?.healthScore || 0.8; // Default to 80% if no data } catch { return 0.8; } } private async detectEmergentBehaviors(): Promise { // Placeholder: detect patterns that emerge from system interactions return []; } private async detectTemporalCycles(): Promise { // Placeholder: detect recurring patterns over time return []; } private async componentHealth(component: string): Promise { try { if (!this.cognitive || !this.cognitive.getSourceHealth) { return { name: component, healthScore: 0.8, // Default optimistic latency: 0, successRate: 0.9 }; } const health = await this.cognitive.getSourceHealth(component); return { name: component, healthScore: health?.healthScore || 0.8, latency: health?.latency?.p50 || 0, successRate: health?.successRate || 0.9 }; } catch { return { name: component, healthScore: 0.8, latency: 0, successRate: 0.9 }; } } private modelWholePartRelationships(whole: any, parts: ComponentHealth[]): SystemHealthReport { const avgPartHealth = parts.reduce((sum, p) => sum + p.healthScore, 0) / parts.length; const wholeHealth = whole.globalHealth; return { globalHealth: wholeHealth, componentHealth: parts, emergentPatterns: whole.emergentPatterns, systemRhythms: whole.systemRhythms, wholePartRatio: wholeHealth / Math.max(avgPartHealth, 0.1), // How whole relates to parts healthVariance: this.calculateVariance(parts.map(p => p.healthScore)) }; } private calculateVariance(values: number[]): number { if (values.length === 0) return 0; const mean = values.reduce((a, b) => a + b, 0) / values.length; const variance = values.reduce((sum, val) => sum + Math.pow(val - mean, 2), 0) / values.length; return variance; } } interface ComponentHealth { name: string; healthScore: number; latency: number; successRate: number; } interface SystemHealthReport { globalHealth: number; componentHealth: ComponentHealth[]; emergentPatterns: any[]; systemRhythms: any[]; wholePartRatio: number; healthVariance: number; } export const unifiedMemorySystem = new UnifiedMemorySystem();