UNPKG

task-master-neo-sdlc

Version:

Enhanced task management system with Neo SDLC agents and MCP tools for comprehensive, AI-driven software development lifecycle management.

408 lines (353 loc) 16.9 kB
import { KnowledgeGraph } from './knowledge-graph.js'; import { AgentWorkflowSystem } from './agent-workflow.js'; import { ChainSystem } from './chain-system.js'; import { MonitoringSystem } from './monitoring.js'; import { DesignSystemManager } from './design-system-manager.js'; import { log } from '../../utils/logging.js'; export class NeoOrchestrator { constructor() { this.knowledgeGraph = new KnowledgeGraph(); this.agentWorkflow = new AgentWorkflowSystem(this.knowledgeGraph); this.chainSystem = new ChainSystem(this.knowledgeGraph); this.monitoring = new MonitoringSystem(this.knowledgeGraph); this.designSystem = new DesignSystemManager(this.knowledgeGraph); this.initialized = false; this.log = console; } async initialize() { if (this.initialized) { throw new Error('Neo Orchestrator already initialized'); } try { // Initialize core systems await this.knowledgeGraph.initialize(); await this.agentWorkflow.initialize(); await this.chainSystem.initialize(); await this.monitoring.initialize(); await this.designSystem.initialize(); // Register orchestrator node await this.knowledgeGraph.addNode({ id: 'neo-orchestrator', type: 'system', data: { status: 'active', version: '1.0.0', systems: ['knowledge-graph', 'agent-workflow', 'chain-system', 'monitoring', 'design-system'] } }); this.initialized = true; log.info('Neo Orchestrator initialized successfully'); } catch (error) { log.error('Failed to initialize Neo Orchestrator:', error); throw error; } } async createWorkflow(config) { this._checkInitialized(); const { agents, steps, chainType = 'sequential', options = {} } = config; // Register agents if they don't exist for (const agent of agents) { if (!this.agentWorkflow.hasAgent(agent.id)) { await this.agentWorkflow.registerAgent(agent); } } // Create workflow const workflowId = await this.agentWorkflow.createWorkflow({ name: config.name, description: config.description, metadata: config.metadata }); // Create corresponding chain const chainId = await this.chainSystem.registerChain({ id: `chain-${workflowId}`, type: chainType, steps: steps.map(s => s.id), options }); // Register step handlers that connect to agent workflow steps.forEach(step => { this.chainSystem.registerStepHandler(step.id, async () => { const assignedAgent = await this.agentWorkflow.assignStep(workflowId, step, step.agentId); const result = await this._executeAgentStep(assignedAgent, step); await this.agentWorkflow.completeStep(workflowId, step.id, result); return result; }); }); return { workflowId, chainId }; } async executeWorkflow(workflowId) { this._checkInitialized(); const chainId = `chain-${workflowId}`; try { // Start monitoring const monitoringSession = await this.monitoring.startSession(workflowId); // Execute chain const results = await this.chainSystem.executeChain(chainId); // Update workflow status await this.agentWorkflow.updateWorkflowStatus(workflowId, 'completed'); // Stop monitoring await this.monitoring.endSession(monitoringSession); return results; } catch (error) { await this.agentWorkflow.updateWorkflowStatus(workflowId, 'failed'); throw error; } } async getSystemStatus() { this._checkInitialized(); const knowledgeGraphStats = await this.knowledgeGraph.getStats(); const workflowStats = await this.agentWorkflow.getStats(); const chainStats = await this.chainSystem.getChainSystemStats(); const monitoringStats = await this.monitoring.getMetricsReport('1h'); return { status: 'active', timestamp: new Date().toISOString(), systems: { knowledgeGraph: knowledgeGraphStats, agentWorkflow: workflowStats, chainSystem: chainStats, monitoring: monitoringStats } }; } async _executeAgentStep(agent, step) { // Get logger from instance const log = this.log; // --- Start of Task Master Integration Refactor --- // 1. Assume the 'step' object now contains the corresponding Task Master ID // TODO: Determine how step.taskMasterId is populated (e.g., during workflow creation) const taskMasterId = step.taskMasterId; if (!taskMasterId) { log.warn(`Step ${step.id} is missing Task Master ID. Skipping Task Master integration for this step.`); // Fallback to original execution logic if no TM ID return this._executeOriginalStepLogic(agent, step); } let subtasksToExecute = []; let mainTaskDetails = null; // 2. Check if the task needs expansion (logic TBD - maybe based on step properties?) // TODO: Determine how needsExpansion is decided (e.g., property on step or TM task) let needsExpansion = step.needsExpansion || false; // Example flag if (needsExpansion) { log.info(`Requesting expansion for Task Master task ${taskMasterId}`); const expansionResult = await this.agentWorkflow.expandTaskMasterTask(taskMasterId); if (expansionResult && expansionResult.task && expansionResult.task.subtasks && expansionResult.task.subtasks.length > 0) { log.info(`Task ${taskMasterId} expanded into ${expansionResult.task.subtasks.length} subtasks.`); subtasksToExecute = expansionResult.task.subtasks; mainTaskDetails = expansionResult.task; // Keep parent task details } else { log.warn(`Expansion requested for ${taskMasterId}, but no subtasks were returned or found in result. Fetching main task.`); mainTaskDetails = await this.agentWorkflow.fetchTaskMasterTaskById(taskMasterId); subtasksToExecute = mainTaskDetails ? [mainTaskDetails] : []; if (subtasksToExecute.length === 0) { log.error(`Failed to fetch main task details for ${taskMasterId} after expansion attempt.`); throw new Error(`Could not retrieve task details for ${taskMasterId}`); } } } else { log.info(`Task ${taskMasterId} does not require expansion. Fetching details...`); mainTaskDetails = await this.agentWorkflow.fetchTaskMasterTaskById(taskMasterId); subtasksToExecute = mainTaskDetails ? [mainTaskDetails] : []; if (subtasksToExecute.length === 0) { log.error(`Failed to fetch main task details for ${taskMasterId}.`); throw new Error(`Could not retrieve task details for ${taskMasterId}`); } } // 3. Iterate through subtasks (or the main task if not expanded) let overallStepResult = {}; // Aggregate results let finalStatus = 'success'; for (const subtask of subtasksToExecute) { const currentSubtaskId = subtask.id; // Task Master task/subtask ID (e.g., '5' or '5.1') log.info(`Agent ${agent.id} starting work on Task Master task/subtask: ${currentSubtaskId}`); // Get relevant design system components if needed (using original step requirements) let designComponents = null; if (step.requiresDesignSystem) { designComponents = await this.designSystem.getComponents(step.designRequirements); } // Execute the specific subtask with the agent const startTime = Date.now(); let subtaskResult; try { // Adapt the input for the agent's execute method // ---> REVISED: Determine target method based on subtask type/details const agentExecutionInput = subtask; // Pass the whole subtask object for now let agentResult; // TODO: Define a robust way to map subtask details to agent methods // This is a simplified example based on a hypothetical 'subtask.action' field const action = subtask.action || (mainTaskDetails ? mainTaskDetails.action : null); log.info(`Determined action for subtask ${currentSubtaskId}: ${action}`); // Set Task Master status to in-progress before execution await this.agentWorkflow.setTaskMasterTaskStatus(currentSubtaskId, 'in-progress'); // --- Call Specific Agent Method based on Action --- switch (action) { // Frontend Agent Actions case 'createComponent': if (typeof agent.createComponent === 'function') { agentResult = await agent.createComponent( agentExecutionInput.name, agentExecutionInput.description, agentExecutionInput.componentType, agentExecutionInput.props, agentExecutionInput.dependencies, agentExecutionInput.tokens ); } else { throw new Error(`Agent ${agent.id} does not have 'createComponent' method.`); } break; case 'implementUILogic': if (typeof agent.implementUILogic === 'function') { agentResult = await agent.implementUILogic( agentExecutionInput.componentId, agentExecutionInput.logicDescription ); } else { throw new Error(`Agent ${agent.id} does not have 'implementUILogic' method.`); } break; case 'connectComponentToApi': if (typeof agent.connectComponentToApi === 'function') { agentResult = await agent.connectComponentToApi( agentExecutionInput.componentId, agentExecutionInput.apiEndpointNodeId, agentExecutionInput.dataMapping ); } else { throw new Error(`Agent ${agent.id} does not have 'connectComponentToApi' method.`); } break; // Backend Agent Actions case 'createApiEndpoint': if (typeof agent.createApiEndpoint === 'function') { agentResult = await agent.createApiEndpoint( agentExecutionInput.path, agentExecutionInput.method, agentExecutionInput.description, agentExecutionInput.requestSchema, agentExecutionInput.responseSchema ); } else { throw new Error(`Agent ${agent.id} does not have 'createApiEndpoint' method.`); } break; case 'implementApiLogic': if (typeof agent.implementApiLogic === 'function') { agentResult = await agent.implementApiLogic( agentExecutionInput.endpointId, agentExecutionInput.logicImplementation, agentExecutionInput.dependencies ); } else { throw new Error(`Agent ${agent.id} does not have 'implementApiLogic' method.`); } break; case 'defineDatabaseModel': if (typeof agent.defineDatabaseModel === 'function') { agentResult = await agent.defineDatabaseModel( agentExecutionInput.modelName, agentExecutionInput.schemaDefinition ); } else { throw new Error(`Agent ${agent.id} does not have 'defineDatabaseModel' method.`); } break; // Default / Fallback (if generic execute exists or error) default: if (typeof agent.execute === 'function') { log.warn(`No specific action found for subtask ${currentSubtaskId}, attempting generic execute.`); // Prepare a generic input object if needed const genericInput = { neoStepId: step.id, neoWorkflowId: step.workflowId, taskMasterId: currentSubtaskId, ...subtask // Pass all subtask details }; agentResult = await agent.execute(genericInput, { designComponents }); } else { throw new Error(`Unknown action '${action}' for subtask ${currentSubtaskId} and agent ${agent.id} has no fallback execute method.`); } } // --- End Specific Method Call Logic --- subtaskResult = agentResult; // Assign result from the specific call // Validate subtask result using Neo's validation logic // TODO: Decide if validation uses original step criteria or subtask criteria const validationResult = await this.agentWorkflow.validateStepResult(step, subtaskResult); if (!validationResult || !validationResult.valid) { // Ensure validationResult is checked const errorMsg = validationResult ? validationResult.errors.join(', ') : 'Validation failed without details'; throw new Error(`Subtask ${currentSubtaskId} validation failed: ${errorMsg}`); } // Record success metrics await this.monitoring.recordMetric('subtaskExecution', { agentId: agent.id, subtaskId: currentSubtaskId, duration: Date.now() - startTime, status: 'success' }); // Update Task Master status for the completed subtask await this.agentWorkflow.setTaskMasterTaskStatus(currentSubtaskId, 'done'); // Aggregate results overallStepResult[currentSubtaskId] = subtaskResult; } catch (error) { finalStatus = 'failed'; log.error(`Agent ${agent.id} failed on subtask ${currentSubtaskId}: ${error.message}`); // Record failure metrics await this.monitoring.recordMetric('subtaskExecution', { agentId: agent.id, subtaskId: currentSubtaskId, duration: Date.now() - startTime, status: 'failed', error: error.message }); // Update Task Master status for the failed subtask await this.agentWorkflow.setTaskMasterTaskStatus(currentSubtaskId, 'failed'); // Or another appropriate status // Stop the whole Neo step on the first subtask failure throw new Error(`Agent ${agent.id} failed processing Neo step ${step.id} due to subtask ${currentSubtaskId}: ${error.message}`); } } // --- End of Task Master Integration Refactor --- // Return the aggregated result if all subtasks succeeded return overallStepResult; } // Helper for original logic if TM integration is skipped async _executeOriginalStepLogic(agent, step) { const log = this.log; log.warn(`Executing step ${step.id} with original logic (no Task Master integration).`); // Get relevant design system components if needed let designComponents = null; if (step.requiresDesignSystem) { designComponents = await this.designSystem.getComponents(step.designRequirements); } const startTime = Date.now(); try { const result = await agent.execute(step, { designComponents }); // Validate step result const validationResult = await this.agentWorkflow.validateStepResult(step, result); if (!validationResult || !validationResult.valid) { // Ensure validationResult is checked const errorMsg = validationResult ? validationResult.errors.join(', ') : 'Validation failed without details'; throw new Error(`Step validation failed: ${errorMsg}`); } // Update metrics (using original step metric name) await this.monitoring.recordMetric('stepExecution', { agentId: agent.id, stepId: step.id, duration: Date.now() - startTime, status: 'success' }); return result; } catch (error) { // Record failure metrics (using original step metric name) await this.monitoring.recordMetric('stepExecution', { agentId: agent.id, stepId: step.id, duration: Date.now() - startTime, status: 'failed', error: error.message }); throw error; // Re-throw original error } } _checkInitialized() { if (!this.initialized) { throw new Error('Neo Orchestrator not initialized'); } } }