workflow_execution_operations
Manages workflow execution by creating, querying, updating, and completing workflows with validated parameters. Tracks context and progress to ensure efficient workflow orchestration and state management.
Instructions
Manages workflow execution state through strongly-typed operations for creating, querying, updating, and completing workflow executions. Handles execution context and progress tracking with validated parameters.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| autoCreatedTask | No | Whether task was auto-created | |
| contextUpdates | No | Context updates to merge with existing execution context | |
| dataKey | No | Specific data key to retrieve from context | |
| executionContext | No | Additional execution context | |
| executionId | No | Execution ID for operations requiring it | |
| executionMode | No | Execution mode | |
| operation | Yes | Operation to execute | |
| orchestrationConfig | No | Configuration for orchestrating multiple service calls | |
| roleName | No | Role name for execution | |
| stepId | No | Current step ID | |
| taskId | No | Task ID (optional for bootstrap executions) | |
| updateData | No | Fields that can be updated in WorkflowExecution |
Implementation Reference
- Tool registration via @Tool decorator with name 'workflow_execution_operations' and the entry point handler function.@Tool({ name: 'workflow_execution_operations', description: `Manages workflow execution state through strongly-typed operations for creating, querying, updating, and completing workflow executions. Handles execution context and progress tracking with validated parameters.`, parameters: WorkflowExecutionSchema, })
- Handler logic that parses input.operation and delegates to corresponding methods in WorkflowExecutionOperationsService.async executeWorkflowOperation( input: WorkflowExecutionInputSchema, ): Promise<McpResponse> { try { const workflowInput: WorkflowExecutionInput = { taskId: input.taskId, executionId: input.executionId, roleName: input.roleName, executionMode: input.executionMode, executionContext: input.executionContext, updateData: input.updateData, stepId: input.stepId, orchestrationConfig: input.orchestrationConfig, }; let result: any; switch (input.operation) { case 'create_execution': result = await this.executionOps.createExecution(workflowInput); break; case 'get_execution': result = await this.executionOps.getExecution(workflowInput); break; case 'update_execution': result = await this.executionOps.updateExecution(workflowInput); break; case 'complete_execution': result = await this.executionOps.completeExecution(workflowInput); break; case 'get_active_executions': result = await this.executionOps.getActiveExecutions(); break; case 'get_execution_context': if (!input.executionId) { throw new Error( 'executionId is required for get_execution_context', ); } result = await this.executionOps.getExecutionContext({ executionId: input.executionId, dataKey: input.dataKey, }); break; case 'update_execution_context': if (!input.executionId) { throw new Error( 'executionId is required for update_execution_context', ); } if (!input.contextUpdates) { throw new Error( 'contextUpdates is required for update_execution_context', ); } result = await this.executionOps.updateExecutionContext({ executionId: input.executionId, contextUpdates: input.contextUpdates, }); break; default: { const exhaustiveCheck: never = input.operation; throw new Error(`Unknown operation: ${String(exhaustiveCheck)}`); } } // Return MINIMAL state data only - NO guidance generation, NO envelopes return this.buildResponse({ success: true, data: result, timestamp: new Date().toISOString(), }); } catch (error: unknown) { const errorMessage = error instanceof Error ? error.message : 'Unknown error'; return this.buildErrorResponse( errorMessage, '', 'WORKFLOW_EXECUTION_FAILED', ); } } }
- Primary Zod schema for tool input validation, including operation enum and conditional requirements via refine.const WorkflowExecutionSchema = z .object({ operation: z .enum([ 'create_execution', 'get_execution', 'update_execution', 'complete_execution', 'get_active_executions', 'get_execution_context', 'update_execution_context', ]) .describe('Operation to execute'), // Identifiers taskId: z .number() .optional() .describe('Task ID (optional for bootstrap executions)'), executionId: z .string() .optional() .describe('Execution ID for operations requiring it'), // Role and execution settings roleName: z .enum(['product-manager', 'architect', 'senior-developer', 'code-review']) .optional() .describe('Role name for execution'), executionMode: z .enum(['GUIDED', 'AUTOMATED', 'HYBRID']) .optional() .describe('Execution mode'), autoCreatedTask: z .boolean() .optional() .describe('Whether task was auto-created'), // Structured data fields - NO MORE z.any() executionContext: ExecutionContextSchema.optional(), updateData: UpdateDataSchema.optional(), stepId: z.string().optional().describe('Current step ID'), orchestrationConfig: OrchestrationConfigSchema.optional(), // Context operation fields dataKey: z .string() .optional() .describe('Specific data key to retrieve from context'), contextUpdates: ContextUpdatesSchema.optional(), }) .refine( (data) => { // Validation rules for different operations if (data.operation === 'get_execution') { return data.taskId !== undefined || data.executionId !== undefined; } if ( [ 'update_execution', 'complete_execution', 'get_execution_context', 'update_execution_context', ].includes(data.operation) ) { return data.executionId !== undefined; } if (data.operation === 'create_execution') { return data.roleName !== undefined; } if (data.operation === 'update_execution_context') { return data.contextUpdates !== undefined; } return true; }, { message: 'Invalid operation parameters - check required fields for each operation', }, ) .describe('Workflow execution operation with strongly typed parameters');
- src/domains/workflow-rules/workflow-rules.module.ts:68-97 (registration)NestJS module registration of WorkflowExecutionMcpService in providers and exports arrays.WorkflowGuidanceMcpService, StepExecutionMcpService, RoleTransitionMcpService, WorkflowExecutionMcpService, WorkflowBootstrapMcpService, // Core Services WorkflowGuidanceService, ProgressCalculatorService, StepExecutionService, StepGuidanceService, StepProgressTrackerService, StepQueryService, RoleTransitionService, WorkflowExecutionService, WorkflowExecutionOperationsService, ExecutionDataEnricherService, WorkflowBootstrapService, ExecutionAnalyticsService, WorkflowContextCacheService, // Guards WorkflowContextValidationGuard, ], exports: [ // MCP Operations WorkflowGuidanceMcpService, StepExecutionMcpService, RoleTransitionMcpService, WorkflowExecutionMcpService,
- Core service implementing the execution operations (create, get, update, complete, etc.) delegated by the MCP handler.export class WorkflowExecutionOperationsService extends ConfigurableService<ExecutionOperationsConfig> { // Configuration with sensible defaults protected readonly defaultConfig: ExecutionOperationsConfig = { defaults: { executionMode: 'GUIDED', orchestrationMode: 'sequential', continueOnFailure: false, }, validation: { requireExecutionId: true, requireRoleName: true, maxServiceCalls: 20, }, performance: { operationTimeoutMs: 30000, maxConcurrentExecutions: 10, cacheResultsMs: 300000, // 5 minutes }, }; constructor( private readonly workflowExecution: WorkflowExecutionService, private readonly dataEnricher: ExecutionDataEnricherService, private readonly analytics: ExecutionAnalyticsService, ) { super(); this.initializeConfig(); } /** * Validate input parameters */ private validateInput( input: WorkflowExecutionInput, operation: string, ): void { // Special handling for operations that can work without taskId // get_execution can work with either taskId OR executionId if (operation === 'get_execution') { if (!input.taskId && !input.executionId) { throw new Error(`get_execution requires either taskId or executionId`); } } if ( operation === 'create' && this.getConfigValue('validation').requireRoleName && !input.roleName ) { throw new Error(`roleName is required for ${operation}`); } if ( ['update', 'complete'].includes(operation) && this.getConfigValue('validation').requireExecutionId && !input.executionId ) { throw new Error(`executionId is required for ${operation}`); } if (input.orchestrationConfig?.serviceCalls) { const serviceCallCount = input.orchestrationConfig.serviceCalls.length; const maxServiceCalls = this.getConfigValue('validation').maxServiceCalls; if (serviceCallCount > maxServiceCalls) { throw new Error( `Too many service calls: ${serviceCallCount}. Maximum allowed: ${maxServiceCalls}`, ); } } } /** * Create new workflow execution */ async createExecution( input: WorkflowExecutionInput, ): Promise<ExecutionResult> { this.validateInput(input, 'create'); const createInput: CreateWorkflowExecutionInput = { taskId: input.taskId, currentRoleId: input.roleName!, // Safe after validation executionMode: input.executionMode || this.getConfigValue('defaults').executionMode, executionContext: input.executionContext, }; const execution = await this.workflowExecution.createExecution(createInput); const nextSteps = await this.dataEnricher.getNextStepsForExecution( execution.id, ); return { execution, nextSteps, }; } /** * Get execution with enriched context */ async getExecution(input: WorkflowExecutionInput): Promise<ExecutionResult> { this.validateInput(input, 'get'); let execution: WorkflowExecutionWithRelations | null; if (!input.executionId) { if (!input.taskId) { throw new Error( `Either taskId or executionId is required for get operation`, ); } execution = await this.workflowExecution.getExecutionByTaskId( input.taskId, ); if (!execution) { throw new Error(`No execution found for task ${input.taskId}`); } } else { execution = await this.workflowExecution.getExecutionById( input.executionId, // Safe after validation ); } return await this.dataEnricher.enrichExecutionData(execution); } /** * Get execution context data * Used by product-manager workflow to retrieve task creation data */ async getExecutionContext(input: { executionId: string; dataKey?: string; }): Promise<any> { const execution = await this.workflowExecution.getExecutionById( input.executionId, ); if (input.dataKey) { // Return specific data from execution context if ( execution.executionContext && typeof execution.executionContext === 'object' && execution.executionContext !== null && input.dataKey in execution.executionContext ) { return (execution.executionContext as Record<string, any>)[ input.dataKey ]; } // Also check in taskCreationData for backward compatibility if (execution.taskCreationData && input.dataKey === 'taskCreationData') { return execution.taskCreationData; } throw new Error( `Data key '${input.dataKey}' not found in execution context`, ); } // Return full execution context return { executionContext: execution.executionContext, taskCreationData: execution.taskCreationData, executionState: execution.executionState, }; } /** * Update execution context * Used by product-manager workflow to update context after task updates */ async updateExecutionContext(input: { executionId: string; contextUpdates: Record<string, any>; }): Promise<any> { const execution = await this.workflowExecution.getExecutionById( input.executionId, ); // Merge context updates with existing context const currentContext = execution.executionContext && typeof execution.executionContext === 'object' && execution.executionContext !== null ? (execution.executionContext as Record<string, any>) : {}; const updatedContext = { ...currentContext, ...input.contextUpdates, }; const updatedExecution = await this.workflowExecution.updateExecution( input.executionId, { executionContext: updatedContext, }, ); return { success: true, updatedContext: updatedExecution.executionContext, executionId: input.executionId, }; } /** * Update execution state */ async updateExecution( input: WorkflowExecutionInput, ): Promise<ExecutionResult> { this.validateInput(input, 'update'); const execution = await this.workflowExecution.updateExecution( input.executionId!, // Safe after validation input.updateData || {}, ); const nextActions = await this.dataEnricher.getNextStepsForExecution( execution.id, ); const progressMatrix = this.dataEnricher.calculateProgressMetrics(execution); return { execution, progressMatrix, nextActions, }; } /** * Complete execution */ async completeExecution( input: WorkflowExecutionInput, ): Promise<ExecutionResult> { this.validateInput(input, 'complete'); const execution = await this.workflowExecution.completeExecution( input.executionId!, // Safe after validation ); const completionSummary = this.analytics.generateCompletionSummary(execution); const finalRecommendations = this.analytics.getFinalRecommendations(); return { execution, completionSummary, finalRecommendations, }; } /** * Get active executions with summary */ async getActiveExecutions(): Promise<ExecutionsSummary> { const executions = await this.workflowExecution.getActiveExecutions(); return { executions, summary: { total: executions.length, byRole: this.analytics.groupExecutionsByRole(executions), progressOverview: this.analytics.calculateOverallProgress(executions), }, }; } }