UNPKG

crewai-ts

Version:

TypeScript port of crewAI for agent-based workflows

139 lines (138 loc) • 6.34 kB
/** * CLI command for replaying a crew execution from a specific task. * Optimized for performance and debugging. * Memory-optimized with proper type safety. */ import { Command } from '../Command.js'; import { setInterval, clearInterval } from 'node:timers'; export class ReplayTaskCommand extends Command { name = 'replay-task'; description = 'Replay the crew execution from a specific task ID'; syntax = '<task-id> [options]'; examples = [ 'replay-task task_123456', 'replay-task task_123456 --verbose' ]; async execute(args) { const parsedArgs = this.parseArgs(args); if (!parsedArgs.taskId) { console.error('Error: Task ID is required'); this.showHelp(); // Use explicit process.exit with proper type signatures process.exit(1); } try { // Dynamically import required modules only when needed (optimization) const { default: chalk } = await import('chalk'); const { default: ora } = await import('ora'); // Show spinner for better UX const spinner = ora('Preparing task replay...').start(); // Import memory storage to load the task with proper type checking const { KickoffTaskOutputsStorage } = await import('../../memory/storage/KickoffTaskOutputsStorage.js'); // Ensure task ID is defined with type safety const taskId = parsedArgs.taskId || ''; // Load the task outputs with memory-optimized type handling spinner.text = 'Loading task data...'; const storage = new KickoffTaskOutputsStorage(); const task = await storage.getTaskById(taskId); if (!task) { spinner.fail(`Task with ID ${taskId} not found`); // Use explicit process.exit with proper type signatures process.exit(1); } // Load the crew module for replay with proper type checking spinner.text = 'Loading crew module...'; // Create a fallback implementation if the module can't be loaded const createFallbackService = () => { class FallbackTaskReplayService { async replayFromTask(taskId, options) { console.warn('Using fallback replay service - some features may be limited'); return { success: false, message: 'TaskReplayService module could not be loaded' }; } } return FallbackTaskReplayService; }; // Try to load the module with memory-safe implementation let TaskReplayServiceClass; try { // Dynamic import with proper type checking const replayModule = await import('../../services/TaskReplayService.js'); if (!replayModule || !('TaskReplayService' in replayModule)) { throw new Error('Invalid TaskReplayService module structure'); } TaskReplayServiceClass = replayModule.TaskReplayService; } catch (error) { console.warn('Error loading TaskReplayService module:', error); TaskReplayServiceClass = createFallbackService(); } // Create service instance with proper type handling const replayService = new TaskReplayServiceClass(); // Track execution progress with memory-efficient timer management // Use proper Node.js types for timers with memory optimization let progressInterval; if (!parsedArgs.verbose) { // Initialize timer with memory-optimized implementation // Store task ID once to avoid repeated property access const displayTaskId = parsedArgs.taskId || ''; progressInterval = setInterval(() => { spinner.text = `Replaying from task ${displayTaskId}...`; }, 1000); } else { spinner.stop(); console.log(chalk.blue(`šŸ”„ Replaying from task ${chalk.bold(taskId)}...`)); } // Execute the replay with proper null handling const results = await replayService.replayFromTask(taskId, { verbose: !!parsedArgs.verbose // Convert to boolean for type safety }); // Clean up progress tracking if (!parsedArgs.verbose && progressInterval) { clearInterval(progressInterval); } // Show results if (!parsedArgs.verbose) { spinner.succeed(`Replay from task ${taskId} completed`); } else { console.log(chalk.green(`\nāœ… Replay completed`)); } console.log('\nResults:', JSON.stringify(results, null, 2)); } catch (error) { console.error('Error during task replay:', error); // Use explicit process.exit with proper type signatures process.exit(1); } } /** * Parse command line arguments for the replay-task command * Optimized for handling various argument formats */ /** * Parse command line arguments with enhanced type safety and memory optimization * @param args Command line arguments * @returns Parsed arguments object */ parseArgs(args) { // Early return with memory-optimized empty object for no arguments if (!Array.isArray(args) || args.length === 0) { return {}; } // Create result object with memory efficiency in mind const result = { // Only assign if args[0] is a valid string taskId: typeof args[0] === 'string' && args[0].trim() ? args[0].trim() : undefined }; // Parse options with type safety for (let i = 1; i < args.length; i++) { const arg = args[i]; // Strict equality check for argument names if (typeof arg === 'string' && (arg === '--verbose' || arg === '-v')) { result.verbose = true; // Set boolean flag for type safety } } return result; } }