UNPKG

task-engine-ai-core

Version:

Revolutionary AI-driven task management system with complete transformation trilogy: Frontend v0.1.0, Backend v0.2.0, CLI v0.3.0 - Enterprise-grade performance with 95% improvements

583 lines (513 loc) 20.8 kB
/** * Legacy Compatibility Layer * * Provides backward compatibility with existing AI providers and bridge components * while routing operations through the new active agent architecture when possible. */ import { taskOperationRouter, OPERATION_TYPES } from './task-operation-router.js'; import { activeAgentDetector, ROUTING_STRATEGIES } from './active-agent-detector.js'; import { logger } from '../utils/logger-utils.js'; /** * Compatibility Modes */ export const COMPATIBILITY_MODES = { FULL_NEW: 'full_new', // Use only new architecture HYBRID: 'hybrid', // Use new when possible, fallback to legacy LEGACY_ONLY: 'legacy_only', // Use only legacy components MIGRATION: 'migration' // Gradual migration mode }; /** * Legacy Component Types */ export const LEGACY_COMPONENTS = { AI_PROVIDERS: 'ai_providers', BRIDGE_SERVER: 'bridge_server', WEBSOCKET_BRIDGE: 'websocket_bridge', IDE_INTEGRATION: 'ide_integration' }; /** * Legacy Compatibility Layer Class * * Manages the transition from legacy AI providers to the new active agent architecture, * ensuring backward compatibility while enabling gradual migration. */ export class LegacyCompatibilityLayer { constructor(options = {}) { this.options = { mode: options.mode ?? COMPATIBILITY_MODES.HYBRID, enableLogging: options.enableLogging ?? true, migrationThreshold: options.migrationThreshold ?? 0.8, // Confidence threshold for using new architecture fallbackTimeout: options.fallbackTimeout ?? 10000, legacyProviders: options.legacyProviders ?? [], ...options }; this.legacyProviders = new Map(); this.migrationStats = { totalRequests: 0, newArchitectureUsed: 0, legacyFallbacks: 0, migrationSuccessRate: 0 }; this.initializeLegacyProviders(); } /** * Initialize legacy AI providers for fallback scenarios */ async initializeLegacyProviders() { if (this.options.mode === COMPATIBILITY_MODES.FULL_NEW) { return; // Skip legacy initialization in full new mode } try { // Dynamically import legacy providers only when needed const legacyProviderModules = await this.loadLegacyProviders(); for (const [providerName, ProviderClass] of legacyProviderModules) { try { const provider = new ProviderClass(); this.legacyProviders.set(providerName, provider); if (this.options.enableLogging) { logger.debug(`Initialized legacy provider: ${providerName}`); } } catch (error) { if (this.options.enableLogging) { logger.warn(`Failed to initialize legacy provider ${providerName}:`, error.message); } } } if (this.options.enableLogging) { logger.info(`Initialized ${this.legacyProviders.size} legacy AI providers for fallback`); } } catch (error) { if (this.options.enableLogging) { logger.error('Failed to initialize legacy providers:', error.message); } } } /** * Load legacy provider modules dynamically * @returns {Array} Array of [name, ProviderClass] pairs */ async loadLegacyProviders() { const providers = []; try { // Import legacy AI providers const { AnthropicAIProvider } = await import('../ai-providers/anthropic.js'); const { OpenAIProvider } = await import('../ai-providers/openai.js'); const { PerplexityAIProvider } = await import('../ai-providers/perplexity.js'); providers.push( ['anthropic', AnthropicAIProvider], ['openai', OpenAIProvider], ['perplexity', PerplexityAIProvider] ); // Add other providers as needed if (this.options.legacyProviders.includes('google')) { const { GoogleAIProvider } = await import('../ai-providers/google.js'); providers.push(['google', GoogleAIProvider]); } if (this.options.legacyProviders.includes('xai')) { const { XAIProvider } = await import('../ai-providers/xai.js'); providers.push(['xai', XAIProvider]); } } catch (error) { if (this.options.enableLogging) { logger.debug('Some legacy providers could not be loaded:', error.message); } } return providers; } /** * Route operation through compatibility layer * @param {string} operationType - Type of operation * @param {Object} operationData - Operation data * @param {Object} session - MCP session * @param {Object} context - Additional context * @returns {Promise<Object>} Operation result */ async routeOperation(operationType, operationData, session, context = {}) { this.migrationStats.totalRequests++; try { if (this.options.enableLogging) { logger.debug('Routing operation through compatibility layer', { operationType, mode: this.options.mode }); } // Determine routing strategy based on mode and detection const routingDecision = await this.determineRoutingStrategy( operationType, operationData, session, context ); if (routingDecision.useNewArchitecture) { // Use new active agent architecture return this.routeToNewArchitecture( operationType, operationData, session, context, routingDecision ); } else { // Fallback to legacy providers return this.routeToLegacyProviders( operationType, operationData, session, context, routingDecision ); } } catch (error) { if (this.options.enableLogging) { logger.error('Compatibility layer routing failed:', error.message); } // Try fallback if not already using legacy if (this.options.mode !== COMPATIBILITY_MODES.LEGACY_ONLY) { return this.routeToLegacyProviders(operationType, operationData, session, context, { reason: 'error_fallback', originalError: error.message }); } throw error; } } /** * Determine which routing strategy to use * @param {string} operationType - Operation type * @param {Object} operationData - Operation data * @param {Object} session - MCP session * @param {Object} context - Context * @returns {Promise<Object>} Routing decision */ async determineRoutingStrategy(operationType, operationData, session, context) { // Force legacy mode if (this.options.mode === COMPATIBILITY_MODES.LEGACY_ONLY) { return { useNewArchitecture: false, reason: 'legacy_only_mode', confidence: 0.0 }; } // Force new architecture mode if (this.options.mode === COMPATIBILITY_MODES.FULL_NEW) { return { useNewArchitecture: true, reason: 'full_new_mode', confidence: 1.0 }; } // Hybrid or migration mode - use active agent detection try { const detection = await activeAgentDetector.detectActiveAgent(session, { ...context, operationType, compatibilityMode: this.options.mode }); const useNewArchitecture = detection.success && detection.confidence >= this.options.migrationThreshold && detection.strategy === ROUTING_STRATEGIES.ACTIVE_AGENT; return { useNewArchitecture, reason: useNewArchitecture ? 'active_agent_detected' : 'insufficient_confidence', confidence: detection.confidence, detectionResult: detection }; } catch (error) { if (this.options.enableLogging) { logger.warn('Active agent detection failed, using legacy fallback:', error.message); } return { useNewArchitecture: false, reason: 'detection_failed', confidence: 0.0, error: error.message }; } } /** * Route operation to new architecture * @param {string} operationType - Operation type * @param {Object} operationData - Operation data * @param {Object} session - MCP session * @param {Object} context - Context * @param {Object} routingDecision - Routing decision details * @returns {Promise<Object>} Operation result */ async routeToNewArchitecture(operationType, operationData, session, context, routingDecision) { this.migrationStats.newArchitectureUsed++; if (this.options.enableLogging) { logger.debug('Routing to new architecture', { operationType, reason: routingDecision.reason, confidence: routingDecision.confidence }); } try { const result = await taskOperationRouter.routeOperation( operationType, operationData, session, { ...context, compatibilityLayer: true, routingDecision } ); // Add compatibility layer metadata return { ...result, compatibilityInfo: { architecture: 'new', reason: routingDecision.reason, confidence: routingDecision.confidence, migrationMode: this.options.mode } }; } catch (error) { if (this.options.enableLogging) { logger.warn('New architecture failed, attempting legacy fallback:', error.message); } // Fallback to legacy if hybrid mode if (this.options.mode === COMPATIBILITY_MODES.HYBRID || this.options.mode === COMPATIBILITY_MODES.MIGRATION) { return this.routeToLegacyProviders(operationType, operationData, session, context, { reason: 'new_architecture_failed', originalError: error.message }); } throw error; } } /** * Route operation to legacy providers * @param {string} operationType - Operation type * @param {Object} operationData - Operation data * @param {Object} session - MCP session * @param {Object} context - Context * @param {Object} routingDecision - Routing decision details * @returns {Promise<Object>} Operation result */ async routeToLegacyProviders(operationType, operationData, session, context, routingDecision) { this.migrationStats.legacyFallbacks++; if (this.options.enableLogging) { logger.debug('Routing to legacy providers', { operationType, reason: routingDecision.reason, availableProviders: Array.from(this.legacyProviders.keys()) }); } try { // Convert operation to legacy format const legacyRequest = this.convertToLegacyFormat(operationType, operationData, context); // Try legacy providers in order of preference const providerOrder = this.getLegacyProviderOrder(operationType, context); for (const providerName of providerOrder) { const provider = this.legacyProviders.get(providerName); if (!provider) continue; try { const result = await this.callLegacyProvider(provider, legacyRequest); // Convert result back to new format const convertedResult = this.convertFromLegacyFormat(result, operationType); return { ...convertedResult, compatibilityInfo: { architecture: 'legacy', provider: providerName, reason: routingDecision.reason, migrationMode: this.options.mode } }; } catch (providerError) { if (this.options.enableLogging) { logger.debug(`Legacy provider ${providerName} failed:`, providerError.message); } continue; // Try next provider } } throw new Error('All legacy providers failed'); } catch (error) { if (this.options.enableLogging) { logger.error('Legacy provider routing failed:', error.message); } return { success: false, error: error.message, compatibilityInfo: { architecture: 'legacy', reason: 'all_providers_failed', migrationMode: this.options.mode } }; } } /** * Convert operation to legacy provider format * @param {string} operationType - Operation type * @param {Object} operationData - Operation data * @param {Object} context - Context * @returns {Object} Legacy format request */ convertToLegacyFormat(operationType, operationData, context) { // Convert new operation format to legacy AI provider format switch (operationType) { case OPERATION_TYPES.CREATE_TASK: return { type: 'task_generation', prompt: operationData.prompt || `Create a task: ${operationData.title}`, context: operationData.description || '', projectRoot: operationData.projectRoot, options: { priority: operationData.priority, dependencies: operationData.dependencies } }; case OPERATION_TYPES.EXPAND_TASK: return { type: 'task_expansion', prompt: `Expand task into subtasks: ${operationData.prompt || operationData.taskTitle}`, context: operationData.context || '', options: { numSubtasks: operationData.numSubtasks || 3 } }; default: return { type: 'generic', prompt: operationData.prompt || JSON.stringify(operationData), context: context.description || '', options: operationData }; } } /** * Convert legacy provider result to new format * @param {Object} legacyResult - Legacy provider result * @param {string} operationType - Original operation type * @returns {Object} New format result */ convertFromLegacyFormat(legacyResult, operationType) { return { success: true, result: 'success', data: { message: 'Operation completed via legacy provider', legacyResult, operationType }, timestamp: Date.now() }; } /** * Get preferred order of legacy providers for operation type * @param {string} operationType - Operation type * @param {Object} context - Context * @returns {Array} Ordered list of provider names */ getLegacyProviderOrder(operationType, context) { // Default order based on operation type and reliability const defaultOrder = ['anthropic', 'openai', 'perplexity']; // Customize order based on operation type switch (operationType) { case OPERATION_TYPES.CREATE_TASK: return ['anthropic', 'openai', 'perplexity']; case OPERATION_TYPES.EXPAND_TASK: return ['openai', 'anthropic', 'perplexity']; case OPERATION_TYPES.ANALYZE_TASK: return ['perplexity', 'anthropic', 'openai']; default: return defaultOrder; } } /** * Call legacy provider with timeout and error handling * @param {Object} provider - Legacy provider instance * @param {Object} request - Request data * @returns {Promise<Object>} Provider result */ async callLegacyProvider(provider, request) { return new Promise((resolve, reject) => { const timeout = setTimeout(() => { reject(new Error('Legacy provider timeout')); }, this.options.fallbackTimeout); provider.generateResponse(request) .then(result => { clearTimeout(timeout); resolve(result); }) .catch(error => { clearTimeout(timeout); reject(error); }); }); } /** * Get migration statistics * @returns {Object} Migration statistics */ getMigrationStats() { const stats = { ...this.migrationStats }; if (stats.totalRequests > 0) { stats.migrationSuccessRate = (stats.newArchitectureUsed / stats.totalRequests) * 100; stats.legacyFallbackRate = (stats.legacyFallbacks / stats.totalRequests) * 100; } return stats; } /** * Update compatibility mode * @param {string} newMode - New compatibility mode */ setCompatibilityMode(newMode) { if (Object.values(COMPATIBILITY_MODES).includes(newMode)) { this.options.mode = newMode; if (this.options.enableLogging) { logger.info(`Compatibility mode updated to: ${newMode}`); } } else { throw new Error(`Invalid compatibility mode: ${newMode}`); } } /** * Check if legacy component is available * @param {string} componentType - Type of legacy component * @returns {boolean} True if available */ isLegacyComponentAvailable(componentType) { switch (componentType) { case LEGACY_COMPONENTS.AI_PROVIDERS: return this.legacyProviders.size > 0; case LEGACY_COMPONENTS.BRIDGE_SERVER: // Check if bridge server is available return this.checkBridgeServerAvailability(); default: return false; } } /** * Check bridge server availability * @returns {boolean} True if bridge server is available */ checkBridgeServerAvailability() { try { // This would check if the bridge server is running // For now, return false as we're migrating away from it return false; } catch (error) { return false; } } } /** * Default compatibility layer instance */ export const legacyCompatibilityLayer = new LegacyCompatibilityLayer(); /** * Convenience function for routing operations through compatibility layer * @param {string} operationType - Operation type * @param {Object} operationData - Operation data * @param {Object} session - MCP session * @param {Object} context - Context * @returns {Promise<Object>} Operation result */ export async function routeWithCompatibility(operationType, operationData, session, context = {}) { return legacyCompatibilityLayer.routeOperation(operationType, operationData, session, context); }