Skip to main content
Glama
backend-registry.js8.47 kB
/** * @fileoverview BackendRegistry - Config-driven backend management * @module backends/backend-registry * * Central registry for all AI backends with: * - Config-driven registration * - Dynamic adapter loading * - Fallback chain management * - Health status tracking * * Adapted from MKG V2 for Smart AI Bridge v1.3.0 * @source mecha-king-ghidorah-v2/src/backends/backend-registry.js */ /** * Default backend configurations for Smart AI Bridge * Note: User-configurable - these are defaults, not hardcoded requirements */ const DEFAULT_BACKENDS = { local: { type: 'local', enabled: true, priority: 1, description: 'Local Qwen2.5-Coder-7B-Instruct (128K+ context)', config: {} }, gemini: { type: 'gemini', enabled: true, priority: 2, description: 'Google Gemini Enhanced (32K context)', config: {} }, deepseek: { type: 'deepseek', enabled: true, priority: 3, description: 'NVIDIA DeepSeek V3.1 Terminus (reasoning, 8K tokens)', config: {} }, qwen: { type: 'qwen', enabled: true, priority: 4, description: 'NVIDIA Qwen3 Coder 480B (coding, 32K tokens)', config: {} } }; class BackendRegistry { /** * Create a BackendRegistry * @param {Object} [config] - Registry configuration */ constructor(config = {}) { /** @type {Map<string, Object>} */ this.backends = new Map(); /** @type {Map<string, Object>} */ this.adapters = new Map(); /** @type {Object} */ this.config = { autoInitialize: true, ...config }; /** @type {string[]} */ this.fallbackChain = []; if (this.config.autoInitialize) { this.initializeDefaults(); } } /** * Initialize default backends * @private */ initializeDefaults() { for (const [name, backendConfig] of Object.entries(DEFAULT_BACKENDS)) { this.register(name, backendConfig); } console.error(`[BackendRegistry] Initialized ${this.backends.size} backends`); } /** * Register a backend * @param {string} name - Backend name * @param {Object} backendConfig - Backend configuration */ register(name, backendConfig) { const { type, enabled = true, priority = 99, config = {} } = backendConfig; this.backends.set(name, { name, type, enabled, priority, config, description: backendConfig.description || `Backend: ${name}` }); console.error(`[BackendRegistry] Registered backend: ${name} (type: ${type}, priority: ${priority})`); // Update fallback chain this.updateFallbackChain(); } /** * Set adapter for a backend * Note: Adapters are set externally after creation * @param {string} name - Backend name * @param {Object} adapter - Backend adapter instance */ setAdapter(name, adapter) { this.adapters.set(name, adapter); console.error(`[BackendRegistry] Set adapter for ${name}`); } /** * Update fallback chain based on priorities * @private */ updateFallbackChain() { const enabled = Array.from(this.backends.values()) .filter(b => b.enabled) .sort((a, b) => a.priority - b.priority); this.fallbackChain = enabled.map(b => b.name); } /** * Get adapter by name * @param {string} name - Backend name * @returns {Object|null} */ getAdapter(name) { return this.adapters.get(name) || null; } /** * Get backend configuration * @param {string} name - Backend name * @returns {Object|null} */ getBackend(name) { return this.backends.get(name) || null; } /** * Get all enabled backend names * @returns {string[]} */ getEnabledBackends() { return Array.from(this.backends.values()) .filter(b => b.enabled) .map(b => b.name); } /** * Get fallback chain * @returns {string[]} */ getFallbackChain() { return [...this.fallbackChain]; } /** * Enable/disable backend * @param {string} name - Backend name * @param {boolean} enabled - Enable state */ setEnabled(name, enabled) { const backend = this.backends.get(name); if (!backend) return; backend.enabled = enabled; if (!enabled && this.adapters.has(name)) { this.adapters.delete(name); } this.updateFallbackChain(); } /** * Update backend priority * @param {string} name - Backend name * @param {number} priority - New priority */ setPriority(name, priority) { const backend = this.backends.get(name); if (!backend) return; backend.priority = priority; this.updateFallbackChain(); } /** * Get next available backend in fallback chain * @param {string[]} [exclude=[]] - Backends to exclude * @returns {string|null} */ getNextAvailable(exclude = []) { for (const name of this.fallbackChain) { if (!exclude.includes(name)) { const adapter = this.adapters.get(name); if (adapter && !adapter.circuitOpen) { return name; } } } return null; } /** * Make request with automatic fallback * @param {string} prompt - Prompt to send * @param {string} [preferredBackend] - Preferred backend * @param {Object} [options] - Request options * @returns {Promise<Object>} */ async makeRequestWithFallback(prompt, preferredBackend = null, options = {}) { const attempted = []; let lastError = null; // Try preferred backend first if (preferredBackend) { const adapter = this.adapters.get(preferredBackend); if (adapter && !adapter.circuitOpen) { try { const result = await adapter.execute(prompt, options); return { ...result, fallbackChain: attempted, backend: preferredBackend }; } catch (error) { lastError = error; attempted.push(preferredBackend); } } } // Fallback through chain for (const name of this.fallbackChain) { if (attempted.includes(name)) continue; const adapter = this.adapters.get(name); if (!adapter || adapter.circuitOpen) continue; try { const result = await adapter.execute(prompt, options); return { ...result, fallbackChain: attempted, backend: name }; } catch (error) { lastError = error; attempted.push(name); } } throw new Error(`All backends failed. Last error: ${lastError?.message}`); } /** * Check health of all backends * @returns {Promise<Object>} */ async checkHealth() { const results = {}; for (const [name, adapter] of this.adapters) { try { results[name] = await adapter.checkHealth(); } catch (error) { results[name] = { healthy: false, error: error.message, checkedAt: new Date() }; } } return results; } /** * Get registry statistics * @returns {Object} */ getStats() { const total = this.backends.size; const enabled = this.getEnabledBackends().length; const healthy = Array.from(this.adapters.values()) .filter(a => a.lastHealth?.healthy).length; return { totalBackends: total, enabledBackends: enabled, healthyBackends: healthy, fallbackChain: this.fallbackChain, backends: Array.from(this.backends.values()).map(b => ({ name: b.name, type: b.type, enabled: b.enabled, priority: b.priority, description: b.description })) }; } /** * Load configuration from JSON * @param {Object} config - Configuration object */ loadConfig(config) { // Clear existing this.backends.clear(); this.adapters.clear(); // Load new for (const [name, backendConfig] of Object.entries(config.backends || {})) { this.register(name, backendConfig); } console.error(`[BackendRegistry] Loaded ${this.backends.size} backends from config`); } /** * Export current configuration * @returns {Object} */ exportConfig() { const backends = {}; for (const [name, backend] of this.backends) { backends[name] = { type: backend.type, enabled: backend.enabled, priority: backend.priority, description: backend.description, config: backend.config }; } return { backends }; } } export { BackendRegistry, DEFAULT_BACKENDS };

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/Platano78/Smart-AI-Bridge'

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