Skip to main content
Glama
orneryd

M.I.M.I.R - Multi-agent Intelligent Memory & Insight Repository

by orneryd
create-agent.ts9.64 kB
#!/usr/bin/env node /** * Create Agent Script * * Uses claudette-agentinator to generate a new agent preamble based on a role description. * This is the first hop in the two-hop validation process. * * Usage: * npm run create-agent "role description" * * Example: * npm run create-agent "senior developer with golang and cryptography expertise" */ import { CopilotAgentClient } from './llm-client.js'; import fs from 'fs/promises'; import path from 'path'; import crypto from 'crypto'; interface AgentRequest { roleDescription: string; benchmarkTask: string; benchmarkName: string; } /** * Clean LLM output by removing markdown code blocks and extra whitespace * * LLMs sometimes wrap their output in markdown code blocks (```markdown...```). * This function strips those wrappers to get the raw content. * * @param output - Raw output from LLM that may contain markdown wrappers * @returns Cleaned output with code blocks and extra whitespace removed * * @example * ```ts * const raw = '```markdown\n# Title\nContent\n```'; * const clean = cleanLLMOutput(raw); * // Returns: '# Title\nContent' * ``` */ function cleanLLMOutput(output: string): string { let cleaned = output.trim(); // Remove markdown code blocks (```markdown ... ``` or ``` ... ```) cleaned = cleaned.replace(/^```(?:markdown)?\s*\n/i, ''); cleaned = cleaned.replace(/\n```\s*$/i, ''); // Remove any leading/trailing whitespace again cleaned = cleaned.trim(); return cleaned; } /** * Create a new agent preamble using the Agentinator system * * This function orchestrates the agent creation process: * 1. Loads the appropriate template (Worker or QC) * 2. Initializes the Agentinator agent * 3. Generates a customized preamble based on role description * 4. Saves the preamble to a hashed filename for caching * * The generated agent follows strict template structure preservation rules * to ensure consistency across all generated agents. * * @param roleDescription - Natural language description of the agent's role * Example: "senior golang developer with cryptography expertise" * @param outputDir - Directory to save generated agent preambles (default: 'generated-agents') * @param model - LLM model to use for generation (default: from MIMIR_DEFAULT_MODEL env) * @param taskExample - Optional task object to provide context for generation * @param isQC - Whether to generate a QC agent (true) or Worker agent (false) * * @returns Path to the generated agent preamble file * * @example * ```ts * // Create a worker agent * const agentPath = await createAgent( * 'senior golang developer', * 'generated-agents', * 'gpt-4.1' * ); * console.log(`Agent saved to: ${agentPath}`); * // Output: Agent saved to: generated-agents/worker-a3f2b8c1.md * * // Create a QC agent with task context * const qcPath = await createAgent( * 'security auditor', * 'generated-agents', * 'gpt-4.1', * { id: 't1', title: 'Audit auth system', prompt: '...' }, * true * ); * ``` */ export async function createAgent( roleDescription: string, outputDir: string = 'generated-agents', model: string = process.env.MIMIR_DEFAULT_MODEL || 'gpt-4.1', taskExample?: any, isQC: boolean = false ): Promise<string> { console.log(`\n🤖 Creating ${isQC ? 'QC' : 'Worker'} Agent for role: ${roleDescription}\n`); // 1. Determine agent type from role description const agentType = isQC ? 'QC' : 'Worker'; const templatePath = isQC ? 'docs/agents/v2/templates/qc-template.md' : 'docs/agents/v2/templates/worker-template.md'; console.log(`🔍 Detected agent type: ${agentType}`); console.log(`📄 Loading template: ${templatePath}\n`); // 2. Load the template let templateContent: string; try { templateContent = await fs.readFile(templatePath, 'utf-8'); console.log(`✅ Template loaded: ${templateContent.length} characters\n`); } catch (error) { console.error(`❌ Failed to load template: ${error}`); throw new Error(`Template not found: ${templatePath}`); } // 3. Initialize Agentinator const agentinator = new CopilotAgentClient({ preamblePath: 'docs/agents/v2/02-agentinator-preamble.md', model, temperature: 0.0, }); await agentinator.loadPreamble('docs/agents/v2/02-agentinator-preamble.md'); // 4. Create task prompt for Agentinator with template const aginatorTask = `YOU ARE GENERATING A ${agentType.toUpperCase()} AGENT PREAMBLE. **CRITICAL: YOU MUST FOLLOW THE TEMPLATE STRUCTURE EXACTLY** <agent_type> ${agentType} </agent_type> <role_description> ${roleDescription} </role_description> <task_requirements> ${taskExample ? ` **Specific Task Example:** **Task ID:** ${taskExample.id} **Title:** ${taskExample.title} **Prompt:** ${taskExample.prompt} **Success Criteria:** ${taskExample.verificationCriteria || 'Complete all requirements in the prompt above'} **Estimated Tool Calls:** ${taskExample.estimatedToolCalls || 'Not specified'} ` : `The agent must be able to work autonomously on tasks related to: ${roleDescription}`} </task_requirements> <task_context> ${taskExample ? ` **Actual Task Context:** - Task dependencies: ${taskExample.dependencies?.join(', ') || 'None'} - Estimated duration: ${taskExample.estimatedDuration || 'Not specified'} - Recommended model: ${taskExample.recommendedModel || 'Not specified'} ` : ''} - Tools available: run_terminal_cmd, read_file, write, search_replace, list_dir, grep, delete_file, web_search - Must work without user intervention - Must provide evidence for all claims - Must follow best practices for the domain </task_context> <template_path> ${templatePath} </template_path> <template_content> ${templateContent} </template_content> MANDATORY INSTRUCTIONS: 1. **LOAD THE TEMPLATE ABOVE** - The template content is provided in <template_content> 2. **PRESERVE EXACT STRUCTURE** - Follow the "CRITICAL: TEMPLATE STRUCTURE PRESERVATION" section in your preamble 3. **CUSTOMIZE CONTENT ONLY** - Replace placeholders like [ROLE_TITLE], [DOMAIN_EXPERTISE] with specifics 4. **DO NOT RENAME SECTIONS** - Section headers must match template exactly (emoji + text) 5. **DO NOT REORDER SECTIONS** - Keep sections in template order 6. **PRESERVE STEP STRUCTURE** - For Worker: STEP 0-5, For QC: STEP 1-5 as SEPARATE sections 7. **INCLUDE <reasoning> TAGS** - In STEP 1, use proper <reasoning></reasoning> format 8. **INCLUDE ALL CHECKLISTS** - Preserve all "- [ ]" checklists from template 9. **INCLUDE ANTI-PATTERNS** - Keep the Anti-Patterns section with all 6 patterns 10. **INCLUDE FINAL CHECKLIST** - Keep the Final Verification Checklist section VALIDATION BEFORE OUTPUT: - [ ] All 11 sections from template present? - [ ] Section headers match template exactly? - [ ] Section order matches template? - [ ] STEP numbers correct (0-5 for Worker, 1-5 for QC)? - [ ] <reasoning> tags in STEP 1? - [ ] Checklists preserved? - [ ] Anti-Patterns section included? - [ ] Final Verification Checklist included? OUTPUT FORMAT: - Start with YAML frontmatter (description, tools) - Then output the complete preamble following the template structure - Do NOT wrap in \`\`\`markdown code blocks - Do NOT add meta-commentary NOW: Generate the ${agentType} agent preamble by customizing the template above.`; // 5. Execute Agentinator console.log('⚙️ Generating agent preamble with Agentinator...\n'); const result = await agentinator.execute(aginatorTask); console.log(`✅ Preamble generated - Tool calls: ${result.toolCalls}, Tokens: ${result.tokens.input + result.tokens.output}\n`); // 6. Clean the output (remove markdown code blocks if present) const cleanedOutput = cleanLLMOutput(result.output); if (cleanedOutput !== result.output) { console.log('🧹 Cleaned markdown code blocks from output\n'); } // 7. Generate hashed filename for caching const roleHash = crypto.createHash('md5').update(roleDescription).digest('hex').substring(0, 8); const prefix = isQC ? 'qc' : 'worker'; const agentFilename = `${prefix}-${roleHash}.md`; const agentPath = path.join(outputDir, agentFilename); await fs.mkdir(outputDir, { recursive: true }); await fs.writeFile(agentPath, cleanedOutput, 'utf-8'); console.log(`📄 Agent preamble saved to: ${agentPath}`); console.log(`📊 Generation stats:`); console.log(` - Tool calls: ${result.toolCalls}`); console.log(` - Input tokens: ${result.tokens.input}`); console.log(` - Output tokens: ${result.tokens.output}`); console.log(` - Preamble length: ${cleanedOutput.length} characters\n`); // Metadata is no longer saved to reduce file clutter // (Can be re-enabled for debugging if needed) return agentPath; } // CLI usage - only run if this file is executed directly (not imported) if (import.meta.url === `file://${process.argv[1]}`) { const args = process.argv.slice(2); // Skip node and script path if (args.length < 1) { console.error('Usage: npm run create-agent "role description"'); console.error('\nExample:'); console.error(' npm run create-agent "senior golang developer"'); console.error('\nSet model: export COPILOT_MODEL=gpt-4_1'); process.exit(1); } const [roleDescription] = args; const model = process.env.MIMIR_DEFAULT_MODEL || 'gpt-4.1'; createAgent( roleDescription, 'generated-agents', model ).then((agentPath) => { console.log('✅ Agent creation complete!'); console.log(`\n💡 Next step: Validate the generated agent:`); console.log(` npm run validate ${agentPath}\n`); }).catch(console.error); }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/orneryd/Mimir'

If you have feedback or need assistance with the MCP directory API, please join our Discord server