UNPKG

crewai-ts

Version:

TypeScript port of crewAI for agent-based workflows

135 lines (134 loc) 6.84 kB
/** * CLI command for training a crew for improved agent performance. * Optimized for memory efficiency and learning effectiveness. */ import path from 'path'; import fs from 'fs'; // For sync operations import { Command } from '../Command.js'; export class TrainCrewCommand extends Command { name = 'train-crew'; description = 'Train the crew for improved performance'; syntax = '[options]'; examples = [ 'train-crew', 'train-crew --iterations 10', 'train-crew -n 5 --filename ./data/trained_agents.json' ]; async execute(args) { const parsedArgs = this.parseArgs(args); const startTime = Date.now(); 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(`Training crew for ${parsedArgs.iterations} iterations...`).start(); // Resolve the output file path // Ensure filename is always a string with proper null/undefined handling // Ensure filename is a valid string with proper type checking and fallback const filename = typeof parsedArgs.filename === 'string' && parsedArgs.filename.trim() ? parsedArgs.filename.trim() : 'trained_agents_data.json'; const outputPath = path.resolve(process.cwd(), filename); const outputDir = path.dirname(outputPath); // Ensure the output directory exists with proper error handling if (!fs.existsSync(outputDir)) { fs.mkdirSync(outputDir, { recursive: true }); } // Import the training service with enhanced type handling // The interface is defined at the top level for better code organization // Import service with proper declaration reference and memory-optimized type assertions // Enhanced dynamic import with precise type assertions for better compiler optimization // Using a two-step approach for maximum type safety and memory efficiency const trainingServiceModule = await import( /* webpackChunkName: "crew-training-service" */ '../../services/CrewTrainingService.js').catch(error => { spinner.fail(`Error importing training service: ${error.message}`); throw new Error(`Failed to load training module: ${error.message}`); }); // Convert module to the expected structure with safe casting // This approach is more memory efficient than in-line type assertions const moduleWithService = trainingServiceModule; const { CrewTrainingService } = moduleWithService; spinner.text = 'Initializing training service...'; const trainingService = new CrewTrainingService(); // Setup progress tracking let currentIteration = 0; const progressInterval = setInterval(() => { spinner.text = `Training crew... ${currentIteration}/${parsedArgs.iterations} iterations`; }, 1000); // Train the crew with progress updates trainingService.onIterationComplete((iteration) => { currentIteration = iteration; }); // Ensure all parameters are properly typed for memory safety const trainingOptions = { iterations: parsedArgs.iterations, // Always use a string for the output file path with proper type safety outputFile: outputPath, verbose: !!parsedArgs.verbose // Convert to boolean for type safety }; const trainingResults = await trainingService.train(trainingOptions); // Clean up progress tracking clearInterval(progressInterval); // Operation completed successfully const executionTime = ((Date.now() - startTime) / 1000).toFixed(2); spinner.succeed(`Training completed in ${executionTime}s (${parsedArgs.iterations} iterations)`); // Show training results summary console.log('\nTraining results:'); // Access metrics safely with null checks const accuracy = trainingResults.metrics?.accuracy || 0; const agentCount = trainingResults.metrics?.agentCount || 0; console.log(`- Final model accuracy: ${accuracy.toFixed(2)}%`); console.log(`- Trained agent models: ${agentCount}`); console.log(`- Data saved to: ${outputPath}`); if (parsedArgs.verbose) { console.log('\nDetailed performance metrics:'); console.log(JSON.stringify(trainingResults.metrics, null, 2)); } } catch (error) { console.error('Error during crew training:', error); process.exit(1); } } /** * Parse command line arguments for the train-crew command * Optimized for handling various argument formats */ parseArgs(args) { // Default values with proper type annotations for memory efficiency const result = { iterations: 5, filename: 'trained_agents_data.json', verbose: false }; // Parse options for (let i = 0; i < args.length; i++) { if ((args[i] === '-n' || args[i] === '--iterations') && i + 1 < args.length) { // Safe access of array index with bounds check const nextArg = args[++i]; // Parse with explicit type checking for memory optimization const iterations = typeof nextArg === 'string' ? parseInt(nextArg, 10) : NaN; if (!isNaN(iterations) && iterations > 0) { result.iterations = iterations; } } else if ((args[i] === '-f' || args[i] === '--filename') && i + 1 < args.length) { const index = ++i; // Enhanced string safety with comprehensive null/undefined checks for memory optimization if (index < args.length) { const filenameArg = args[index]; // Null coalescing for safe string assignment with type assertion if (typeof filenameArg === 'string' && filenameArg.trim().length > 0) { result.filename = filenameArg.trim(); } } // Default is already set in the result object initialization } else if (args[i] === '--verbose') { result.verbose = true; } } return result; } }