il2cpp-dump-analyzer-mcp
Version:
Agentic RAG system for analyzing IL2CPP dump.cs files from Unity games
845 lines • 33.8 kB
JavaScript
"use strict";
/**
* @fileoverview MCP Tool Orchestration Engine
* Provides intelligent tool orchestration, task decomposition, and workflow management
* for complex IL2CPP analysis requests within the MCP framework
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.MCPOrchestrator = void 0;
const tool_registry_1 = require("../mcp/tools/tool-registry");
/**
* Default configuration for the MCP Orchestrator
*/
const DEFAULT_CONFIG = {
maxWorkflowDepth: 5,
maxParallelTools: 3,
timeoutMs: 30000,
enableCaching: true,
retryAttempts: 2,
enableLearning: false,
confidenceThreshold: 0.7,
enableContextPersistence: true
};
/**
* MCP Tool Orchestration Engine
* Intelligently decomposes complex requests into MCP tool workflows
*/
class MCPOrchestrator {
constructor(context, config = {}) {
this.context = context;
this.config = { ...DEFAULT_CONFIG, ...config };
this.stats = this.initializeStats();
this.cache = new Map();
this.workflowHistory = [];
this.context.logger.info('MCP Orchestrator initialized', {
config: this.config,
availableTools: (0, tool_registry_1.getAllToolNames)().length
});
}
/**
* Decompose a complex request into executable subtasks
*/
async decomposeTask(request) {
this.context.logger.debug('Decomposing task', { request });
try {
// Step 1: Analyze intent from natural language request
const intent = this.analyzeIntent(request);
this.context.logger.debug('Intent analyzed', { intent });
// Step 2: Generate subtasks based on intent
const subtasks = this.generateSubtasks(intent, request);
// Step 3: Determine execution strategy
const executionStrategy = this.determineExecutionStrategy(subtasks);
// Step 4: Calculate estimated duration
const estimatedDuration = this.calculateEstimatedDuration(subtasks, executionStrategy);
const decomposition = {
originalRequest: request,
subtasks,
executionStrategy,
estimatedDuration,
confidence: intent.confidence,
explanation: this.generateDecompositionExplanation(subtasks, executionStrategy)
};
this.context.logger.info('Task decomposed successfully', {
subtaskCount: subtasks.length,
strategy: executionStrategy,
estimatedDuration
});
return decomposition;
}
catch (error) {
this.context.logger.error('Task decomposition failed', { error, request });
throw new Error(`Failed to decompose task: ${error instanceof Error ? error.message : 'Unknown error'}`);
}
}
/**
* Execute a complete workflow from task decomposition
*/
async executeWorkflow(decomposition) {
const startTime = Date.now();
this.context.logger.info('Starting workflow execution', {
request: decomposition.originalRequest,
subtasks: decomposition.subtasks.length,
strategy: decomposition.executionStrategy
});
const workflowContext = {
state: 'initializing',
completedTasks: {},
sharedData: {},
startTime
};
try {
workflowContext.state = 'executing';
let results;
let totalRetryCount = 0;
// Execute based on strategy
if (decomposition.executionStrategy === 'parallel') {
const parallelResults = await this.executeParallel(decomposition.subtasks, workflowContext);
results = parallelResults.results;
totalRetryCount = parallelResults.retryCount;
}
else {
const sequentialResults = await this.executeSequential(decomposition.subtasks, workflowContext);
results = sequentialResults.results;
totalRetryCount = sequentialResults.retryCount;
}
workflowContext.state = 'completed';
const executionTime = Date.now() - startTime;
const execution = {
success: true,
results,
executionTime,
retryCount: totalRetryCount,
context: workflowContext.sharedData,
metrics: this.calculateWorkflowMetrics(results, executionTime)
};
// Update statistics
this.updateStats(decomposition, execution);
// Store in history for learning
this.workflowHistory.push({
request: decomposition.originalRequest,
decomposition,
result: execution
});
this.context.logger.info('Workflow executed successfully', {
executionTime,
successfulTasks: results.filter(r => r.success).length,
totalTasks: results.length
});
return execution;
}
catch (error) {
workflowContext.state = 'failed';
workflowContext.errorInfo = {
taskId: workflowContext.currentTask || 'unknown',
error: error instanceof Error ? error.message : 'Unknown error',
timestamp: Date.now()
};
const executionTime = Date.now() - startTime;
const execution = {
success: false,
results: [],
executionTime,
retryCount: 0,
context: workflowContext.sharedData,
error: error instanceof Error ? error.message : 'Unknown error'
};
this.context.logger.error('Workflow execution failed', {
error: execution.error,
executionTime,
request: decomposition.originalRequest
});
return execution;
}
}
/**
* Select the most appropriate tool for a given intent
*/
selectTool(intent) {
this.context.logger.debug('Selecting tool for intent', { intent });
// Tool selection logic based on intent analysis
const { action, target, type } = intent;
// Search-related intents
if (action === 'search' || action === 'find') {
if (target.toLowerCase().includes('monobehaviour') || type === 'component') {
return 'find_monobehaviours';
}
if (type === 'enum' || target.toLowerCase().includes('enum')) {
return 'find_enum_values';
}
return 'search_code';
}
// Analysis-related intents
if (action === 'analyze') {
if (target.toLowerCase().includes('hierarchy') || target.toLowerCase().includes('inheritance')) {
return 'find_class_hierarchy';
}
if (target.toLowerCase().includes('dependencies') || target.toLowerCase().includes('dependency')) {
return 'analyze_dependencies';
}
if (target.toLowerCase().includes('pattern') || target.toLowerCase().includes('design')) {
return 'find_design_patterns';
}
if (target.toLowerCase().includes('reference') || target.toLowerCase().includes('usage')) {
return 'find_cross_references';
}
return 'analyze_dependencies'; // Default analysis tool
}
// Generation-related intents
if (action === 'generate') {
if (target.toLowerCase().includes('monobehaviour') || type === 'template') {
return 'generate_monobehaviour_template';
}
if (target.toLowerCase().includes('method') || target.toLowerCase().includes('stub')) {
return 'generate_method_stubs';
}
if (target.toLowerCase().includes('wrapper') || target.toLowerCase().includes('class')) {
return 'generate_class_wrapper';
}
return 'generate_class_wrapper'; // Default generation tool
}
// Default fallback
this.context.logger.warn('No specific tool found for intent, using default', { intent });
return 'search_code';
}
/**
* Get orchestrator statistics
*/
getStats() {
return { ...this.stats };
}
/**
* Clear cache and reset statistics
*/
reset() {
this.cache.clear();
this.workflowHistory = [];
this.stats = this.initializeStats();
this.context.logger.info('MCP Orchestrator reset');
}
// ============================================================================
// PRIVATE METHODS
// ============================================================================
/**
* Initialize orchestrator statistics
*/
initializeStats() {
return {
totalWorkflows: 0,
successfulWorkflows: 0,
averageExecutionTime: 0,
popularTools: [],
cacheStats: {
hits: 0,
misses: 0,
hitRate: 0
}
};
}
/**
* Analyze intent from natural language request
*/
analyzeIntent(request) {
const lowerRequest = request.toLowerCase();
// Extract action
let action = 'search';
if (lowerRequest.includes('find') || lowerRequest.includes('search') || lowerRequest.includes('look')) {
action = lowerRequest.includes('monobehaviour') ? 'find' : 'search';
}
else if (lowerRequest.includes('analyze') || lowerRequest.includes('analysis')) {
action = 'analyze';
}
else if (lowerRequest.includes('generate') || lowerRequest.includes('create')) {
action = 'generate';
}
else if (lowerRequest.includes('compare')) {
action = 'compare';
}
else if (lowerRequest.includes('list')) {
action = 'list';
}
// Extract target and type
const target = this.extractTarget(request);
const type = this.extractType(request);
// Extract filters
const filters = this.extractFilters(request);
// Extract keywords
const keywords = this.extractKeywords(request);
// Calculate confidence based on keyword matches and clarity
const confidence = this.calculateIntentConfidence(request, action, target, type);
return {
action,
target,
type,
filters,
confidence,
keywords
};
}
/**
* Extract target entity from request
*/
extractTarget(request) {
// Look for common class names, patterns
const classPatterns = /\b([A-Z][a-zA-Z]*(?:Manager|Controller|Player|Enemy|Game|UI|System)?)\b/g;
const matches = request.match(classPatterns);
if (matches && matches.length > 0) {
return matches[0];
}
// Fallback to first capitalized word
const capitalizedWords = request.match(/\b[A-Z][a-z]+\b/g);
return capitalizedWords ? capitalizedWords[0] : 'unknown';
}
/**
* Extract type from request
*/
extractType(request) {
const lowerRequest = request.toLowerCase();
if (lowerRequest.includes('class'))
return 'class';
if (lowerRequest.includes('method'))
return 'method';
if (lowerRequest.includes('enum'))
return 'enum';
if (lowerRequest.includes('interface'))
return 'interface';
if (lowerRequest.includes('monobehaviour') || lowerRequest.includes('component'))
return 'component';
if (lowerRequest.includes('template'))
return 'template';
if (lowerRequest.includes('wrapper'))
return 'wrapper';
if (lowerRequest.includes('stub'))
return 'stub';
return 'unknown';
}
/**
* Extract filters from request
*/
extractFilters(request) {
const filters = {};
const lowerRequest = request.toLowerCase();
if (lowerRequest.includes('monobehaviour')) {
filters.filter_monobehaviour = true;
}
// Extract namespace if mentioned
const namespaceMatch = request.match(/namespace\s+([a-zA-Z.]+)/i);
if (namespaceMatch) {
filters.filter_namespace = namespaceMatch[1];
}
return filters;
}
/**
* Extract keywords from request
*/
extractKeywords(request) {
// Remove common words and extract meaningful keywords
const commonWords = ['the', 'and', 'or', 'but', 'in', 'on', 'at', 'to', 'for', 'of', 'with', 'by', 'a', 'an'];
const words = request.toLowerCase().split(/\s+/);
return words
.filter(word => word.length > 2 && !commonWords.includes(word))
.filter(word => /^[a-zA-Z]+$/.test(word));
}
/**
* Calculate confidence score for intent analysis
*/
calculateIntentConfidence(request, action, target, type) {
let confidence = 0.5; // Base confidence
// Increase confidence for clear action words
const actionWords = ['find', 'search', 'analyze', 'generate', 'create'];
if (actionWords.some(word => request.toLowerCase().includes(word))) {
confidence += 0.2;
}
// Increase confidence for clear targets
if (target !== 'unknown' && target.length > 2) {
confidence += 0.2;
}
// Increase confidence for clear types
if (type !== 'unknown') {
confidence += 0.1;
}
return Math.min(confidence, 1.0);
}
/**
* Generate subtasks based on intent analysis
*/
generateSubtasks(intent, request) {
const subtasks = [];
// Handle complex requests that require multiple tools
if (this.isComplexRequest(request)) {
return this.generateComplexSubtasks(intent, request);
}
// Simple request - single tool
const toolName = this.selectTool(intent);
const parameters = this.generateToolParameters(intent, toolName);
subtasks.push({
id: 'task-1',
toolName,
parameters,
dependencies: [],
priority: 1,
description: `Execute ${toolName} for ${intent.target}`
});
return subtasks;
}
/**
* Check if request requires multiple tools
*/
isComplexRequest(request) {
const complexIndicators = [
'and', 'then', 'also', 'hierarchy', 'dependencies', 'generate',
'analyze.*and', 'find.*and.*analyze', 'search.*and.*generate'
];
return complexIndicators.some(indicator => new RegExp(indicator, 'i').test(request));
}
/**
* Generate subtasks for complex requests
*/
generateComplexSubtasks(intent, request) {
const subtasks = [];
const lowerRequest = request.toLowerCase();
// Pattern: Find class and analyze hierarchy
if (lowerRequest.includes('hierarchy') || lowerRequest.includes('inheritance')) {
subtasks.push({
id: 'task-1',
toolName: 'search_code',
parameters: { query: intent.target, filter_type: 'class' },
dependencies: [],
priority: 1,
description: `Find ${intent.target} class`
});
subtasks.push({
id: 'task-2',
toolName: 'find_class_hierarchy',
parameters: { class_name: '${task-1.className}' },
dependencies: ['task-1'],
priority: 2,
description: `Analyze class hierarchy for ${intent.target}`
});
}
// Pattern: Find class and analyze dependencies
if (lowerRequest.includes('dependencies') || lowerRequest.includes('dependency')) {
if (subtasks.length === 0) {
subtasks.push({
id: 'task-1',
toolName: 'search_code',
parameters: { query: intent.target, filter_type: 'class' },
dependencies: [],
priority: 1,
description: `Find ${intent.target} class`
});
}
subtasks.push({
id: `task-${subtasks.length + 1}`,
toolName: 'analyze_dependencies',
parameters: { class_name: '${task-1.className}' },
dependencies: ['task-1'],
priority: 2,
description: `Analyze dependencies for ${intent.target}`
});
}
// Pattern: Generate templates
if (lowerRequest.includes('generate') || lowerRequest.includes('template')) {
if (subtasks.length === 0) {
subtasks.push({
id: 'task-1',
toolName: 'search_code',
parameters: { query: intent.target, filter_type: 'class' },
dependencies: [],
priority: 1,
description: `Find ${intent.target} class`
});
}
const generationTool = lowerRequest.includes('monobehaviour')
? 'generate_monobehaviour_template'
: lowerRequest.includes('method')
? 'generate_method_stubs'
: 'generate_class_wrapper';
subtasks.push({
id: `task-${subtasks.length + 1}`,
toolName: generationTool,
parameters: { class_name: '${task-1.className}' },
dependencies: ['task-1'],
priority: 2,
description: `Generate template for ${intent.target}`
});
}
// Pattern: MonoBehaviour analysis
if (lowerRequest.includes('monobehaviour') && lowerRequest.includes('pattern')) {
subtasks.push({
id: 'task-1',
toolName: 'find_monobehaviours',
parameters: { query: intent.target },
dependencies: [],
priority: 1,
description: 'Find MonoBehaviour classes'
});
subtasks.push({
id: 'task-2',
toolName: 'find_design_patterns',
parameters: { pattern_types: ['singleton', 'observer', 'state'] },
dependencies: [],
priority: 1,
description: 'Analyze design patterns'
});
}
// If no complex patterns matched, fall back to simple
if (subtasks.length === 0) {
const toolName = this.selectTool(intent);
const parameters = this.generateToolParameters(intent, toolName);
subtasks.push({
id: 'task-1',
toolName,
parameters,
dependencies: [],
priority: 1,
description: `Execute ${toolName} for ${intent.target}`
});
}
return subtasks;
}
/**
* Generate parameters for a specific tool based on intent
*/
generateToolParameters(intent, toolName) {
const params = {};
switch (toolName) {
case 'search_code':
params.query = intent.target;
if (intent.type !== 'unknown') {
params.filter_type = intent.type;
}
if (intent.filters.filter_monobehaviour) {
params.filter_monobehaviour = true;
}
if (intent.filters.filter_namespace) {
params.filter_namespace = intent.filters.filter_namespace;
}
break;
case 'find_monobehaviours':
if (intent.target !== 'unknown') {
params.query = intent.target;
}
break;
case 'find_enum_values':
params.enum_name = intent.target;
break;
case 'find_class_hierarchy':
params.class_name = intent.target;
break;
case 'analyze_dependencies':
params.class_name = intent.target;
break;
case 'find_cross_references':
params.target_name = intent.target;
params.target_type = intent.type !== 'unknown' ? intent.type : 'class';
break;
case 'find_design_patterns':
params.pattern_types = ['singleton', 'observer', 'factory', 'strategy'];
break;
case 'generate_class_wrapper':
case 'generate_method_stubs':
case 'generate_monobehaviour_template':
params.class_name = intent.target;
break;
}
return params;
}
/**
* Determine execution strategy for subtasks
*/
determineExecutionStrategy(subtasks) {
// If any task has dependencies, use sequential
if (subtasks.some(task => task.dependencies.length > 0)) {
return 'sequential';
}
// If multiple independent tasks, use parallel
if (subtasks.length > 1) {
return 'parallel';
}
// Single task or simple workflow
return 'sequential';
}
/**
* Calculate estimated duration for workflow
*/
calculateEstimatedDuration(subtasks, strategy) {
const toolDurations = {
'search_code': 2000,
'find_monobehaviours': 3000,
'find_enum_values': 1500,
'find_class_hierarchy': 4000,
'analyze_dependencies': 5000,
'find_cross_references': 6000,
'find_design_patterns': 8000,
'generate_class_wrapper': 3000,
'generate_method_stubs': 4000,
'generate_monobehaviour_template': 3500
};
const taskDurations = subtasks.map(task => toolDurations[task.toolName] || 3000);
if (strategy === 'parallel') {
return Math.max(...taskDurations);
}
else {
return taskDurations.reduce((sum, duration) => sum + duration, 0);
}
}
/**
* Generate explanation for decomposition strategy
*/
generateDecompositionExplanation(subtasks, strategy) {
if (subtasks.length === 1) {
return `Single tool execution: ${subtasks[0].toolName}`;
}
if (strategy === 'parallel') {
return `Parallel execution of ${subtasks.length} independent tasks`;
}
return `Sequential execution of ${subtasks.length} dependent tasks`;
}
/**
* Execute subtasks in parallel
*/
async executeParallel(subtasks, context) {
this.context.logger.debug('Executing subtasks in parallel', { count: subtasks.length });
const promises = subtasks.map(async (subtask) => {
context.currentTask = subtask.id;
return await this.executeSubtask(subtask, context);
});
const results = await Promise.all(promises);
const totalRetryCount = results.reduce((sum, result) => sum + (result.retryCount || 0), 0);
return { results, retryCount: totalRetryCount };
}
/**
* Execute subtasks sequentially with dependency resolution
*/
async executeSequential(subtasks, context) {
this.context.logger.debug('Executing subtasks sequentially', { count: subtasks.length });
const results = [];
let totalRetryCount = 0;
// Sort by priority and dependencies
const sortedTasks = this.sortTasksByDependencies(subtasks);
for (const subtask of sortedTasks) {
context.currentTask = subtask.id;
// Resolve dependencies
const resolvedSubtask = this.resolveDependencies(subtask, context.completedTasks);
// Execute the subtask
const result = await this.executeSubtask(resolvedSubtask, context);
results.push(result);
totalRetryCount += result.retryCount || 0;
// Store result for dependency resolution
context.completedTasks[subtask.id] = result;
// If task failed and no retry succeeded, stop execution
if (!result.success) {
this.context.logger.error('Sequential execution stopped due to task failure', {
taskId: subtask.id,
error: result.error
});
break;
}
}
return { results, retryCount: totalRetryCount };
}
/**
* Execute a single subtask with retry logic
*/
async executeSubtask(subtask, context) {
const startTime = Date.now();
let lastError = null;
for (let attempt = 0; attempt <= this.config.retryAttempts; attempt++) {
try {
this.context.logger.debug('Executing subtask', {
taskId: subtask.id,
toolName: subtask.toolName,
attempt: attempt + 1
});
// Check cache first
const cacheKey = this.generateCacheKey(subtask);
if (this.config.enableCaching && this.cache.has(cacheKey)) {
this.stats.cacheStats.hits++;
const cachedResult = this.cache.get(cacheKey);
this.context.logger.debug('Cache hit for subtask', { taskId: subtask.id });
return {
...cachedResult,
executionTime: Date.now() - startTime,
retryCount: attempt
};
}
this.stats.cacheStats.misses++;
// Execute the tool
const result = await this.executeTool(subtask.toolName, subtask.parameters);
const executionResult = {
success: true,
data: result.data || [],
metadata: result.metadata || {},
executionTime: Date.now() - startTime,
retryCount: attempt
};
// Cache successful results
if (this.config.enableCaching) {
this.cache.set(cacheKey, executionResult);
}
this.context.logger.debug('Subtask executed successfully', {
taskId: subtask.id,
executionTime: executionResult.executionTime
});
return executionResult;
}
catch (error) {
lastError = error instanceof Error ? error : new Error('Unknown error');
this.context.logger.warn('Subtask execution failed', {
taskId: subtask.id,
attempt: attempt + 1,
error: lastError.message
});
// Wait before retry (exponential backoff)
if (attempt < this.config.retryAttempts) {
const delay = Math.pow(2, attempt) * 1000;
await new Promise(resolve => setTimeout(resolve, delay));
}
}
}
// All retries failed
return {
success: false,
data: [],
metadata: {},
error: lastError?.message || 'Unknown error',
executionTime: Date.now() - startTime,
retryCount: this.config.retryAttempts
};
}
/**
* Execute a specific MCP tool
*/
async executeTool(toolName, parameters) {
if (!(0, tool_registry_1.isValidTool)(toolName)) {
throw new Error(`Invalid tool name: ${toolName}`);
}
// This would integrate with the actual MCP tool execution
// For now, we'll simulate the execution
this.context.logger.debug('Executing MCP tool', { toolName, parameters });
// Simulate tool execution delay
await new Promise(resolve => setTimeout(resolve, 100));
// Return mock result for testing
return {
success: true,
data: [{ content: `Mock result for ${toolName}`, metadata: { toolName, parameters } }],
metadata: { resultCount: 1, toolName }
};
}
/**
* Sort tasks by dependencies and priority
*/
sortTasksByDependencies(subtasks) {
const sorted = [];
const remaining = [...subtasks];
while (remaining.length > 0) {
const readyTasks = remaining.filter(task => task.dependencies.every(dep => sorted.some(completed => completed.id === dep)));
if (readyTasks.length === 0) {
// Circular dependency or missing dependency
this.context.logger.warn('Circular or missing dependencies detected', {
remaining: remaining.map(t => ({ id: t.id, deps: t.dependencies }))
});
// Add remaining tasks anyway to prevent infinite loop
sorted.push(...remaining);
break;
}
// Sort ready tasks by priority
readyTasks.sort((a, b) => a.priority - b.priority);
// Add the highest priority task
const nextTask = readyTasks[0];
sorted.push(nextTask);
// Remove from remaining
const index = remaining.findIndex(t => t.id === nextTask.id);
remaining.splice(index, 1);
}
return sorted;
}
/**
* Resolve parameter dependencies using completed task results
*/
resolveDependencies(subtask, completedTasks) {
const resolvedParameters = { ...subtask.parameters };
// Look for dependency placeholders in parameters
for (const [key, value] of Object.entries(resolvedParameters)) {
if (typeof value === 'string' && value.startsWith('${') && value.endsWith('}')) {
const dependencyRef = value.slice(2, -1); // Remove ${ and }
const [taskId, property] = dependencyRef.split('.');
if (completedTasks[taskId]) {
const taskResult = completedTasks[taskId];
if (property && taskResult.metadata[property]) {
resolvedParameters[key] = taskResult.metadata[property];
}
else if (taskResult.data.length > 0 && taskResult.data[0].metadata) {
// Try to extract from first result's metadata
const firstResult = taskResult.data[0];
if (property && firstResult.metadata[property]) {
resolvedParameters[key] = firstResult.metadata[property];
}
else {
// Fallback: use the target from the original subtask
resolvedParameters[key] = subtask.parameters.class_name || 'Unknown';
}
}
}
}
}
return {
...subtask,
parameters: resolvedParameters
};
}
/**
* Generate cache key for subtask
*/
generateCacheKey(subtask) {
const paramString = JSON.stringify(subtask.parameters);
return `${subtask.toolName}:${paramString}`;
}
/**
* Calculate workflow metrics
*/
calculateWorkflowMetrics(results, totalExecutionTime) {
const successfulExecutions = results.filter(r => r.success).length;
const failedExecutions = results.length - successfulExecutions;
const averageExecutionTime = results.reduce((sum, r) => sum + (r.executionTime || 0), 0) / results.length;
return {
toolsExecuted: results.length,
successfulExecutions,
failedExecutions,
averageExecutionTime,
cacheHitRate: this.stats.cacheStats.hits / (this.stats.cacheStats.hits + this.stats.cacheStats.misses)
};
}
/**
* Update orchestrator statistics
*/
updateStats(decomposition, execution) {
this.stats.totalWorkflows++;
if (execution.success) {
this.stats.successfulWorkflows++;
}
// Update average execution time
const totalTime = this.stats.averageExecutionTime * (this.stats.totalWorkflows - 1) + execution.executionTime;
this.stats.averageExecutionTime = totalTime / this.stats.totalWorkflows;
// Update popular tools
for (const subtask of decomposition.subtasks) {
const existingTool = this.stats.popularTools.find(t => t.toolName === subtask.toolName);
if (existingTool) {
existingTool.usageCount++;
}
else {
this.stats.popularTools.push({
toolName: subtask.toolName,
usageCount: 1,
successRate: 1.0
});
}
}
// Sort popular tools by usage
this.stats.popularTools.sort((a, b) => b.usageCount - a.usageCount);
// Update cache stats
this.stats.cacheStats.hitRate = this.stats.cacheStats.hits / (this.stats.cacheStats.hits + this.stats.cacheStats.misses);
}
}
exports.MCPOrchestrator = MCPOrchestrator;
//# sourceMappingURL=mcp-orchestrator.js.map