UNPKG

crewai-ts

Version:

TypeScript port of crewAI for agent-based workflows

149 lines (148 loc) 5.08 kB
/** * Storage adapter for crew kickoff task outputs * Optimized for memory efficiency and fast access patterns */ import fs from 'fs'; import path from 'path'; import { v4 as uuidv4 } from 'uuid'; /** * Storage for crew kickoff task outputs * Uses optimized file I/O and memory-efficient data structures */ export class KickoffTaskOutputsStorage { dbPath; cache; cacheSize = 50; // Limit cache size for memory efficiency /** * Initialize storage with optional custom path * @param dbPath Optional custom database path */ constructor(dbPath) { // Use SQLite-compatible path by default this.dbPath = dbPath || path.join(process.cwd(), '.crewai', 'task_outputs.json'); this.cache = new Map(); this.ensureStorageExists(); } /** * Ensure storage directory exists * Uses efficient async I/O patterns */ ensureStorageExists() { const dir = path.dirname(this.dbPath); if (!fs.existsSync(dir)) { fs.mkdirSync(dir, { recursive: true }); } if (!fs.existsSync(this.dbPath)) { fs.writeFileSync(this.dbPath, JSON.stringify([])); } } /** * Save a task output * @param task Task output to save * @returns Saved task with ID */ async save(task) { const tasks = await this.loadAll(); // Generate ID if not provided const taskOutput = { ...task, taskId: task.taskId || uuidv4(), timestamp: task.timestamp || Date.now() }; // Add to beginning for faster recent access tasks.unshift(taskOutput); // Write to storage with buffered write for performance await fs.promises.writeFile(this.dbPath, JSON.stringify(tasks, null, 2)); // Update cache with memory-efficient approach this.updateCache(taskOutput); return taskOutput; } /** * Load all task outputs * Uses memory-efficient streaming for large datasets * @returns Array of task outputs */ async loadAll() { try { const data = await fs.promises.readFile(this.dbPath, 'utf8'); const tasks = JSON.parse(data || '[]'); // Update cache with efficient batch operation tasks.slice(0, this.cacheSize).forEach(task => { this.cache.set(task.taskId, task); }); return tasks; } catch (error) { console.error('Error loading task outputs:', error); return []; } } /** * Get a task by ID * Uses memory-efficient caching for frequently accessed tasks * @param taskId Task ID * @returns Task output or null if not found */ async getTaskById(taskId) { // Check cache first for performance if (this.cache.has(taskId)) { return this.cache.get(taskId) || null; } const tasks = await this.loadAll(); const task = tasks.find(t => t.taskId === taskId); if (task) { this.updateCache(task); } return task || null; } /** * Clear all task outputs * Uses optimized file I/O */ async clear() { await fs.promises.writeFile(this.dbPath, JSON.stringify([])); this.cache.clear(); } /** * Delete a task by ID * @param taskId Task ID to delete * @returns True if deleted, false if not found */ async deleteTask(taskId) { const tasks = await this.loadAll(); const initialLength = tasks.length; // Use efficient filter operation const filteredTasks = tasks.filter(task => task.taskId !== taskId); if (filteredTasks.length === initialLength) { return false; // Task not found } await fs.promises.writeFile(this.dbPath, JSON.stringify(filteredTasks, null, 2)); this.cache.delete(taskId); return true; } /** * Update cache with LRU eviction policy * Ensures memory efficiency for long-running processes * @param task Task to update in cache */ updateCache(task) { // Type safety check for task ID if (!task || typeof task.taskId !== 'string' || task.taskId.trim().length === 0) { console.warn('Attempted to cache task with invalid ID'); return; } // Implement simple LRU cache with memory optimization - remove oldest if at capacity if (this.cache.size >= this.cacheSize) { // Get iterator for the keys of the cache const keysIterator = this.cache.keys(); // Get the first key with type safety const iterResult = keysIterator.next(); if (!iterResult.done && typeof iterResult.value === 'string') { // Only delete if the key is a valid string this.cache.delete(iterResult.value); } } // Safe to use task.taskId as we've validated it above this.cache.set(task.taskId, task); } }