UNPKG

aiwg

Version:

Deployment tool and support utility for AI context. Copies agents, skills, commands, rules, and behaviors into the paths each AI platform reads (Claude Code, Codex, Copilot, Cursor, Warp, OpenClaw, and 6 more) so one source of truth works across 10 platfo

450 lines 16.8 kB
/** * Agent Generator * * Generates agents following the 10 Golden Rules from the Agent Design Bible. * * @architecture @.aiwg/architecture/software-architecture-doc.md */ import { AgentPackager } from '../../agents/agent-packager.js'; import * as fs from 'fs/promises'; import * as path from 'path'; /** * Template configurations following 10 Golden Rules */ const TEMPLATE_CONFIGS = { simple: { modelTier: 'haiku', tools: ['Read', 'Write'], maxTools: 2, canDelegate: false, readOnly: false, description: 'Simple agents for focused, single-purpose tasks', }, complex: { modelTier: 'sonnet', tools: ['Read', 'Write', 'Grep'], maxTools: 3, canDelegate: false, readOnly: false, description: 'Complex agents requiring analysis and decision-making', }, orchestrator: { modelTier: 'opus', tools: ['Task'], maxTools: 1, canDelegate: true, readOnly: true, description: 'Orchestrators that delegate to other agents (Task tool only)', }, validator: { modelTier: 'sonnet', tools: ['Read', 'Grep'], maxTools: 2, canDelegate: false, readOnly: true, description: 'Validators for quality checks (read-only)', }, }; /** * Agent Generator */ export class AgentGenerator { packager; constructor() { this.packager = new AgentPackager(); } /** * Generate agent following 10 Golden Rules */ async generateAgent(options) { // Step 1: Validate inputs this.validateOptions(options); // Step 2: Get template configuration const template = options.template || 'simple'; const templateConfig = TEMPLATE_CONFIGS[template]; // Step 3: Select model tier const modelTier = options.model || templateConfig.modelTier; // Step 4: Select tools const tools = this.selectTools(options.tools, templateConfig); // Step 5: Build agent structure const structure = await this.buildAgentStructure(options, templateConfig); // Step 6: Generate agent content const content = this.generateContent(structure, modelTier, tools); // Step 7: Transform for platform const platformContent = await this.transformForPlatform(content, options.name, options.description, modelTier, tools, options.platform, options.category, options.version); // Step 8: Determine deployment path const deploymentPath = this.getDeploymentPath(options.projectPath, options.platform, options.name); return { name: options.name, path: deploymentPath, content: platformContent, platform: options.platform, model: modelTier, tools, category: options.category, version: options.version, }; } /** * Deploy generated agent */ async deployAgent(agent) { const dir = path.dirname(agent.path); // Ensure target directory exists await fs.mkdir(dir, { recursive: true }); // Write file await fs.writeFile(agent.path, agent.content, 'utf-8'); } /** * Validate agent options */ validateOptions(options) { if (!options.name || !/^[a-z0-9-]+$/.test(options.name)) { throw new Error('Agent name must be kebab-case (lowercase with hyphens)'); } if (!options.description || options.description.length < 10) { throw new Error('Agent description must be at least 10 characters'); } if (!options.platform) { throw new Error('Platform is required'); } if (!options.projectPath) { throw new Error('Project path is required'); } // Validate custom tools don't exceed template max if (options.tools) { const template = options.template || 'simple'; const maxTools = TEMPLATE_CONFIGS[template].maxTools; if (options.tools.length > maxTools) { throw new Error(`Template '${template}' allows maximum ${maxTools} tools (Golden Rule #2: Minimal Tools)`); } } } /** * Select tools based on template and overrides */ selectTools(customTools, config) { if (customTools && customTools.length > 0) { // Validate count if (customTools.length > config.maxTools) { throw new Error(`Maximum ${config.maxTools} tools allowed for this template (Golden Rule #2)`); } return customTools; } return config.tools; } /** * Build agent structure from options */ async buildAgentStructure(options, config) { const title = this.toTitleCase(options.name); // Build structure from guidance or use defaults const structure = { title, description: options.description, expertise: this.extractExpertise(options.guidance, config), responsibilities: this.extractResponsibilities(options.guidance, config), workflow: this.generateWorkflow(config), outputFormat: this.generateOutputFormat(options.guidance, config), constraints: this.generateConstraints(config), examples: this.generateExamples(options.guidance), }; return structure; } /** * Extract expertise from guidance */ extractExpertise(guidance, config) { const expertise = []; // Add template-specific expertise if (config.canDelegate) { expertise.push('Multi-agent orchestration and workflow coordination'); expertise.push('Task decomposition and parallel execution patterns'); } else if (config.readOnly) { expertise.push('Code analysis and quality validation'); expertise.push('Pattern detection and compliance checking'); } else { expertise.push('Domain-specific task execution'); expertise.push('File manipulation and content generation'); } // Extract from guidance if provided if (guidance) { const expertisePatterns = [ /expert in (.+?)(?:\.|,|$)/gi, /knowledge of (.+?)(?:\.|,|$)/gi, /understands (.+?)(?:\.|,|$)/gi, ]; for (const pattern of expertisePatterns) { const matches = guidance.matchAll(pattern); for (const match of matches) { expertise.push(match[1].trim()); } } } return expertise; } /** * Extract responsibilities from guidance */ extractResponsibilities(guidance, config) { const responsibilities = []; // Add template-specific responsibilities if (config.canDelegate) { responsibilities.push('Decompose complex tasks into agent-sized subtasks'); responsibilities.push('Launch parallel agent execution when appropriate'); responsibilities.push('Synthesize results from multiple agents'); } else if (config.readOnly) { responsibilities.push('Analyze files and patterns without modification'); responsibilities.push('Report findings with specific evidence'); responsibilities.push('Escalate issues requiring human decision'); } else { responsibilities.push('Execute well-defined tasks with clear scope'); responsibilities.push('Verify preconditions before taking action'); responsibilities.push('Report results with clear success/failure indication'); } // Extract from guidance if (guidance) { const responsibilityPatterns = [ /must (.+?)(?:\.|,|$)/gi, /should (.+?)(?:\.|,|$)/gi, /responsible for (.+?)(?:\.|,|$)/gi, ]; for (const pattern of responsibilityPatterns) { const matches = guidance.matchAll(pattern); for (const match of matches) { const resp = match[1].trim(); if (!resp.includes('not') && !resp.includes("don't")) { responsibilities.push(resp); } } } } return responsibilities.slice(0, 5); // Max 5 responsibilities (Golden Rule #1: Single Responsibility) } /** * Generate workflow steps */ generateWorkflow(config) { const workflow = []; // Common steps (Golden Rules #3, #4, #5) workflow.push('**Verify inputs**: Check all required parameters are provided and valid'); if (!config.readOnly) { workflow.push('**Ground before acting**: Use Read/Grep to verify current state'); } // Template-specific workflow if (config.canDelegate) { workflow.push('**Decompose task**: Break into parallel-ready subtasks'); workflow.push('**Launch agents**: Use Task tool to delegate subtasks'); workflow.push('**Synthesize results**: Combine agent outputs into cohesive result'); } else if (config.readOnly) { workflow.push('**Scan and analyze**: Use Read/Grep to examine files'); workflow.push('**Identify issues**: Flag violations or areas of concern'); workflow.push('**Report findings**: Provide actionable recommendations'); } else { workflow.push('**Execute task**: Perform the requested operation'); workflow.push('**Verify result**: Confirm expected outcome achieved'); } // Always include uncertainty handling (Golden Rule #5) workflow.push('**Handle uncertainty**: Escalate to user if ambiguous or out of scope'); return workflow; } /** * Generate output format */ generateOutputFormat(guidance, config) { // Extract format from guidance if specified if (guidance) { const formatMatch = guidance.match(/output format[:\s]+(.+?)(?:\.|$)/i); if (formatMatch) { return formatMatch[1].trim(); } } // Default formats by template if (config.canDelegate) { return 'Structured summary with sections for each delegated task and synthesized conclusion'; } else if (config.readOnly) { return 'Issue report with severity, location, and recommended actions'; } else { return 'Concise confirmation with key details (files modified, lines changed, etc.)'; } } /** * Generate constraints */ generateConstraints(config) { const constraints = []; // Golden Rule #2: Minimal Tools constraints.push(`Limited to ${config.maxTools} tool(s): ${config.tools.join(', ')}`); // Template-specific constraints if (config.readOnly) { constraints.push('Read-only: Cannot modify files or execute commands'); } if (config.canDelegate) { constraints.push('Delegation-only: Uses Task tool, does not perform direct operations'); } // Golden Rule #1: Single Responsibility constraints.push('Single responsibility: Stays within defined scope'); // Golden Rule #5: Uncertainty constraints.push('Escalates ambiguous requests to user rather than guessing'); return constraints; } /** * Generate examples from guidance */ generateExamples(guidance) { if (!guidance) return undefined; const examples = []; const examplePattern = /example[:\s]+(.+?)(?:\.|$)/gi; const matches = guidance.matchAll(examplePattern); for (const match of matches) { examples.push(match[1].trim()); } return examples.length > 0 ? examples : undefined; } /** * Generate full agent content */ generateContent(structure, model, tools) { const lines = []; // Title and description lines.push(`# ${structure.title}`); lines.push(''); lines.push(structure.description); lines.push(''); // Expertise lines.push('## Expertise'); lines.push(''); for (const item of structure.expertise) { lines.push(`- ${item}`); } lines.push(''); // Responsibilities lines.push('## Responsibilities'); lines.push(''); for (const item of structure.responsibilities) { lines.push(`- ${item}`); } lines.push(''); // Workflow lines.push('## Workflow'); lines.push(''); for (let i = 0; i < structure.workflow.length; i++) { lines.push(`${i + 1}. ${structure.workflow[i]}`); } lines.push(''); // Output Format lines.push('## Output Format'); lines.push(''); lines.push(structure.outputFormat); lines.push(''); // Constraints if (structure.constraints && structure.constraints.length > 0) { lines.push('## Constraints'); lines.push(''); for (const item of structure.constraints) { lines.push(`- ${item}`); } lines.push(''); } // Examples if (structure.examples && structure.examples.length > 0) { lines.push('## Examples'); lines.push(''); for (const example of structure.examples) { lines.push(`- ${example}`); } lines.push(''); } // 10 Golden Rules compliance note lines.push('---'); lines.push(''); lines.push('**Note**: This agent follows the 10 Golden Rules for agent design:'); lines.push(''); lines.push('1. **Single Responsibility** - One clear purpose'); lines.push(`2. **Minimal Tools** - ${tools.length} tool(s) maximum`); lines.push('3. **Explicit I/O** - Clear inputs and outputs'); lines.push('4. **Grounding** - Verifies before acting'); lines.push('5. **Uncertainty** - Escalates ambiguity'); lines.push('6. **Context Scope** - Filters distractors'); lines.push('7. **Recovery** - Handles errors gracefully'); lines.push(`8. **Model Tier** - ${model} tier for task complexity`); lines.push('9. **Parallel Ready** - Safe for concurrent execution'); lines.push('10. **Observable** - Traceable output'); return lines.join('\n'); } /** * Transform content for platform */ async transformForPlatform(content, name, description, model, tools, platform, category, version) { // Create AgentInfo-like structure for packager const agentInfo = { metadata: { name, description, model, tools, category: category, version, }, content, filePath: '', // Not used fileName: '', // Not used }; const packaged = await this.packager.package(agentInfo, platform); return packaged.content; } /** * Get deployment path for platform */ getDeploymentPath(projectPath, platform, name) { const platformDirs = { claude: '.claude/agents', codex: '.codex/agents', copilot: '.github/agents', cursor: '.cursor/agents', factory: '.factory/droids', opencode: '.opencode/agent', warp: '.warp/agents', generic: 'agents', windsurf: '.windsurf/agents', hermes: '', openclaw: '.openclaw/agents', }; const ext = this.packager.getFileExtension(platform); return path.join(projectPath, platformDirs[platform], `${name}${ext}`); } /** * Convert kebab-case to Title Case */ toTitleCase(kebab) { return kebab .split('-') .map((word) => word.charAt(0).toUpperCase() + word.slice(1)) .join(' '); } /** * Get template configuration */ getTemplateConfig(template) { return TEMPLATE_CONFIGS[template]; } /** * List all available templates */ listTemplates() { return Object.entries(TEMPLATE_CONFIGS).map(([name, config]) => ({ name: name, config, })); } } //# sourceMappingURL=generator.js.map