UNPKG

@hivetechs/hive-ai

Version:

Real-time streaming AI consensus platform with HTTP+SSE MCP integration for Claude Code, VS Code, Cursor, and Windsurf - powered by OpenRouter's unified API

238 lines • 10.6 kB
/** * Health Status Tool * * Provides comprehensive system health monitoring for hive-ai. * Displays OpenRouter connectivity, database health, model availability, and error statistics. */ import { z } from "zod"; import { globalHealthMonitor } from '../health-monitor.js'; import { globalErrorHandler } from '../error-handling.js'; export const HealthStatusToolSchema = z.object({ detailed: z.boolean().default(false).describe('Show detailed health report with error statistics') }); export async function runHealthStatusTool(args) { try { // Force fresh health checks await globalHealthMonitor.runHealthChecks(); if (args.detailed) { return await getDetailedHealthReport(); } else { return await getBasicHealthReport(); } } catch (error) { return { result: `āŒ Error checking system health: ${error instanceof Error ? error.message : 'Unknown error'}` }; } } async function getBasicHealthReport() { const health = globalHealthMonitor.getSystemHealth(); let report = '\nšŸ„ System Health Status\n'; report += '='.repeat(50) + '\n\n'; // Overall status const overallEmoji = health.overall === 'healthy' ? 'āœ…' : health.overall === 'degraded' ? 'āš ļø' : 'āŒ'; report += `${overallEmoji} Overall Status: ${health.overall.toUpperCase()}\n\n`; // Service details report += 'šŸ“Š Services:\n'; report += ` šŸ”— OpenRouter API: ${getStatusEmoji(health.openrouter.status)} ${health.openrouter.status}`; if (health.openrouter.responseTime > 0) { report += ` (${health.openrouter.responseTime}ms)`; } if (health.openrouter.lastError) { report += `\n Error: ${health.openrouter.lastError}`; } report += '\n'; report += ` šŸ’¾ Database: ${getStatusEmoji(health.database.status)} ${health.database.status}`; if (health.database.responseTime > 0) { report += ` (${health.database.responseTime}ms)`; } if (health.database.lastError) { report += `\n Error: ${health.database.lastError}`; } report += '\n\n'; // Model health summary if (health.models.length > 0) { const availableModels = health.models.filter(m => m.status === 'available').length; const degradedModels = health.models.filter(m => m.status === 'degraded').length; const unavailableModels = health.models.filter(m => m.status === 'unavailable').length; report += 'šŸ¤– Model Health Summary:\n'; if (availableModels > 0) report += ` āœ… Available: ${availableModels} models\n`; if (degradedModels > 0) report += ` āš ļø Degraded: ${degradedModels} models\n`; if (unavailableModels > 0) report += ` āŒ Unavailable: ${unavailableModels} models\n`; report += '\n'; } report += `ā° Last updated: ${health.timestamp.toLocaleString()}\n`; // Show recent errors if any const errorStats = globalErrorHandler.getErrorStats(3600000); // Last hour if (errorStats.totalErrors > 0) { report += `\nāš ļø Recent Issues:\n`; report += ` • ${errorStats.totalErrors} errors in the last hour\n`; const topErrors = Object.entries(errorStats.errorsByType) .sort(([, a], [, b]) => b - a) .slice(0, 3); if (topErrors.length > 0) { report += ` • Top error types: ${topErrors.map(([type, count]) => `${type} (${count})`).join(', ')}\n`; } } report += '\nšŸ’” Use --detailed for comprehensive health report\n'; return { result: report }; } async function getDetailedHealthReport() { const health = globalHealthMonitor.getSystemHealth(); const errorStats = globalErrorHandler.getErrorStats(3600000); // Last hour const circuitBreakers = globalErrorHandler.getCircuitBreakerStatus(); let report = '\nšŸ„ Detailed System Health Report\n'; report += '='.repeat(60) + '\n\n'; // Overall status const overallEmoji = health.overall === 'healthy' ? 'āœ…' : health.overall === 'degraded' ? 'āš ļø' : 'āŒ'; report += `${overallEmoji} Overall Status: ${health.overall.toUpperCase()}\n`; report += `ā° Report generated: ${new Date().toLocaleString()}\n`; report += `šŸ”„ System uptime: ${formatUptime(process.uptime())}\n\n`; // Detailed service status report += 'šŸ“Š Service Details:\n'; report += '-'.repeat(40) + '\n'; // OpenRouter API report += `šŸ”— OpenRouter API:\n`; report += ` Status: ${getStatusEmoji(health.openrouter.status)} ${health.openrouter.status}\n`; report += ` Response Time: ${health.openrouter.responseTime}ms\n`; report += ` Last Checked: ${health.openrouter.lastChecked.toLocaleString()}\n`; report += ` Consecutive Failures: ${health.openrouter.consecutiveFailures}\n`; if (health.openrouter.lastError) { report += ` Last Error: ${health.openrouter.lastError}\n`; } if (health.openrouter.metadata) { report += ` Models Available: ${health.openrouter.metadata.modelsCount || 'Unknown'}\n`; } report += '\n'; // Database report += `šŸ’¾ Database:\n`; report += ` Status: ${getStatusEmoji(health.database.status)} ${health.database.status}\n`; report += ` Response Time: ${health.database.responseTime}ms\n`; report += ` Last Checked: ${health.database.lastChecked.toLocaleString()}\n`; report += ` Consecutive Failures: ${health.database.consecutiveFailures}\n`; if (health.database.lastError) { report += ` Last Error: ${health.database.lastError}\n`; } if (health.database.metadata) { report += ` Profile Count: ${health.database.metadata.profileCount || 'Unknown'}\n`; } report += '\n'; // Individual model health if (health.models.length > 0) { report += 'šŸ¤– Model Health Details:\n'; report += '-'.repeat(40) + '\n'; health.models.forEach(model => { const emoji = model.status === 'available' ? 'āœ…' : model.status === 'degraded' ? 'āš ļø' : 'āŒ'; report += `${emoji} ${model.provider}/${model.model}:\n`; report += ` Status: ${model.status}\n`; report += ` Success Rate: ${model.successRate}%\n`; report += ` Avg Response Time: ${model.avgResponseTime}ms\n`; report += ` Error Count: ${model.errorCount}\n`; report += ` Last Tested: ${model.lastTested.toLocaleString()}\n\n`; }); } // Error statistics if (errorStats.totalErrors > 0) { report += 'šŸ“ˆ Error Statistics (Last Hour):\n'; report += '-'.repeat(40) + '\n'; report += `Total Errors: ${errorStats.totalErrors}\n\n`; if (Object.keys(errorStats.errorsByType).length > 0) { report += 'By Type:\n'; Object.entries(errorStats.errorsByType) .sort(([, a], [, b]) => b - a) .forEach(([type, count]) => { report += ` • ${type}: ${count}\n`; }); report += '\n'; } if (Object.keys(errorStats.errorsByProvider).length > 0) { report += 'By Provider:\n'; Object.entries(errorStats.errorsByProvider) .sort(([, a], [, b]) => b - a) .forEach(([provider, count]) => { report += ` • ${provider}: ${count}\n`; }); report += '\n'; } if (errorStats.recentErrors.length > 0) { report += 'Recent Errors:\n'; errorStats.recentErrors.slice(-5).forEach((error, index) => { report += ` ${index + 1}. [${error.type}] ${error.stage} - ${error.message}\n`; report += ` Provider: ${error.provider}/${error.model}\n`; report += ` Time: ${error.timestamp.toLocaleString()}\n\n`; }); } } // Circuit breaker status if (Object.keys(circuitBreakers).length > 0) { report += 'šŸ”Œ Circuit Breaker Status:\n'; report += '-'.repeat(40) + '\n'; Object.entries(circuitBreakers).forEach(([key, status]) => { const [provider, model] = key.split(':'); const emoji = status.state === 'CLOSED' ? 'āœ…' : status.state === 'HALF_OPEN' ? 'āš ļø' : 'āŒ'; report += `${emoji} ${provider}/${model}:\n`; report += ` State: ${status.state}\n`; report += ` Failures: ${status.failures}\n`; if (status.nextAttemptTime) { report += ` Next Attempt: ${status.nextAttemptTime.toLocaleString()}\n`; } report += '\n'; }); } // Recommendations report += 'šŸ’” Recommendations:\n'; report += '-'.repeat(40) + '\n'; if (health.overall === 'unhealthy') { report += '• System is experiencing significant issues\n'; report += '• Check OpenRouter API key and connectivity\n'; report += '• Verify database is accessible\n'; } else if (health.overall === 'degraded') { report += '• Some services are experiencing issues\n'; report += '• Monitor error rates and response times\n'; } else { report += '• All systems operational\n'; report += '• Continue monitoring for optimal performance\n'; } if (errorStats.totalErrors > 10) { report += '• High error rate detected - investigate recent failures\n'; } report += '• Run health checks regularly with: hive-ai health\n'; report += '• Use circuit breaker resets if needed: hive-ai reset-circuit <provider>/<model>\n'; return { result: report }; } function getStatusEmoji(status) { switch (status) { case 'healthy': return 'āœ…'; case 'degraded': return 'āš ļø'; case 'unhealthy': return 'āŒ'; default: return 'ā“'; } } function formatUptime(seconds) { const days = Math.floor(seconds / 86400); const hours = Math.floor((seconds % 86400) / 3600); const minutes = Math.floor((seconds % 3600) / 60); if (days > 0) { return `${days}d ${hours}h ${minutes}m`; } else if (hours > 0) { return `${hours}h ${minutes}m`; } else { return `${minutes}m`; } } export const healthStatusToolName = 'health_status'; export const healthStatusToolDescription = 'Check system health including OpenRouter connectivity, database status, and error statistics'; //# sourceMappingURL=health-status.js.map