UNPKG

@agentdao/core

Version:

Core functionality, skills, and ready-made UI components for AgentDAO - Web3 subscriptions, content generation, social media, help support, live chat, RSS fetching, web search, and agent pricing integration

312 lines (311 loc) 12.7 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ContentGeneratorSkill = void 0; const content_utils_1 = require("./content-utils"); class ContentGeneratorSkill { constructor(config) { this.retryCount = 0; this.maxRetries = 3; this.validateConfig(config); this.config = config; } /** * Validate configuration on initialization */ validateConfig(config) { if (!config.ai?.apiKey) { throw new Error('AI API key is required for ContentGeneratorSkill'); } if (!config.ai.model) { throw new Error('AI model is required for ContentGeneratorSkill'); } if (config.ai.temperature < 0 || config.ai.temperature > 2) { throw new Error('Temperature must be between 0 and 2'); } if (config.ai.maxTokens < 1 || config.ai.maxTokens > 4000) { throw new Error('Max tokens must be between 1 and 4000'); } if (!config.brand?.name) { throw new Error('Brand name is required for ContentGeneratorSkill'); } } /** * Generate blog post with robust error handling and retries */ async generateBlogPost(topic, keywords = [], options = {}) { const { length = 'medium', tone = 'professional', includeSEO = true, retryOnFailure = true } = options; // Input validation this.validateInput('topic', topic, 'string', 1, 200); this.validateInput('keywords', keywords, 'array'); this.validateInput('length', length, 'enum', undefined, undefined, ['short', 'medium', 'long']); this.validateInput('tone', tone, 'enum', undefined, undefined, ['professional', 'casual', 'technical']); // Merge brand keywords with provided keywords const allKeywords = [...new Set([...keywords, ...(this.config.brand.keywords || [])])]; return this.executeWithRetry(async () => { try { return await content_utils_1.ContentGenerators.generateBlogPost(topic, allKeywords, { length, tone, includeSEO }); } catch (error) { this.handleContentGenerationError(error, 'blog post', topic); throw error; } }, retryOnFailure, `Failed to generate blog post about "${topic}"`); } /** * Generate social media post with robust error handling */ async generateSocialPost(platform, topic, options = {}) { const { tone = 'engaging', includeHashtags = true, retryOnFailure = true } = options; // Input validation this.validateInput('platform', platform, 'enum', undefined, undefined, ['twitter', 'linkedin', 'facebook', 'instagram']); this.validateInput('topic', topic, 'string', 1, 100); return this.executeWithRetry(async () => { try { return await content_utils_1.ContentGenerators.generateSocialPost(platform, topic, { tone, includeHashtags }); } catch (error) { this.handleContentGenerationError(error, `${platform} post`, topic); throw error; } }, retryOnFailure, `Failed to generate ${platform} post about "${topic}"`); } /** * Generate email content with robust error handling */ async generateEmail(purpose, recipient, options = {}) { const { tone = 'formal', length = 'medium', retryOnFailure = true } = options; // Input validation this.validateInput('purpose', purpose, 'string', 1, 100); this.validateInput('recipient', recipient, 'string', 1, 100); return this.executeWithRetry(async () => { try { return await content_utils_1.ContentGenerators.generateEmail(purpose, recipient, { tone, length }); } catch (error) { this.handleContentGenerationError(error, 'email', purpose); throw error; } }, retryOnFailure, `Failed to generate email for "${purpose}"`); } /** * Generate content using custom template */ async generateFromTemplate(templateId, variables, options = {}) { const { retryOnFailure = true } = options; // Validate template exists const template = this.config.templates[templateId]; if (!template) { throw new Error(`Template "${templateId}" not found`); } // Validate required variables this.validateTemplateVariables(template, variables); return this.executeWithRetry(async () => { try { // This would be implemented based on template type return await this.generateFromTemplateInternal(template, variables); } catch (error) { this.handleContentGenerationError(error, template.type, templateId); throw error; } }, retryOnFailure, `Failed to generate content from template "${templateId}"`); } /** * Optimize existing content for SEO */ async optimizeContent(content, keywords = [], options = {}) { const { retryOnFailure = true } = options; // Input validation this.validateInput('content', content, 'string', 10, 10000); this.validateInput('keywords', keywords, 'array'); // Merge with brand keywords const allKeywords = [...new Set([...keywords, ...(this.config.brand.keywords || [])])]; return this.executeWithRetry(async () => { try { return await content_utils_1.ContentGenerators.optimizeContent(content, allKeywords); } catch (error) { this.handleContentGenerationError(error, 'content optimization', 'content'); throw error; } }, retryOnFailure, 'Failed to optimize content'); } /** * Generate meta tags for SEO */ async generateMetaTags(title, content, options = {}) { const { retryOnFailure = true } = options; // Input validation this.validateInput('title', title, 'string', 1, 200); this.validateInput('content', content, 'string', 10, 10000); return this.executeWithRetry(async () => { try { return await content_utils_1.ContentGenerators.generateMetaTags(title, content); } catch (error) { this.handleContentGenerationError(error, 'meta tags', title); throw error; } }, retryOnFailure, `Failed to generate meta tags for "${title}"`); } /** * Execute function with retry logic */ async executeWithRetry(fn, retryOnFailure, errorMessage) { let lastError = null; const maxAttempts = retryOnFailure ? this.config.ai.retryAttempts || this.maxRetries : 1; for (let attempt = 1; attempt <= maxAttempts; attempt++) { try { return await fn(); } catch (error) { lastError = error; // Don't retry on certain types of errors if (this.shouldNotRetry(error)) { throw error; } // If this is the last attempt, throw the error if (attempt === maxAttempts) { throw new content_utils_1.ContentGenerationError(`${errorMessage} after ${maxAttempts} attempts: ${lastError.message}`, lastError); } // Wait before retrying (exponential backoff) const delay = Math.min(1000 * Math.pow(2, attempt - 1), 10000); await this.sleep(delay); } } throw lastError || new Error(errorMessage); } /** * Determine if an error should not be retried */ shouldNotRetry(error) { // Don't retry on authentication errors, invalid input, or rate limits const nonRetryableErrors = [ 'APIKeyMissingError', 'authentication', 'unauthorized', 'invalid input', 'rate limit', 'quota exceeded' ]; return nonRetryableErrors.some(keyword => error.message.toLowerCase().includes(keyword.toLowerCase())); } /** * Input validation helper */ validateInput(fieldName, value, type, minLength, maxLength, allowedValues) { // Type validation if (type === 'string' && typeof value !== 'string') { throw new Error(`${fieldName} must be a string`); } if (type === 'array' && !Array.isArray(value)) { throw new Error(`${fieldName} must be an array`); } // Length validation for strings if (type === 'string' && typeof value === 'string') { if (minLength && value.length < minLength) { throw new Error(`${fieldName} must be at least ${minLength} characters long`); } if (maxLength && value.length > maxLength) { throw new Error(`${fieldName} must be no more than ${maxLength} characters long`); } } // Enum validation if (type === 'enum' && allowedValues && !allowedValues.includes(value)) { throw new Error(`${fieldName} must be one of: ${allowedValues.join(', ')}`); } } /** * Validate template variables */ validateTemplateVariables(template, variables) { const requiredVars = template.variables || []; const missingVars = requiredVars.filter((varName) => !variables[varName]); if (missingVars.length > 0) { throw new Error(`Missing required template variables: ${missingVars.join(', ')}`); } } /** * Handle content generation errors with detailed logging */ handleContentGenerationError(error, contentType, context) { console.error(`Content generation error for ${contentType} (${context}):`, { error: error.message, type: error.constructor.name, stack: error.stack, timestamp: new Date().toISOString(), config: { model: this.config.ai.model, temperature: this.config.ai.temperature, maxTokens: this.config.ai.maxTokens } }); // Log to external service if configured if (this.config.integration.autoSave) { this.logErrorToExternalService(error, contentType, context); } } /** * Log error to external service (placeholder for monitoring) */ async logErrorToExternalService(error, contentType, context) { try { // This would integrate with your error monitoring service // e.g., Sentry, LogRocket, etc. console.log('Error logged to external service:', { error: error.message, contentType, context, timestamp: new Date().toISOString() }); } catch (logError) { console.error('Failed to log error to external service:', logError); } } /** * Generate content from template (internal implementation) */ async generateFromTemplateInternal(template, variables) { // This is a placeholder implementation // In a real implementation, you would: // 1. Replace variables in the template prompt // 2. Call the appropriate AI service // 3. Format the response according to the template format const prompt = this.replaceTemplateVariables(template.prompt, variables); // For now, return a mock response return { id: `template_${Date.now()}`, type: template.type, content: `Generated ${template.type} content: ${prompt}`, timestamp: new Date().toISOString() }; } /** * Replace variables in template prompt */ replaceTemplateVariables(prompt, variables) { let result = prompt; Object.entries(variables).forEach(([key, value]) => { result = result.replace(new RegExp(`\\{\\{${key}\\}\\}`, 'g'), value); }); return result; } /** * Sleep utility for retry delays */ sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } } exports.ContentGeneratorSkill = ContentGeneratorSkill;