task-master-neo-sdlc
Version:
Enhanced task management system with Neo SDLC agents and MCP tools for comprehensive, AI-driven software development lifecycle management.
163 lines (143 loc) • 7.55 kB
JavaScript
import { KnowledgeGraph } from '../knowledge-graph';
import { AgentWorkflowSystem } from '../agent-workflow';
// Assume workflow definitions might be stored in KG or loaded from files
// import workflowLoader from '../../utils/workflowLoader';
export class ProcessManagerAgent {
constructor(knowledgeGraph, workflowSystem) {
this.knowledgeGraph = knowledgeGraph;
this.workflowSystem = workflowSystem; // Use the existing workflow system
this.runningProcesses = new Map(); // Track ongoing processes
}
/**
* Starts a defined process or workflow.
* @param {string} workflowDefinitionId - ID of the workflow definition (in KG or file).
* @param {object} initialContext - Initial data for the workflow instance.
* @returns {Promise<string>} The ID of the started process instance.
*/
async startProcess(workflowDefinitionId, initialContext = {}) {
console.log(`Starting process based on workflow definition: ${workflowDefinitionId}`);
// Placeholder: Load workflow definition
// const definition = await workflowLoader.load(workflowDefinitionId);
const definition = {
id: workflowDefinitionId,
name: `Workflow ${workflowDefinitionId}`,
steps: [
{ id: 'step1', action: 'agentA.doSomething', next: 'step2' },
{ id: 'step2', action: 'agentB.doAnotherThing', params: { input: '${step1.output}' } , next: null }, // Example: Using output from step1
]
};
if (!definition || !definition.steps || definition.steps.length === 0) {
throw new Error(`Workflow definition ${workflowDefinitionId} is invalid or empty.`);
}
const processInstanceId = `process_${Date.now()}`;
const processState = {
id: processInstanceId,
definitionId: workflowDefinitionId,
status: 'running', // running, completed, failed, suspended
currentStepId: definition.steps[0].id,
context: { ...initialContext },
history: [{ stepId: null, status: 'started', timestamp: Date.now() }]
};
this.runningProcesses.set(processInstanceId, processState);
// Add process instance to knowledge graph
await this.knowledgeGraph.addNode({
id: `processInstance:${processInstanceId}`,
type: 'process_instance',
data: { ...processState, history: processState.history.slice(-5) } // Store recent history
});
console.log(`Process instance ${processInstanceId} started at step ${processState.currentStepId}.`);
// Trigger the first step execution asynchronously
this.executeStep(processInstanceId);
return processInstanceId;
}
/**
* Executes the current step of a running process instance.
* (Typically called internally or triggered by events)
* @param {string} processInstanceId - The ID of the process instance.
*/
async executeStep(processInstanceId) {
const processState = this.runningProcesses.get(processInstanceId);
if (!processState || processState.status !== 'running') {
console.log(`Process ${processInstanceId} is not in a runnable state (${processState?.status}).`);
return;
}
// Placeholder: Load definition again if needed
const definition = { steps: [{ id: 'step1', action: 'agentA.doSomething', next: 'step2' }, { id: 'step2', action: 'agentB.doAnotherThing', params: { input: '${step1.output}' }, next: null }] };
const currentStep = definition.steps.find(s => s.id === processState.currentStepId);
if (!currentStep) {
console.error(`Current step ${processState.currentStepId} not found in definition for process ${processInstanceId}. Failing process.`);
processState.status = 'failed';
processState.history.push({ stepId: processState.currentStepId, status: 'error', details: 'Step definition not found', timestamp: Date.now() });
this.runningProcesses.delete(processInstanceId); // Or mark as failed
await this._updateProcessStateInKG(processInstanceId, processState);
return;
}
console.log(`Executing step ${currentStep.id} for process ${processInstanceId}: ${currentStep.action}`);
processState.history.push({ stepId: currentStep.id, status: 'executing', timestamp: Date.now() });
await this._updateProcessStateInKG(processInstanceId, processState);
try {
// Placeholder: Execute the action defined in the step.
// This would involve resolving the action string (e.g., 'agentA.doSomething')
// to an actual function call, potentially via the AgentWorkflowSystem.
// It would also handle parameter substitution from context.
// const result = await this.workflowSystem.executeAction(currentStep.action, currentStep.params, processState.context);
const result = { output: `Result from ${currentStep.action}` }; // Simulate result
// Update context with step result
processState.context[currentStep.id] = result;
processState.history.push({ stepId: currentStep.id, status: 'completed', timestamp: Date.now() });
// Move to next step or complete
if (currentStep.next) {
processState.currentStepId = currentStep.next;
await this._updateProcessStateInKG(processInstanceId, processState);
// Trigger next step asynchronously
setImmediate(() => this.executeStep(processInstanceId));
} else {
processState.status = 'completed';
this.runningProcesses.delete(processInstanceId); // Remove completed process
console.log(`Process instance ${processInstanceId} completed successfully.`);
await this._updateProcessStateInKG(processInstanceId, processState);
}
} catch (error) {
console.error(`Error executing step ${currentStep.id} for process ${processInstanceId}:`, error);
processState.status = 'failed';
processState.history.push({ stepId: currentStep.id, status: 'failed', details: error.message, timestamp: Date.now() });
this.runningProcesses.delete(processInstanceId); // Remove failed process
await this._updateProcessStateInKG(processInstanceId, processState);
}
}
/**
* Gets the status and context of a running process instance.
* @param {string} processInstanceId - The ID of the process instance.
* @returns {Promise<object|null>} The process state or null if not found.
*/
async getProcessStatus(processInstanceId) {
const state = this.runningProcesses.get(processInstanceId);
if (state) {
return { ...state }; // Return a copy
}
// Maybe check KG for historical/completed processes
const node = await this.knowledgeGraph.findNodes({ id: `processInstance:${processInstanceId}` }).then(n => n[0]);
return node ? node.data : null;
}
/**
* Helper to update process state in Knowledge Graph.
* @param {string} instanceId - The process instance ID.
* @param {object} state - The current process state.
*/
async _updateProcessStateInKG(instanceId, state) {
try {
await this.knowledgeGraph.updateContext({
id: `processInstance:${instanceId}`,
// type: 'process_instance', // Type might not be needed for updateContext
data: { ...state, history: state.history.slice(-10) } // Update with recent history
});
} catch (kgError) {
console.error(`Failed to update process state in KG for ${instanceId}:`, kgError);
// Decide how to handle KG update failure (retry, log, etc.)
}
}
// Other potential methods:
// - suspendProcess(processInstanceId)
// - resumeProcess(processInstanceId)
// - cancelProcess(processInstanceId)
}