Skip to main content
Glama

Prompt Auto-Optimizer MCP

by sloth-wq
performance-tracker.ts31.8 kB
/** * Performance Tracker Service * Comprehensive metric collection, analysis, and reporting for GEPA system */ import { EventEmitter } from 'events'; // Core Types and Interfaces export interface PerformanceMetricData { [key: string]: unknown; } // Utility type for ensuring objects can be converted to PerformanceMetricData export type ToPerformanceMetricData<T> = T & PerformanceMetricData; export interface PerformanceMetric { id: string; name: string; category: string; timestamp: number; duration?: number; data: PerformanceMetricData; tags?: Record<string, string>; } export interface MetricCollectionConfig { category: string; tags?: Record<string, string>; } export interface StatisticalAnalysis { mean: number; median: number; min: number; max: number; standardDeviation: number; variance: number; sampleSize: number; percentiles: { p25: number; p50: number; p75: number; p90: number; p95: number; p99: number; }; } export interface TrendAnalysis { trend: 'improving' | 'degrading' | 'stable'; slope: number; confidence: number; dataPoints: number; timeWindow: number; } export interface PerformanceReportMetadata { [key: string]: unknown; } export interface ReportData { summary: { totalMetrics: number; timeRange: { start: number; end: number }; categories: string[]; }; metrics: PerformanceMetric[]; statistics?: Record<string, StatisticalAnalysis>; trends?: Record<string, TrendAnalysis>; insights?: string[]; } export type FormattedReportData = ReportData | string; export interface PerformanceReport { format: 'json' | 'human-readable' | 'csv'; data: FormattedReportData; generatedAt: number; timeRange?: { start: number; end: number }; metadata?: PerformanceReportMetadata; } export interface MemoryMetrics { rss: number; heapTotal: number; heapUsed: number; external: number; arrayBuffers: number; } export interface ExecutionMetrics { startTime: number; endTime?: number; duration?: number; category: string; tags?: Record<string, string>; } export interface TokenUsageMetrics { inputTokens: number; outputTokens: number; totalTokens: number; cost: number; model: string; } // Operation and Evolution Types export interface OperationData { [key: string]: string | number | boolean | null | undefined; } export interface OperationResult { success: boolean; data: OperationData; } export interface EvolutionCycleData { id: string; config: EvolutionCycleConfig; startTime: number; endTime?: number; generations: EvolutionGenerationMetrics[]; status: 'running' | 'completed' | 'failed'; result?: EvolutionCycleResult; } export interface EvolutionMetrics { evolutionId: string; totalGenerations: number; finalFitness: number; convergenceAchieved: boolean; fitnessImprovement: number; duration: number; } export interface MutationEffectivenessAnalysis { byType: Record<string, { successRate: number; averageFitnessChange: number; totalOperations: number; }>; overall: { successRate: number; averageFitnessChange: number; }; } export interface EvolutionInsights { evolutionId: string; convergenceRate: number; diversityTrend: 'increasing' | 'decreasing' | 'stable'; recommendedAdjustments: string[]; } export interface InsightThresholds { slowOperationThreshold?: number; highMemoryThreshold?: number; anomalyDetectionEnabled?: boolean; } // Evolution Engine Integration Types export interface EvolutionCycleConfig { initialPopulationSize: number; targetFitness: number; maxGenerations: number; } export interface EvolutionGenerationMetrics { generation: number; bestFitness: number; averageFitness: number; diversityScore: number; mutationRate: number; selectionPressure: number; } export interface EvolutionCycleResult { finalFitness: number; totalGenerations: number; convergenceAchieved: boolean; terminationReason: string; } export interface MutationResult { success: boolean; fitnessChange: number; executionTime: number; resourceUsage: { memoryPeak: number; cpuTime: number; }; } // Configuration Types export interface PerformanceTrackerConfig { enableRealTimeMonitoring?: boolean; maxMetricsHistorySize?: number; aggregationWindowSize?: number; statisticalAnalysisEnabled?: boolean; memoryTrackingEnabled?: boolean; tokenUsageTrackingEnabled?: boolean; timeProvider?: () => number; memoryProvider?: () => NodeJS.MemoryUsage; } export interface ReportConfig { timeRange?: { start: number; end: number }; categories?: string[]; includeStatistics?: boolean; includeTrends?: boolean; includeInsights?: boolean; insightThresholds?: { slowOperationThreshold?: number; highMemoryThreshold?: number; anomalyDetectionEnabled?: boolean; }; } export interface AggregationConfig { windowSize: number; aggregationFunction: 'average' | 'sum' | 'max' | 'min'; categories: string[]; } // Analysis Types export interface SuccessRateAnalysis { successRate: number; totalOperations: number; successfulOperations: number; failedOperations: number; } export interface AnomalyDetection { metric: PerformanceMetric; score: number; threshold: number; method: string; } export interface MovingAveragePoint { timestamp: number; value: number; windowSize: number; } export interface MemoryAnalysis { peakHeapUsed: number; averageHeapUsed: number; memoryGrowthRate: number; potentialLeaks: boolean; } export interface LeakDetection { leakDetected: boolean; leakRate: number; confidence: number; recommendedActions: string[]; } export interface GarbageCollectionEvent { type: 'minor' | 'major'; duration: number; heapBefore: number; heapAfter: number; } export interface GarbageCollectionAnalysis { totalEvents: number; averageDuration: number; totalMemoryReclaimed: number; gcEfficiency: number; } // Active Metric Tracking interface ActiveMetric { id: string; name: string; category: string; startTime: number; tags?: Record<string, string>; } /** * Main Performance Tracker Class */ export class PerformanceTracker extends EventEmitter { private config: Required<PerformanceTrackerConfig>; private metrics: PerformanceMetric[] = []; private activeMetrics: Map<string, ActiveMetric> = new Map(); private operationResults: Map<string, Array<OperationResult>> = new Map(); private evolutionCycles: Map<string, EvolutionCycleData> = new Map(); private mutationResults: Map<string, MutationResult[]> = new Map(); private memorySnapshots: MemoryMetrics[] = []; private gcEvents: GarbageCollectionEvent[] = []; private aggregationConfig?: AggregationConfig; private aggregatedMetrics: Map<string, PerformanceMetric[]> = new Map(); constructor(config: PerformanceTrackerConfig = {}) { super(); this.config = { enableRealTimeMonitoring: config.enableRealTimeMonitoring ?? true, maxMetricsHistorySize: config.maxMetricsHistorySize ?? 10000, aggregationWindowSize: config.aggregationWindowSize ?? 1000, statisticalAnalysisEnabled: config.statisticalAnalysisEnabled ?? true, memoryTrackingEnabled: config.memoryTrackingEnabled ?? true, tokenUsageTrackingEnabled: config.tokenUsageTrackingEnabled ?? true, timeProvider: config.timeProvider ?? (() => Date.now()), memoryProvider: config.memoryProvider ?? (() => process.memoryUsage()) }; } // Metric Collection Methods startMetricCollection(name: string, config: MetricCollectionConfig): string { const id = `metric_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`; const startTime = this.config.timeProvider(); const activeMetric: ActiveMetric = { id, name, category: config.category, startTime, tags: config.tags || {} }; this.activeMetrics.set(id, activeMetric); return id; } endMetricCollection(metricId: string): PerformanceMetric { const activeMetric = this.activeMetrics.get(metricId); if (!activeMetric) { throw new Error('Metric not found'); } const endTime = this.config.timeProvider(); const duration = endTime - activeMetric.startTime; const metric: PerformanceMetric = { id: activeMetric.id, name: activeMetric.name, category: activeMetric.category, timestamp: activeMetric.startTime, duration, data: {}, tags: activeMetric.tags || {} }; this.recordMetric(metric); this.activeMetrics.delete(metricId); return metric; } recordMetric(metric: PerformanceMetric): void { // Validate metric data if (!metric.id || !metric.name || !metric.category) { throw new Error('Invalid metric data'); } if (metric.duration !== undefined && metric.duration < 0) { throw new Error('Invalid metric data'); } // Ensure tags is properly defined const metricWithTags = { ...metric, tags: metric.tags || {} }; this.metrics.push(metricWithTags); // Maintain history size limit if (this.metrics.length > this.config.maxMetricsHistorySize) { this.metrics = this.metrics.slice(-this.config.maxMetricsHistorySize); } // Emit for real-time monitoring if (this.config.enableRealTimeMonitoring) { this.emit('metric', metric); } } recordTokenUsage(operationId: string, tokenMetrics: TokenUsageMetrics): void { if (!this.config.tokenUsageTrackingEnabled) return; const metric: PerformanceMetric = { id: `token_${operationId}`, name: 'token-usage', category: 'token-usage', timestamp: this.config.timeProvider(), data: tokenMetrics as unknown as PerformanceMetricData }; this.recordMetric(metric); } recordMemorySnapshot(label: string): void { if (!this.config.memoryTrackingEnabled) return; const memoryUsage = this.config.memoryProvider(); const memoryMetrics: MemoryMetrics = { rss: memoryUsage.rss, heapTotal: memoryUsage.heapTotal, heapUsed: memoryUsage.heapUsed, external: memoryUsage.external, arrayBuffers: memoryUsage.arrayBuffers }; this.memorySnapshots.push(memoryMetrics); const metric: PerformanceMetric = { id: `memory_${label}_${Date.now()}`, name: 'memory-snapshot', category: 'memory', timestamp: this.config.timeProvider(), data: memoryMetrics as unknown as PerformanceMetricData }; this.recordMetric(metric); } recordOperationResult(operationName: string, success: boolean, data: OperationData): void { if (!this.operationResults.has(operationName)) { this.operationResults.set(operationName, []); } const results = this.operationResults.get(operationName); if (results) { results.push({ success, data }); } } recordGarbageCollection(event: GarbageCollectionEvent): void { this.gcEvents.push(event); } // Statistical Analysis Methods calculateStatistics(category: string): StatisticalAnalysis { const categoryMetrics = this.getMetricsByCategory(category); if (categoryMetrics.length === 0) { return { mean: 0, median: 0, min: 0, max: 0, standardDeviation: 0, variance: 0, sampleSize: 0, percentiles: { p25: 0, p50: 0, p75: 0, p90: 0, p95: 0, p99: 0 } }; } const durations = categoryMetrics .filter(m => m.duration !== undefined) .map(m => m.duration!); if (durations.length === 0) { return { mean: 0, median: 0, min: 0, max: 0, standardDeviation: 0, variance: 0, sampleSize: 0, percentiles: { p25: 0, p50: 0, p75: 0, p90: 0, p95: 0, p99: 0 } }; } const sorted = durations.sort((a, b) => a - b); const mean = durations.reduce((sum, d) => sum + d, 0) / durations.length; const variance = durations.reduce((sum, d) => sum + Math.pow(d - mean, 2), 0) / durations.length; const standardDeviation = Math.sqrt(variance); return { mean, median: this.calculatePercentile(sorted, 50), min: Math.min(...durations), max: Math.max(...durations), standardDeviation, variance, sampleSize: durations.length, percentiles: { p25: this.calculatePercentile(sorted, 25), p50: this.calculatePercentile(sorted, 50), p75: this.calculatePercentile(sorted, 75), p90: this.calculatePercentile(sorted, 90), p95: this.calculatePercentile(sorted, 95), p99: this.calculatePercentile(sorted, 99) } }; } private calculatePercentile(sortedValues: number[], percentile: number): number { if (sortedValues.length === 0) return 0; if (sortedValues.length === 1) return sortedValues[0] || 0; const index = (percentile / 100) * (sortedValues.length - 1); const lower = Math.floor(index); const upper = Math.ceil(index); if (lower === upper) { return sortedValues[lower] || 0; } const lowerValue = sortedValues[lower] || 0; const upperValue = sortedValues[upper] || 0; return lowerValue + (upperValue - lowerValue) * (index - lower); } calculateSuccessRate(operationName: string): SuccessRateAnalysis { const results = this.operationResults.get(operationName) || []; const successful = results.filter(r => r.success).length; return { successRate: results.length > 0 ? successful / results.length : 0, totalOperations: results.length, successfulOperations: successful, failedOperations: results.length - successful }; } analyzeTrends(category: string, options: { timeWindow: number; minimumDataPoints: number }): TrendAnalysis { const now = this.config.timeProvider(); const windowStart = now - options.timeWindow; const recentMetrics = this.getMetricsByCategory(category) .filter(m => m.timestamp >= windowStart && m.duration !== undefined) .sort((a, b) => a.timestamp - b.timestamp); if (recentMetrics.length < options.minimumDataPoints) { return { trend: 'stable', slope: 0, confidence: 0, dataPoints: recentMetrics.length, timeWindow: options.timeWindow }; } // Simple linear regression to determine trend const n = recentMetrics.length; const sumX = recentMetrics.reduce((sum, _, i) => sum + i, 0); const sumY = recentMetrics.reduce((sum, m) => sum + (m.duration || 0), 0); const sumXY = recentMetrics.reduce((sum, m, i) => sum + (i * (m.duration || 0)), 0); const sumXX = recentMetrics.reduce((sum, _, i) => sum + (i * i), 0); const slope = (n * sumXY - sumX * sumY) / (n * sumXX - sumX * sumX); // Calculate correlation coefficient for confidence const meanX = sumX / n; const meanY = sumY / n; const numerator = recentMetrics.reduce((sum, m, i) => sum + (i - meanX) * ((m.duration || 0) - meanY), 0); const denomX = Math.sqrt(recentMetrics.reduce((sum, _, i) => sum + Math.pow(i - meanX, 2), 0)); const denomY = Math.sqrt(recentMetrics.reduce((sum, m) => sum + Math.pow((m.duration || 0) - meanY, 2), 0)); const correlation = numerator / (denomX * denomY); let trend: 'improving' | 'degrading' | 'stable'; if (Math.abs(slope) < 0.01) { trend = 'stable'; } else if (slope < 0) { trend = 'improving'; } else { trend = 'degrading'; } return { trend, slope, confidence: Math.abs(correlation), dataPoints: n, timeWindow: options.timeWindow }; } detectAnomalies(category: string, options: { threshold: number; method: string }): AnomalyDetection[] { const stats = this.calculateStatistics(category); const metrics = this.getMetricsByCategory(category).filter(m => m.duration !== undefined); const anomalies: AnomalyDetection[] = []; for (const metric of metrics) { const zscore = Math.abs((metric.duration! - stats.mean) / stats.standardDeviation); if (zscore > options.threshold) { anomalies.push({ metric, score: zscore, threshold: options.threshold, method: options.method }); } } return anomalies; } calculateMovingAverage(category: string, options: { windowSize: number; metric: string }): MovingAveragePoint[] { const metrics = this.getMetricsByCategory(category) .filter(m => m.duration !== undefined) .sort((a, b) => a.timestamp - b.timestamp); const movingAverages: MovingAveragePoint[] = []; for (let i = options.windowSize - 1; i < metrics.length; i++) { const window = metrics.slice(i - options.windowSize + 1, i + 1); const average = window.reduce((sum, m) => sum + m.duration!, 0) / window.length; movingAverages.push({ timestamp: metrics[i]?.timestamp || 0, value: average, windowSize: options.windowSize }); } return movingAverages; } // Memory Analysis Methods analyzeMemoryUsage(): MemoryAnalysis { if (this.memorySnapshots.length === 0) { return { peakHeapUsed: 0, averageHeapUsed: 0, memoryGrowthRate: 0, potentialLeaks: false }; } const heapUsages = this.memorySnapshots.map(s => s.heapUsed); const peakHeapUsed = Math.max(...heapUsages); const averageHeapUsed = heapUsages.reduce((sum, h) => sum + h, 0) / heapUsages.length; // Calculate growth rate let memoryGrowthRate = 0; if (this.memorySnapshots.length > 1) { const first = this.memorySnapshots[0]; const last = this.memorySnapshots[this.memorySnapshots.length - 1]; if (first && last) { memoryGrowthRate = (last.heapUsed - first.heapUsed) / this.memorySnapshots.length; } } return { peakHeapUsed, averageHeapUsed, memoryGrowthRate, potentialLeaks: memoryGrowthRate > 1024 * 1024 // 1MB growth suggests potential leak }; } detectMemoryLeaks(): LeakDetection { if (this.memorySnapshots.length < 5) { return { leakDetected: false, leakRate: 0, confidence: 0, recommendedActions: [] }; } // Analyze heap usage trend const heapUsages = this.memorySnapshots.map(s => s.heapUsed); const n = heapUsages.length; // Linear regression on heap usage const sumX = heapUsages.reduce((sum, _, i) => sum + i, 0); const sumY = heapUsages.reduce((sum, h) => sum + h, 0); const sumXY = heapUsages.reduce((sum, h, i) => sum + (i * h), 0); const sumXX = heapUsages.reduce((sum, _, i) => sum + (i * i), 0); const slope = (n * sumXY - sumX * sumY) / (n * sumXX - sumX * sumX); // Calculate correlation for confidence const meanX = sumX / n; const meanY = sumY / n; const numerator = heapUsages.reduce((sum, h, i) => sum + (i - meanX) * (h - meanY), 0); const denomX = Math.sqrt(heapUsages.reduce((sum, _, i) => sum + Math.pow(i - meanX, 2), 0)); const denomY = Math.sqrt(heapUsages.reduce((sum, h) => sum + Math.pow(h - meanY, 2), 0)); const correlation = numerator / (denomX * denomY); const leakDetected = slope > 1024 * 1024 && correlation > 0.8; // 1MB growth with high correlation return { leakDetected, leakRate: slope, confidence: Math.abs(correlation), recommendedActions: leakDetected ? [ 'Review recent code changes for memory allocation patterns', 'Check for unclosed resources or event listeners', 'Monitor object retention and garbage collection', 'Consider memory profiling tools' ] : [] }; } analyzeGarbageCollection(): GarbageCollectionAnalysis { if (this.gcEvents.length === 0) { return { totalEvents: 0, averageDuration: 0, totalMemoryReclaimed: 0, gcEfficiency: 0 }; } const totalDuration = this.gcEvents.reduce((sum, e) => sum + e.duration, 0); const totalMemoryReclaimed = this.gcEvents.reduce((sum, e) => sum + Math.max(0, e.heapBefore - e.heapAfter), 0); return { totalEvents: this.gcEvents.length, averageDuration: totalDuration / this.gcEvents.length, totalMemoryReclaimed, gcEfficiency: totalDuration > 0 ? totalMemoryReclaimed / totalDuration : 0 }; } // Report Generation Methods generateReport(format: 'json' | 'human-readable' | 'csv', config: ReportConfig = {}): PerformanceReport { const now = this.config.timeProvider(); const timeRange = config.timeRange || { start: 0, end: now }; const filteredMetrics = this.metrics.filter(m => m.timestamp >= timeRange.start && m.timestamp <= timeRange.end && (!config.categories || config.categories.includes(m.category)) ); const reportData: ReportData = { summary: { totalMetrics: filteredMetrics.length, timeRange: timeRange, categories: Array.from(new Set(filteredMetrics.map(m => m.category))) }, metrics: filteredMetrics }; if (config.includeStatistics) { reportData.statistics = {}; for (const category of reportData.summary.categories) { reportData.statistics[category] = this.calculateStatistics(category); } } if (config.includeTrends) { reportData.trends = {}; for (const category of reportData.summary.categories) { reportData.trends[category] = this.analyzeTrends(category, { timeWindow: 60000, minimumDataPoints: 5 }); } } if (config.includeInsights) { reportData.insights = this.generateInsights(config.insightThresholds || {}); } let formattedData: FormattedReportData; switch (format) { case 'json': formattedData = reportData; break; case 'human-readable': formattedData = this.formatHumanReadableReport(reportData); break; case 'csv': formattedData = this.formatCSVReport(filteredMetrics); break; default: throw new Error(`Unsupported format: ${format}`); } return { format, data: formattedData, generatedAt: now, timeRange, metadata: config as unknown as PerformanceReportMetadata }; } private formatHumanReadableReport(data: ReportData): string { let report = '# Performance Report\n\n'; report += `## Summary\n`; report += `- Total Metrics: ${data.summary.totalMetrics}\n`; report += `- Categories: ${data.summary.categories.join(', ')}\n`; if (data.summary.timeRange) { report += `- Time Range: ${new Date(data.summary.timeRange.start).toISOString()} to ${new Date(data.summary.timeRange.end).toISOString()}\n\n`; } if (data.statistics) { report += `## Statistics\n`; for (const [category, stats] of Object.entries(data.statistics)) { const s = stats as StatisticalAnalysis; report += `### ${category} metrics\n`; report += `- Mean: ${s.mean.toFixed(2)}ms\n`; report += `- Median: ${s.median.toFixed(2)}ms\n`; report += `- P95: ${s.percentiles.p95.toFixed(2)}ms\n`; report += `- Sample Size: ${s.sampleSize}\n\n`; } } return report; } private formatCSVReport(metrics: PerformanceMetric[]): string { const headers = ['timestamp', 'name', 'category', 'duration', 'tags']; const rows = metrics.map(m => [ m.timestamp, m.name, m.category, m.duration || '', JSON.stringify(m.tags || {}) ]); return [headers.join(','), ...rows.map(row => row.join(','))].join('\n'); } private generateInsights(_thresholds: InsightThresholds): string[] { const insights: string[] = []; // Add basic insights based on available data if (this.metrics.length > 0) { insights.push('Performance tracking is active and collecting metrics'); } return insights; } // Real-time Monitoring Methods subscribeToMetrics(callback: (metric: PerformanceMetric) => void): () => void { this.on('metric', callback); return () => this.removeListener('metric', callback); } configureAggregation(config: AggregationConfig): void { this.aggregationConfig = config; // Start aggregation process for configured categories setTimeout(() => { this.performAggregation(); }, config.windowSize); } private performAggregation(): void { if (!this.aggregationConfig) return; const now = this.config.timeProvider(); const windowStart = now - this.aggregationConfig.windowSize; for (const category of this.aggregationConfig.categories) { const recentMetrics = this.getMetricsByCategory(category) .filter(m => m.timestamp >= windowStart); if (recentMetrics.length > 0) { const aggregatedMetric = this.createAggregatedMetric(recentMetrics, this.aggregationConfig.aggregationFunction); if (!this.aggregatedMetrics.has(category)) { this.aggregatedMetrics.set(category, []); } const metrics = this.aggregatedMetrics.get(category); if (metrics) { metrics.push(aggregatedMetric); } } } } private createAggregatedMetric(metrics: PerformanceMetric[], aggregationFunction: string): PerformanceMetric { const durations = metrics.filter(m => m.duration !== undefined).map(m => m.duration!); let aggregatedValue = 0; switch (aggregationFunction) { case 'average': aggregatedValue = durations.reduce((sum, d) => sum + d, 0) / durations.length; break; case 'sum': aggregatedValue = durations.reduce((sum, d) => sum + d, 0); break; case 'max': aggregatedValue = Math.max(...durations); break; case 'min': aggregatedValue = Math.min(...durations); break; default: aggregatedValue = durations.reduce((sum, d) => sum + d, 0) / durations.length; } return { id: `aggregated_${Date.now()}`, name: `${aggregationFunction}_${metrics[0]?.category || 'unknown'}`, category: metrics[0]?.category || 'unknown', timestamp: this.config.timeProvider(), duration: aggregatedValue, data: { aggregationFunction, sourceMetricsCount: metrics.length, windowSize: this.aggregationConfig?.windowSize } }; } getAggregatedMetrics(category: string): PerformanceMetric[] { return this.aggregatedMetrics.get(category) || []; } // Evolution Engine Integration Methods startEvolutionCycle(evolutionId: string, config: EvolutionCycleConfig): void { this.evolutionCycles.set(evolutionId, { id: evolutionId, config, startTime: this.config.timeProvider(), generations: [], status: 'running' }); } recordEvolutionGeneration(evolutionId: string, metrics: EvolutionGenerationMetrics): void { const cycle = this.evolutionCycles.get(evolutionId); if (cycle) { cycle.generations.push(metrics); } } endEvolutionCycle(evolutionId: string, result: EvolutionCycleResult): void { const cycle = this.evolutionCycles.get(evolutionId); if (cycle) { cycle.endTime = this.config.timeProvider(); cycle.result = result; cycle.status = 'completed'; } } getEvolutionMetrics(evolutionId: string): EvolutionMetrics | null { const cycle = this.evolutionCycles.get(evolutionId); if (!cycle || !cycle.result) return null; const generations = cycle.generations as EvolutionGenerationMetrics[]; const firstGen = generations[0]; return { evolutionId, totalGenerations: cycle.result.totalGenerations, finalFitness: cycle.result.finalFitness, convergenceAchieved: cycle.result.convergenceAchieved, fitnessImprovement: firstGen ? cycle.result.finalFitness - firstGen.bestFitness : 0, duration: (cycle.endTime || 0) - cycle.startTime }; } recordMutationResult(mutationType: string, result: MutationResult): void { if (!this.mutationResults.has(mutationType)) { this.mutationResults.set(mutationType, []); } const results = this.mutationResults.get(mutationType); if (results) { results.push(result); } } analyzeMutationEffectiveness(): MutationEffectivenessAnalysis { const analysis: MutationEffectivenessAnalysis = { byType: {}, overall: { successRate: 0, averageFitnessChange: 0 } }; let totalOperations = 0; let totalSuccessful = 0; let totalFitnessChange = 0; for (const [type, results] of Array.from(this.mutationResults.entries())) { const successful = results.filter(r => r.success).length; const avgFitnessChange = results.reduce((sum, r) => sum + r.fitnessChange, 0) / results.length; analysis.byType[type] = { successRate: successful / results.length, averageFitnessChange: avgFitnessChange, totalOperations: results.length }; totalOperations += results.length; totalSuccessful += successful; totalFitnessChange += results.reduce((sum, r) => sum + r.fitnessChange, 0); } if (totalOperations > 0) { analysis.overall.successRate = totalSuccessful / totalOperations; analysis.overall.averageFitnessChange = totalFitnessChange / totalOperations; } return analysis; } getEvolutionInsights(evolutionId: string): EvolutionInsights | null { const cycle = this.evolutionCycles.get(evolutionId); if (!cycle) return null; const generations = cycle.generations as EvolutionGenerationMetrics[]; if (generations.length < 2) return null; // Analyze diversity trend const diversityScores = generations.map(g => g.diversityScore); const lastScore = diversityScores[diversityScores.length - 1] || 0; const firstScore = diversityScores[0] || 0; const diversitySlope = (lastScore - firstScore) / diversityScores.length; let diversityTrend: 'increasing' | 'decreasing' | 'stable'; if (Math.abs(diversitySlope) < 0.01) { diversityTrend = 'stable'; } else if (diversitySlope < 0) { diversityTrend = 'decreasing'; } else { diversityTrend = 'increasing'; } // Calculate convergence rate const fitnessValues = generations.map(g => g.bestFitness); const lastFitness = fitnessValues[fitnessValues.length - 1] || 0; const firstFitness = fitnessValues[0] || 0; const convergenceRate = (lastFitness - firstFitness) / generations.length; const recommendedAdjustments: string[] = []; if (diversityTrend === 'decreasing') { recommendedAdjustments.push('Consider increasing mutation rate to maintain diversity'); } if (convergenceRate < 0.01) { recommendedAdjustments.push('Slow convergence detected - consider adjusting selection pressure'); } return { evolutionId, convergenceRate, diversityTrend, recommendedAdjustments }; } // Utility Methods getMetricsByCategory(category: string): PerformanceMetric[] { return this.metrics.filter(m => m.category === category); } getAllMetrics(): PerformanceMetric[] { return [...this.metrics]; } clearMetrics(): void { this.metrics = []; this.operationResults.clear(); this.memorySnapshots = []; this.gcEvents = []; } }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/sloth-wq/prompt-auto-optimizer-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server