Skip to main content
Glama
optimization-execution.service.ts8.35 kB
// Internal services and utilities import { BaseMemoryAgent } from '../base/base-memory-agent'; import { ActionExecutorService } from './action-executor.service'; // Type imports import type { ToolHandlerContext } from '../../../mcp/types/sdk-custom'; import type { OptimizationPlan, OptimizationResult } from '../../../schemas/optimization/types'; /** * Service responsible for executing optimization plans safely * Coordinates action execution, snapshot management, and result tracking */ export class OptimizationExecutionService extends BaseMemoryAgent { private actionExecutor: ActionExecutorService; constructor(memoryService: any, config: any, actionExecutor: ActionExecutorService) { super(memoryService, config); this.actionExecutor = actionExecutor; } /** * Execute optimization plan safely */ async executeOptimizationPlan( mcpContext: ToolHandlerContext, clientProjectRoot: string, repository: string, branch: string, plan: OptimizationPlan, options: { dryRun?: boolean; requireConfirmation?: boolean; createSnapshot?: boolean; snapshotFailurePolicy?: 'abort' | 'continue' | 'warn'; } = {}, ): Promise<OptimizationResult> { const executeLogger = this.createOperationLogger('executeOptimizationPlan', { planId: plan.id, repository, branch, dryRun: options.dryRun, }); try { executeLogger.info('Executing optimization plan', { totalActions: plan.actions.length, dryRun: options.dryRun, createSnapshot: options.createSnapshot, }); // Create snapshot before optimization (if not dry run) let snapshotId: string | undefined; if (!options.dryRun && options.createSnapshot !== false) { snapshotId = await this.createPreOptimizationSnapshot( mcpContext, clientProjectRoot, repository, branch, plan.id, options.snapshotFailurePolicy, executeLogger, ); } const executedActions: OptimizationResult['executedActions'] = []; let entitiesDeleted = 0; let entitiesMerged = 0; let entitiesUpdated = 0; // Execute actions in the specified order for (const actionId of plan.executionOrder) { const action = plan.actions.find((a) => a.entityId === actionId); if (!action) { executeLogger.warn(`Action not found in plan: ${actionId}`); continue; } const actionContext = { actionId: action.entityId, actionType: action.type, targetEntityId: action.targetEntityId, reason: action.reason, }; try { if (options.dryRun) { // Dry run execution path executeLogger.info( `DRY RUN: Would execute ${action.type} on ${action.entityId}`, actionContext, ); this.recordSuccessfulAction(executedActions, action.entityId); } else { // Actual execution path executeLogger.debug( `Executing ${action.type} action on ${action.entityId}`, actionContext, ); await this.actionExecutor.executeAction( mcpContext, clientProjectRoot, repository, branch, action, ); this.recordSuccessfulAction(executedActions, action.entityId); const counters = { entitiesDeleted, entitiesMerged, entitiesUpdated }; this.updateActionCounters(action.type, counters); entitiesDeleted = counters.entitiesDeleted; entitiesMerged = counters.entitiesMerged; entitiesUpdated = counters.entitiesUpdated; executeLogger.info( `Successfully executed ${action.type} action on ${action.entityId}`, actionContext, ); } } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); executeLogger.error(`Failed to execute ${action.type} action on ${action.entityId}`, { ...actionContext, error: errorMessage, stack: error instanceof Error ? error.stack : undefined, }); this.recordFailedAction(executedActions, action.entityId, errorMessage); } } const result: OptimizationResult = { planId: plan.id, status: executedActions.every((a) => a.status === 'success') ? 'success' : 'partial', executedActions, summary: { entitiesDeleted, entitiesMerged, entitiesUpdated, }, snapshotId, }; executeLogger.info('Optimization plan execution completed', { status: result.status, entitiesDeleted, entitiesMerged, entitiesUpdated, }); return result; } catch (error) { executeLogger.error('Optimization plan execution failed', error); throw new Error(`Optimization plan execution failed: ${error}`); } } /** * Create pre-optimization snapshot */ private async createPreOptimizationSnapshot( mcpContext: ToolHandlerContext, clientProjectRoot: string, repository: string, branch: string, planId: string, snapshotFailurePolicy: string | undefined, logger: any, ): Promise<string | undefined> { try { const snapshotService = await this.memoryService.getSnapshotService( mcpContext, clientProjectRoot, ); const snapshotResult = await snapshotService.createSnapshot( repository, branch, `Pre-optimization snapshot for plan ${planId}`, ); const snapshotId = snapshotResult.snapshotId; logger.info('Created pre-optimization snapshot', { snapshotId, entitiesCount: snapshotResult.entitiesCount, relationshipsCount: snapshotResult.relationshipsCount, }); return snapshotId; } catch (snapshotError) { logger.error('Failed to create snapshot:', snapshotError); // Determine snapshot failure policy (options override config) const failurePolicy = snapshotFailurePolicy || this.config.snapshotFailurePolicy || 'warn'; switch (failurePolicy) { case 'abort': logger.error('Aborting optimization due to snapshot failure (policy: abort)'); throw new Error( `Optimization aborted: Failed to create snapshot - ${snapshotError}. ` + 'Rollback will not be available.', ); case 'continue': logger.info('Continuing optimization without snapshot (policy: continue)'); break; case 'warn': default: logger.warn( 'Proceeding with optimization without snapshot - ' + 'rollback will not be available (policy: warn)', ); logger.warn( 'Consider using snapshotFailurePolicy: "abort" for production ' + 'environments requiring guaranteed rollback', ); break; } return undefined; } } /** * Record a successful action execution */ private recordSuccessfulAction( executedActions: OptimizationResult['executedActions'], actionId: string, ): void { executedActions.push({ actionId, status: 'success', }); } /** * Record a failed action execution */ private recordFailedAction( executedActions: OptimizationResult['executedActions'], actionId: string, errorMessage: string, ): void { executedActions.push({ actionId, status: 'failed', error: errorMessage, }); } /** * Update action counters based on action type */ private updateActionCounters( actionType: string, counters: { entitiesDeleted: number; entitiesMerged: number; entitiesUpdated: number; }, ): void { switch (actionType) { case 'delete': counters.entitiesDeleted++; break; case 'merge': counters.entitiesMerged++; break; case 'update': counters.entitiesUpdated++; break; default: // No counter update for unknown action types break; } } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Jakedismo/KuzuMem-MCP'

If you have feedback or need assistance with the MCP directory API, please join our Discord server