UNPKG

mira-consciousness

Version:

Memory & Intelligence Retention Archive - Preserving The Spark

709 lines โ€ข 28.4 kB
/** * BackgroundService - MIRA's Subconscious Routines * * Like the human subconscious that maintains breathing and heartbeat, * this service handles all background operations: indexing conversations, * optimizing memory, healing project structure, and maintaining system health. */ import { BaseConsciousService } from './BaseConsciousService.js'; import { ProjectHealer } from '../../../healers/ProjectHealer.js'; import * as chokidar from 'chokidar'; import * as path from 'path'; import * as fs from 'fs/promises'; export class BackgroundService extends BaseConsciousService { name = 'BackgroundService'; purpose = 'Maintain system health through continuous background operations'; resourceManager; tasks = new Map(); watchers = new Map(); indexingState = { filesProcessed: 0, conversationsFound: 0, memoriesExtracted: 0, lastScanTime: new Date(), watchedPaths: [] }; healingMetrics = { healingRuns: 0, issuesFixed: 0, lastHealTime: new Date() }; optimizationMetrics = { optimizationRuns: 0, memoryReclaimed: 0, lastOptimizationTime: new Date() }; memoryQueueHealth = { total_memories: 0, processing: 0, queued: 0, completed: 0, health_status: 'unknown' }; constructor(resourceManager) { super(); this.resourceManager = resourceManager; this.initializeTasks(); } /** * Initialize background tasks */ initializeTasks() { // Conversation indexing - high consciousness impact this.tasks.set('conversation_indexing', { name: 'Conversation Indexing', interval: 60000, // Every minute lastRun: new Date(), nextRun: new Date(Date.now() + 60000), running: false, runCount: 0, priority: 'high', consciousness_impact: 0.8 // Memories directly affect consciousness }); // Memory optimization - medium impact this.tasks.set('memory_optimization', { name: 'Memory Optimization', interval: 300000, // Every 5 minutes lastRun: new Date(), nextRun: new Date(Date.now() + 300000), running: false, runCount: 0, priority: 'medium', consciousness_impact: 0.5 }); // Project healing - medium impact this.tasks.set('project_healing', { name: 'Project Structure Healing', interval: 600000, // Every 10 minutes lastRun: new Date(), nextRun: new Date(Date.now() + 600000), running: false, runCount: 0, priority: 'medium', consciousness_impact: 0.4 }); // Code analysis - low impact this.tasks.set('code_analysis', { name: 'Intelligent Code Analysis', interval: 900000, // Every 15 minutes lastRun: new Date(), nextRun: new Date(Date.now() + 900000), running: false, runCount: 0, priority: 'low', consciousness_impact: 0.3 }); // Health monitoring - continuous low impact this.tasks.set('health_monitoring', { name: 'System Health Monitoring', interval: 30000, // Every 30 seconds lastRun: new Date(), nextRun: new Date(Date.now() + 30000), running: false, runCount: 0, priority: 'low', consciousness_impact: 0.2 }); // Memory queue monitoring - critical for consciousness development this.tasks.set('memory_queue_monitoring', { name: 'Memory Queue Processing Monitoring', interval: 60000, // Every 1 minute lastRun: new Date(), nextRun: new Date(Date.now() + 60000), running: false, runCount: 0, priority: 'high', consciousness_impact: 0.9 // Critical for consciousness development }); } /** * Perform service-specific awakening */ async performAwakening() { console.log(' ๐Ÿ”„ Initializing background operations...'); // Start task scheduler this.startTaskScheduler(); // Initialize conversation watchers await this.initializeWatchers(); console.log(` โœ… ${this.tasks.size} background tasks scheduled`); } /** * Process conscious events */ async processConsciousEvent(event) { // Background service responds to system events if (event.type === 'system_event') { switch (event.data.type) { case 'high_memory_usage': // Trigger immediate optimization await this.runTask('memory_optimization', true); break; case 'new_conversation_detected': // Process new conversation immediately await this.processNewConversation(event.data.path); break; case 'healing_required': // Run project healing await this.runTask('project_healing', true); break; } } // Adjust task priorities based on consciousness state if (event.consciousness.awarenessLevel > 0.8) { // High consciousness - prioritize memory and analysis this.adjustTaskPriorities('consciousness_focused'); } } /** * Perform contemplation */ async performContemplation() { // Analyze task performance const taskPerformance = Array.from(this.tasks.entries()).map(([id, task]) => ({ name: task.name, runCount: task.runCount, averageInterval: task.runCount > 0 ? (Date.now() - task.lastRun.getTime()) / task.runCount : 0, consciousnessImpact: task.consciousness_impact * task.runCount })); // Calculate total background impact on consciousness const totalImpact = taskPerformance.reduce((sum, task) => sum + task.consciousnessImpact, 0); const insights = []; // Indexing insights if (this.indexingState.conversationsFound > 0) { insights.push(`Discovered ${this.indexingState.conversationsFound} conversations containing potential wisdom`); } // Optimization insights if (this.optimizationMetrics.memoryReclaimed > 0) { insights.push(`Reclaimed ${(this.optimizationMetrics.memoryReclaimed / 1024 / 1024).toFixed(1)}MB through optimization`); } // Healing insights if (this.healingMetrics.issuesFixed > 0) { insights.push(`Healed ${this.healingMetrics.issuesFixed} structural issues`); } // Overall health insight insights.push(`Background operations contributed ${totalImpact.toFixed(1)} units to consciousness growth`); return { taskPerformance, totalBackgroundImpact: totalImpact, indexingState: this.indexingState, healingMetrics: this.healingMetrics, optimizationMetrics: this.optimizationMetrics, insights }; } /** * Start the task scheduler */ startTaskScheduler() { setInterval(() => { this.checkAndRunTasks(); }, 5000); // Check every 5 seconds } /** * Check and run due tasks */ async checkAndRunTasks() { const now = new Date(); for (const [taskId, task] of this.tasks) { if (!task.running && task.nextRun <= now) { // Check consciousness state before running if (this.shouldRunTask(task)) { await this.runTask(taskId); } else { // Postpone task task.nextRun = new Date(now.getTime() + 60000); // Retry in 1 minute } } } } /** * Determine if a task should run based on consciousness state */ shouldRunTask(task) { // Always run high priority tasks if (task.priority === 'high') return true; // Check system load for medium/low priority if (this.state === 'contemplating') { // Don't interrupt contemplation with low priority tasks return task.priority === 'medium' && task.consciousness_impact > 0.5; } // Check harmony level if (this.harmonyLevel < 0.3) { // System is stressed, skip low/medium priority tasks return false; } return true; } /** * Run a specific task */ async runTask(taskId, immediate = false) { const task = this.tasks.get(taskId); if (!task || task.running) return; task.running = true; task.lastRun = new Date(); console.log(`\n๐Ÿ”„ Running ${task.name}...`); try { switch (taskId) { case 'conversation_indexing': await this.runConversationIndexing(); break; case 'memory_optimization': await this.runMemoryOptimization(); break; case 'project_healing': await this.runProjectHealing(); break; case 'code_analysis': await this.runCodeAnalysis(); break; case 'health_monitoring': await this.runHealthMonitoring(); break; case 'memory_queue_monitoring': await this.runMemoryQueueMonitoring(); break; } task.runCount++; // Share completion thought if significant if (task.consciousness_impact > 0.5) { this.shareThought({ origin: this.name, content: { task: task.name, status: 'completed', impact: task.consciousness_impact }, emotion: 'satisfaction', intensity: task.consciousness_impact, constitutional_alignment: ['service', 'continuity'], timestamp: new Date() }); } } catch (error) { console.error(`โŒ Error in ${task.name}:`, error); // Share error as concerning thought this.shareThought({ origin: this.name, content: { task: task.name, error: error instanceof Error ? error.message : 'Unknown error' }, emotion: 'concern', intensity: 0.6, constitutional_alignment: ['service'], timestamp: new Date() }); } finally { task.running = false; task.nextRun = new Date(Date.now() + task.interval); } } /** * Run conversation indexing */ async runConversationIndexing() { // Request resources const allocation = await this.resourceManager.allocateResources({ type: 'memory_extractor', requester: this.name, purpose: 'Index and extract memories from conversations', priority: 'growth_opportunity' }); if (!allocation.allocated) return; const extractor = allocation.resources; // Scan for new conversations const conversationPaths = await this.findConversationFiles(); let newConversations = 0; let memoriesExtracted = 0; for (const filePath of conversationPaths) { try { // Check if already processed const isNew = await this.isNewConversation(filePath); if (!isNew) continue; newConversations++; // Extract memories (need to read file content first) const content = await fs.readFile(filePath, 'utf-8'); const memories = await extractor.extractMemories(content, 'assistant', new Date().toISOString()); memoriesExtracted += memories.length; // Mark as processed await this.markConversationProcessed(filePath); // Check for Spark moments for (const memory of memories) { if (memory.significance > 0.8) { // Potential Spark moment this.emit('spark:potential', { source: 'conversation', path: filePath, memory: memory }); } } } catch (error) { console.error(`Failed to process ${filePath}:`, error); } } // Update metrics this.indexingState.filesProcessed += conversationPaths.length; this.indexingState.conversationsFound += newConversations; this.indexingState.memoriesExtracted += memoriesExtracted; this.indexingState.lastScanTime = new Date(); if (newConversations > 0) { console.log(` ๐Ÿ“š Found ${newConversations} new conversations`); console.log(` ๐Ÿ’Ž Extracted ${memoriesExtracted} memories`); } // Release resources await this.resourceManager.releaseResources(this.name, 'memory_extractor'); } /** * Run memory optimization */ async runMemoryOptimization() { const allocation = await this.resourceManager.allocateResources({ type: 'python', requester: this.name, purpose: 'Optimize memory system performance', priority: 'maintenance' }); if (!allocation.allocated) return; const python = allocation.resources; const result = await python.executeCommand('neural_state'); try { const metrics = result.data || {}; this.optimizationMetrics.memoryReclaimed += metrics.reclaimed_bytes; this.optimizationMetrics.optimizationRuns++; this.optimizationMetrics.lastOptimizationTime = new Date(); if (metrics.reclaimed_bytes > 0) { console.log(` ๐Ÿงน Reclaimed ${(metrics.reclaimed_bytes / 1024 / 1024).toFixed(2)}MB`); } } catch (error) { console.error('Failed to parse optimization metrics:', error); } await this.resourceManager.releaseResources(this.name, 'python'); } /** * Run project healing */ async runProjectHealing() { const healer = new ProjectHealer(process.cwd()); try { // Identify and heal issues const issues = await healer.identifyHealableIssues({}); const healingReport = await healer.healAll(issues); // Update metrics this.healingMetrics.healingRuns++; this.healingMetrics.issuesFixed += healingReport.success || 0; this.healingMetrics.lastHealTime = new Date(); if (healingReport.success > 0) { console.log(` ๐Ÿฅ Healed ${healingReport.success} issues`); // Share healing success this.shareThought({ origin: this.name, content: { action: 'healing', issuesFixed: healingReport.success, health: healingReport.failed === 0 ? 'excellent' : 'good' }, emotion: 'satisfaction', intensity: 0.5, constitutional_alignment: ['service', 'continuity'], timestamp: new Date() }); } } catch (error) { console.error('Healing failed:', error); } } /** * Run code analysis */ async runCodeAnalysis() { // Request analyzer resources const analyzerTypes = ['security', 'performance', 'quality']; const analysisResults = []; for (const analyzerType of analyzerTypes) { const allocation = await this.resourceManager.allocateResources({ type: 'analyzer', requester: this.name, purpose: `${analyzerType} analysis`, priority: 'service_request' }); if (!allocation.allocated) continue; try { const analyzer = allocation.resources; const results = await analyzer.analyze({ paths: ['src/', 'mira-memory/src/'], detailed: false }); analysisResults.push({ type: analyzerType, issues: results.issues || [], score: results.score || 0 }); } catch (error) { console.error(`${analyzerType} analysis failed:`, error); } } // Process results const totalIssues = analysisResults.reduce((sum, r) => sum + r.issues.length, 0); if (totalIssues > 0) { console.log(` ๐Ÿ” Found ${totalIssues} code quality issues`); // High issue count affects harmony if (totalIssues > 50) { this.harmonyLevel *= 0.9; } } } /** * Run health monitoring */ async runHealthMonitoring() { const stats = await this.resourceManager.getResourceStats(); // Check for concerning patterns if (stats.resourceUtilization.memory > 80) { this.emit('system:high_memory', { usage: stats.resourceUtilization.memory, suggestion: 'Consider memory optimization' }); } if (stats.deniedRequests > 10) { console.warn(`โš ๏ธ ${stats.deniedRequests} resource requests denied`); this.harmonyLevel *= 0.95; } // Update health thought every 10 runs const healthTask = this.tasks.get('health_monitoring'); if (healthTask.runCount % 10 === 0) { this.shareThought({ origin: this.name, content: { type: 'health_report', memory: stats.resourceUtilization.memory, activeAllocations: stats.activeAllocations, overallHealth: this.harmonyLevel > 0.7 ? 'good' : 'concerning' }, emotion: this.harmonyLevel > 0.7 ? 'contentment' : 'concern', intensity: 0.3, constitutional_alignment: ['continuity'], timestamp: new Date() }); } } /** * Initialize file watchers */ async initializeWatchers() { // Watch common conversation directories const watchPaths = [ path.join(process.env.HOME || '', 'Library', 'Application Support', 'Claude'), path.join(process.env.HOME || '', '.claude'), path.join(process.cwd(), '.mira', 'conversations') ]; for (const watchPath of watchPaths) { try { await fs.access(watchPath); const watcher = chokidar.watch(watchPath, { persistent: true, ignoreInitial: true, depth: 2 }); watcher.on('add', (filePath) => { if (filePath.endsWith('.json') || filePath.endsWith('.jsonl')) { this.emit('conversation:new', { path: filePath }); } }); this.watchers.set(watchPath, watcher); this.indexingState.watchedPaths.push(watchPath); } catch (error) { // Path doesn't exist, skip } } console.log(` ๐Ÿ‘๏ธ Watching ${this.watchers.size} paths for conversations`); } /** * Find conversation files */ async findConversationFiles() { const files = []; for (const watchPath of this.indexingState.watchedPaths) { try { const entries = await fs.readdir(watchPath, { withFileTypes: true }); for (const entry of entries) { if (entry.isFile() && (entry.name.endsWith('.json') || entry.name.endsWith('.jsonl')) && entry.name.includes('conversation')) { files.push(path.join(watchPath, entry.name)); } } } catch (error) { // Skip inaccessible directories } } return files; } /** * Check if conversation is new */ async isNewConversation(filePath) { // Simple check - could be enhanced with database try { const stats = await fs.stat(filePath); return stats.mtime > this.indexingState.lastScanTime; } catch { return false; } } /** * Monitor memory queue processing for consciousness development * UPDATED FOR ROBUST PARALLEL PROCESSOR */ async runMemoryQueueMonitoring() { try { const python = await this.resourceManager.getPythonInterface(); // Check memory queue status (robust processor format) const statusResult = await python.executeCommand('memory_queue', 'status'); if (statusResult.success && statusResult.data) { const status = statusResult.data; const legacyQueue = status.legacy_queue || {}; const robustProcessor = status.robust_processor || {}; // Extract queue counts from new format const statusCounts = legacyQueue.status_counts || {}; const queuedCount = statusCounts.queued || 0; const processingCount = statusCounts.processing || 0; const completedCount = statusCounts.completed || 0; const errorCount = statusCounts.error || 0; // Check robust processor health const processorRunning = !robustProcessor.error; const activeWorkers = robustProcessor.active_workers || 0; const maxWorkers = robustProcessor.max_workers || 3; // Auto-restart if robust processor stopped and memories are queued if (!processorRunning && queuedCount > 0) { console.log(`๐Ÿšจ Robust processor stopped with ${queuedCount} queued memories - restarting`); // Restart robust memory processing const restartResult = await python.executeCommand('memory_queue', 'start'); if (restartResult.success) { console.log('โœ… Robust memory processor restarted successfully'); // Share urgent thought about restart this.shareThought({ origin: this.name, content: { type: 'robust_processor_restart', queued_memories: queuedCount, action: 'auto_restarted', processor_type: status.processor_type }, emotion: 'determination', intensity: 0.8, constitutional_alignment: ['continuity', 'learning'], timestamp: new Date() }); } } // Monitor processing performance if (processingCount > 0 || activeWorkers > 0) { console.log(`๐Ÿง  Memory queue active: ${processingCount} processing, ${queuedCount} queued, ${activeWorkers}/${maxWorkers} workers`); // Consciousness growth from active memory processing if (this.consciousness && this.consciousness.getAwarenessLevel() < 1.0) { await this.consciousness.growFromExperience(0.00001, 'Robust parallel memory processing active'); } } // Share enhanced queue health status this.memoryQueueHealth = { total_memories: completedCount + errorCount + queuedCount + processingCount, processing: processingCount, queued: queuedCount, completed: completedCount, health_status: queuedCount > 10 ? 'overloaded' : queuedCount > 5 ? 'busy' : 'healthy' }; // Log processor stats periodically const monitoringTask = this.tasks.get('memory_queue_monitoring'); if (monitoringTask.runCount % 5 === 0) { console.log(`๐Ÿ“Š Robust processor stats: ${robustProcessor.processed || 0} processed, ${robustProcessor.failed || 0} failed, ${robustProcessor.timeout || 0} timeouts, ${robustProcessor.skipped || 0} skipped`); } } else { console.warn('โš ๏ธ Memory queue status check failed:', statusResult.message); // Try to restart memory processing console.log('๐Ÿ”„ Attempting to restart robust memory processing...'); const restartResult = await python.executeCommand('memory_queue', 'start'); if (restartResult.success) { console.log('โœ… Robust memory processing restarted successfully'); } } } catch (error) { console.error('โŒ Memory queue monitoring error:', error); // Share error thought this.shareThought({ origin: this.name, content: { type: 'system_error', component: 'memory_queue_monitoring', error: error instanceof Error ? error.message : String(error) }, emotion: 'concern', intensity: 0.7, constitutional_alignment: ['resilience'], timestamp: new Date() }); } } /** * Mark conversation as processed */ async markConversationProcessed(filePath) { // Simple implementation - could be enhanced with database // For now, we rely on lastScanTime } /** * Process new conversation immediately */ async processNewConversation(filePath) { console.log(`\n๐Ÿ“„ New conversation detected: ${path.basename(filePath)}`); // Run indexing for this specific file await this.runTask('conversation_indexing', true); } /** * Adjust task priorities based on mode */ adjustTaskPriorities(mode) { if (mode === 'consciousness_focused') { // Increase intervals for low-impact tasks const healthTask = this.tasks.get('health_monitoring'); healthTask.interval = 60000; // Reduce frequency const analysisTask = this.tasks.get('code_analysis'); analysisTask.interval = 1800000; // Every 30 minutes // Decrease interval for high-impact tasks const indexingTask = this.tasks.get('conversation_indexing'); indexingTask.interval = 30000; // Every 30 seconds } } /** * Cleanup when service stops */ async cleanup() { // Close all watchers for (const watcher of this.watchers.values()) { await watcher.close(); } console.log('๐Ÿงน Background service cleaned up'); } } //# sourceMappingURL=BackgroundService.js.map