UNPKG

agent-team-composer

Version:

Transform README files into GitHub project plans with AI-powered agent teams

133 lines (124 loc) 5.79 kB
import Anthropic from '@anthropic-ai/sdk'; import { z } from 'zod'; import { RobustLLMHandler } from './json-extractor.js'; import { PromptSanitizer } from './prompt-sanitizer.js'; const FORM_POPULATION_PROMPT = `You are an AI assistant that analyzes project README content to intelligently suggest form field values for a project planning tool. Given the README content below, analyze it and provide intelligent suggestions for the following fields: 1. **Target Users**: Identify the primary user groups or personas who would use this product based on the README content. Consider both explicitly mentioned users and inferred users based on features. 2. **Tech Stack**: Extract and infer the technologies, frameworks, libraries, and tools used in the project. Look for: - Explicitly mentioned technologies - Dependencies in package files - File extensions and project structure clues - API mentions and integrations 3. **Key Features**: Extract the main features and capabilities of the project. Look for: - Feature lists - Functionality descriptions - Use cases mentioned - Problem-solving capabilities 4. **Domain**: Determine the most appropriate domain category based on the project's purpose and functionality. 5. **Complexity**: Assess the project complexity as simple, moderate, or complex based on: - Number of features - Technical stack diversity - Integration requirements - Scalability mentions README CONTENT: {readmeContent} EXISTING PARSED DATA (use this as context but provide enhanced suggestions): Title: {title} Description: {description} Basic Features: {basicFeatures} Basic Tech Stack: {basicTechStack} Provide your analysis in the following JSON format: { "targetUsers": ["user group 1", "user group 2", ...], "techStack": ["technology 1", "technology 2", ...], "features": ["feature 1", "feature 2", ...], "domain": "domain_category", "complexity": "simple|moderate|complex" }`; export class AIFormPopulator { anthropic; model = 'claude-3-sonnet-20240229'; constructor(apiKey = process.env.ANTHROPIC_API_KEY) { this.anthropic = new Anthropic({ apiKey }); } async populateFormFields(readmeContent, existingData) { // Sanitize inputs const sanitizedReadme = PromptSanitizer.sanitizeReadme(readmeContent); // Check for suspicious patterns if (PromptSanitizer.containsSuspiciousPatterns(readmeContent)) { throw new Error('Input contains potentially malicious patterns'); } // Build the prompt with existing data as context const prompt = PromptSanitizer.buildSafePrompt(FORM_POPULATION_PROMPT, { readmeContent: sanitizedReadme, title: existingData?.title || 'Not provided', description: existingData?.description || 'Not provided', basicFeatures: existingData?.features?.join(', ') || 'None detected', basicTechStack: existingData?.techStack?.join(', ') || 'None detected' }); // Define schema for validation const FormSuggestionsSchema = z.object({ targetUsers: z.array(z.string()).min(1), techStack: z.array(z.string()).min(1), features: z.array(z.string()).min(1), domain: z.string(), complexity: z.enum(['simple', 'moderate', 'complex']) }); try { // Use bulletproof extraction const suggestions = await RobustLLMHandler.getStructuredResponse(this.anthropic, prompt, FormSuggestionsSchema, 'form-field-population'); // Post-process suggestions to ensure quality return { targetUsers: this.deduplicateAndClean(suggestions.targetUsers), techStack: this.deduplicateAndClean(suggestions.techStack), features: this.deduplicateAndClean(suggestions.features), domain: this.validateDomain(suggestions.domain), complexity: suggestions.complexity }; } catch (error) { console.error('AI form population failed:', error); // Return fallback suggestions based on basic parsing return this.getFallbackSuggestions(existingData); } } deduplicateAndClean(items) { // Remove duplicates and clean up strings const seen = new Set(); return items .map(item => item.trim()) .filter(item => item.length > 0 && item.length < 100) // Reasonable length .filter(item => { const normalized = item.toLowerCase(); if (seen.has(normalized)) return false; seen.add(normalized); return true; }); } validateDomain(domain) { const validDomains = [ 'e-commerce', 'social-media', 'productivity', 'healthcare', 'education', 'finance', 'entertainment', 'devtools', 'iot', 'general', 'communication', 'analytics', 'gaming' ]; const normalized = domain.toLowerCase().replace(/\s+/g, '-'); return validDomains.includes(normalized) ? normalized : 'general'; } getFallbackSuggestions(existingData) { return { targetUsers: ['developers', 'end-users'], techStack: existingData?.techStack || ['JavaScript', 'Node.js'], features: existingData?.features || ['Core functionality'], domain: 'general', complexity: 'moderate' }; } } // Singleton instance for easy access export async function populateFormWithAI(readmeContent, existingData) { const populator = new AIFormPopulator(); return populator.populateFormFields(readmeContent, existingData); } //# sourceMappingURL=ai-form-populator.js.map