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