UNPKG

shipdeck

Version:

Ship MVPs in 48 hours. Fix bugs in 30 seconds. The command deck for developers who ship.

284 lines (247 loc) 7.67 kB
/** * Base Agent Class for Shipdeck Ultimate * Provides foundation for all specialized agents with common functionality */ const { AnthropicClient } = require('../anthropic/client'); class BaseAgent { constructor(options = {}) { this.name = options.name || this.constructor.name; this.description = options.description || 'Base agent for common functionality'; this.version = options.version || '1.0.0'; // Initialize Anthropic client this.client = options.anthropicClient || new AnthropicClient(options.anthropicConfig); // Agent configuration this.config = { maxRetries: 3, temperature: 0.7, maxTokens: 4096, ...options.config }; // Validation this.validateConfig(); } /** * Validate agent configuration */ validateConfig() { if (!this.client) { throw new Error('Anthropic client is required'); } if (typeof this.config.maxRetries !== 'number' || this.config.maxRetries < 0) { throw new Error('maxRetries must be a non-negative number'); } } /** * Get agent capabilities - to be overridden by specialized agents * @returns {Array<string>} Array of capability strings */ getCapabilities() { return ['base']; } /** * Get agent metadata * @returns {Object} Agent metadata */ getMetadata() { return { name: this.name, description: this.description, version: this.version, capabilities: this.getCapabilities(), config: { maxRetries: this.config.maxRetries, temperature: this.config.temperature, maxTokens: this.config.maxTokens } }; } /** * Execute agent task - must be implemented by specialized agents * @param {Object} task - Task configuration * @param {Object} context - Execution context * @returns {Promise<Object>} Execution result */ async execute(task, context = {}) { throw new Error('execute() method must be implemented by specialized agents'); } /** * Validate task input * @param {Object} task - Task to validate * @returns {boolean} True if valid */ validateTask(task) { if (!task || typeof task !== 'object') { throw new Error('Task must be an object'); } if (!task.type) { throw new Error('Task must have a type property'); } return true; } /** * Create standardized prompt for the agent * @param {Object} task - Task configuration * @param {Object} context - Additional context * @returns {string} Formatted prompt */ createPrompt(task, context = {}) { const systemPrompt = this.getSystemPrompt(); const taskPrompt = this.formatTaskPrompt(task); const contextPrompt = context ? this.formatContextPrompt(context) : ''; return [systemPrompt, taskPrompt, contextPrompt].filter(Boolean).join('\n\n'); } /** * Get system prompt - to be overridden by specialized agents * @returns {string} System prompt */ getSystemPrompt() { return `You are ${this.name}, a specialized AI agent. Description: ${this.description} Capabilities: ${this.getCapabilities().join(', ')} Please provide helpful, accurate, and well-structured responses.`; } /** * Format task into prompt * @param {Object} task - Task configuration * @returns {string} Formatted task prompt */ formatTaskPrompt(task) { return `Task Type: ${task.type} ${task.description ? `Description: ${task.description}` : ''} ${task.requirements ? `Requirements:\n${Array.isArray(task.requirements) ? task.requirements.map(r => `- ${r}`).join('\n') : task.requirements}` : ''} ${task.input ? `Input:\n${typeof task.input === 'object' ? JSON.stringify(task.input, null, 2) : task.input}` : ''}`; } /** * Format context into prompt * @param {Object} context - Context information * @returns {string} Formatted context prompt */ formatContextPrompt(context) { if (!context || Object.keys(context).length === 0) { return ''; } const contextEntries = Object.entries(context) .map(([key, value]) => `${key}: ${typeof value === 'object' ? JSON.stringify(value, null, 2) : value}`) .join('\n'); return `Context:\n${contextEntries}`; } /** * Send message to Anthropic API with error handling * @param {string|Array} messages - Message(s) to send * @param {Object} options - Request options * @returns {Promise<Object>} API response */ async sendMessage(messages, options = {}) { try { const messageArray = Array.isArray(messages) ? messages : [{ role: 'user', content: messages }]; const response = await this.client.createMessage(messageArray, { maxTokens: options.maxTokens || this.config.maxTokens, temperature: options.temperature ?? this.config.temperature, ...options }); return { success: true, content: response.content[0]?.text || '', usage: response.usage, metadata: response._metadata }; } catch (error) { return { success: false, error: error.message, errorType: error.constructor.name, retryable: error.isRetryable ? error.isRetryable() : false }; } } /** * Execute task with retry logic * @param {Object} task - Task to execute * @param {Object} context - Execution context * @returns {Promise<Object>} Execution result */ async executeWithRetry(task, context = {}) { this.validateTask(task); let lastError; for (let attempt = 1; attempt <= this.config.maxRetries; attempt++) { try { const result = await this.execute(task, { ...context, attempt }); return { success: true, result, metadata: { agent: this.name, attempt, timestamp: new Date().toISOString() } }; } catch (error) { lastError = error; if (attempt < this.config.maxRetries) { const delay = Math.pow(2, attempt - 1) * 1000; // Exponential backoff await this.sleep(delay); } } } return { success: false, error: lastError.message, metadata: { agent: this.name, maxAttempts: this.config.maxRetries, timestamp: new Date().toISOString() } }; } /** * Sleep utility for retry delays * @param {number} ms - Milliseconds to sleep * @returns {Promise} */ sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } /** * Log message with agent context * @param {string} level - Log level (info, warn, error) * @param {string} message - Message to log * @param {Object} data - Additional data */ log(level, message, data = {}) { const timestamp = new Date().toISOString(); const logEntry = { timestamp, agent: this.name, level, message, ...data }; console[level] || console.log(`[${timestamp}] [${this.name}] [${level.toUpperCase()}] ${message}`, data); } /** * Parse and structure response from AI * @param {string} response - Raw AI response * @returns {Object} Structured response */ parseResponse(response) { try { // Try to parse as JSON first return JSON.parse(response); } catch { // Return as structured text return { type: 'text', content: response, parsed: false }; } } /** * Cleanup resources */ cleanup() { // Override in specialized agents if needed this.log('info', 'Agent cleanup completed'); } } module.exports = { BaseAgent };