mcp-subagents
Version:
Multi-Agent AI Orchestration via Model Context Protocol - Access specialized CLI AI agents (Aider, Qwen, Gemini, Goose, etc.) with intelligent fallback and configuration
111 lines • 4.67 kB
JavaScript
import { QwenAgent } from './qwen.js';
import { GeminiAgent } from './gemini.js';
import { AiderAgent } from './aider.js';
import { GooseAgent } from './goose.js';
import { CodexAgent } from './codex.js';
import { OpenCodeAgent } from './opencode.js';
import { ClaudeAgent } from './claude.js';
import { AgentNotFoundError } from '../errors.js';
import { ConfigManager } from '../config.js';
export class AgentRegistry {
agents = new Map();
detectionResults = new Map();
configManager;
constructor() {
this.configManager = new ConfigManager();
}
static async create(detectedAgents) {
const registry = new AgentRegistry();
await registry.initialize(detectedAgents);
return registry;
}
async initialize(detectedAgents) {
for (const detection of detectedAgents) {
this.detectionResults.set(detection.name, detection);
// Only create agents that are available and ready
if (detection.available && detection.authStatus === 'ready') {
const agent = this.createAgent(detection);
this.agents.set(detection.name, agent);
}
}
}
createAgent(detection) {
// Get configuration from config file/environment (this has priority over defaults)
const globalConfig = this.configManager.getAgentConfig(detection.name);
// Get agent-specific defaults
const agentDefaults = this.getAgentDefaults(detection.name);
// Merge defaults with global config (global config overrides defaults)
const mergedDefaults = {
...agentDefaults,
...globalConfig.env, // merge environment variables from config
...(globalConfig.model !== undefined && { model: globalConfig.model }) // prefer config model over default
};
const agentConfig = {
priority: globalConfig.priority || 1,
maxConcurrent: globalConfig.maxConcurrent || 1,
inputMethod: detection.inputMethod,
defaults: mergedDefaults,
...(detection.autoAcceptFlag && { autoAcceptFlag: detection.autoAcceptFlag }),
...(detection.modelFlag && { modelFlag: detection.modelFlag }),
...(detection.requiresSubcommand && { subcommand: detection.requiresSubcommand })
};
switch (detection.name) {
case 'qwen':
return new QwenAgent('qwen', agentConfig);
case 'gemini':
return new GeminiAgent('gemini', agentConfig);
case 'aider':
return new AiderAgent('aider', agentConfig);
case 'goose':
return new GooseAgent('goose', agentConfig);
case 'codex':
return new CodexAgent('codex', agentConfig);
case 'opencode':
return new OpenCodeAgent('opencode', agentConfig);
case 'claude':
return new ClaudeAgent('claude', agentConfig);
default:
// This will never be reached if the agent is correctly detected
}
// Should be unreachable if detection logic is correct
throw new Error(`Unknown agent: ${detection.name}`);
}
getAgent(name) {
const agent = this.agents.get(name);
if (!agent) {
const detection = this.detectionResults.get(name);
if (!detection) {
throw new AgentNotFoundError(`Agent '${name}' not detected`);
}
if (!detection.available) {
throw new AgentNotFoundError(`Agent '${name}' not available. Install it first.`);
}
if (detection.authStatus !== 'ready') {
throw new AgentNotFoundError(`Agent '${name}' requires authentication: ${detection.authInstructions}`);
}
throw new AgentNotFoundError(`Agent '${name}' is detected but not initialized`);
}
return agent;
}
listAvailableAgents() {
return Array.from(this.agents.keys());
}
getDetectionResults() {
return Array.from(this.detectionResults.values());
}
getAgentDefaults(agent) {
// Built-in defaults - these have the LOWEST priority and will be overridden
// by configuration file settings and environment variables
const defaults = {
qwen: { model: 'qwen3-coder-max' },
gemini: {},
aider: { model: 'gpt-4o' },
goose: {},
codex: { fullAuto: true },
opencode: {},
claude: {}
};
return defaults[agent] || {};
}
}
//# sourceMappingURL=registry.js.map