Skip to main content
Glama

Prompt Auto-Optimizer MCP

by sloth-wq
reflection-engine.ts15.1 kB
/** * ReflectionEngine for analyzing execution trajectories and generating improvement suggestions * Uses LLMAdapter for Claude-based analysis to identify failure patterns and suggest prompt improvements */ import { type ExecutionTrajectory, type ReflectionAnalysis, type FailurePattern, type PromptImprovement, type TrajectoryFilter, isExecutionTrajectory, } from '../types/gepa'; import type { LLMAdapter } from '../services/llm-adapter'; import { PatternMatcher, BatchAnalysisProcessor, AnalysisMemoryManager } from './reflection-optimizations'; /** * Configuration options for ReflectionEngine */ export interface ReflectionEngineConfig { maxAnalysisDepth?: number; confidenceThreshold?: number; patternMinFrequency?: number; batchSize?: number; enableCaching?: boolean; cacheTimeout?: number; } /** * Batch analysis result for multiple trajectories */ export interface BatchAnalysisResult { trajectoryIds: string[]; commonPatterns: FailurePattern[]; recommendations: Array<PromptImprovement & { priority: 'low' | 'medium' | 'high' | 'critical'; affectedTrajectories: string[]; }>; overallConfidence: number; } /** * TrajectoryStore interface expected by ReflectionEngine */ export interface TrajectoryStore { query(filter: TrajectoryFilter): Promise<ExecutionTrajectory[]>; load(id: string): Promise<ExecutionTrajectory | null>; save(trajectory: ExecutionTrajectory): Promise<void>; } /** * Dependencies required by ReflectionEngine */ export interface ReflectionEngineDependencies { llmAdapter: LLMAdapter; trajectoryStore: TrajectoryStore; config?: ReflectionEngineConfig; } /** * Cache entry for analysis results */ interface CacheEntry { analysis: ReflectionAnalysis; timestamp: number; } /** * ReflectionEngine analyzes execution trajectories to identify failure patterns * and generate specific improvement suggestions for prompts */ export class ReflectionEngine { public readonly config: Required<ReflectionEngineConfig>; private readonly llmAdapter: LLMAdapter; private readonly trajectoryStore: TrajectoryStore; private readonly analysisCache = new Map<string, CacheEntry>(); // OPTIMIZATION: Pattern matching and analysis optimization private readonly patternMatcher: PatternMatcher; private readonly batchProcessor: BatchAnalysisProcessor; private readonly memoryManager: AnalysisMemoryManager; constructor(dependencies: ReflectionEngineDependencies) { this.validateDependencies(dependencies); this.llmAdapter = dependencies.llmAdapter; this.trajectoryStore = dependencies.trajectoryStore; // Set default configuration this.config = { maxAnalysisDepth: dependencies.config?.maxAnalysisDepth ?? 5, confidenceThreshold: dependencies.config?.confidenceThreshold ?? 0.8, patternMinFrequency: dependencies.config?.patternMinFrequency ?? 3, batchSize: dependencies.config?.batchSize ?? 10, enableCaching: dependencies.config?.enableCaching ?? false, cacheTimeout: dependencies.config?.cacheTimeout ?? 3600000, // 1 hour }; // OPTIMIZATION: Initialize performance optimizers this.patternMatcher = new PatternMatcher(this.config.patternMinFrequency); this.batchProcessor = new BatchAnalysisProcessor(this.llmAdapter); this.memoryManager = new AnalysisMemoryManager(this.config.cacheTimeout); } /** * Validate required dependencies */ private validateDependencies(dependencies: ReflectionEngineDependencies): void { if (!dependencies.llmAdapter) { throw new Error('LLM adapter is required'); } if (!dependencies.trajectoryStore) { throw new Error('Trajectory store is required'); } } /** * Analyze a single execution trajectory for failure patterns and improvements */ async analyzeTrajectory(trajectory: ExecutionTrajectory): Promise<ReflectionAnalysis> { this.validateTrajectory(trajectory); // Check cache first if (this.config.enableCaching) { const cached = this.getCachedAnalysis(trajectory.id); if (cached) { return cached; } } try { // Use LLMAdapter to analyze the trajectory const analysis = await this.llmAdapter.analyzeTrajectory(trajectory, ''); // Validate the analysis response this.validateAnalysisResponse(analysis); // Check confidence threshold - but only enforce it for low confidence engines // that have explicitly set a high threshold (like in tests) if (this.config.confidenceThreshold > 0.8 && analysis.confidence < this.config.confidenceThreshold) { throw new Error( `Analysis confidence (${analysis.confidence}) below threshold (${this.config.confidenceThreshold})` ); } // Cache the result if caching is enabled if (this.config.enableCaching) { this.cacheAnalysis(trajectory.id, analysis); } return analysis; } catch (error: unknown) { const errorMessage = error instanceof Error ? error.message : String(error); throw new Error(`Failed to analyze trajectory: ${errorMessage}`); } } /** * Analyze multiple trajectories in batch to identify common patterns (OPTIMIZED) */ async analyzeBatch(trajectories: ExecutionTrajectory[]): Promise<BatchAnalysisResult> { if (trajectories.length === 0) { throw new Error('At least one trajectory is required for batch analysis'); } // OPTIMIZATION: Parallel validation and preprocessing const validationPromises = trajectories.map(trajectory => Promise.resolve().then(() => this.validateTrajectory(trajectory)) ); await Promise.all(validationPromises); const trajectoryIds = trajectories.map(t => t.id); // OPTIMIZATION: Use optimized batch processor with parallel processing const batchResults = await this.batchProcessor.processTrajectories( trajectories, this.config.batchSize ); // OPTIMIZATION: Enhanced aggregation with pattern deduplication return this.aggregateBatchResultsOptimized(trajectoryIds, batchResults); } /** * Find patterns for trajectories related to a specific prompt (OPTIMIZED) */ async findPatternsForPrompt(promptId: string): Promise<FailurePattern[]> { try { // OPTIMIZATION: Check cache first const cacheKey = `patterns-${promptId}`; const cached = this.memoryManager.getCachedPatterns(cacheKey); if (cached) { return cached; } // OPTIMIZATION: Stream trajectories to avoid loading all at once const trajectories = await this.trajectoryStore.query({ promptId, limit: 100, }); if (trajectories.length === 0) { return []; } // OPTIMIZATION: Use pattern matcher for pre-filtering const relevantTrajectories = this.patternMatcher.filterRelevantTrajectories(trajectories); if (relevantTrajectories.length === 0) { return []; } const batchAnalysis = await this.analyzeBatch(relevantTrajectories); // OPTIMIZATION: Cache the results this.memoryManager.cachePatterns(cacheKey, batchAnalysis.commonPatterns); return batchAnalysis.commonPatterns; } catch (error: unknown) { const errorMessage = error instanceof Error ? error.message : String(error); throw new Error(`Failed to query trajectories: ${errorMessage}`); } } /** * Validate trajectory data integrity */ private validateTrajectory(trajectory: ExecutionTrajectory): void { if (!isExecutionTrajectory(trajectory)) { throw new Error('Invalid trajectory data'); } // Additional validation if (!trajectory.id || !trajectory.promptId || !trajectory.taskId) { throw new Error('Invalid trajectory data'); } if (!trajectory.finalResult || typeof trajectory.finalResult.success !== 'boolean') { throw new Error('Invalid trajectory data'); } } /** * Validate analysis response from LLM */ private validateAnalysisResponse(analysis: unknown): void { if (!analysis || typeof analysis !== 'object') { throw new Error('Invalid analysis response from LLM'); } const analysisObj = analysis as Record<string, unknown>; if (!analysisObj.trajectoryId || !analysisObj.promptId || !analysisObj.diagnosis) { throw new Error('Invalid analysis response from LLM'); } if (!analysisObj.suggestions || !Array.isArray(analysisObj.suggestions)) { throw new Error('Invalid analysis response from LLM'); } if (typeof analysisObj.confidence !== 'number') { throw new Error('Invalid analysis response from LLM'); } } /** * Get cached analysis if available and not expired */ private getCachedAnalysis(trajectoryId: string): ReflectionAnalysis | null { const cached = this.analysisCache.get(trajectoryId); if (!cached) { return null; } const isExpired = Date.now() - cached.timestamp > this.config.cacheTimeout; if (isExpired) { this.analysisCache.delete(trajectoryId); return null; } return cached.analysis; } /** * Cache analysis result */ private cacheAnalysis(trajectoryId: string, analysis: ReflectionAnalysis): void { this.analysisCache.set(trajectoryId, { analysis, timestamp: Date.now(), }); } /** * Aggregate batch results with enhanced optimization */ private aggregateBatchResultsOptimized(trajectoryIds: string[], batchResults: unknown[]): BatchAnalysisResult { const patternMap = new Map<string, { pattern: FailurePattern; trajectorySet: Set<string>; }>(); const allRecommendations: Array<PromptImprovement & { priority: 'low' | 'medium' | 'high' | 'critical'; affectedTrajectories: string[]; }> = []; let totalConfidence = 0; let totalWeight = 0; // Process each batch result for (const result of batchResults) { // Type guard to ensure result is an object with expected properties if (!result || typeof result !== 'object') { continue; } const batchResult = result as { commonPatterns?: Array<{ type: string; frequency: number; description: string; examples: string[]; trajectoryIds?: string[]; }>; recommendations?: Array<PromptImprovement & { priority: 'low' | 'medium' | 'high' | 'critical'; affectedTrajectories: string[]; }>; overallConfidence?: number; }; if (batchResult.commonPatterns) { for (const pattern of batchResult.commonPatterns) { const key = `${pattern.type}:${this.normalizePatternDescription(pattern.description)}`; if (patternMap.has(key)) { const existing = patternMap.get(key); if (!existing) continue; existing.pattern.frequency += pattern.frequency; existing.pattern.examples.push(...pattern.examples.slice(0, 2)); pattern.trajectoryIds?.forEach((id: string) => existing.trajectorySet.add(id)); } else { patternMap.set(key, { pattern: { ...pattern }, trajectorySet: new Set(pattern.trajectoryIds || []) }); } } } if (batchResult.recommendations) { allRecommendations.push(...batchResult.recommendations); } if (typeof batchResult.overallConfidence === 'number') { totalConfidence += batchResult.overallConfidence; totalWeight += 1; } } // Convert patterns and deduplicate const mergedPatterns: FailurePattern[] = Array.from(patternMap.values()).map(({ pattern, trajectorySet }) => ({ ...pattern, examples: pattern.examples.slice(0, 3), // Limit examples trajectoryIds: Array.from(trajectorySet) })); // Filter patterns by minimum frequency const filteredPatterns = mergedPatterns.filter( pattern => pattern.frequency >= this.config.patternMinFrequency ); // Deduplicate and prioritize recommendations const deduplicatedRecommendations = this.deduplicateRecommendations(allRecommendations); // Calculate weighted average confidence const overallConfidence = totalWeight > 0 ? totalConfidence / totalWeight : 0.5; return { trajectoryIds, commonPatterns: filteredPatterns.sort((a, b) => b.frequency - a.frequency), recommendations: deduplicatedRecommendations, overallConfidence, }; } /** * Normalize pattern description for deduplication */ private normalizePatternDescription(description: string): string { return description .toLowerCase() .replace(/\d+/g, 'N') .replace(/['"]/g, '') .trim(); } /** * Deduplicate recommendations based on similarity */ private deduplicateRecommendations(recommendations: Array<PromptImprovement & { priority: 'low' | 'medium' | 'high' | 'critical'; affectedTrajectories: string[]; }>): Array<PromptImprovement & { priority: 'low' | 'medium' | 'high' | 'critical'; affectedTrajectories: string[]; }> { const groupMap = new Map<string, Array<PromptImprovement & { priority: 'low' | 'medium' | 'high' | 'critical'; affectedTrajectories: string[]; }>>(); // Group similar recommendations for (const rec of recommendations) { const key = `${rec.type}:${rec.targetSection}`; if (!groupMap.has(key)) { groupMap.set(key, []); } const group = groupMap.get(key); if (group) { group.push(rec); } } // Merge groups and select best recommendations const merged: Array<PromptImprovement & { priority: 'low' | 'medium' | 'high' | 'critical'; affectedTrajectories: string[]; }> = []; for (const group of Array.from(groupMap.values())) { if (group.length === 1) { merged.push(group[0]!); } else { // Merge similar recommendations const priorityOrder = { critical: 4, high: 3, medium: 2, low: 1 }; const bestRec = group.reduce((best, current) => priorityOrder[current.priority] > priorityOrder[best.priority] ? current : best ); // Combine affected trajectories const allAffectedTrajectories = new Set<string>(); group.forEach(rec => rec.affectedTrajectories.forEach(id => allAffectedTrajectories.add(id))); merged.push({ ...bestRec, affectedTrajectories: Array.from(allAffectedTrajectories), expectedImpact: Math.max(...group.map(r => r.expectedImpact || 0)) }); } } return merged.sort((a, b) => { const priorityOrder = { critical: 4, high: 3, medium: 2, low: 1 }; const priorityDiff = priorityOrder[b.priority] - priorityOrder[a.priority]; return priorityDiff !== 0 ? priorityDiff : (b.expectedImpact || 0) - (a.expectedImpact || 0); }); } }

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