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
JavaScript
/**
* 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);
}