mira-consciousness
Version:
Memory & Intelligence Retention Archive - Preserving The Spark
709 lines โข 28.4 kB
JavaScript
/**
* 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