UNPKG

thoughtmcp

Version:

AI that thinks more like humans do - MCP server with human-like cognitive architecture for enhanced reasoning, memory, and self-monitoring

321 lines 12.1 kB
/** * Comprehensive error handling utilities for the cognitive MCP server * Provides graceful degradation and component failure recovery */ import { Logger } from "./logger.js"; export var ErrorSeverity; (function (ErrorSeverity) { ErrorSeverity["LOW"] = "low"; ErrorSeverity["MEDIUM"] = "medium"; ErrorSeverity["HIGH"] = "high"; ErrorSeverity["CRITICAL"] = "critical"; })(ErrorSeverity || (ErrorSeverity = {})); export class ErrorHandler { static logger = Logger.getInstance(); static componentErrors = new Map(); static MAX_ERROR_HISTORY = 100; /** * Handle errors with appropriate logging and recovery strategies */ static async handleError(error, component, context, options) { const errorObj = typeof error === "string" ? new Error(error) : error; const severity = this.assessErrorSeverity(errorObj, component); // Log the error this.logError(errorObj, component, severity, context); // Record error for tracking this.recordComponentError(component, errorObj, severity, context); // Determine if we can continue with graceful degradation const canContinue = this.canGracefullyDegrade(component, severity, options); if (canContinue && options?.enableFallbacks !== false) { const fallbackData = await this.attemptFallback(component, errorObj, context); return { canContinue: true, fallbackData }; } return { canContinue: false }; } /** * Wrap async operations with error handling and retries */ static async withErrorHandling(operation, component, options) { const maxRetries = options?.maxRetries || 3; const retryDelay = options?.retryDelayMs || 1000; const timeout = options?.timeoutMs || 30000; for (let attempt = 1; attempt <= maxRetries; attempt++) { try { // Wrap with timeout const result = await Promise.race([ operation(), this.createTimeoutPromise(timeout), ]); return { success: true, data: result }; } catch (error) { const errorObj = error instanceof Error ? error : new Error(String(error)); this.logger.warn(component, `Attempt ${attempt}/${maxRetries} failed: ${errorObj.message}`); // If this is the last attempt, handle the error if (attempt === maxRetries) { const handleResult = await this.handleError(errorObj, component, { attempt, }); return { success: false, error: errorObj, data: handleResult.fallbackData, }; } // Wait before retry (exponential backoff) await this.delay(retryDelay * Math.pow(2, attempt - 1)); } } return { success: false, error: new Error("Max retries exceeded") }; } /** * Check if a component can gracefully degrade */ static canGracefullyDegrade(component, severity, options) { // Critical errors cannot be gracefully degraded if (severity === ErrorSeverity.CRITICAL) { return false; } // Check if component is marked as critical const criticalComponents = options?.criticalComponents || [ "CognitiveOrchestrator", "MemorySystem", ]; if (criticalComponents.includes(component) && severity === ErrorSeverity.HIGH) { return false; } // Check error frequency for this component const recentErrors = this.getRecentErrors(component, 60000); // Last minute if (recentErrors.length > 5) { this.logger.error(component, `Too many recent errors (${recentErrors.length}), cannot degrade gracefully`); return false; } return true; } /** * Attempt to provide fallback functionality */ static async attemptFallback(component, error, context) { this.logger.info(component, `Attempting fallback for error: ${error.message}`); switch (component) { case "SensoryProcessor": return this.sensoryProcessorFallback(context); case "EmotionalProcessor": return this.emotionalProcessorFallback(context); case "MetacognitionModule": return this.metacognitionFallback(context); case "PredictiveProcessor": return this.predictiveProcessorFallback(context); case "StochasticNeuralProcessor": return this.stochasticProcessorFallback(context); case "DualProcessController": return this.dualProcessFallback(context); default: this.logger.warn(component, `No fallback available for component: ${component}`); return null; } } /** * Fallback implementations for various components */ static sensoryProcessorFallback(context) { return { tokens: context?.input ? [ { text: String(context.input), position: 0, semantic_weight: 1.0, attention_score: 1.0, context_tags: ["fallback"], }, ] : [], patterns: [], salience_map: new Map(), }; } static emotionalProcessorFallback(_context) { return { valence: 0, arousal: 0.5, dominance: 0.5, specific_emotions: new Map(), }; } static metacognitionFallback(_context) { return { confidence: 0.5, coherence: 0.5, completeness: 0.5, biases_detected: [], suggestions: [ "Metacognitive monitoring unavailable - using default assessment", ], reasoning: "Fallback assessment due to component failure", }; } static predictiveProcessorFallback(_context) { return { predictions: [], confidence: 0.5, model_updates: [], }; } static stochasticProcessorFallback(context) { // Return input unchanged when stochastic processing fails return context?.input || null; } static dualProcessFallback(context) { return { system1_response: { content: String(context?.input || ""), confidence: 0.5, processing_time: 0, heuristics_used: ["fallback"], patterns_detected: [], }, system2_response: null, conflict_detected: false, resolution_strategy: "fallback_system1_only", processing_time_system1: 0, processing_time_system2: 0, }; } /** * Assess error severity based on error type and component */ static assessErrorSeverity(error, component) { const message = error.message.toLowerCase(); // Critical errors that should stop processing if (message.includes("out of memory") || message.includes("stack overflow") || message.includes("segmentation fault")) { return ErrorSeverity.CRITICAL; } // High severity for core component failures const coreComponents = [ "CognitiveOrchestrator", "MemorySystem", "DualProcessController", ]; if (coreComponents.includes(component)) { if (message.includes("initialization") || message.includes("configuration") || message.includes("connection")) { return ErrorSeverity.HIGH; } } // Medium severity for processing errors if (message.includes("processing") || message.includes("timeout") || message.includes("validation")) { return ErrorSeverity.MEDIUM; } // Default to low severity return ErrorSeverity.LOW; } /** * Log errors with appropriate detail level */ static logError(error, component, severity, context) { const logData = { component, severity, message: error.message, stack: error.stack, context, timestamp: new Date().toISOString(), }; switch (severity) { case ErrorSeverity.CRITICAL: this.logger.error(component, `CRITICAL ERROR: ${error.message}`, logData); break; case ErrorSeverity.HIGH: this.logger.error(component, `HIGH SEVERITY: ${error.message}`, logData); break; case ErrorSeverity.MEDIUM: this.logger.warn(component, `MEDIUM SEVERITY: ${error.message}`, logData); break; case ErrorSeverity.LOW: this.logger.info(component, `LOW SEVERITY: ${error.message}`, logData); break; } } /** * Record component error for tracking and analysis */ static recordComponentError(component, error, severity, context) { if (!this.componentErrors.has(component)) { this.componentErrors.set(component, []); } const errors = this.componentErrors.get(component); errors.push({ component, error, severity, timestamp: Date.now(), context: context || {}, }); // Keep only recent errors to prevent memory leaks if (errors.length > this.MAX_ERROR_HISTORY) { errors.splice(0, errors.length - this.MAX_ERROR_HISTORY); } } /** * Get recent errors for a component */ static getRecentErrors(component, timeWindowMs) { const errors = this.componentErrors.get(component) || []; const cutoff = Date.now() - timeWindowMs; return errors.filter((error) => error.timestamp > cutoff); } /** * Get error statistics for monitoring */ static getErrorStatistics() { const stats = {}; const recentCutoff = Date.now() - 300000; // Last 5 minutes for (const [component, errors] of this.componentErrors.entries()) { const recentErrors = errors.filter((e) => e.timestamp > recentCutoff); stats[component] = { total: errors.length, recent: recentErrors.length, by_severity: { [ErrorSeverity.LOW]: errors.filter((e) => e.severity === ErrorSeverity.LOW).length, [ErrorSeverity.MEDIUM]: errors.filter((e) => e.severity === ErrorSeverity.MEDIUM).length, [ErrorSeverity.HIGH]: errors.filter((e) => e.severity === ErrorSeverity.HIGH).length, [ErrorSeverity.CRITICAL]: errors.filter((e) => e.severity === ErrorSeverity.CRITICAL).length, }, }; } return stats; } /** * Clear error history for a component */ static clearErrorHistory(component) { if (component) { this.componentErrors.delete(component); } else { this.componentErrors.clear(); } } /** * Create a timeout promise */ static createTimeoutPromise(timeoutMs) { return new Promise((_, reject) => { setTimeout(() => reject(new Error(`Operation timed out after ${timeoutMs}ms`)), timeoutMs); }); } /** * Delay utility for retries */ static delay(ms) { return new Promise((resolve) => setTimeout(resolve, ms)); } } //# sourceMappingURL=ErrorHandler.js.map