UNPKG

il2cpp-dump-analyzer-mcp

Version:

Agentic RAG system for analyzing IL2CPP dump.cs files from Unity games

1,175 lines 48.7 kB
"use strict"; /** * @fileoverview MCP Response Synthesis and Aggregation Engine * Provides intelligent aggregation and synthesis of MCP tool results with * context-aware response formatting and quality assessment */ Object.defineProperty(exports, "__esModule", { value: true }); exports.MCPResponseSynthesizer = void 0; /** * Default configuration for the MCP Response Synthesizer */ const DEFAULT_CONFIG = { enableSemanticCorrelation: true, maxResponseLength: 10000, qualityThreshold: 0.6, enableCaching: true, cacheConfig: { maxEntries: 500, ttlMs: 300000, // 5 minutes enableSemanticCaching: true }, formatting: { includeMetadata: true, includeQualityMetrics: false, includeCorrelations: true, preferredFormat: 'hybrid' } }; /** * MCP Response Synthesis and Aggregation Engine * Intelligently combines and synthesizes results from multiple MCP tools */ class MCPResponseSynthesizer { constructor(context, config = {}) { this.context = context; this.config = { ...DEFAULT_CONFIG, ...config }; this.cache = new Map(); this.statistics = this.initializeStatistics(); if (this.context.logger) { this.context.logger.info('MCP Response Synthesizer initialized', { config: this.config, cacheEnabled: this.config.enableCaching }); } } /** * Synthesize a single tool result into a coherent response */ async synthesizeSingleResult(toolResult, toolName, context) { const startTime = Date.now(); this.context.logger.debug('Synthesizing single tool result', { toolName, context }); try { // Check cache first if (this.config.enableCaching) { const cacheKey = this.generateCacheKey('single', [toolResult], [toolName]); const cached = this.getCachedResponse(cacheKey); if (cached) { this.statistics.cacheStats.hits++; return cached; } this.statistics.cacheStats.misses++; } // Validate input if (!this.validateToolResult(toolResult)) { return this.createErrorResponse('Invalid tool result structure', toolName, startTime); } // Handle failed tool execution if (!toolResult.success) { return this.createFailureResponse(toolResult, toolName, startTime); } // Synthesize content const synthesizedContent = this.synthesizeContent([toolResult], [toolName], 'single'); // Assess quality const qualityAssessment = this.assessResultQuality(toolResult, context || ''); // Create response const response = { success: true, synthesizedContent, qualityAssessment, metadata: { originalToolName: toolName, synthesisTimestamp: Date.now(), synthesisTime: Date.now() - startTime, resultCount: toolResult.data?.length || 0, contentLength: synthesizedContent.length }, issues: qualityAssessment.issues, suggestions: qualityAssessment.suggestions }; // Cache the response if (this.config.enableCaching) { const cacheKey = this.generateCacheKey('single', [toolResult], [toolName]); this.cacheResponse(cacheKey, response, [toolName]); } // Update statistics this.updateStatistics(response, Date.now() - startTime); this.context.logger.debug('Single tool result synthesized successfully', { toolName, qualityScore: qualityAssessment.qualityScore, contentLength: synthesizedContent.length }); return response; } catch (error) { this.context.logger.error('Single tool synthesis failed', { error, toolName }); return this.createErrorResponse(`Synthesis failed: ${error instanceof Error ? error.message : 'Unknown error'}`, toolName, startTime); } } /** * Aggregate results from multiple tools into a unified response */ async aggregateMultipleResults(toolResults, toolNames, originalRequest) { const startTime = Date.now(); this.context.logger.debug('Aggregating multiple tool results', { toolCount: toolResults.length, toolNames, originalRequest }); try { // Check cache first if (this.config.enableCaching) { const cacheKey = this.generateCacheKey('multiple', toolResults, toolNames); const cached = this.getCachedResponse(cacheKey); if (cached) { this.statistics.cacheStats.hits++; return cached; } this.statistics.cacheStats.misses++; } // Validate inputs const validResults = toolResults.filter(result => this.validateToolResult(result)); if (validResults.length === 0) { return this.createAggregationErrorResponse('No valid tool results to aggregate', toolNames, startTime); } // Find correlations between results const correlations = this.config.enableSemanticCorrelation ? this.findResultCorrelations(validResults, toolNames) : []; // Synthesize aggregated content const synthesizedContent = this.synthesizeContent(validResults, toolNames, 'aggregated', correlations); // Assess overall quality const qualityAssessment = this.assessAggregatedQuality(validResults, originalRequest, correlations); // Create aggregation summary const successfulTools = validResults.filter(r => r.success).length; const failedTools = toolResults.length - successfulTools; const response = { success: successfulTools > 0, synthesizedContent, correlations, qualityAssessment, aggregationSummary: { totalTools: toolResults.length, successfulTools, failedTools, correlationsFound: correlations.length, synthesisStrategy: this.determineSynthesisStrategy(validResults, correlations) }, metadata: { toolNames, aggregationTimestamp: Date.now(), aggregationTime: Date.now() - startTime, totalResultCount: validResults.reduce((sum, r) => sum + (r.data?.length || 0), 0), contentLength: synthesizedContent.length }, issues: qualityAssessment.issues, suggestions: qualityAssessment.suggestions }; // Cache the response if (this.config.enableCaching) { const cacheKey = this.generateCacheKey('multiple', toolResults, toolNames); this.cacheResponse(cacheKey, response, toolNames); } // Update statistics this.updateStatistics(response, Date.now() - startTime); this.context.logger.info('Multiple tool results aggregated successfully', { toolCount: toolResults.length, correlationsFound: correlations.length, qualityScore: qualityAssessment.qualityScore }); return response; } catch (error) { this.context.logger.error('Multiple tool aggregation failed', { error, toolNames }); return this.createAggregationErrorResponse(`Aggregation failed: ${error instanceof Error ? error.message : 'Unknown error'}`, toolNames, startTime); } } /** * Synthesize complete workflow execution results */ async synthesizeWorkflowResults(workflowExecution, originalRequest) { const startTime = Date.now(); this.context.logger.debug('Synthesizing workflow results', { originalRequest, resultCount: workflowExecution.results.length, workflowSuccess: workflowExecution.success }); try { // Extract tool names from results const toolNames = workflowExecution.results.map(r => r.metadata?.toolName || 'unknown'); // Check cache first if (this.config.enableCaching) { const cacheKey = this.generateCacheKey('workflow', workflowExecution.results, toolNames); const cached = this.getCachedResponse(cacheKey); if (cached) { this.statistics.cacheStats.hits++; return cached; } this.statistics.cacheStats.misses++; } // Filter valid results const validResults = workflowExecution.results.filter(result => this.validateToolResult(result)); // Find correlations across workflow results const correlations = this.config.enableSemanticCorrelation ? this.findResultCorrelations(validResults, toolNames) : []; // Synthesize workflow content const synthesizedContent = this.synthesizeWorkflowContent(workflowExecution, validResults, toolNames, correlations, originalRequest); // Assess workflow quality const qualityAssessment = this.assessWorkflowQuality(workflowExecution, validResults, originalRequest, correlations); // Create workflow summary const successfulTools = validResults.filter(r => r.success).length; const failedTools = workflowExecution.results.length - successfulTools; const response = { success: workflowExecution.success && successfulTools > 0, synthesizedContent, correlations, qualityAssessment, workflowSummary: { totalTools: workflowExecution.results.length, successfulTools, failedTools, executionTime: workflowExecution.executionTime, retryCount: workflowExecution.retryCount, correlationsFound: correlations.length }, metadata: { originalRequest, toolNames, synthesisTimestamp: Date.now(), synthesisTime: Date.now() - startTime, totalResultCount: validResults.reduce((sum, r) => sum + (r.data?.length || 0), 0), contentLength: synthesizedContent.length }, issues: qualityAssessment.issues, suggestions: qualityAssessment.suggestions }; // Cache the response if (this.config.enableCaching) { const cacheKey = this.generateCacheKey('workflow', workflowExecution.results, toolNames); this.cacheResponse(cacheKey, response, toolNames); } // Update statistics this.updateStatistics(response, Date.now() - startTime); this.context.logger.info('Workflow results synthesized successfully', { originalRequest, correlationsFound: correlations.length, qualityScore: qualityAssessment.qualityScore, workflowSuccess: response.success }); return response; } catch (error) { this.context.logger.error('Workflow synthesis failed', { error, originalRequest }); return this.createWorkflowErrorResponse(workflowExecution, `Workflow synthesis failed: ${error instanceof Error ? error.message : 'Unknown error'}`, originalRequest, startTime); } } /** * Assess the quality of a tool result */ assessResultQuality(toolResult, context) { const issues = []; const suggestions = []; // Check basic validity if (!toolResult.success) { issues.push('Tool execution failed'); suggestions.push('Retry the operation or use alternative tools'); } // Check data availability if (!toolResult.data || toolResult.data.length === 0) { issues.push('No results found'); suggestions.push('Try broader search criteria or different parameters'); } // Calculate quality scores const relevanceScore = this.calculateRelevanceScore(toolResult, context); const completenessScore = this.calculateCompletenessScore(toolResult); const coherenceScore = this.calculateCoherenceScore(toolResult); const qualityScore = (relevanceScore + completenessScore + coherenceScore) / 3; const overallQuality = Math.max(0, qualityScore); return { isValid: toolResult.success && (toolResult.data?.length || 0) > 0, qualityScore, relevanceScore, completenessScore, coherenceScore, overallQuality, issues, suggestions, metrics: { informationDensity: this.calculateInformationDensity(toolResult), structuralIntegrity: this.calculateStructuralIntegrity(toolResult), semanticConsistency: this.calculateSemanticConsistency(toolResult), factualAccuracy: this.calculateFactualAccuracy(toolResult) } }; } /** * Get cache statistics */ getCacheStats() { return { ...this.statistics.cacheStats, totalEntries: this.cache.size, memoryUsage: this.calculateCacheMemoryUsage() }; } /** * Get synthesis statistics */ getStatistics() { return { ...this.statistics, cacheStats: this.getCacheStats() }; } /** * Clear cache and reset statistics */ reset() { this.cache.clear(); this.statistics = this.initializeStatistics(); this.context.logger.info('MCP Response Synthesizer reset'); } // ============================================================================ // PRIVATE METHODS // ============================================================================ /** * Initialize synthesis statistics */ initializeStatistics() { return { totalSyntheses: 0, successfulSyntheses: 0, averageSynthesisTime: 0, averageQualityScore: 0, cacheStats: { hits: 0, misses: 0, hitRate: 0, totalEntries: 0, memoryUsage: 0 }, correlationStats: { totalCorrelations: 0, averageCorrelationStrength: 0, correlationsByType: {} }, qualityStats: { averageRelevance: 0, averageCompleteness: 0, averageCoherence: 0, commonIssues: [] } }; } /** * Validate tool result structure */ validateToolResult(toolResult) { if (!toolResult || typeof toolResult !== 'object') { return false; } if (!('success' in toolResult)) { return false; } // Check for malformed data if (toolResult.success && toolResult.data === null) { return false; } return true; } /** * Generate cache key for results */ generateCacheKey(type, results, toolNames) { const resultHashes = results.map(r => this.hashObject(r)).join('|'); return `${type}:${toolNames.join(',')}:${resultHashes}`; } /** * Get cached response if available and valid */ getCachedResponse(cacheKey) { const entry = this.cache.get(cacheKey); if (!entry) return null; // Check TTL if (Date.now() > entry.metadata.createdAt + entry.metadata.ttl) { this.cache.delete(cacheKey); return null; } // Update access metadata entry.metadata.lastAccessedAt = Date.now(); entry.metadata.accessCount++; return entry.response; } /** * Cache a synthesized response */ cacheResponse(cacheKey, response, toolNames) { // Check cache size limit if (this.cache.size >= this.config.cacheConfig.maxEntries) { this.evictOldestCacheEntry(); } const entry = { key: cacheKey, response, metadata: { createdAt: Date.now(), lastAccessedAt: Date.now(), accessCount: 1, ttl: this.config.cacheConfig.ttlMs, size: JSON.stringify(response).length }, semanticTags: this.extractSemanticTags(response), inputHash: this.hashObject({ toolNames, response }) }; this.cache.set(cacheKey, entry); } /** * Evict oldest cache entry */ evictOldestCacheEntry() { let oldestKey = ''; let oldestTime = Date.now(); for (const [key, entry] of this.cache.entries()) { if (entry.metadata.lastAccessedAt < oldestTime) { oldestTime = entry.metadata.lastAccessedAt; oldestKey = key; } } if (oldestKey) { this.cache.delete(oldestKey); } } /** * Extract semantic tags from response for correlation */ extractSemanticTags(response) { const tags = []; const content = response.synthesizedContent.toLowerCase(); // Extract common IL2CPP entities const entityPatterns = [ /\bclass\s+(\w+)/g, /\binterface\s+(\w+)/g, /\benum\s+(\w+)/g, /\bnamespace\s+([\w.]+)/g, /\bmonobehaviour\b/g ]; entityPatterns.forEach(pattern => { const matches = content.match(pattern); if (matches) { tags.push(...matches.map(match => match.toLowerCase())); } }); return [...new Set(tags)]; // Remove duplicates } /** * Calculate cache memory usage */ calculateCacheMemoryUsage() { let totalSize = 0; for (const entry of this.cache.values()) { totalSize += entry.metadata.size; } return totalSize; } /** * Hash object for cache key generation */ hashObject(obj) { const str = JSON.stringify(obj, Object.keys(obj).sort()); let hash = 0; for (let i = 0; i < str.length; i++) { const char = str.charCodeAt(i); hash = ((hash << 5) - hash) + char; hash = hash & hash; // Convert to 32-bit integer } return hash.toString(36); } /** * Create error response for single tool synthesis */ createErrorResponse(error, toolName, startTime) { return { success: false, synthesizedContent: `Tool synthesis failed: ${error}`, qualityAssessment: { isValid: false, qualityScore: 0, relevanceScore: 0, completenessScore: 0, coherenceScore: 0, overallQuality: 0, issues: [error], suggestions: ['Check tool parameters and try again'], metrics: { informationDensity: 0, structuralIntegrity: 0, semanticConsistency: 0, factualAccuracy: 0 } }, metadata: { originalToolName: toolName, synthesisTimestamp: Date.now(), synthesisTime: Date.now() - startTime, resultCount: 0, contentLength: 0 }, issues: [error], suggestions: ['Check tool parameters and try again'] }; } /** * Create failure response for failed tool execution */ createFailureResponse(toolResult, toolName, startTime) { const errorMessage = toolResult.error || 'Tool execution failed'; return { success: false, synthesizedContent: `Tool execution failed: ${errorMessage}`, qualityAssessment: { isValid: false, qualityScore: 0, relevanceScore: 0, completenessScore: 0, coherenceScore: 0, overallQuality: 0, issues: [errorMessage], suggestions: ['Retry with different parameters', 'Check tool availability'], metrics: { informationDensity: 0, structuralIntegrity: 0, semanticConsistency: 0, factualAccuracy: 0 } }, metadata: { originalToolName: toolName, synthesisTimestamp: Date.now(), synthesisTime: Date.now() - startTime, resultCount: 0, contentLength: 0 }, issues: [errorMessage], suggestions: ['Retry with different parameters', 'Check tool availability'] }; } /** * Synthesize content from tool results */ synthesizeContent(toolResults, toolNames, synthesisType, correlations) { if (toolResults.length === 0) { return 'No results found for the requested analysis.'; } const sections = []; // Add summary section if (synthesisType !== 'single') { sections.push(this.createSummarySection(toolResults, toolNames)); } // Add results from each tool toolResults.forEach((result, index) => { if (result.success && result.data && result.data.length > 0) { const toolName = toolNames[index] || 'unknown'; sections.push(this.createToolResultSection(result, toolName)); } }); // Add correlations section if available if (correlations && correlations.length > 0) { sections.push(this.createCorrelationsSection(correlations)); } // Handle empty results if (sections.length === 0) { return 'No results found for the requested analysis.'; } return sections.join('\n\n'); } /** * Create summary section for multiple results */ createSummarySection(toolResults, toolNames) { const successfulTools = toolResults.filter(r => r.success).length; const totalResults = toolResults.reduce((sum, r) => sum + (r.data?.length || 0), 0); return `## Analysis Summary\n\n` + `- **Tools executed**: ${toolNames.join(', ')}\n` + `- **Successful tools**: ${successfulTools}/${toolResults.length}\n` + `- **Total results found**: ${totalResults}`; } /** * Create section for individual tool result */ createToolResultSection(result, toolName) { const sections = []; // Tool header sections.push(`### ${this.formatToolName(toolName)} Results`); // Add result count const resultCount = result.data?.length || 0; sections.push(`Found ${resultCount} result${resultCount !== 1 ? 's' : ''}`); // Add results if (result.data && result.data.length > 0) { result.data.forEach((item, index) => { sections.push(this.formatResultItem(item, index + 1, toolName)); }); } return sections.join('\n\n'); } /** * Format individual result item */ formatResultItem(item, index, toolName) { if (!item) return `${index}. No data available`; // Handle different result types based on tool if (toolName.includes('search') || toolName.includes('find')) { return this.formatSearchResult(item, index); } else if (toolName.includes('generate')) { return this.formatGenerationResult(item, index); } else if (toolName.includes('analyze')) { return this.formatAnalysisResult(item, index); } // Default formatting return `${index}. ${item.content || JSON.stringify(item, null, 2)}`; } /** * Format search result item */ formatSearchResult(item, index) { const name = item.metadata?.name || item.name || 'Unknown'; const type = item.metadata?.type || item.type || 'unknown'; const namespace = item.metadata?.namespace || item.namespace || ''; let result = `${index}. **${name}** (${type})`; if (namespace) { result += ` - Namespace: ${namespace}`; } if (item.content) { const preview = item.content.length > 100 ? item.content.substring(0, 100) + '...' : item.content; result += `\n \`\`\`csharp\n ${preview}\n \`\`\``; } return result; } /** * Format generation result item */ formatGenerationResult(item, index) { if (item.generatedCode) { const preview = item.generatedCode.length > 200 ? item.generatedCode.substring(0, 200) + '...' : item.generatedCode; return `${index}. Generated Code:\n\`\`\`csharp\n${preview}\n\`\`\``; } return `${index}. ${item.content || 'Generated content'}`; } /** * Format analysis result item */ formatAnalysisResult(item, index) { if (item.metadata) { const details = Object.entries(item.metadata) .map(([key, value]) => `- ${key}: ${value}`) .join('\n'); return `${index}. Analysis Result:\n${details}`; } return `${index}. ${item.content || 'Analysis data'}`; } /** * Create correlations section */ createCorrelationsSection(correlations) { const sections = ['## Correlations Found']; correlations.forEach((correlation, index) => { sections.push(`${index + 1}. **${correlation.correlationType}** (Strength: ${(correlation.strength * 100).toFixed(1)}%)\n` + ` - Entities: ${correlation.entities.join(', ')}\n` + ` - Description: ${correlation.description}`); }); return sections.join('\n\n'); } /** * Format tool name for display */ formatToolName(toolName) { return toolName .split('_') .map(word => word.charAt(0).toUpperCase() + word.slice(1)) .join(' '); } /** * Find correlations between tool results */ findResultCorrelations(toolResults, toolNames) { const correlations = []; // Find entity relationships for (let i = 0; i < toolResults.length; i++) { for (let j = i + 1; j < toolResults.length; j++) { const correlation = this.findEntityCorrelation(toolResults[i], toolNames[i], toolResults[j], toolNames[j]); if (correlation) { correlations.push(correlation); } } } return correlations; } /** * Find correlation between two tool results */ findEntityCorrelation(result1, tool1, result2, tool2) { if (!result1.success || !result2.success || !result1.data || !result2.data) { return null; } // Extract entity names from both results const entities1 = this.extractEntityNames(result1); const entities2 = this.extractEntityNames(result2); // Find common entities const commonEntities = entities1.filter(e => entities2.includes(e)); if (commonEntities.length > 0) { return { id: `correlation-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`, correlationType: 'entity_relationship', entities: commonEntities, sourceTools: [tool1, tool2], strength: commonEntities.length / Math.max(entities1.length, entities2.length), confidence: 0.8, description: `Found ${commonEntities.length} common entities between ${tool1} and ${tool2}`, evidence: commonEntities.map(entity => ({ source: `${tool1} + ${tool2}`, content: `Entity "${entity}" found in both results`, relevance: 0.9 })) }; } return null; } /** * Extract entity names from tool result */ extractEntityNames(result) { const entities = []; if (result.data) { result.data.forEach(item => { if (item.metadata?.name) { entities.push(item.metadata.name); } if (item.name) { entities.push(item.name); } if (item.metadata?.className) { entities.push(item.metadata.className); } if (item.className) { entities.push(item.className); } // Extract from content using regex if (item.content) { const classMatches = item.content.match(/class\s+(\w+)/g); if (classMatches) { classMatches.forEach((match) => { const className = match.replace('class ', ''); entities.push(className); }); } } }); } return [...new Set(entities)]; // Remove duplicates } /** * Calculate relevance score for tool result */ calculateRelevanceScore(toolResult, context) { if (!toolResult.success || !toolResult.data) return 0; let relevanceScore = 0.5; // Base score // Check if results contain context keywords const contextKeywords = context.toLowerCase().split(/\s+/); const resultContent = JSON.stringify(toolResult.data).toLowerCase(); const matchingKeywords = contextKeywords.filter(keyword => keyword.length > 2 && resultContent.includes(keyword)); relevanceScore += (matchingKeywords.length / Math.max(contextKeywords.length, 1)) * 0.3; // Check result count const resultCount = toolResult.data.length; if (resultCount > 0) { relevanceScore += Math.min(resultCount / 10, 0.2); // Up to 0.2 bonus for multiple results } return Math.min(relevanceScore, 1.0); } /** * Calculate completeness score for tool result */ calculateCompletenessScore(toolResult) { if (!toolResult.success) return 0; if (!toolResult.data || toolResult.data.length === 0) return 0; let completenessScore = 0.3; // Base score for having data // Check data richness const hasMetadata = toolResult.data.some(item => item.metadata && Object.keys(item.metadata).length > 0); if (hasMetadata) completenessScore += 0.3; const hasContent = toolResult.data.some(item => item.content && item.content.length > 0); if (hasContent) completenessScore += 0.4; return Math.min(completenessScore, 1.0); } /** * Calculate coherence score for tool result */ calculateCoherenceScore(toolResult) { if (!toolResult.success || !toolResult.data) return 0; let coherenceScore = 0.5; // Base score // Check structural consistency const hasConsistentStructure = toolResult.data.every(item => typeof item === 'object' && (item.content || item.metadata)); if (hasConsistentStructure) coherenceScore += 0.3; // Check for error indicators const hasErrors = toolResult.data.some(item => JSON.stringify(item).toLowerCase().includes('error')); if (!hasErrors) coherenceScore += 0.2; return Math.min(coherenceScore, 1.0); } /** * Calculate information density */ calculateInformationDensity(toolResult) { if (!toolResult.success || !toolResult.data) return 0; const totalContent = toolResult.data.reduce((sum, item) => { const contentLength = (item.content || '').length; const metadataSize = Object.keys(item.metadata || {}).length; return sum + contentLength + metadataSize * 10; }, 0); return Math.min(totalContent / 1000, 1.0); // Normalize to 0-1 } /** * Calculate structural integrity */ calculateStructuralIntegrity(toolResult) { if (!toolResult.success || !toolResult.data) return 0; const validItems = toolResult.data.filter(item => item && typeof item === 'object' && (item.content || item.metadata)); return validItems.length / Math.max(toolResult.data.length, 1); } /** * Calculate semantic consistency */ calculateSemanticConsistency(toolResult) { if (!toolResult.success || !toolResult.data) return 0; // Check if all results are of similar type const types = toolResult.data.map(item => item.metadata?.type || 'unknown'); const uniqueTypes = [...new Set(types)]; // More consistent if fewer unique types return Math.max(0, 1 - (uniqueTypes.length - 1) * 0.2); } /** * Calculate factual accuracy (basic heuristics) */ calculateFactualAccuracy(toolResult) { if (!toolResult.success || !toolResult.data) return 0; let accuracyScore = 0.7; // Base assumption of accuracy // Check for common error patterns const resultText = JSON.stringify(toolResult.data).toLowerCase(); const errorPatterns = ['undefined', 'null', 'error', 'failed', 'invalid']; const errorCount = errorPatterns.reduce((count, pattern) => { return count + (resultText.match(new RegExp(pattern, 'g')) || []).length; }, 0); accuracyScore -= errorCount * 0.1; return Math.max(0, Math.min(accuracyScore, 1.0)); } /** * Assess quality of aggregated results */ assessAggregatedQuality(toolResults, originalRequest, correlations) { const issues = []; const suggestions = []; // Calculate individual scores const relevanceScores = toolResults.map(r => this.calculateRelevanceScore(r, originalRequest)); const completenessScores = toolResults.map(r => this.calculateCompletenessScore(r)); const coherenceScores = toolResults.map(r => this.calculateCoherenceScore(r)); const relevanceScore = relevanceScores.reduce((sum, score) => sum + score, 0) / relevanceScores.length; const completenessScore = completenessScores.reduce((sum, score) => sum + score, 0) / completenessScores.length; const coherenceScore = coherenceScores.reduce((sum, score) => sum + score, 0) / coherenceScores.length; // Bonus for correlations const correlationBonus = Math.min(correlations.length * 0.1, 0.3); const qualityScore = (relevanceScore + completenessScore + coherenceScore) / 3 + correlationBonus; // Check for issues const failedTools = toolResults.filter(r => !r.success).length; if (failedTools > 0) { issues.push(`${failedTools} tool(s) failed to execute`); suggestions.push('Retry failed tools with different parameters'); } const emptyResults = toolResults.filter(r => !r.data || r.data.length === 0).length; if (emptyResults > 0) { issues.push(`${emptyResults} tool(s) returned no results`); suggestions.push('Try broader search criteria or alternative tools'); } return { isValid: qualityScore > 0.3 && failedTools < toolResults.length, qualityScore: Math.max(0, qualityScore), relevanceScore, completenessScore, coherenceScore, overallQuality: Math.max(0, qualityScore), issues, suggestions, metrics: { informationDensity: toolResults.reduce((sum, r) => sum + this.calculateInformationDensity(r), 0) / toolResults.length, structuralIntegrity: toolResults.reduce((sum, r) => sum + this.calculateStructuralIntegrity(r), 0) / toolResults.length, semanticConsistency: toolResults.reduce((sum, r) => sum + this.calculateSemanticConsistency(r), 0) / toolResults.length, factualAccuracy: toolResults.reduce((sum, r) => sum + this.calculateFactualAccuracy(r), 0) / toolResults.length } }; } /** * Synthesize workflow content with execution context */ synthesizeWorkflowContent(workflowExecution, validResults, toolNames, correlations, originalRequest) { const sections = []; // Add workflow summary sections.push(this.createWorkflowSummary(workflowExecution, originalRequest)); // Add synthesized content from valid results if (validResults.length > 0) { const synthesizedContent = this.synthesizeContent(validResults, toolNames, 'workflow', correlations); sections.push(synthesizedContent); } // Add workflow execution details if (workflowExecution.executionTime > 0 || workflowExecution.retryCount > 0) { sections.push(this.createExecutionDetailsSection(workflowExecution)); } // Handle partial failures if (!workflowExecution.success) { sections.push(this.createPartialFailureSection(workflowExecution)); } return sections.join('\n\n'); } /** * Create workflow summary section */ createWorkflowSummary(workflowExecution, originalRequest) { const successfulTools = workflowExecution.results.filter(r => r.success).length; const totalTools = workflowExecution.results.length; return `## Workflow Analysis Results\n\n` + `**Original Request**: ${originalRequest}\n\n` + `**Execution Status**: ${workflowExecution.success ? 'Completed' : 'Partial completion'}\n` + `**Tools Executed**: ${successfulTools}/${totalTools} successful\n` + `**Execution Time**: ${workflowExecution.executionTime}ms\n` + `**Retry Count**: ${workflowExecution.retryCount}`; } /** * Create execution details section */ createExecutionDetailsSection(workflowExecution) { const sections = ['## Execution Details']; if (workflowExecution.metrics) { sections.push(`- **Tools Executed**: ${workflowExecution.metrics.toolsExecuted}\n` + `- **Successful Executions**: ${workflowExecution.metrics.successfulExecutions}\n` + `- **Failed Executions**: ${workflowExecution.metrics.failedExecutions}\n` + `- **Average Execution Time**: ${workflowExecution.metrics.averageExecutionTime}ms`); if (workflowExecution.metrics.cacheHitRate !== undefined) { sections.push(`- **Cache Hit Rate**: ${(workflowExecution.metrics.cacheHitRate * 100).toFixed(1)}%`); } } return sections.join('\n\n'); } /** * Create partial failure section */ createPartialFailureSection(workflowExecution) { const sections = ['## Partial Results']; if (workflowExecution.error) { sections.push(`**Error**: ${workflowExecution.error}`); } const failedResults = workflowExecution.results.filter(r => !r.success); if (failedResults.length > 0) { sections.push(`**Failed Tools**: ${failedResults.length}`); failedResults.forEach((result, index) => { if (result.error) { sections.push(`${index + 1}. ${result.error}`); } }); } sections.push('**Note**: The above results represent partial completion of the requested analysis.'); return sections.join('\n\n'); } /** * Assess workflow quality */ assessWorkflowQuality(workflowExecution, validResults, originalRequest, correlations) { const issues = []; const suggestions = []; // Base quality assessment from aggregated results const baseQuality = this.assessAggregatedQuality(validResults, originalRequest, correlations); // Workflow-specific adjustments let workflowQualityScore = baseQuality.qualityScore; // Penalize for workflow failure if (!workflowExecution.success) { workflowQualityScore *= 0.7; issues.push('Workflow execution was not fully successful'); suggestions.push('Review failed tools and retry with adjusted parameters'); } // Penalize for high retry count if (workflowExecution.retryCount > 2) { workflowQualityScore *= 0.9; issues.push('Multiple retry attempts were required'); suggestions.push('Check tool parameters and system stability'); } // Bonus for efficient execution if (workflowExecution.executionTime < 5000 && workflowExecution.retryCount === 0) { workflowQualityScore *= 1.1; } return { ...baseQuality, qualityScore: Math.min(workflowQualityScore, 1.0), overallQuality: Math.min(workflowQualityScore, 1.0), issues: [...baseQuality.issues, ...issues], suggestions: [...baseQuality.suggestions, ...suggestions] }; } /** * Determine synthesis strategy based on results and correlations */ determineSynthesisStrategy(results, correlations) { if (results.length === 1) return 'single'; if (correlations.length > 0) return 'integrative'; if (results.length > 3) return 'structured'; return 'concatenative'; } /** * Create error response for aggregation */ createAggregationErrorResponse(error, toolNames, startTime) { return { success: false, synthesizedContent: `Aggregation failed: ${error}`, correlations: [], qualityAssessment: { isValid: false, qualityScore: 0, relevanceScore: 0, completenessScore: 0, coherenceScore: 0, overallQuality: 0, issues: [error], suggestions: ['Check tool parameters and try again'], metrics: { informationDensity: 0, structuralIntegrity: 0, semanticConsistency: 0, factualAccuracy: 0 } }, aggregationSummary: { totalTools: toolNames.length, successfulTools: 0, failedTools: toolNames.length, correlationsFound: 0, synthesisStrategy: 'error' }, metadata: { toolNames, aggregationTimestamp: Date.now(), aggregationTime: Date.now() - startTime, totalResultCount: 0, contentLength: 0 }, issues: [error], suggestions: ['Check tool parameters and try again'] }; } /** * Create error response for workflow synthesis */ createWorkflowErrorResponse(workflowExecution, error, originalRequest, startTime) { const toolNames = workflowExecution.results.map(r => r.metadata?.toolName || 'unknown'); return { success: false, synthesizedContent: `Workflow synthesis failed: ${error}`, correlations: [], qualityAssessment: { isValid: false, qualityScore: 0, relevanceScore: 0, completenessScore: 0, coherenceScore: 0, overallQuality: 0, issues: [error], suggestions: ['Check workflow configuration and try again'], metrics: { informationDensity: 0, structuralIntegrity: 0, semanticConsistency: 0, factualAccuracy: 0 } }, workflowSummary: { totalTools: workflowExecution.results.length, successfulTools: 0, failedTools: workflowExecution.results.length, executionTime: workflowExecution.executionTime, retryCount: workflowExecution.retryCount, correlationsFound: 0 }, metadata: { originalRequest, toolNames, synthesisTimestamp: Date.now(), synthesisTime: Date.now() - startTime, totalResultCount: 0, contentLength: 0 }, issues: [error], suggestions: ['Check workflow configuration and try again'] }; } /** * Update synthesis statistics */ updateStatistics(response, synthesisTime) { this.statistics.totalSyntheses++; if (response.success) { this.statistics.successfulSyntheses++; } // Update average synthesis time this.statistics.averageSynthesisTime = (this.statistics.averageSynthesisTime * (this.statistics.totalSyntheses - 1) + synthesisTime) / this.statistics.totalSyntheses; // Update average quality score this.statistics.averageQualityScore = (this.statistics.averageQualityScore * (this.statistics.totalSyntheses - 1) + response.qualityAssessment.qualityScore) / this.statistics.totalSyntheses; // Update cache hit rate if (this.statistics.cacheStats.hits + this.statistics.cacheStats.misses > 0) { this.statistics.cacheStats.hitRate = this.statistics.cacheStats.hits / (this.statistics.cacheStats.hits + this.statistics.cacheStats.misses); } // Update correlation statistics if ('correlations' in response) { this.statistics.correlationStats.totalCorrelations += response.correlations.length; if (response.correlations.length > 0) { const avgStrength = response.correlations.reduce((sum, c) => sum + c.strength, 0) / response.correlations.length; this.statistics.correlationStats.averageCorrelationStrength = (this.statistics.correlationStats.averageCorrelationStrength + avgStrength) / 2; // Update correlation types response.correlations.forEach(correlation => { this.statistics.correlationStats.correlationsByType[correlation.correlationType] = (this.statistics.correlationStats.correlationsByType[correlation.correlationType] || 0) + 1; }); } } // Update quality statistics this.statistics.qualityStats.averageRelevance = (this.statistics.qualityStats.averageRelevance + response.qualityAssessment.relevanceScore) / 2; this.statistics.qualityStats.averageCompleteness = (this.statistics.qualityStats.averageCompleteness + response.qualityAssessment.completenessScore) / 2; this.statistics.qualityStats.averageCoherence = (this.statistics.qualityStats.averageCoherence + response.qualityAssessment.coherenceScore) / 2; } } exports.MCPResponseSynthesizer = MCPResponseSynthesizer; //# sourceMappingURL=mcp-response-synthesizer.js.map