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

759 lines (663 loc) 25.4 kB
/** * Task Engine Frontend Service * * Main service that orchestrates the reworked frontend architecture, * using active agent detection and MCP communication for all task operations. */ import { taskOperationRouter, OPERATION_TYPES } from './task-operation-router.js'; import { mcpCommunicationLayer, MCP_TOOLS } from './mcp-communication-layer.js'; import { activeAgentDetector } from './active-agent-detector.js'; import { enhancedTaskOperations } from './enhanced-task-operations.js'; import { performanceOptimizationEngine } from './performance-optimization-engine.js'; import { logger } from '../utils/logger-utils.js'; /** * Service States */ export const SERVICE_STATES = { INITIALIZING: 'initializing', READY: 'ready', BUSY: 'busy', ERROR: 'error', DISCONNECTED: 'disconnected' }; /** * Task Engine Frontend Service Class * * Provides a unified interface for all task management operations, * leveraging the active agent pattern and MCP middleware. */ export class TaskEngineFrontendService { constructor(options = {}) { this.options = { enableLogging: options.enableLogging ?? true, autoInitialize: options.autoInitialize ?? true, projectRoot: options.projectRoot, sessionTimeout: options.sessionTimeout ?? 3600000, // 1 hour enableEnhancedOperations: options.enableEnhancedOperations ?? true, enablePerformanceOptimization: options.enablePerformanceOptimization ?? true, ...options }; this.state = SERVICE_STATES.INITIALIZING; this.session = null; this.projectContext = null; this.operationQueue = []; this.isProcessingQueue = false; this.serviceStats = { operationsCompleted: 0, operationsFailed: 0, activeAgentOperations: 0, fallbackOperations: 0, enhancedOperations: 0, optimizedOperations: 0, startTime: Date.now() }; if (this.options.autoInitialize) { this.initialize(); } } /** * Initialize the frontend service * @param {Object} session - MCP session object * @param {Object} projectContext - Project context information * @returns {Promise<Object>} Initialization result */ async initialize(session = null, projectContext = null) { try { if (this.options.enableLogging) { logger.info('Initializing Task Engine Frontend Service'); } this.state = SERVICE_STATES.INITIALIZING; this.session = session; this.projectContext = projectContext || this.detectProjectContext(); // Validate project root if (!this.options.projectRoot && !this.projectContext?.projectRoot) { throw new Error('Project root must be specified for Task Engine operations'); } // Test MCP connection await this.testMCPConnection(); // Detect active agent capabilities const agentDetection = await activeAgentDetector.detectActiveAgent( this.session, { projectContext: this.projectContext } ); this.state = SERVICE_STATES.READY; if (this.options.enableLogging) { logger.info('Task Engine Frontend Service initialized successfully', { agentDetected: agentDetection.result, strategy: agentDetection.strategy, projectRoot: this.getProjectRoot() }); } return { success: true, state: this.state, agentDetection, projectRoot: this.getProjectRoot() }; } catch (error) { this.state = SERVICE_STATES.ERROR; logger.error('Failed to initialize Task Engine Frontend Service', { error: error.message }); return { success: false, error: error.message, state: this.state }; } } /** * Create a new task * @param {Object} taskData - Task creation data * @param {Object} options - Creation options * @returns {Promise<Object>} Creation result */ async createTask(taskData, options = {}) { return this.executeOperation(OPERATION_TYPES.CREATE_TASK, { projectRoot: this.getProjectRoot(), ...taskData }, options); } /** * Get all tasks * @param {Object} filters - Task filters * @param {Object} options - Query options * @returns {Promise<Object>} Tasks result */ async getTasks(filters = {}, options = {}) { return this.executeOperation(OPERATION_TYPES.GET_TASKS, { projectRoot: this.getProjectRoot(), ...filters }, options); } /** * Get a specific task * @param {string|number} taskId - Task ID * @param {Object} options - Query options * @returns {Promise<Object>} Task result */ async getTask(taskId, options = {}) { return this.executeOperation(OPERATION_TYPES.GET_TASK, { projectRoot: this.getProjectRoot(), id: taskId.toString() }, options); } /** * Update a task * @param {string|number} taskId - Task ID * @param {Object} updateData - Update data * @param {Object} options - Update options * @returns {Promise<Object>} Update result */ async updateTask(taskId, updateData, options = {}) { return this.executeOperation(OPERATION_TYPES.UPDATE_TASK, { projectRoot: this.getProjectRoot(), id: taskId.toString(), ...updateData }, options); } /** * Set task status * @param {string|number} taskId - Task ID * @param {string} status - New status * @param {Object} options - Status update options * @returns {Promise<Object>} Status update result */ async setTaskStatus(taskId, status, options = {}) { return this.executeOperation(OPERATION_TYPES.SET_STATUS, { projectRoot: this.getProjectRoot(), id: taskId.toString(), status }, options); } /** * Expand a task into subtasks * @param {string|number} taskId - Task ID * @param {Object} expansionData - Expansion parameters * @param {Object} options - Expansion options * @returns {Promise<Object>} Expansion result */ async expandTask(taskId, expansionData = {}, options = {}) { return this.executeOperation(OPERATION_TYPES.EXPAND_TASK, { projectRoot: this.getProjectRoot(), taskId: taskId.toString(), ...expansionData }, options); } /** * Analyze task complexity * @param {Object} analysisData - Analysis parameters * @param {Object} options - Analysis options * @returns {Promise<Object>} Analysis result */ async analyzeTaskComplexity(analysisData = {}, options = {}) { return this.executeOperation(OPERATION_TYPES.ANALYZE_TASK, { projectRoot: this.getProjectRoot(), ...analysisData }, options); } /** * Execute a task operation through the routing system * @param {string} operationType - Type of operation * @param {Object} operationData - Operation data * @param {Object} options - Execution options * @returns {Promise<Object>} Operation result */ async executeOperation(operationType, operationData, options = {}) { try { // Check service state if (this.state !== SERVICE_STATES.READY) { throw new Error(`Service not ready. Current state: ${this.state}`); } this.state = SERVICE_STATES.BUSY; if (this.options.enableLogging) { logger.info('Executing task operation', { operationType, dataKeys: Object.keys(operationData), enhancedMode: this.options.enableEnhancedOperations, optimizedMode: this.options.enablePerformanceOptimization }); } let result; // Use enhanced operations if enabled and available if (this.options.enableEnhancedOperations && this.isEnhancedOperationSupported(operationType)) { result = await this.executeEnhancedOperation(operationType, operationData, options); this.serviceStats.enhancedOperations++; } else { // Fall back to standard routing result = await taskOperationRouter.routeOperation( operationType, operationData, this.session, { projectContext: this.projectContext, serviceOptions: this.options, ...options } ); } // Update statistics this.updateOperationStats(result); this.state = SERVICE_STATES.READY; if (this.options.enableLogging) { logger.info('Task operation completed', { operationType, success: result.success, strategy: result.routingInfo?.strategy || result.operationMetadata?.flowType, enhanced: !!result.operationMetadata, optimized: !!result.optimizationMetadata }); } return result; } catch (error) { this.state = SERVICE_STATES.ERROR; this.serviceStats.operationsFailed++; logger.error('Task operation failed', { operationType, error: error.message }); return { success: false, error: error.message, operationType, timestamp: Date.now() }; } } /** * Execute operation using enhanced task operations * @param {string} operationType - Operation type * @param {Object} operationData - Operation data * @param {Object} options - Execution options * @returns {Promise<Object>} Enhanced operation result */ async executeEnhancedOperation(operationType, operationData, options) { // Wrap enhanced operation with performance optimization if enabled if (this.options.enablePerformanceOptimization) { return performanceOptimizationEngine.optimizeOperation( operationType, operationData, () => this.callEnhancedOperation(operationType, operationData, options), options ); } else { return this.callEnhancedOperation(operationType, operationData, options); } } /** * Call enhanced operation directly * @param {string} operationType - Operation type * @param {Object} operationData - Operation data * @param {Object} options - Execution options * @returns {Promise<Object>} Operation result */ async callEnhancedOperation(operationType, operationData, options) { switch (operationType) { case OPERATION_TYPES.CREATE_TASK: return enhancedTaskOperations.createTask(operationData, this.session, options); case OPERATION_TYPES.GET_TASKS: return enhancedTaskOperations.getTasks(operationData, this.session, options); case OPERATION_TYPES.UPDATE_TASK: return enhancedTaskOperations.updateTask( operationData.id, operationData, this.session, options ); case OPERATION_TYPES.SET_STATUS: return enhancedTaskOperations.setTaskStatus( operationData.id, operationData.status, this.session, options ); case OPERATION_TYPES.EXPAND_TASK: return enhancedTaskOperations.expandTask( operationData.taskId || operationData.id, operationData, this.session, options ); default: // Fall back to standard routing for unsupported operations return taskOperationRouter.routeOperation( operationType, operationData, this.session, { projectContext: this.projectContext, serviceOptions: this.options, ...options } ); } } /** * Check if enhanced operation is supported * @param {string} operationType - Operation type * @returns {boolean} True if supported */ isEnhancedOperationSupported(operationType) { const supportedOperations = [ OPERATION_TYPES.CREATE_TASK, OPERATION_TYPES.GET_TASKS, OPERATION_TYPES.UPDATE_TASK, OPERATION_TYPES.SET_STATUS, OPERATION_TYPES.EXPAND_TASK ]; return supportedOperations.includes(operationType); } /** * Queue an operation for batch processing * @param {string} operationType - Type of operation * @param {Object} operationData - Operation data * @param {Object} options - Execution options * @returns {Promise<string>} Operation ID for tracking */ async queueOperation(operationType, operationData, options = {}) { const operationId = this.generateOperationId(); this.operationQueue.push({ id: operationId, type: operationType, data: operationData, options, timestamp: Date.now(), status: 'queued' }); if (this.options.enableLogging) { logger.debug('Operation queued', { operationId, operationType, queueLength: this.operationQueue.length }); } // Start processing queue if not already processing if (!this.isProcessingQueue) { this.processOperationQueue(); } return operationId; } /** * Process queued operations */ async processOperationQueue() { if (this.isProcessingQueue || this.operationQueue.length === 0) { return; } this.isProcessingQueue = true; try { while (this.operationQueue.length > 0) { const operation = this.operationQueue.shift(); operation.status = 'processing'; try { const result = await this.executeOperation( operation.type, operation.data, operation.options ); operation.status = result.success ? 'completed' : 'failed'; operation.result = result; } catch (error) { operation.status = 'failed'; operation.error = error.message; } if (this.options.enableLogging) { logger.debug('Queued operation processed', { operationId: operation.id, status: operation.status }); } } } finally { this.isProcessingQueue = false; } } /** * Test MCP connection * @returns {Promise<boolean>} Connection test result */ async testMCPConnection() { try { const result = await mcpCommunicationLayer.callTool( MCP_TOOLS.GET_TASKS, { projectRoot: this.getProjectRoot() }, this.session, { timeout: 5000 } ); return result.success; } catch (error) { if (this.options.enableLogging) { logger.warn('MCP connection test failed', { error: error.message }); } return false; } } /** * Detect project context from environment * @returns {Object} Project context */ detectProjectContext() { // This would implement actual project detection logic return { projectRoot: this.options.projectRoot || process.cwd(), projectType: 'task-engine', detectedAt: Date.now() }; } /** * Get project root directory * @returns {string} Project root path */ getProjectRoot() { return this.options.projectRoot || this.projectContext?.projectRoot || process.cwd(); } /** * Update operation statistics * @param {Object} result - Operation result */ updateOperationStats(result) { this.serviceStats.operationsCompleted++; // Track routing strategy if (result.routingInfo?.strategy === 'active_agent') { this.serviceStats.activeAgentOperations++; } else { this.serviceStats.fallbackOperations++; } // Track enhanced operations if (result.operationMetadata) { this.serviceStats.enhancedOperations++; } // Track optimized operations if (result.optimizationMetadata) { this.serviceStats.optimizedOperations++; } } /** * Generate unique operation ID * @returns {string} Operation ID */ generateOperationId() { return `op_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`; } /** * Get service status and statistics * @returns {Object} Service status */ getStatus() { const baseStatus = { state: this.state, stats: { ...this.serviceStats }, projectRoot: this.getProjectRoot(), queueLength: this.operationQueue.length, isProcessingQueue: this.isProcessingQueue, uptime: Date.now() - this.serviceStats.startTime, mcpStats: mcpCommunicationLayer.getStats(), routingStats: taskOperationRouter.getRoutingStats(), enhancedOperationsEnabled: this.options.enableEnhancedOperations, performanceOptimizationEnabled: this.options.enablePerformanceOptimization }; // Add enhanced operation statistics if enabled if (this.options.enableEnhancedOperations) { baseStatus.enhancedOperationStats = enhancedTaskOperations.getOperationStats(); } // Add performance optimization statistics if enabled if (this.options.enablePerformanceOptimization) { baseStatus.performanceStats = performanceOptimizationEngine.getPerformanceMetrics(); } return baseStatus; } /** * Shutdown the service gracefully * @returns {Promise<void>} */ async shutdown() { if (this.options.enableLogging) { logger.info('Shutting down Task Engine Frontend Service'); } this.state = SERVICE_STATES.DISCONNECTED; // Wait for queue to finish processing while (this.isProcessingQueue) { await new Promise(resolve => setTimeout(resolve, 100)); } // Clear caches mcpCommunicationLayer.clearCache(); activeAgentDetector.clearCache(); if (this.options.enableLogging) { logger.info('Task Engine Frontend Service shutdown complete'); } } } /** * Default service instance */ export const taskEngineFrontendService = new TaskEngineFrontendService(); /** * Convenience functions for common operations * These functions now route through the service manager for better architecture integration */ export async function createTask(taskData, options) { // Check if service manager is available for enhanced routing try { const { frontendServiceManager } = await import('./frontend-service-manager.js'); if (frontendServiceManager.state === 'ready') { return frontendServiceManager.handleOperation('CREATE_TASK', { projectRoot: taskData.projectRoot || process.cwd(), ...taskData }, options); } } catch (error) { // Fall back to direct service if manager not available } return taskEngineFrontendService.createTask(taskData, options); } export async function getTasks(filters, options) { try { const { frontendServiceManager } = await import('./frontend-service-manager.js'); if (frontendServiceManager.state === 'ready') { return frontendServiceManager.handleOperation('GET_TASKS', { projectRoot: filters?.projectRoot || process.cwd(), ...filters }, options); } } catch (error) { // Fall back to direct service } return taskEngineFrontendService.getTasks(filters, options); } export async function getTask(taskId, options) { try { const { frontendServiceManager } = await import('./frontend-service-manager.js'); if (frontendServiceManager.state === 'ready') { return frontendServiceManager.handleOperation('GET_TASK', { projectRoot: options?.projectRoot || process.cwd(), id: taskId.toString() }, options); } } catch (error) { // Fall back to direct service } return taskEngineFrontendService.getTask(taskId, options); } export async function updateTask(taskId, updateData, options) { try { const { frontendServiceManager } = await import('./frontend-service-manager.js'); if (frontendServiceManager.state === 'ready') { return frontendServiceManager.handleOperation('UPDATE_TASK', { projectRoot: updateData.projectRoot || process.cwd(), id: taskId.toString(), ...updateData }, options); } } catch (error) { // Fall back to direct service } return taskEngineFrontendService.updateTask(taskId, updateData, options); } export async function setTaskStatus(taskId, status, options) { try { const { frontendServiceManager } = await import('./frontend-service-manager.js'); if (frontendServiceManager.state === 'ready') { return frontendServiceManager.handleOperation('SET_STATUS', { projectRoot: options?.projectRoot || process.cwd(), id: taskId.toString(), status }, options); } } catch (error) { // Fall back to direct service } return taskEngineFrontendService.setTaskStatus(taskId, status, options); } export async function expandTask(taskId, expansionData, options) { try { const { frontendServiceManager } = await import('./frontend-service-manager.js'); if (frontendServiceManager.state === 'ready') { return frontendServiceManager.handleOperation('EXPAND_TASK', { projectRoot: expansionData.projectRoot || process.cwd(), taskId: taskId.toString(), ...expansionData }, options); } } catch (error) { // Fall back to direct service } return taskEngineFrontendService.expandTask(taskId, expansionData, options); } export async function initializeService(session, projectContext) { // Try to initialize through service manager for enhanced capabilities try { const { frontendServiceManager } = await import('./frontend-service-manager.js'); const managerResult = await frontendServiceManager.initialize(session, projectContext); if (managerResult.success) { return { ...managerResult, enhancedMode: true, migrationInfo: { phase: managerResult.migrationPhase, readinessScore: managerResult.migrationAssessment?.readinessScore } }; } } catch (error) { // Fall back to direct service initialization logger.debug('Service manager not available, using direct service initialization'); } return taskEngineFrontendService.initialize(session, projectContext); } export async function getServiceStatus() { // Try to get enhanced status from service manager try { const { frontendServiceManager } = await import('./frontend-service-manager.js'); if (frontendServiceManager.state === 'ready') { const managerStatus = frontendServiceManager.getStatus(); return { ...managerStatus, enhancedMode: true, directServiceStatus: taskEngineFrontendService.getStatus() }; } } catch (error) { // Fall back to direct service status } return taskEngineFrontendService.getStatus(); }