Skip to main content
Glama
AgentManager.ts6.32 kB
import { readFile, readdir } from 'fs/promises'; import { join, extname } from 'path'; import { existsSync } from 'fs'; export interface AgentTemplate { id: string; name: string; content: string; metadata: { role?: string; expertise?: string[]; category?: string; lastModified?: string; }; } export class AgentManager { private agentsPath: string; private templates: Map<string, AgentTemplate>; private activeAgent: string | null; constructor(agentsPath: string = join(process.cwd(), 'agents')) { this.agentsPath = agentsPath; this.templates = new Map(); this.activeAgent = null; } async initialize(): Promise<void> { if (!existsSync(this.agentsPath)) { throw new Error(`Agents directory not found: ${this.agentsPath}`); } await this.loadTemplates(); } private async loadTemplates(): Promise<void> { const files = await readdir(this.agentsPath); const mdFiles = files.filter(file => extname(file) === '.md'); for (const file of mdFiles) { const filePath = join(this.agentsPath, file); const content = await readFile(filePath, 'utf-8'); const id = file.replace('.md', ''); const template: AgentTemplate = { id, name: this.formatName(id), content, metadata: this.extractMetadata(content) }; this.templates.set(id, template); } } private formatName(id: string): string { return id .split('-') .map(word => word.charAt(0).toUpperCase() + word.slice(1)) .join(' '); } private extractMetadata(content: string): AgentTemplate['metadata'] { const metadata: AgentTemplate['metadata'] = {}; // Extract role from ## Role section const roleMatch = content.match(/## Role\n(.+?)(?=\n\n|$)/s); if (roleMatch) { metadata.role = roleMatch[1].trim(); } // Extract expertise from ## Core Expertise section const expertiseMatch = content.match(/## Core Expertise\n([\s\S]+?)(?=\n##|$)/); if (expertiseMatch) { const expertiseLines = expertiseMatch[1] .split('\n') .filter(line => line.trim().startsWith('-')) .map(line => line.replace(/^-\s*/, '').trim()); metadata.expertise = expertiseLines; } // Extract category from content patterns if (content.includes('Blue Team')) { metadata.category = 'Cybersecurity - Defensive'; } else if (content.includes('Red Team')) { metadata.category = 'Cybersecurity - Offensive'; } else if (content.includes('Purple Team')) { metadata.category = 'Cybersecurity - Collaborative'; } else if (content.includes('IT Expert') || content.includes('IT Professional')) { metadata.category = 'Technology'; } else if (content.includes('Sales')) { metadata.category = 'Business'; } else if (content.includes('Ethical Hacker')) { metadata.category = 'Cybersecurity'; } return metadata; } // Get all available templates getTemplates(): AgentTemplate[] { return Array.from(this.templates.values()); } // Get template by ID getTemplate(id: string): AgentTemplate | undefined { return this.templates.get(id); } // Get templates by category getTemplatesByCategory(category: string): AgentTemplate[] { return Array.from(this.templates.values()) .filter(template => template.metadata.category === category); } // Set active agent setActiveAgent(id: string): boolean { if (this.templates.has(id)) { this.activeAgent = id; return true; } return false; } // Get active agent getActiveAgent(): AgentTemplate | null { if (this.activeAgent) { return this.templates.get(this.activeAgent) || null; } return null; } // Get agent instructions (formatted for LLM) getAgentInstructions(id: string): string | null { const template = this.templates.get(id); if (!template) return null; // Format the content for LLM consumption return `# AI AGENT INSTRUCTIONS - ${template.name}\n\n${template.content}`; } // Get agent context (summary for quick reference) getAgentContext(id: string): any { const template = this.templates.get(id); if (!template) return null; return { id: template.id, name: template.name, role: template.metadata.role, category: template.metadata.category, expertise: template.metadata.expertise?.slice(0, 5), // Top 5 expertise areas active: this.activeAgent === id }; } // List all available categories getCategories(): string[] { const categories = new Set<string>(); this.templates.forEach(template => { if (template.metadata.category) { categories.add(template.metadata.category); } }); return Array.from(categories); } // Quick switch between common agents quickSwitch(type: 'it' | 'hacker' | 'sales' | 'blue' | 'red' | 'purple'): boolean { const mapping: Record<string, string> = { 'it': 'it-expert', 'hacker': 'ethical-hacker', 'sales': 'sales-expert', 'blue': 'blue-team', 'red': 'red-team', 'purple': 'purple-team' }; const id = mapping[type]; if (id) { return this.setActiveAgent(id); } return false; } // Reload templates (useful for development) async reload(): Promise<void> { this.templates.clear(); await this.loadTemplates(); } // Get formatted list for display getFormattedList(): string { const categories = this.getCategories(); let output = '# Available AI Agent Templates\n\n'; for (const category of categories) { output += `## ${category}\n`; const templates = this.getTemplatesByCategory(category); for (const template of templates) { const active = this.activeAgent === template.id ? ' ✓ [ACTIVE]' : ''; output += `- **${template.name}** (${template.id})${active}\n`; if (template.metadata.role) { output += ` ${template.metadata.role.substring(0, 100)}...\n`; } } output += '\n'; } return output; } }

Implementation Reference

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/hlsitechio/mcp-instruct'

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