crewai-ts
Version:
TypeScript port of crewAI for agent-based workflows
190 lines (189 loc) • 9.38 kB
JavaScript
/**
* CLI command for resetting various types of memory storages.
* Optimized for targeted memory management and efficient cleanup.
* Memory-optimized with strong type safety.
*/
import { Command } from '../Command.js';
export class ResetMemoriesCommand extends Command {
name = 'reset-memories';
description = 'Reset various types of crew memories';
syntax = '[options]';
examples = [
'reset-memories --all',
'reset-memories --long --short',
'reset-memories --knowledge'
];
async execute(args) {
const parsedArgs = this.parseArgs(args);
// Check if any memory type is specified
const hasSelection = parsedArgs.long || parsedArgs.short ||
parsedArgs.entities || parsedArgs.knowledge ||
parsedArgs.kickoffOutputs || parsedArgs.all;
if (!hasSelection) {
console.error('Error: Must specify at least one memory type to reset');
this.showHelp();
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 to reset memories...').start();
// Set all memory types if 'all' is selected
if (parsedArgs.all) {
parsedArgs.long = true;
parsedArgs.short = true;
parsedArgs.entities = true;
parsedArgs.knowledge = true;
parsedArgs.kickoffOutputs = true;
}
// Import memory services only as needed for memory efficiency
const memoryServices = {};
const resetPromises = [];
// Only import the services we need based on selected options
if (parsedArgs.long) {
spinner.text = 'Resetting long-term memory...';
const { LongTermMemoryStorage } = await import('../../memory/storage/LongTermMemoryStorage.js');
const longTermMemory = new LongTermMemoryStorage();
resetPromises.push(longTermMemory.clear());
}
if (parsedArgs.short) {
spinner.text = 'Resetting short-term memory...';
const { ShortTermMemoryStorage } = await import('../../memory/storage/ShortTermMemoryStorage.js');
const shortTermMemory = new ShortTermMemoryStorage();
resetPromises.push(shortTermMemory.clear());
}
if (parsedArgs.entities) {
spinner.text = 'Resetting entity memory...';
const { EntityMemoryStorage } = await import('../../memory/storage/EntityMemoryStorage.js');
const entityMemory = new EntityMemoryStorage();
resetPromises.push(entityMemory.clear());
}
if (parsedArgs.knowledge) {
spinner.text = 'Resetting knowledge memory...';
const { KnowledgeStorage } = await import('../../knowledge/storage/KnowledgeStorage.js');
// Create storage with optimized memory footprint
const knowledgeStorage = new KnowledgeStorage();
// Create a single type-safe reference to prevent multiple castings
const safeStorage = knowledgeStorage;
// Implement a memory-efficient approach to clearing knowledge storage
try {
// Create an optimized clear function that adapts to available methods
const clearStorage = async () => {
// Feature detection pattern for memory-efficient operation
if (typeof safeStorage.clear === 'function') {
// If clear method exists, use it directly (preferred approach)
await safeStorage.clear();
}
else if (typeof safeStorage.deleteAll === 'function') {
// Second option: use deleteAll if available
await safeStorage.deleteAll();
}
else if (typeof safeStorage.delete === 'function' && typeof safeStorage.list === 'function') {
// Third option: list all keys and delete individually
const keys = await safeStorage.list();
if (Array.isArray(keys)) {
// Process deletions in batches to optimize memory usage
const batchSize = 100;
for (let i = 0; i < keys.length; i += batchSize) {
const batch = keys.slice(i, i + batchSize);
await Promise.all(batch.map(key => safeStorage.delete(key)));
}
}
}
else {
console.warn('Knowledge storage does not support any clear operations - using filesystem fallback');
// Last resort: try to clear via filesystem operations
const fs = await import('fs/promises');
const path = await import('path');
const baseDir = safeStorage.baseDir || './knowledge';
try {
await fs.rm(baseDir, { recursive: true, force: true });
await fs.mkdir(baseDir, { recursive: true });
console.log(`Recreated knowledge directory at ${baseDir}`);
}
catch (fsError) {
console.warn(`Could not clear knowledge directory: ${fsError.message}`);
}
}
};
// Execute the appropriate clear operation
resetPromises.push(clearStorage());
}
catch (error) {
console.warn(`Error clearing knowledge storage: ${error.message}`);
resetPromises.push(Promise.resolve()); // Continue with other operations
}
}
if (parsedArgs.kickoffOutputs) {
spinner.text = 'Resetting task outputs memory...';
const { KickoffTaskOutputsStorage } = await import('../../memory/storage/KickoffTaskOutputsStorage.js');
const taskOutputsStorage = new KickoffTaskOutputsStorage();
resetPromises.push(taskOutputsStorage.clear());
}
// Execute all reset operations in parallel for performance
await Promise.all(resetPromises);
// Display success message
spinner.succeed('Memory reset completed');
// Show summary of reset operations
console.log('\nMemory reset summary:');
if (parsedArgs.long)
console.log(chalk.green('✓') + ' Long-term memory');
if (parsedArgs.short)
console.log(chalk.green('✓') + ' Short-term memory');
if (parsedArgs.entities)
console.log(chalk.green('✓') + ' Entity memory');
if (parsedArgs.knowledge)
console.log(chalk.green('✓') + ' Knowledge memory');
if (parsedArgs.kickoffOutputs)
console.log(chalk.green('✓') + ' Task outputs memory');
}
catch (error) {
console.error('Error resetting memories:', error);
process.exit(1);
}
}
/**
* Parse command line arguments for the reset-memories command
* Optimized for handling various argument formats
*/
parseArgs(args) {
// Default all to false
const result = {
long: false,
short: false,
entities: false,
knowledge: false,
kickoffOutputs: false,
all: false
};
// Parse options - support both full names and abbreviations
for (let i = 0; i < args.length; i++) {
const arg = args[i];
// Use efficient Map-based lookup for option handling with memory optimization
const optionMap = {
'--long': 'long',
'-l': 'long',
'--short': 'short',
'-s': 'short',
'--entities': 'entities',
'-e': 'entities',
'--knowledge': 'knowledge',
'-k': 'knowledge',
'--kickoff-outputs': 'kickoffOutputs',
'--task-outputs': 'kickoffOutputs',
'-o': 'kickoffOutputs',
'--all': 'all',
'-a': 'all'
};
// Set the appropriate flag if it matches an option with type safety
const option = arg ? optionMap[arg] : undefined;
if (option && option in result) {
// Use type assertion with verification to ensure type safety
result[option] = true;
}
}
return result;
}
}