UNPKG

crewai-ts

Version:

TypeScript port of crewAI for agent-based workflows

248 lines (247 loc) 8.24 kB
/** * Base Agent Builder * Abstract base class for agent builders that provides a foundation for creating agents * with optimized performance and memory usage */ import { v4 as uuidv4 } from 'uuid'; import { createHash } from 'crypto'; // These will be implemented later, for now create placeholder types class CacheHandler { getOrCompute(key, producer) { return producer(); } } class ToolsHandler { setCache(cache) { } addTool(tool) { } addTools(tools) { } } /** * Base Agent Builder class that provides core functionality for building agents * Optimized for performance and memory efficiency */ export class BaseAgentBuilder { id; originalRole; originalGoal; originalBackstory; // Implementing getters/setters for mutable properties that are readonly in the interface _role; _goal; _backstory; get role() { return this._role; } get goal() { return this._goal; } get backstory() { return this._backstory; } // Configuration properties _verbose; _allowDelegation; _maxIterations; _maxRpm; _memory; _cache; _tools; _llm; _functionCallingLlm; _knowledgeSources; _knowledgeStorage; // Will be properly typed later _systemPrompt; _useSystemPrompt; // Original values are now defined as readonly properties in the class signature // Handlers and utilities _cacheHandler; _toolsHandler; _logger; // Will be properly typed later _rpmController; // Will be properly typed later // Weakmap for storing agent executors to avoid memory leaks static _agentExecutors = new WeakMap(); /** * Constructor for the BaseAgentBuilder * @param config Configuration for the agent */ constructor(config) { // Generate a unique ID for the agent this.id = uuidv4(); // Set original immutable properties this.originalRole = config.role; this.originalGoal = config.goal; this.originalBackstory = config.backstory; // Set mutable properties this._role = config.role; this._goal = config.goal; this._backstory = config.backstory; this._llm = config.llm; this._functionCallingLlm = config.functionCallingLlm; this._verbose = config.verbose ?? false; this._allowDelegation = config.allowDelegation ?? true; this._maxIterations = config.maxIterations ?? 15; this._maxRpm = config.maxRpm; this._memory = config.memory ?? true; this._cache = config.memory ?? false; this._systemPrompt = config.systemPrompt; this._useSystemPrompt = config.useSystemPrompt ?? true; // Initialize handlers this._toolsHandler = new ToolsHandler(); this._tools = this.validateTools(config.tools || []); // Set up cache if needed if (this._cache) { this._cacheHandler = new CacheHandler(); this._toolsHandler.setCache(this._cacheHandler); } } /** * Set knowledge for the agent * @param knowledge Knowledge sources or embeddings */ async setKnowledge(knowledge) { // Implementation for setting agent knowledge would go here // This would connect to a vector store or other knowledge base } /** * Generate a unique key for this agent based on its configuration * Used for caching purposes */ get key() { const hashContent = `${this.role}:${this.goal}:${this.backstory || ''}`; return createHash('md5').update(hashContent).digest('hex'); } /** * Create a deep copy of the Agent * Optimized to avoid unnecessary duplication of resources */ copy() { // This is a placeholder - subclasses will implement proper copying throw new Error('copy() must be implemented by subclasses'); } /** * Interpolate inputs into the agent description and backstory * @param inputs Values to interpolate into the agent template strings */ interpolateInputs(inputs) { if (inputs && Object.keys(inputs).length > 0) { this._role = this.interpolateString(this.originalRole, inputs); this._goal = this.interpolateString(this.originalGoal, inputs); if (this.originalBackstory) { this._backstory = this.interpolateString(this.originalBackstory, inputs); } } } /** * Set the cache handler for the agent * @param cacheHandler An instance of the CacheHandler class */ setCacheHandler(cacheHandler) { this._toolsHandler = new ToolsHandler(); if (this._cache) { this._cacheHandler = cacheHandler; this._toolsHandler.setCache(cacheHandler); } this.createAgentExecutor(); } /** * Set the RPM controller for the agent * @param rpmController An instance of the RPMController class */ setRpmController(rpmController) { if (!this._rpmController) { this._rpmController = rpmController; this.createAgentExecutor(); } } /** * Validate and process the tools provided to the agent * Ensures each tool meets required criteria and converts non-BaseTool to BaseTool * * @param tools List of tools to validate * @returns List of validated BaseTool instances */ validateTools(tools) { const validatedTools = []; for (const tool of tools) { // Fast path: tool is already a BaseTool if (this.isBaseTool(tool)) { validatedTools.push(tool); continue; } // Check if it has the necessary properties to be converted to a BaseTool if (this.canBeConvertedToTool(tool)) { validatedTools.push(this.convertToBaseTool(tool)); continue; } throw new Error(`Tool validation failed: ${JSON.stringify(tool)}. ` + `Tools must be an instance of BaseTool or have 'name', 'func', and 'description' properties.`); } return validatedTools; } /** * Check if an object is a BaseTool instance * @param obj Object to check * @returns True if the object is a BaseTool instance */ isBaseTool(obj) { return obj && typeof obj === 'object' && 'name' in obj && 'description' in obj && typeof obj.execute === 'function'; } /** * Check if an object can be converted to a BaseTool * @param obj Object to check * @returns True if the object can be converted to a BaseTool */ canBeConvertedToTool(obj) { return obj && typeof obj === 'object' && 'name' in obj && 'description' in obj && 'func' in obj && typeof obj.func === 'function'; } /** * Convert an object to a BaseTool instance * @param obj Object to convert * @returns BaseTool instance */ convertToBaseTool(obj) { // This is a simplified implementation // In practice, you would create a proper BaseTool implementation const customTool = { name: obj.name, description: obj.description, verbose: false, cacheResults: false, execute: async (input) => { return await obj.func(input); }, getMetadata: () => ({ name: obj.name, description: obj.description }) }; return customTool; } /** * Interpolate a string with values from an object * @param str String to interpolate * @param values Values to interpolate * @returns Interpolated string */ interpolateString(str, values) { return str.replace(/\{([^}]+)\}/g, (match, key) => { const value = values[key.trim()]; return value !== undefined ? String(value) : match; }); } /** * String representation of the agent */ toString() { return `Agent(id=${this.id}, role=${this.role})`; } }