Spaces:
Paused
Paused
| /** | |
| * ╔═══════════════════════════════════════════════════════════════════════════════════════╗ | |
| * ║ KNOWLEDGE COMPILER ║ | |
| * ║═══════════════════════════════════════════════════════════════════════════════════════║ | |
| * ║ ║ | |
| * ║ Aggregerer viden fra hele systemet til en unified "System State Summary" ║ | |
| * ║ ║ | |
| * ║ DATAKILDER: ║ | |
| * ║ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ║ | |
| * ║ │ HyperLog │ │ Neo4j │ │ Metrics │ │ SelfHealing │ ║ | |
| * ║ │ (Events) │ │ (Graph) │ │ (Counters) │ │ (Status) │ ║ | |
| * ║ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ ║ | |
| * ║ │ │ │ │ ║ | |
| * ║ └────────────────┴────────────────┴────────────────┘ ║ | |
| * ║ │ ║ | |
| * ║ ▼ ║ | |
| * ║ ┌─────────────────────────┐ ║ | |
| * ║ │ KNOWLEDGE COMPILER │ ║ | |
| * ║ │ • compile() │ ║ | |
| * ║ │ • getSystemSummary() │ ║ | |
| * ║ │ • getInsights() │ ║ | |
| * ║ └───────────┬─────────────┘ ║ | |
| * ║ │ ║ | |
| * ║ ▼ ║ | |
| * ║ ┌─────────────────────────┐ ║ | |
| * ║ │ CognitiveNode Widget │ ║ | |
| * ║ │ (Visual Dashboard) │ ║ | |
| * ║ └─────────────────────────┘ ║ | |
| * ║ ║ | |
| * ╚═══════════════════════════════════════════════════════════════════════════════════════╝ | |
| */ | |
| import { hyperLog, HyperLog } from '../HyperLog.js'; | |
| import { selfHealing, SelfHealingAdapter } from '../SelfHealingAdapter.js'; | |
| import { neo4jAdapter } from '../../adapters/Neo4jAdapter.js'; | |
| // ═══════════════════════════════════════════════════════════════════════════ | |
| // TYPES | |
| // ═══════════════════════════════════════════════════════════════════════════ | |
| export interface HealthStatus { | |
| overall: 'HEALTHY' | 'DEGRADED' | 'CRITICAL'; | |
| score: number; | |
| services: { | |
| name: string; | |
| status: 'healthy' | 'unhealthy' | 'unknown'; | |
| lastCheck: string; | |
| }[]; | |
| healingStats: { | |
| attempts: number; | |
| successes: number; | |
| failures: number; | |
| successRate: number; | |
| }; | |
| } | |
| export interface ActivitySummary { | |
| last24h: { | |
| events: number; | |
| errors: number; | |
| healingAttempts: number; | |
| graphChanges: number; | |
| }; | |
| topEventTypes: { type: string; count: number }[]; | |
| activeAgents: string[]; | |
| } | |
| export interface GraphStats { | |
| totalNodes: number; | |
| totalRelationships: number; | |
| nodesByLabel: Record<string, number>; | |
| recentChanges: { | |
| added: number; | |
| modified: number; | |
| deleted: number; | |
| }; | |
| } | |
| export interface Insight { | |
| id: string; | |
| type: 'anomaly' | 'pattern' | 'trend'; | |
| severity: 'info' | 'warning' | 'critical'; | |
| title: string; | |
| description: string; | |
| data?: any; | |
| timestamp: string; | |
| } | |
| export interface Recommendation { | |
| id: string; | |
| priority: 'low' | 'medium' | 'high'; | |
| action: string; | |
| reason: string; | |
| impact: string; | |
| } | |
| export interface RecentEvent { | |
| id: string; | |
| type: string; | |
| timestamp: string; | |
| summary: string; | |
| data?: Record<string, any>; | |
| } | |
| export interface SystemStateSummary { | |
| timestamp: string; | |
| health: HealthStatus; | |
| activity: ActivitySummary; | |
| insights: Insight[]; | |
| recommendations: Recommendation[]; | |
| recentEvents: RecentEvent[]; | |
| graphStats: GraphStats; | |
| } | |
| // ═══════════════════════════════════════════════════════════════════════════ | |
| // KNOWLEDGE COMPILER CLASS | |
| // ═══════════════════════════════════════════════════════════════════════════ | |
| export class KnowledgeCompiler { | |
| private static instance: KnowledgeCompiler; | |
| private lastCompilation: SystemStateSummary | null = null; | |
| private autoCompilationInterval: ReturnType<typeof setInterval> | null = null; | |
| private constructor() { } | |
| public static getInstance(): KnowledgeCompiler { | |
| if (!KnowledgeCompiler.instance) { | |
| KnowledgeCompiler.instance = new KnowledgeCompiler(); | |
| } | |
| return KnowledgeCompiler.instance; | |
| } | |
| /** | |
| * Start auto-compilation at the specified interval | |
| */ | |
| public startAutoCompilation(intervalMs: number = 60000): void { | |
| if (this.autoCompilationInterval) { | |
| console.log('[KnowledgeCompiler] Auto-compilation already running'); | |
| return; | |
| } | |
| console.log(`[KnowledgeCompiler] Starting auto-compilation every ${intervalMs / 1000}s`); | |
| // Run initial compilation after 5 seconds | |
| setTimeout(() => this.compile().catch(err => | |
| console.warn('[KnowledgeCompiler] Initial compilation failed:', err) | |
| ), 5000); | |
| // Set up periodic compilation | |
| this.autoCompilationInterval = setInterval(async () => { | |
| try { | |
| await this.compile(); | |
| } catch (error) { | |
| console.warn('[KnowledgeCompiler] Periodic compilation failed:', error); | |
| } | |
| }, intervalMs); | |
| } | |
| /** | |
| * Stop auto-compilation | |
| */ | |
| public stopAutoCompilation(): void { | |
| if (this.autoCompilationInterval) { | |
| clearInterval(this.autoCompilationInterval); | |
| this.autoCompilationInterval = null; | |
| console.log('[KnowledgeCompiler] Auto-compilation stopped'); | |
| } | |
| } | |
| /** | |
| * MAIN COMPILATION METHOD | |
| */ | |
| async compile(): Promise<SystemStateSummary> { | |
| console.log('[KnowledgeCompiler] Starting compilation...'); | |
| const startTime = Date.now(); | |
| try { | |
| // Gather data from all sources in parallel | |
| const [health, activity, graphStats, recentEvents] = await Promise.all([ | |
| this.compileHealthStatus(), | |
| this.compileActivitySummary(), | |
| this.compileGraphStats(), | |
| this.compileRecentEvents(), | |
| ]); | |
| // Generate insights based on compiled data | |
| const insights = this.generateInsights(health, activity, graphStats); | |
| // Generate recommendations | |
| const recommendations = this.generateRecommendations(health, activity, insights); | |
| const summary: SystemStateSummary = { | |
| timestamp: new Date().toISOString(), | |
| health, | |
| activity, | |
| insights, | |
| recommendations, | |
| recentEvents, | |
| graphStats, | |
| }; | |
| this.lastCompilation = summary; | |
| const duration = Date.now() - startTime; | |
| console.log(`[KnowledgeCompiler] Compilation complete in ${duration}ms`); | |
| return summary; | |
| } catch (error) { | |
| console.error('[KnowledgeCompiler] Compilation failed:', error); | |
| throw error; | |
| } | |
| } | |
| /** | |
| * Get the last compiled summary (cached) | |
| */ | |
| getLastCompilation(): SystemStateSummary | null { | |
| return this.lastCompilation; | |
| } | |
| /** | |
| * Get system summary (compile if needed) | |
| */ | |
| async getSystemSummary(forceRefresh: boolean = false): Promise<SystemStateSummary> { | |
| if (forceRefresh || !this.lastCompilation) { | |
| return await this.compile(); | |
| } | |
| return this.lastCompilation; | |
| } | |
| /** | |
| * Quick health check without full compilation | |
| */ | |
| async quickHealth(): Promise<{ status: string; score: number; timestamp: string }> { | |
| const health = await this.compileHealthStatus(); | |
| return { | |
| status: health.overall, | |
| score: health.score, | |
| timestamp: new Date().toISOString(), | |
| }; | |
| } | |
| // ═══════════════════════════════════════════════════════════════════════════ | |
| // DATA SOURCE COMPILATION METHODS | |
| // ═══════════════════════════════════════════════════════════════════════════ | |
| /** | |
| * Compile health status from SelfHealing + services | |
| */ | |
| private async compileHealthStatus(): Promise<HealthStatus> { | |
| const systemStatus = selfHealing.getSystemStatus(); | |
| const hyperLogData = hyperLog.exportForAnalysis(); | |
| // Calculate healing stats from HyperLog | |
| const healingAttempts = hyperLogData.summary['HEALING_ATTEMPT'] || 0; | |
| const healingSuccesses = hyperLogData.summary['HEALING_SUCCESS'] || 0; | |
| const healingFailures = | |
| hyperLogData.summary['HEALING_CRASH'] || hyperLogData.summary['HEALING_FAILED'] || 0; | |
| const successRate = | |
| healingAttempts > 0 ? Math.round((healingSuccesses / healingAttempts) * 100) : 100; | |
| // Calculate overall score | |
| let score = 100; | |
| if (systemStatus.overallHealth === 'DEGRADED') score = 70; | |
| if (systemStatus.overallHealth === 'CRITICAL') score = 30; | |
| score = Math.max(0, score - healingFailures * 5); | |
| return { | |
| overall: systemStatus.overallHealth as 'HEALTHY' | 'DEGRADED' | 'CRITICAL', | |
| score: Math.max(0, Math.min(100, score)), | |
| services: systemStatus.services.map(s => ({ | |
| name: s.name, | |
| status: s.status as 'healthy' | 'unhealthy' | 'unknown', | |
| lastCheck: new Date().toISOString(), | |
| })), | |
| healingStats: { | |
| attempts: healingAttempts, | |
| successes: healingSuccesses, | |
| failures: healingFailures, | |
| successRate, | |
| }, | |
| }; | |
| } | |
| /** | |
| * Compile activity summary from HyperLog | |
| */ | |
| private async compileActivitySummary(): Promise<ActivitySummary> { | |
| const hyperLogData = hyperLog.exportForAnalysis(); | |
| const recentEvents = hyperLog.getRecentEvents(1000); | |
| // Filter to last 24h | |
| const oneDayAgo = Date.now() - 24 * 60 * 60 * 1000; | |
| const last24hEvents = recentEvents.filter(e => e.timestamp > oneDayAgo); | |
| // Count errors | |
| const errors = last24hEvents.filter( | |
| e => | |
| e.eventType.includes('ERROR') || | |
| e.eventType.includes('FAIL') || | |
| e.eventType.includes('CRASH') | |
| ).length; | |
| // Count healing attempts | |
| const healingAttempts = last24hEvents.filter(e => e.eventType.startsWith('HEALING_')).length; | |
| // Top event types | |
| const eventCounts: Record<string, number> = {}; | |
| for (const event of last24hEvents) { | |
| eventCounts[event.eventType] = (eventCounts[event.eventType] || 0) + 1; | |
| } | |
| const topEventTypes = Object.entries(eventCounts) | |
| .sort((a, b) => b[1] - a[1]) | |
| .slice(0, 10) | |
| .map(([type, count]) => ({ type, count })); | |
| return { | |
| last24h: { | |
| events: last24hEvents.length, | |
| errors, | |
| healingAttempts, | |
| graphChanges: 0, // Will be populated from Neo4j | |
| }, | |
| topEventTypes, | |
| activeAgents: ['claude', 'gemini', 'system'], // TODO: Track from messages | |
| }; | |
| } | |
| /** | |
| * Compile graph statistics from Neo4j | |
| */ | |
| private async compileGraphStats(): Promise<GraphStats> { | |
| try { | |
| const countResult = await neo4jAdapter.executeQuery(` | |
| MATCH (n) | |
| WITH count(n) as nodes | |
| OPTIONAL MATCH ()-[r]->() | |
| RETURN nodes, count(r) as relationships | |
| `); | |
| const labelResult = await neo4jAdapter.executeQuery(` | |
| MATCH (n) | |
| WITH labels(n) as nodeLabels | |
| UNWIND nodeLabels as label | |
| RETURN label, count(*) as count | |
| ORDER BY count DESC | |
| `); | |
| const nodesByLabel: Record<string, number> = {}; | |
| for (const row of labelResult) { | |
| const countVal = row.count; | |
| const count = | |
| typeof countVal === 'object' && countVal !== null && 'low' in countVal | |
| ? countVal.low | |
| : typeof countVal === 'object' && countVal !== null && 'toNumber' in countVal | |
| ? countVal.toNumber() | |
| : Number(countVal || 0); | |
| nodesByLabel[row.label] = count; | |
| } | |
| const rawNodes = countResult[0]?.nodes; | |
| const rawRels = countResult[0]?.relationships; | |
| const totalNodes = | |
| typeof rawNodes === 'object' && rawNodes !== null && 'low' in rawNodes | |
| ? rawNodes.low | |
| : typeof rawNodes === 'object' && rawNodes !== null && 'toNumber' in rawNodes | |
| ? rawNodes.toNumber() | |
| : Number(rawNodes || 0); | |
| const totalRelationships = | |
| typeof rawRels === 'object' && rawRels !== null && 'low' in rawRels | |
| ? rawRels.low | |
| : typeof rawRels === 'object' && rawRels !== null && 'toNumber' in rawRels | |
| ? rawRels.toNumber() | |
| : Number(rawRels || 0); | |
| return { | |
| totalNodes, | |
| totalRelationships, | |
| nodesByLabel, | |
| recentChanges: { | |
| added: 0, | |
| modified: 0, | |
| deleted: 0, | |
| }, | |
| }; | |
| } catch (error) { | |
| console.warn('[KnowledgeCompiler] Failed to get graph stats:', error); | |
| return { | |
| totalNodes: 0, | |
| totalRelationships: 0, | |
| nodesByLabel: {}, | |
| recentChanges: { added: 0, modified: 0, deleted: 0 }, | |
| }; | |
| } | |
| } | |
| /** | |
| * Compile recent events for display | |
| */ | |
| private async compileRecentEvents(): Promise<RecentEvent[]> { | |
| const events = hyperLog.getRecentEvents(20); | |
| return events | |
| .map(e => ({ | |
| id: e.id, | |
| type: e.eventType, | |
| timestamp: new Date(e.timestamp).toISOString(), | |
| summary: this.summarizeEvent(e.eventType, e.data), | |
| data: e.data, | |
| })) | |
| .reverse(); // Most recent first | |
| } | |
| /** | |
| * Generate human-readable event summary | |
| */ | |
| private summarizeEvent(eventType: string, data: Record<string, any>): string { | |
| switch (eventType) { | |
| case 'HEALING_SUCCESS': | |
| return `System healed: ${data.strategy || 'unknown strategy'}`; | |
| case 'HEALING_CRASH': | |
| case 'HEALING_FAILED': | |
| return `Healing failed: ${data.originalError || 'unknown error'}`; | |
| case 'HEALING_ATTEMPT': | |
| return `Attempting to heal: ${data.strategy || 'unknown'}`; | |
| case 'ERROR_UNHANDLED': | |
| return `Unhandled error: ${data.message || data.code || 'unknown'}`; | |
| default: | |
| return `${eventType}: ${JSON.stringify(data).slice(0, 50)}...`; | |
| } | |
| } | |
| // ═══════════════════════════════════════════════════════════════════════════ | |
| // INSIGHT & RECOMMENDATION GENERATION | |
| // ═══════════════════════════════════════════════════════════════════════════ | |
| /** | |
| * Generate insights from compiled data | |
| * ENHANCED: Now includes predictive alerts and proactive pattern detection | |
| */ | |
| private generateInsights( | |
| health: HealthStatus, | |
| activity: ActivitySummary, | |
| graphStats: GraphStats | |
| ): Insight[] { | |
| const insights: Insight[] = []; | |
| // ═══════════════════════════════════════════════════════════════════ | |
| // PREDICTIVE INSIGHTS (from SelfHealing predictive alerts) | |
| // ═══════════════════════════════════════════════════════════════════ | |
| const predictiveAlerts = selfHealing.getPredictiveAlerts(); | |
| for (const alert of predictiveAlerts) { | |
| insights.push({ | |
| id: `insight_predictive_${alert.errorCode}_${Date.now()}`, | |
| type: 'anomaly', | |
| severity: alert.severity === 'critical' ? 'critical' : 'warning', | |
| title: `🔮 Predicted Failure: ${alert.errorCode}`, | |
| description: `${(alert.probability * 100).toFixed(0)}% probability of ${alert.errorCode} failure ${alert.expectedIn}. ${alert.recommendation}`, | |
| data: { | |
| errorCode: alert.errorCode, | |
| probability: alert.probability, | |
| expectedIn: alert.expectedIn, | |
| }, | |
| timestamp: new Date().toISOString(), | |
| }); | |
| } | |
| // ═══════════════════════════════════════════════════════════════════ | |
| // PATTERN DETECTION: Error clustering analysis | |
| // ═══════════════════════════════════════════════════════════════════ | |
| const errorPatterns = this.detectErrorPatterns(activity); | |
| for (const pattern of errorPatterns) { | |
| insights.push({ | |
| id: `insight_pattern_${pattern.code}_${Date.now()}`, | |
| type: 'pattern', | |
| severity: pattern.severity, | |
| title: `📊 Pattern: ${pattern.title}`, | |
| description: pattern.description, | |
| data: pattern.data, | |
| timestamp: new Date().toISOString(), | |
| }); | |
| } | |
| // ═══════════════════════════════════════════════════════════════════ | |
| // USAGE SPIKE DETECTION | |
| // ═══════════════════════════════════════════════════════════════════ | |
| const usageSpikes = this.detectUsageSpikes(activity); | |
| for (const spike of usageSpikes) { | |
| insights.push({ | |
| id: `insight_spike_${spike.eventType}_${Date.now()}`, | |
| type: 'trend', | |
| severity: spike.severity, | |
| title: `📈 Usage Spike: ${spike.eventType}`, | |
| description: spike.description, | |
| data: spike.data, | |
| timestamp: new Date().toISOString(), | |
| }); | |
| } | |
| // Health-based insights | |
| if (health.healingStats.failures > 0) { | |
| insights.push({ | |
| id: `insight_healing_${Date.now()}`, | |
| type: 'anomaly', | |
| severity: health.healingStats.failures > 3 ? 'critical' : 'warning', | |
| title: 'Self-Healing Failures Detected', | |
| description: `${health.healingStats.failures} healing attempts have failed. Success rate: ${health.healingStats.successRate}%`, | |
| timestamp: new Date().toISOString(), | |
| }); | |
| } | |
| // Activity-based insights | |
| if (activity.last24h.errors > 10) { | |
| insights.push({ | |
| id: `insight_errors_${Date.now()}`, | |
| type: 'anomaly', | |
| severity: 'warning', | |
| title: 'High Error Rate', | |
| description: `${activity.last24h.errors} errors detected in the last 24 hours`, | |
| data: { errorCount: activity.last24h.errors }, | |
| timestamp: new Date().toISOString(), | |
| }); | |
| } | |
| // Graph-based insights | |
| if (graphStats.totalNodes > 10000) { | |
| insights.push({ | |
| id: `insight_graph_${Date.now()}`, | |
| type: 'trend', | |
| severity: 'info', | |
| title: 'Large Knowledge Graph', | |
| description: `Knowledge graph has grown to ${graphStats.totalNodes.toLocaleString()} nodes`, | |
| timestamp: new Date().toISOString(), | |
| }); | |
| } | |
| // ═══════════════════════════════════════════════════════════════════ | |
| // DEAD SERVICE DETECTION | |
| // ═══════════════════════════════════════════════════════════════════ | |
| const deadServices = health.services.filter(s => s.status === 'unhealthy'); | |
| if (deadServices.length > 0) { | |
| insights.push({ | |
| id: `insight_dead_services_${Date.now()}`, | |
| type: 'anomaly', | |
| severity: 'critical', | |
| title: `☠️ Dead Services Detected`, | |
| description: `${deadServices.length} service(s) are unhealthy: ${deadServices.map(s => s.name).join(', ')}`, | |
| data: { services: deadServices.map(s => s.name) }, | |
| timestamp: new Date().toISOString(), | |
| }); | |
| } | |
| // Pattern detection from top events | |
| const healingEvents = activity.topEventTypes.filter(e => e.type.startsWith('HEALING_')); | |
| if (healingEvents.length > 0) { | |
| const totalHealingEvents = healingEvents.reduce((sum, e) => sum + e.count, 0); | |
| if (totalHealingEvents > 5) { | |
| insights.push({ | |
| id: `insight_pattern_healing_${Date.now()}`, | |
| type: 'pattern', | |
| severity: 'info', | |
| title: 'Frequent Self-Healing Activity', | |
| description: `System has triggered ${totalHealingEvents} healing events recently`, | |
| data: { events: healingEvents }, | |
| timestamp: new Date().toISOString(), | |
| }); | |
| } | |
| } | |
| return insights; | |
| } | |
| /** | |
| * 📊 PATTERN DETECTION: Analyze error clustering | |
| */ | |
| private detectErrorPatterns(activity: ActivitySummary): Array<{ | |
| code: string; | |
| title: string; | |
| description: string; | |
| severity: 'info' | 'warning' | 'critical'; | |
| data: any; | |
| }> { | |
| const patterns: Array<any> = []; | |
| // Group error events | |
| const errorEvents = activity.topEventTypes.filter( | |
| e => e.type.includes('ERROR') || e.type.includes('FAIL') | |
| ); | |
| // Detect repeated errors (same error > 5 times) | |
| for (const event of errorEvents) { | |
| if (event.count >= 5) { | |
| patterns.push({ | |
| code: event.type, | |
| title: `Repeated ${event.type}`, | |
| description: `${event.type} has occurred ${event.count} times - investigate root cause`, | |
| severity: event.count >= 10 ? 'critical' : 'warning', | |
| data: { eventType: event.type, count: event.count }, | |
| }); | |
| } | |
| } | |
| // Detect error bursts (many errors in short time) | |
| const totalErrors = errorEvents.reduce((sum, e) => sum + e.count, 0); | |
| if (totalErrors > 20 && errorEvents.length > 3) { | |
| patterns.push({ | |
| code: 'ERROR_BURST', | |
| title: 'Error Burst Detected', | |
| description: `${totalErrors} errors across ${errorEvents.length} different error types - possible cascading failure`, | |
| severity: 'critical', | |
| data: { totalErrors, errorTypes: errorEvents.length }, | |
| }); | |
| } | |
| return patterns; | |
| } | |
| /** | |
| * 📈 USAGE SPIKE DETECTION: Find abnormal activity | |
| */ | |
| private detectUsageSpikes(activity: ActivitySummary): Array<{ | |
| eventType: string; | |
| description: string; | |
| severity: 'info' | 'warning' | 'critical'; | |
| data: any; | |
| }> { | |
| const spikes: Array<any> = []; | |
| // Calculate average event count | |
| const avgCount = | |
| activity.topEventTypes.reduce((sum, e) => sum + e.count, 0) / | |
| Math.max(activity.topEventTypes.length, 1); | |
| // Find events significantly above average (3x) | |
| for (const event of activity.topEventTypes) { | |
| if (event.count > avgCount * 3 && event.count >= 10) { | |
| spikes.push({ | |
| eventType: event.type, | |
| description: `${event.type} activity is ${Math.round(event.count / avgCount)}x above average (${event.count} occurrences)`, | |
| severity: event.count > avgCount * 5 ? 'warning' : 'info', | |
| data: { | |
| count: event.count, | |
| average: Math.round(avgCount), | |
| multiplier: Math.round(event.count / avgCount), | |
| }, | |
| }); | |
| } | |
| } | |
| return spikes; | |
| } | |
| /** | |
| * Generate actionable recommendations | |
| */ | |
| private generateRecommendations( | |
| health: HealthStatus, | |
| activity: ActivitySummary, | |
| insights: Insight[] | |
| ): Recommendation[] { | |
| const recommendations: Recommendation[] = []; | |
| // Based on health | |
| if (health.overall === 'DEGRADED') { | |
| recommendations.push({ | |
| id: `rec_health_${Date.now()}`, | |
| priority: 'high', | |
| action: 'Investigate degraded services', | |
| reason: 'System health is degraded', | |
| impact: 'Prevent potential system failures', | |
| }); | |
| } | |
| if (health.healingStats.successRate < 80) { | |
| recommendations.push({ | |
| id: `rec_healing_${Date.now()}`, | |
| priority: 'medium', | |
| action: 'Review self-healing strategies', | |
| reason: `Healing success rate is ${health.healingStats.successRate}%`, | |
| impact: 'Improve system resilience', | |
| }); | |
| } | |
| // Based on activity | |
| if (activity.last24h.errors > 20) { | |
| recommendations.push({ | |
| id: `rec_errors_${Date.now()}`, | |
| priority: 'high', | |
| action: 'Review error logs and implement fixes', | |
| reason: `${activity.last24h.errors} errors in last 24h`, | |
| impact: 'Reduce system instability', | |
| }); | |
| } | |
| // Based on insights | |
| const criticalInsights = insights.filter(i => i.severity === 'critical'); | |
| if (criticalInsights.length > 0) { | |
| recommendations.push({ | |
| id: `rec_critical_${Date.now()}`, | |
| priority: 'high', | |
| action: 'Address critical insights immediately', | |
| reason: `${criticalInsights.length} critical issues detected`, | |
| impact: 'Prevent system failures', | |
| }); | |
| } | |
| return recommendations; | |
| } | |
| } | |
| // ═══════════════════════════════════════════════════════════════════════════ | |
| // SINGLETON EXPORT | |
| // ═══════════════════════════════════════════════════════════════════════════ | |
| export const knowledgeCompiler = KnowledgeCompiler.getInstance(); | |