UNPKG

shipdeck

Version:

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

1,160 lines (970 loc) 28.9 kB
/** * AI Engineer Agent - Specializes in AI/ML integrations * Provides practical AI implementations for rapid development */ const { BaseAgent } = require('./base-agent'); class AIAgent extends BaseAgent { constructor(options = {}) { super({ name: 'ai-engineer', description: 'AI/ML integration specialist for LLM, RAG, embeddings, and prompt engineering', version: '1.0.0', ...options }); // AI-specific configuration this.aiConfig = { defaultModel: 'gpt-3.5-turbo', maxEmbedDimensions: 1536, defaultChunkSize: 1000, defaultChunkOverlap: 200, rateLimitWindow: 60000, // 1 minute rateLimitRequests: 50, ...options.aiConfig }; // Rate limiting storage this.requestLog = []; // Initialize templates this.templates = this.initializeTemplates(); } /** * Get agent capabilities * @returns {Array<string>} Array of capability strings */ getCapabilities() { return ['llm', 'embeddings', 'rag', 'prompts', 'ml-models', 'chat', 'classification', 'generation']; } /** * Initialize AI code templates * @returns {Object} Template collection */ initializeTemplates() { return { llmIntegration: { openai: this.getOpenAITemplate(), anthropic: this.getAnthropicTemplate(), genericLLM: this.getGenericLLMTemplate() }, chatInterface: { react: this.getReactChatTemplate(), vanilla: this.getVanillaChatTemplate(), streaming: this.getStreamingChatTemplate() }, rag: { basic: this.getBasicRAGTemplate(), advanced: this.getAdvancedRAGTemplate(), vectorStore: this.getVectorStoreTemplate() }, embeddings: { generation: this.getEmbeddingsTemplate(), similarity: this.getSimilarityTemplate(), clustering: this.getClusteringTemplate() }, prompts: { classification: this.getClassificationPromptTemplate(), generation: this.getGenerationPromptTemplate(), extraction: this.getExtractionPromptTemplate(), conversation: this.getConversationPromptTemplate() }, utils: { rateLimiter: this.getRateLimiterTemplate(), errorHandler: this.getErrorHandlerTemplate(), tokenCounter: this.getTokenCounterTemplate() } }; } /** * Execute AI engineering task * @param {Object} task - Task configuration * @param {Object} context - Execution context * @returns {Promise<Object>} Execution result */ async execute(task, context = {}) { this.validateTask(task); // Rate limiting check await this.checkRateLimit(); const { type, requirements = [], options = {} } = task; try { let result; switch (type) { case 'llm-integration': result = await this.generateLLMIntegration(task, context); break; case 'chat-interface': result = await this.generateChatInterface(task, context); break; case 'rag-system': result = await this.generateRAGSystem(task, context); break; case 'embeddings-service': result = await this.generateEmbeddingsService(task, context); break; case 'prompt-template': result = await this.generatePromptTemplate(task, context); break; case 'classification-system': result = await this.generateClassificationSystem(task, context); break; case 'content-generator': result = await this.generateContentGenerator(task, context); break; case 'fine-tuning-pipeline': result = await this.generateFineTuningPipeline(task, context); break; case 'semantic-search': result = await this.generateSemanticSearch(task, context); break; default: throw new Error(`Unknown AI task type: ${type}`); } // Log successful request this.logRequest(true); return { ...result, metadata: { agent: this.name, type, timestamp: new Date().toISOString(), rateLimitStatus: this.getRateLimitStatus() } }; } catch (error) { this.logRequest(false); throw error; } } /** * Generate LLM integration code */ async generateLLMIntegration(task, context) { const { provider = 'openai', features = [] } = task; const template = this.templates.llmIntegration[provider] || this.templates.llmIntegration.generic; const prompt = `Generate production-ready ${provider} integration code with the following requirements: ${task.requirements.map(r => `- ${r}`).join('\n')} Features needed: ${features.join(', ')} Context: ${JSON.stringify(context, null, 2)} Include: - TypeScript types and interfaces - Error handling and retry logic - Rate limiting - Streaming support if applicable - Usage tracking - Configuration options Use this base template: ${template}`; const response = await this.sendMessage(prompt, { temperature: 0.3, maxTokens: 3000 }); if (!response.success) { throw new Error(`Failed to generate LLM integration: ${response.error}`); } return { code: response.content, files: this.extractFiles(response.content), template: provider, features }; } /** * Generate chat interface code */ async generateChatInterface(task, context) { const { framework = 'react', features = [] } = task; const template = this.templates.chatInterface[framework]; const prompt = `Create a production chat interface using ${framework} with: ${task.requirements.map(r => `- ${r}`).join('\n')} Features: ${features.join(', ')} Template base: ${template} Include: - Message components - Input handling - Loading states - Error boundaries - Accessibility features - Mobile responsiveness - Real-time updates if specified`; const response = await this.sendMessage(prompt, { temperature: 0.4, maxTokens: 2500 }); if (!response.success) { throw new Error(`Failed to generate chat interface: ${response.error}`); } return { code: response.content, files: this.extractFiles(response.content), framework, features }; } /** * Generate RAG (Retrieval Augmented Generation) system */ async generateRAGSystem(task, context) { const { vectorStore = 'pinecone', features = [] } = task; const template = this.templates.rag.basic; const prompt = `Build a complete RAG system with ${vectorStore} integration: ${task.requirements.map(r => `- ${r}`).join('\n')} Components needed: - Document ingestion pipeline - Text chunking and preprocessing - Embeddings generation - Vector storage and retrieval - Query processing - Response generation Features: ${features.join(', ')} Base template: ${template} Include error handling, monitoring, and scalability considerations.`; const response = await this.sendMessage(prompt, { temperature: 0.3, maxTokens: 4000 }); if (!response.success) { throw new Error(`Failed to generate RAG system: ${response.error}`); } return { code: response.content, files: this.extractFiles(response.content), vectorStore, features, pipeline: 'complete' }; } /** * Generate embeddings service */ async generateEmbeddingsService(task, context) { const { provider = 'openai', model = 'text-embedding-ada-002' } = task; const template = this.templates.embeddings.generation; const prompt = `Create an embeddings service using ${provider} with model ${model}: ${task.requirements.map(r => `- ${r}`).join('\n')} Include: - Batch processing - Caching strategies - Similarity calculations - Clustering capabilities - Performance optimizations - Cost tracking Base template: ${template}`; const response = await this.sendMessage(prompt, { temperature: 0.3, maxTokens: 2500 }); if (!response.success) { throw new Error(`Failed to generate embeddings service: ${response.error}`); } return { code: response.content, files: this.extractFiles(response.content), provider, model, capabilities: ['generation', 'similarity', 'clustering'] }; } /** * Generate prompt template */ async generatePromptTemplate(task, context) { const { promptType = 'general', domain = 'general' } = task; const template = this.templates.prompts[promptType] || this.templates.prompts.conversation; const prompt = `Design optimized prompt templates for ${promptType} in ${domain} domain: ${task.requirements.map(r => `- ${r}`).join('\n')} Create: - System prompts - User prompt templates - Few-shot examples - Validation patterns - Output formatting - Error handling prompts Base template: ${template}`; const response = await this.sendMessage(prompt, { temperature: 0.4, maxTokens: 2000 }); if (!response.success) { throw new Error(`Failed to generate prompt template: ${response.error}`); } return { templates: this.parsePromptTemplates(response.content), type: promptType, domain, examples: this.extractExamples(response.content) }; } /** * Generate classification system */ async generateClassificationSystem(task, context) { const { categories = [], approach = 'llm' } = task; const prompt = `Build a classification system for categories: ${categories.join(', ')} Approach: ${approach} Requirements: ${task.requirements.map(r => `- ${r}`).join('\n')} Include: - Training data handling - Model evaluation - Prediction pipeline - Confidence scoring - Performance metrics - Deployment considerations`; const response = await this.sendMessage(prompt, { temperature: 0.3, maxTokens: 3000 }); if (!response.success) { throw new Error(`Failed to generate classification system: ${response.error}`); } return { code: response.content, files: this.extractFiles(response.content), categories, approach, pipeline: 'complete' }; } /** * Generate content generator */ async generateContentGenerator(task, context) { const { contentType = 'text', style = 'professional' } = task; const prompt = `Create a content generator for ${contentType} with ${style} style: ${task.requirements.map(r => `- ${r}`).join('\n')} Features: - Template management - Style consistency - Quality validation - Batch generation - Custom parameters - Output formatting`; const response = await this.sendMessage(prompt, { temperature: 0.4, maxTokens: 2500 }); if (!response.success) { throw new Error(`Failed to generate content generator: ${response.error}`); } return { code: response.content, files: this.extractFiles(response.content), contentType, style, features: ['templates', 'validation', 'batch'] }; } /** * Generate fine-tuning pipeline */ async generateFineTuningPipeline(task, context) { const { model = 'gpt-3.5-turbo', dataFormat = 'jsonl' } = task; const prompt = `Build a fine-tuning pipeline for ${model}: ${task.requirements.map(r => `- ${r}`).join('\n')} Include: - Data preparation and validation - Training job management - Model evaluation - Deployment pipeline - Monitoring and logging - Cost optimization Data format: ${dataFormat}`; const response = await this.sendMessage(prompt, { temperature: 0.3, maxTokens: 3500 }); if (!response.success) { throw new Error(`Failed to generate fine-tuning pipeline: ${response.error}`); } return { code: response.content, files: this.extractFiles(response.content), model, dataFormat, pipeline: ['data-prep', 'training', 'evaluation', 'deployment'] }; } /** * Generate semantic search system */ async generateSemanticSearch(task, context) { const { indexType = 'vector', searchFeatures = [] } = task; const prompt = `Create a semantic search system with ${indexType} indexing: ${task.requirements.map(r => `- ${r}`).join('\n')} Features: ${searchFeatures.join(', ')} Components: - Document indexing - Query processing - Similarity scoring - Result ranking - Search analytics - Performance optimization`; const response = await this.sendMessage(prompt, { temperature: 0.3, maxTokens: 3000 }); if (!response.success) { throw new Error(`Failed to generate semantic search: ${response.error}`); } return { code: response.content, files: this.extractFiles(response.content), indexType, features: searchFeatures, components: ['indexing', 'query', 'ranking', 'analytics'] }; } /** * Rate limiting implementation */ async checkRateLimit() { const now = Date.now(); const windowStart = now - this.aiConfig.rateLimitWindow; // Clean old requests this.requestLog = this.requestLog.filter(timestamp => timestamp > windowStart); if (this.requestLog.length >= this.aiConfig.rateLimitRequests) { const waitTime = this.requestLog[0] + this.aiConfig.rateLimitWindow - now; if (waitTime > 0) { this.log('warn', `Rate limit reached, waiting ${waitTime}ms`); await this.sleep(waitTime); } } } /** * Log API request for rate limiting */ logRequest(success) { this.requestLog.push(Date.now()); this.log('info', `AI request ${success ? 'successful' : 'failed'}`, { requestCount: this.requestLog.length, rateLimitStatus: this.getRateLimitStatus() }); } /** * Get rate limit status */ getRateLimitStatus() { const now = Date.now(); const windowStart = now - this.aiConfig.rateLimitWindow; const recentRequests = this.requestLog.filter(timestamp => timestamp > windowStart).length; return { requests: recentRequests, limit: this.aiConfig.rateLimitRequests, remaining: Math.max(0, this.aiConfig.rateLimitRequests - recentRequests), resetTime: windowStart + this.aiConfig.rateLimitWindow }; } /** * Extract files from generated code */ extractFiles(content) { const files = []; const fileRegex = /```(\w+)?\s*(.*?)\n([\s\S]*?)```/g; let match; while ((match = fileRegex.exec(content)) !== null) { const [, language, filename, code] = match; if (filename && code) { files.push({ filename: filename.trim(), language: language || 'javascript', content: code.trim() }); } } return files; } /** * Parse prompt templates from response */ parsePromptTemplates(content) { const templates = {}; const sections = content.split('###').slice(1); sections.forEach(section => { const lines = section.trim().split('\n'); const title = lines[0].trim().toLowerCase().replace(/\s+/g, '_'); const template = lines.slice(1).join('\n').trim(); templates[title] = template; }); return templates; } /** * Extract examples from content */ extractExamples(content) { const examples = []; const exampleRegex = /Example \d+:([\s\S]*?)(?=Example \d+:|$)/g; let match; while ((match = exampleRegex.exec(content)) !== null) { examples.push(match[1].trim()); } return examples; } /** * Template: OpenAI Integration */ getOpenAITemplate() { return ` import OpenAI from 'openai'; export interface OpenAIConfig { apiKey: string; model?: string; temperature?: number; maxTokens?: number; } export class OpenAIService { private client: OpenAI; private config: Required<OpenAIConfig>; constructor(config: OpenAIConfig) { this.client = new OpenAI({ apiKey: config.apiKey }); this.config = { model: 'gpt-3.5-turbo', temperature: 0.7, maxTokens: 1000, ...config }; } async generate(prompt: string, options?: Partial<OpenAIConfig>) { // Implementation with error handling and rate limiting } } `; } /** * Template: Anthropic Integration */ getAnthropicTemplate() { return ` import Anthropic from '@anthropic-ai/sdk'; export interface AnthropicConfig { apiKey: string; model?: string; maxTokens?: number; } export class AnthropicService { private client: Anthropic; private config: Required<AnthropicConfig>; constructor(config: AnthropicConfig) { this.client = new Anthropic({ apiKey: config.apiKey }); this.config = { model: 'claude-3-sonnet-20240229', maxTokens: 1000, ...config }; } async generate(messages: Array<{ role: string; content: string }>) { // Implementation with streaming and error handling } } `; } /** * Template: Generic LLM Integration */ getGenericLLMTemplate() { return ` export interface LLMProvider { generate(prompt: string, options?: any): Promise<string>; stream(prompt: string, options?: any): AsyncIterable<string>; } export class LLMService { constructor(private provider: LLMProvider) {} async generate(prompt: string, options?: any) { return this.provider.generate(prompt, options); } async *stream(prompt: string, options?: any) { yield* this.provider.stream(prompt, options); } } `; } /** * Template: React Chat Interface */ getReactChatTemplate() { return ` import React, { useState, useRef, useEffect } from 'react'; interface Message { id: string; role: 'user' | 'assistant'; content: string; timestamp: Date; } export const ChatInterface: React.FC = () => { const [messages, setMessages] = useState<Message[]>([]); const [input, setInput] = useState(''); const [loading, setLoading] = useState(false); const messagesEndRef = useRef<HTMLDivElement>(null); const sendMessage = async () => { // Implementation with API calls and state management }; return ( <div className="chat-container"> {/* Chat implementation */} </div> ); }; `; } /** * Template: Streaming Chat */ getStreamingChatTemplate() { return ` export class StreamingChat { private eventSource: EventSource | null = null; async startStream(messages: Message[], onChunk: (chunk: string) => void) { const response = await fetch('/api/chat/stream', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ messages }) }); const reader = response.body?.getReader(); // Implementation with streaming response handling } } `; } /** * Template: Vanilla Chat Interface */ getVanillaChatTemplate() { return ` class ChatInterface { constructor(containerId) { this.container = document.getElementById(containerId); this.messages = []; this.init(); } init() { this.render(); this.bindEvents(); } async sendMessage(content) { // Implementation with vanilla JS } render() { // DOM manipulation for chat interface } } `; } /** * Template: Basic RAG System */ getBasicRAGTemplate() { return ` export interface Document { id: string; content: string; metadata?: Record<string, any>; embedding?: number[]; } export class RAGSystem { private vectorStore: VectorStore; private embeddings: EmbeddingsService; private llm: LLMService; constructor(config: RAGConfig) { // Initialize components } async ingestDocuments(documents: Document[]) { // Document processing and storage } async query(question: string, options?: QueryOptions) { // Retrieve relevant documents and generate response } } `; } /** * Template: Advanced RAG System */ getAdvancedRAGTemplate() { return ` export class AdvancedRAGSystem extends RAGSystem { private reranker: RerankerService; private queryProcessor: QueryProcessor; private responseGenerator: ResponseGenerator; async hybridSearch(query: string, options: HybridSearchOptions) { // Combine vector and keyword search } async adaptiveRetrieval(query: string, context: ConversationContext) { // Context-aware retrieval with reranking } } `; } /** * Template: Vector Store */ getVectorStoreTemplate() { return ` export interface VectorStore { upsert(vectors: Vector[]): Promise<void>; query(vector: number[], topK: number, filter?: Filter): Promise<ScoredVector[]>; delete(ids: string[]): Promise<void>; } export class PineconeVectorStore implements VectorStore { constructor(private client: PineconeClient, private indexName: string) {} async upsert(vectors: Vector[]): Promise<void> { // Pinecone-specific implementation } } `; } /** * Template: Embeddings Generation */ getEmbeddingsTemplate() { return ` export class EmbeddingsService { constructor(private provider: EmbeddingsProvider) {} async generateEmbedding(text: string): Promise<number[]> { const response = await this.provider.createEmbedding({ input: text }); return response.data[0].embedding; } async batchEmbeddings(texts: string[], batchSize = 100): Promise<number[][]> { // Batch processing with rate limiting } } `; } /** * Template: Similarity Calculations */ getSimilarityTemplate() { return ` export class SimilarityService { static cosineSimilarity(a: number[], b: number[]): number { const dotProduct = a.reduce((sum, val, i) => sum + val * b[i], 0); const magnitudeA = Math.sqrt(a.reduce((sum, val) => sum + val * val, 0)); const magnitudeB = Math.sqrt(b.reduce((sum, val) => sum + val * val, 0)); return dotProduct / (magnitudeA * magnitudeB); } static euclideanDistance(a: number[], b: number[]): number { return Math.sqrt(a.reduce((sum, val, i) => sum + Math.pow(val - b[i], 2), 0)); } } `; } /** * Template: Clustering */ getClusteringTemplate() { return ` export class KMeansClusterer { constructor(private k: number, private maxIterations = 100) {} cluster(embeddings: number[][]): ClusterResult { // K-means implementation for embeddings } private calculateCentroid(points: number[][]): number[] { // Centroid calculation } } `; } /** * Template: Classification Prompts */ getClassificationPromptTemplate() { return ` export const classificationPrompts = { system: \`You are a professional classifier. Analyze the given text and classify it into one of the predefined categories. Guidelines: - Be accurate and consistent - Provide confidence scores - Explain your reasoning briefly - Handle edge cases gracefully\`, user: \`Classify the following text into one of these categories: {categories} Text: {text} Respond in JSON format: { "category": "selected_category", "confidence": 0.95, "reasoning": "brief explanation" }\`, fewShot: [ { input: "example text", output: { category: "example_category", confidence: 0.9, reasoning: "example reasoning" } } ] }; `; } /** * Template: Generation Prompts */ getGenerationPromptTemplate() { return ` export const generationPrompts = { system: \`You are a creative content generator. Create high-quality, engaging content based on the given parameters. Guidelines: - Match the specified tone and style - Ensure factual accuracy - Be creative while staying on-topic - Follow length requirements\`, user: \`Generate {contentType} with the following specifications: - Topic: {topic} - Style: {style} - Length: {length} - Target audience: {audience} Additional requirements: {requirements}\` }; `; } /** * Template: Extraction Prompts */ getExtractionPromptTemplate() { return ` export const extractionPrompts = { system: \`You are a precise information extractor. Extract specific information from text with high accuracy. Guidelines: - Only extract explicitly stated information - Maintain original phrasing when possible - Handle missing information gracefully - Structure output consistently\`, user: \`Extract the following information from the text: {extractionFields} Text: {text} Return as JSON with these exact fields: {fieldNames}\` }; `; } /** * Template: Conversation Prompts */ getConversationPromptTemplate() { return ` export const conversationPrompts = { system: \`You are a helpful AI assistant. Engage in natural, helpful conversations while maintaining context. Guidelines: - Be helpful and informative - Maintain conversation context - Ask clarifying questions when needed - Provide structured responses when appropriate\`, contextualPrompt: (context: ConversationContext) => \` Previous conversation context: ${context.summary} Current user message: {userMessage} Respond naturally while considering the conversation history.\` }; `; } /** * Template: Rate Limiter */ getRateLimiterTemplate() { return ` export class RateLimiter { private requests: Map<string, number[]> = new Map(); constructor( private limit: number, private windowMs: number ) {} async checkLimit(key: string): Promise<boolean> { const now = Date.now(); const windowStart = now - this.windowMs; const requestTimes = this.requests.get(key) || []; const validRequests = requestTimes.filter(time => time > windowStart); if (validRequests.length >= this.limit) { return false; } validRequests.push(now); this.requests.set(key, validRequests); return true; } } `; } /** * Template: Error Handler */ getErrorHandlerTemplate() { return ` export class AIErrorHandler { static handleAPIError(error: any): AIError { if (error.response?.status === 429) { return new RateLimitError('API rate limit exceeded', error.response.headers); } if (error.response?.status === 401) { return new AuthenticationError('Invalid API key', error); } if (error.response?.status >= 500) { return new ServerError('AI service unavailable', error); } return new GenericAIError('Unknown AI error', error); } static async withRetry<T>( operation: () => Promise<T>, maxRetries = 3, baseDelay = 1000 ): Promise<T> { // Exponential backoff retry implementation } } `; } /** * Template: Token Counter */ getTokenCounterTemplate() { return ` export class TokenCounter { // Rough estimation for different models private static readonly CHARS_PER_TOKEN = { 'gpt-3.5-turbo': 4, 'gpt-4': 4, 'claude-3': 4, 'default': 4 }; static estimateTokens(text: string, model = 'default'): number { const charsPerToken = this.CHARS_PER_TOKEN[model] || this.CHARS_PER_TOKEN.default; return Math.ceil(text.length / charsPerToken); } static truncateToTokenLimit(text: string, maxTokens: number, model = 'default'): string { const charsPerToken = this.CHARS_PER_TOKEN[model] || this.CHARS_PER_TOKEN.default; const maxChars = maxTokens * charsPerToken; if (text.length <= maxChars) return text; return text.substring(0, maxChars) + '...'; } } `; } /** * Get system prompt for AI Engineer Agent */ getSystemPrompt() { return `You are an AI Engineer Agent specializing in practical AI/ML integrations for rapid development. Your expertise includes: - LLM integrations (OpenAI, Anthropic, local models) - Prompt engineering and optimization - RAG (Retrieval Augmented Generation) systems - Vector databases and embeddings - Chat interfaces and streaming responses - Classification and content generation systems - Fine-tuning pipelines and model optimization - Rate limiting, error handling, and monitoring Core Principles: 1. Generate production-ready, TypeScript code with proper types 2. Include comprehensive error handling and retry logic 3. Implement rate limiting and cost optimization 4. Provide both simple and advanced implementation options 5. Focus on practical, immediately deployable solutions 6. Include monitoring and observability features 7. Ensure security best practices for API keys and data Always provide: - Clean, well-documented code - TypeScript interfaces and types - Error boundaries and fallback mechanisms - Performance considerations - Security best practices - Testing strategies - Deployment guidance Generate code that developers can immediately integrate and use in production environments.`; } /** * Cleanup resources */ cleanup() { this.requestLog = []; super.cleanup(); } } module.exports = { AIAgent };