UNPKG

@juspay/neurolink

Version:

Universal AI Development Platform with working MCP integration, multi-provider support, voice (TTS/STT/realtime), and professional CLI. 58+ external MCP servers discoverable, multimodal file processing, RAG pipelines. Build, test, and deploy AI applicatio

550 lines (549 loc) 34.6 kB
import { ProviderFactory } from "./providerFactory.js"; import { logger } from "../utils/logger.js"; import { AIProviderName, GoogleAIModels, OpenAIModels, AnthropicModels, VertexModels, MistralModels, OllamaModels, LiteLLMModels, HuggingFaceModels, DeepSeekModels, NvidiaNimModels, OpenRouterModels, XaiModels, GroqModels, CohereModels, TogetherAIModels, FireworksModels, PerplexityModels, CloudflareModels, VoyageModels, JinaModels, StabilityModels, IdeogramModels, RecraftModels, ReplicateModels, } from "../constants/enums.js"; /** * Provider Registry - registers all providers with the factory * This is where we migrate providers one by one to the new pattern */ export class ProviderRegistry { static registered = false; static registrationPromise = null; static options = { enableManualMCP: false, // Default to disabled for safety }; /** * NEW4: per-handler registration outcomes for the realtime voice * providers. `"ok"` = registered; any other string = the error message. * Empty until the first `registerAllProviders()` call. */ static realtimeRegistration = {}; /** * Returns a snapshot of voice provider registration outcomes so callers * can detect at runtime which voice handlers are usable. Useful in * health-check endpoints and CI startup probes. */ static getRegistrationReport() { return { realtime: { ...this.realtimeRegistration } }; } /** * Register all providers with the factory */ static async registerAllProviders() { if (this.registered) { return; } if (this.registrationPromise) { return this.registrationPromise; } this.registrationPromise = this._doRegister(); try { await this.registrationPromise; } catch (error) { this.registrationPromise = null; // Allow retry on failure throw error; } } /** * Internal registration implementation * * This method is a flat list of 13 provider registrations. Each registration * is self-contained and extracting helpers would add indirection without * reducing complexity — the function is long because there are many providers, * not because any single registration is complex. */ // eslint-disable-next-line max-lines-per-function static async _doRegister() { try { // Register providers with dynamic import factory functions const { ProviderFactory } = await import("./providerFactory.js"); // Register Google AI Studio Provider (our validated baseline) ProviderFactory.registerProvider(AIProviderName.GOOGLE_AI, async (modelName, _providerName, sdk, _region, credentials) => { const googleAiCreds = credentials; const { GoogleAIStudioProvider } = await import("../providers/googleAiStudio.js"); return new GoogleAIStudioProvider(modelName, sdk, googleAiCreds); }, GoogleAIModels.GEMINI_2_5_FLASH, ["googleAiStudio", "google", "gemini", "google-ai", "google-ai-studio"]); // Register OpenAI provider ProviderFactory.registerProvider(AIProviderName.OPENAI, async (modelName, _providerName, sdk, _region, credentials) => { const openaiCreds = credentials; const { OpenAIProvider } = await import("../providers/openAI.js"); return new OpenAIProvider(modelName, sdk, undefined, openaiCreds); }, OpenAIModels.GPT_4O_MINI, ["gpt", "chatgpt"]); // Register Anthropic provider ProviderFactory.registerProvider(AIProviderName.ANTHROPIC, async (modelName, _providerName, sdk, _region, credentials) => { const anthropicCreds = credentials; const { AnthropicProvider } = await import("../providers/anthropic.js"); return new AnthropicProvider(modelName, sdk, undefined, anthropicCreds); }, AnthropicModels.CLAUDE_SONNET_4_6, ["claude", "anthropic"]); // Register Amazon Bedrock provider ProviderFactory.registerProvider(AIProviderName.BEDROCK, async (modelName, _providerName, sdk, region, credentials) => { const bedrockCreds = credentials; const { AmazonBedrockProvider } = await import("../providers/amazonBedrock.js"); return new AmazonBedrockProvider(modelName, sdk, region, bedrockCreds); }, undefined, // Let provider read BEDROCK_MODEL from .env ["bedrock", "aws"]); // Register Azure OpenAI provider ProviderFactory.registerProvider(AIProviderName.AZURE, async (modelName, _providerName, sdk, _region, credentials) => { const azureCreds = credentials; const { AzureOpenAIProvider } = await import("../providers/azureOpenai.js"); return new AzureOpenAIProvider(modelName, sdk, undefined, azureCreds); }, process.env.AZURE_MODEL || process.env.AZURE_OPENAI_MODEL || process.env.AZURE_OPENAI_DEPLOYMENT || process.env.AZURE_OPENAI_DEPLOYMENT_ID || "gpt-4o-mini", ["azure", "azureOpenai"]); // Register Google Vertex AI provider ProviderFactory.registerProvider(AIProviderName.VERTEX, async (modelName, providerName, sdk, region, credentials) => { const vertexCreds = credentials; const { GoogleVertexProvider } = await import("../providers/googleVertex.js"); return new GoogleVertexProvider(modelName, providerName, sdk, region, vertexCreds); }, VertexModels.CLAUDE_4_6_SONNET, ["vertex", "googleVertex"]); // Register Hugging Face provider (Unified Router implementation) ProviderFactory.registerProvider(AIProviderName.HUGGINGFACE, async (modelName, _providerName, _sdk, _region, credentials) => { const hfCreds = credentials; const { HuggingFaceProvider } = await import("../providers/huggingFace.js"); return new HuggingFaceProvider(modelName, undefined, hfCreds); }, process.env.HUGGINGFACE_MODEL || HuggingFaceModels.QWEN_2_5_72B_INSTRUCT, ["huggingface", "hf"]); // Register Mistral AI provider ProviderFactory.registerProvider(AIProviderName.MISTRAL, async (modelName, _providerName, sdk, _region, credentials) => { const mistralCreds = credentials; const { MistralProvider } = await import("../providers/mistral.js"); return new MistralProvider(modelName, sdk, undefined, mistralCreds); }, MistralModels.MISTRAL_LARGE_LATEST, ["mistral"]); // Register Ollama provider ProviderFactory.registerProvider(AIProviderName.OLLAMA, async (modelName, _providerName, _sdk, _region, credentials) => { const ollamaCreds = credentials; const { OllamaProvider } = await import("../providers/ollama.js"); return new OllamaProvider(modelName, ollamaCreds); }, process.env.OLLAMA_MODEL || OllamaModels.LLAMA3_2_LATEST, ["ollama", "local"]); // Register LiteLLM provider ProviderFactory.registerProvider(AIProviderName.LITELLM, async (modelName, _providerName, sdk, _region, credentials) => { const litellmCreds = credentials; const { LiteLLMProvider } = await import("../providers/litellm.js"); return new LiteLLMProvider(modelName, sdk, undefined, litellmCreds); }, process.env.LITELLM_MODEL || LiteLLMModels.OPENAI_GPT_4O_MINI, ["litellm"]); // Register OpenAI Compatible provider ProviderFactory.registerProvider(AIProviderName.OPENAI_COMPATIBLE, async (modelName, _providerName, sdk, _region, credentials) => { const openaiCompatCreds = credentials; const { OpenAICompatibleProvider } = await import("../providers/openaiCompatible.js"); return new OpenAICompatibleProvider(modelName, sdk, undefined, openaiCompatCreds); }, process.env.OPENAI_COMPATIBLE_MODEL || undefined, // Enable auto-discovery when no model specified ["openai-compatible", "vllm", "compatible"]); // Register OpenRouter provider (300+ models from 60+ providers) ProviderFactory.registerProvider(AIProviderName.OPENROUTER, async (modelName, _providerName, sdk, _region, credentials) => { const openrouterCreds = credentials; const { OpenRouterProvider } = await import("../providers/openRouter.js"); return new OpenRouterProvider(modelName, sdk, undefined, openrouterCreds); }, // OpenRouter retired `anthropic/claude-3-5-sonnet` in late 2025 — see // src/lib/providers/openRouter.ts and src/lib/utils/modelChoices.ts // for the rationale. Keep the three defaults aligned at the new // model (claude-sonnet-4.5) so the registry doesn't override the // provider's getDefault. process.env.OPENROUTER_MODEL || OpenRouterModels.CLAUDE_SONNET_4_5, ["openrouter", "or"]); // Register Amazon SageMaker provider ProviderFactory.registerProvider(AIProviderName.SAGEMAKER, async (modelName, _providerName, _sdk, region, credentials) => { const sagemakerCreds = credentials; const { AmazonSageMakerProvider } = await import("../providers/amazonSagemaker.js"); return new AmazonSageMakerProvider(modelName, undefined, region, undefined, sagemakerCreds); }, process.env.SAGEMAKER_MODEL || "sagemaker-model", ["sagemaker", "aws-sagemaker"]); // Register DeepSeek provider ProviderFactory.registerProvider(AIProviderName.DEEPSEEK, async (modelName, _providerName, sdk, _region, credentials) => { const deepseekCreds = credentials; const { DeepSeekProvider } = await import("../providers/deepseek.js"); return new DeepSeekProvider(modelName, sdk, undefined, deepseekCreds); }, process.env.DEEPSEEK_MODEL || DeepSeekModels.DEEPSEEK_CHAT, ["deepseek", "ds"]); // Register NVIDIA NIM provider ProviderFactory.registerProvider(AIProviderName.NVIDIA_NIM, async (modelName, _providerName, sdk, _region, credentials) => { const nimCreds = credentials; const { NvidiaNimProvider } = await import("../providers/nvidiaNim.js"); return new NvidiaNimProvider(modelName, sdk, undefined, nimCreds); }, process.env.NVIDIA_NIM_MODEL || NvidiaNimModels.LLAMA_3_3_70B_INSTRUCT, ["nvidia", "nim", "nvidia-nim"]); // Register LM Studio provider (local) ProviderFactory.registerProvider(AIProviderName.LM_STUDIO, async (modelName, _providerName, sdk, _region, credentials) => { const lmStudioCreds = credentials; const { LMStudioProvider } = await import("../providers/lmStudio.js"); return new LMStudioProvider(modelName, sdk, undefined, lmStudioCreds); }, process.env.LM_STUDIO_MODEL || undefined, ["lmstudio", "lm-studio", "lms"]); // Register llama.cpp provider (local) ProviderFactory.registerProvider(AIProviderName.LLAMACPP, async (modelName, _providerName, sdk, _region, credentials) => { const llamaCppCreds = credentials; const { LlamaCppProvider } = await import("../providers/llamaCpp.js"); return new LlamaCppProvider(modelName, sdk, undefined, llamaCppCreds); }, process.env.LLAMACPP_MODEL || undefined, ["llamacpp", "llama.cpp", "llama-cpp"]); // Register xAI Grok provider ProviderFactory.registerProvider(AIProviderName.XAI, async (modelName, _providerName, sdk, _region, credentials) => { const xaiCreds = credentials; const { XaiProvider } = await import("../providers/xai.js"); return new XaiProvider(modelName, sdk, undefined, xaiCreds); }, process.env.XAI_MODEL || XaiModels.GROK_3, ["xai", "grok"]); // Register Groq provider ProviderFactory.registerProvider(AIProviderName.GROQ, async (modelName, _providerName, sdk, _region, credentials) => { const groqCreds = credentials; const { GroqProvider } = await import("../providers/groq.js"); return new GroqProvider(modelName, sdk, undefined, groqCreds); }, process.env.GROQ_MODEL || GroqModels.LLAMA_3_3_70B_VERSATILE, ["groq"]); // Register Cohere provider ProviderFactory.registerProvider(AIProviderName.COHERE, async (modelName, _providerName, sdk, _region, credentials) => { const cohereCreds = credentials; const { CohereProvider } = await import("../providers/cohere.js"); return new CohereProvider(modelName, sdk, undefined, cohereCreds); }, process.env.COHERE_MODEL || CohereModels.COMMAND_R_PLUS, ["cohere"]); // Register Together AI provider ProviderFactory.registerProvider(AIProviderName.TOGETHER_AI, async (modelName, _providerName, sdk, _region, credentials) => { const togetherCreds = credentials; const { TogetherAIProvider } = await import("../providers/togetherAi.js"); return new TogetherAIProvider(modelName, sdk, undefined, togetherCreds); }, process.env.TOGETHER_MODEL || TogetherAIModels.LLAMA_3_3_70B_INSTRUCT_TURBO, ["together-ai", "together"]); // Register Fireworks AI provider ProviderFactory.registerProvider(AIProviderName.FIREWORKS, async (modelName, _providerName, sdk, _region, credentials) => { const fireworksCreds = credentials; const { FireworksProvider } = await import("../providers/fireworks.js"); return new FireworksProvider(modelName, sdk, undefined, fireworksCreds); }, process.env.FIREWORKS_MODEL || FireworksModels.DEEPSEEK_V4_PRO, ["fireworks"]); // Register Perplexity provider ProviderFactory.registerProvider(AIProviderName.PERPLEXITY, async (modelName, _providerName, sdk, _region, credentials) => { const perplexityCreds = credentials; const { PerplexityProvider } = await import("../providers/perplexity.js"); return new PerplexityProvider(modelName, sdk, undefined, perplexityCreds); }, process.env.PERPLEXITY_MODEL || PerplexityModels.SONAR, ["perplexity", "pplx"]); // Register Cloudflare Workers AI provider ProviderFactory.registerProvider(AIProviderName.CLOUDFLARE, async (modelName, _providerName, sdk, _region, credentials) => { const cloudflareCreds = credentials; const { CloudflareProvider } = await import("../providers/cloudflare.js"); return new CloudflareProvider(modelName, sdk, undefined, cloudflareCreds); }, process.env.CLOUDFLARE_MODEL || CloudflareModels.LLAMA_3_3_70B_FAST, ["cloudflare", "workers-ai", "cf-ai"]); // Register Voyage AI embeddings provider ProviderFactory.registerProvider(AIProviderName.VOYAGE, async (modelName, _providerName, sdk, _region, credentials) => { const voyageCreds = credentials; const { VoyageProvider } = await import("../providers/voyage.js"); return new VoyageProvider(modelName, sdk, undefined, voyageCreds); }, process.env.VOYAGE_MODEL || VoyageModels.VOYAGE_3_5, ["voyage", "voyage-ai"]); // Register Jina AI embeddings + reranking provider ProviderFactory.registerProvider(AIProviderName.JINA, async (modelName, _providerName, sdk, _region, credentials) => { const jinaCreds = credentials; const { JinaProvider } = await import("../providers/jina.js"); return new JinaProvider(modelName, sdk, undefined, jinaCreds); }, process.env.JINA_MODEL || JinaModels.JINA_EMBEDDINGS_V3, ["jina", "jina-ai"]); // Register Stability AI image-gen provider ProviderFactory.registerProvider(AIProviderName.STABILITY, async (modelName, _providerName, sdk, _region, credentials) => { const stabilityCreds = credentials; const { StabilityProvider } = await import("../providers/stability.js"); return new StabilityProvider(modelName, sdk, undefined, stabilityCreds); }, process.env.STABILITY_MODEL || StabilityModels.STABLE_IMAGE_ULTRA, ["stability", "stability-ai", "sd"]); // Register Ideogram image-gen provider ProviderFactory.registerProvider(AIProviderName.IDEOGRAM, async (modelName, _providerName, sdk, _region, credentials) => { const ideogramCreds = credentials; const { IdeogramProvider } = await import("../providers/ideogram.js"); return new IdeogramProvider(modelName, sdk, undefined, ideogramCreds); }, process.env.IDEOGRAM_MODEL || IdeogramModels.IDEOGRAM_V3, ["ideogram"]); // Register Replicate LLM provider (multi-modal — also serves video / // avatar / music handlers via dedicated processors registered below) ProviderFactory.registerProvider(AIProviderName.REPLICATE, async (modelName, _providerName, sdk, _region, credentials) => { const replicateCreds = credentials; const { ReplicateProvider } = await import("../providers/replicate.js"); return new ReplicateProvider(modelName, sdk, undefined, replicateCreds); }, process.env.REPLICATE_MODEL || ReplicateModels.LLAMA_3_70B_INSTRUCT, ["replicate"]); // Register Recraft image-gen provider ProviderFactory.registerProvider(AIProviderName.RECRAFT, async (modelName, _providerName, sdk, _region, credentials) => { const recraftCreds = credentials; const { RecraftProvider } = await import("../providers/recraft.js"); return new RecraftProvider(modelName, sdk, undefined, recraftCreds); }, process.env.RECRAFT_MODEL || RecraftModels.RECRAFT_V3, ["recraft"]); logger.debug("All AI providers registered successfully"); // ===== TTS HANDLER REGISTRATION ===== try { // Create handler instance and register explicitly const { GoogleTTSHandler } = await import("../adapters/tts/googleTTSHandler.js"); const { TTSProcessor } = await import("../utils/ttsProcessor.js"); const googleHandler = new GoogleTTSHandler(); TTSProcessor.registerHandler("google-ai", googleHandler); TTSProcessor.registerHandler("vertex", googleHandler); logger.debug("TTS handlers registered successfully", { providers: ["google-ai", "vertex"], }); } catch (ttsError) { logger.warn("Failed to register TTS handlers - TTS functionality will be unavailable", { error: ttsError instanceof Error ? ttsError.message : String(ttsError), }); // Don't throw - TTS is optional functionality } // New TTS providers try { const { TTSProcessor } = await import("../utils/ttsProcessor.js"); const { OpenAITTS } = await import("../voice/providers/OpenAITTS.js"); TTSProcessor.registerHandler("openai-tts", new OpenAITTS()); } catch (err) { logger.debug(`[ProviderRegistry] openai-tts registration skipped: ${err instanceof Error ? err.message : String(err)}`); } try { const { TTSProcessor } = await import("../utils/ttsProcessor.js"); const { ElevenLabsTTS } = await import("../voice/providers/ElevenLabsTTS.js"); const elevenLabsHandler = new ElevenLabsTTS(); TTSProcessor.registerHandler("elevenlabs", elevenLabsHandler); TTSProcessor.registerHandler("elevenlabs-tts", elevenLabsHandler); } catch (err) { logger.debug(`[ProviderRegistry] elevenlabs registration skipped: ${err instanceof Error ? err.message : String(err)}`); } try { const { TTSProcessor } = await import("../utils/ttsProcessor.js"); const { AzureTTS } = await import("../voice/providers/AzureTTS.js"); TTSProcessor.registerHandler("azure-tts", new AzureTTS()); } catch (err) { logger.debug(`[ProviderRegistry] azure-tts registration skipped: ${err instanceof Error ? err.message : String(err)}`); } // ===== STT HANDLER REGISTRATION ===== try { const { STTProcessor } = await import("../utils/sttProcessor.js"); try { const { OpenAISTT } = await import("../voice/providers/OpenAISTT.js"); const openAISTT = new OpenAISTT(); STTProcessor.registerHandler("whisper", openAISTT); STTProcessor.registerHandler("openai-stt", openAISTT); } catch (err) { logger.debug(`[ProviderRegistry] whisper/openai-stt registration skipped: ${err instanceof Error ? err.message : String(err)}`); } try { const { DeepgramSTT } = await import("../voice/providers/DeepgramSTT.js"); STTProcessor.registerHandler("deepgram", new DeepgramSTT()); } catch (err) { logger.debug(`[ProviderRegistry] deepgram registration skipped: ${err instanceof Error ? err.message : String(err)}`); } try { const { GoogleSTT } = await import("../voice/providers/GoogleSTT.js"); STTProcessor.registerHandler("google-stt", new GoogleSTT()); } catch (err) { logger.debug(`[ProviderRegistry] google-stt registration skipped: ${err instanceof Error ? err.message : String(err)}`); } try { const { AzureSTT } = await import("../voice/providers/AzureSTT.js"); STTProcessor.registerHandler("azure-stt", new AzureSTT()); } catch (err) { logger.debug(`[ProviderRegistry] azure-stt registration skipped: ${err instanceof Error ? err.message : String(err)}`); } logger.debug("STT handlers registered successfully", { providers: ["whisper", "deepgram", "google-stt", "azure-stt"], }); } catch (sttError) { logger.warn("Failed to register STT handlers - STT functionality will be unavailable", { error: sttError instanceof Error ? sttError.message : String(sttError), }); } // ===== REALTIME HANDLER REGISTRATION ===== try { const { RealtimeProcessor } = await import("../voice/RealtimeVoiceAPI.js"); // M9 + NEW4: track per-handler registration outcomes so the final // log accurately reflects which voice providers succeeded vs which // were skipped — instead of unconditionally claiming "registered // successfully" or hiding failures at debug level. const realtimeOutcomes = {}; try { const { OpenAIRealtime } = await import("../voice/providers/OpenAIRealtime.js"); RealtimeProcessor.registerHandler("openai-realtime", new OpenAIRealtime()); realtimeOutcomes["openai-realtime"] = "ok"; } catch (err) { const msg = err instanceof Error ? err.message : String(err); realtimeOutcomes["openai-realtime"] = msg; // M9: promote per-handler failures to error level so users can // see which shipped voice provider failed to register at startup. logger.error(`[ProviderRegistry] openai-realtime registration failed: ${msg}`); } try { const { GeminiLive } = await import("../voice/providers/GeminiLive.js"); RealtimeProcessor.registerHandler("gemini-live", new GeminiLive()); realtimeOutcomes["gemini-live"] = "ok"; } catch (err) { const msg = err instanceof Error ? err.message : String(err); realtimeOutcomes["gemini-live"] = msg; logger.error(`[ProviderRegistry] gemini-live registration failed: ${msg}`); } // NEW4: report the actual per-handler outcomes instead of an // unconditional success log. Stored on the registry so callers can // introspect via getRegistrationReport(). ProviderRegistry.realtimeRegistration = realtimeOutcomes; const skipped = Object.entries(realtimeOutcomes).filter(([, v]) => v !== "ok"); if (skipped.length === 0) { logger.info("[ProviderRegistry] Realtime handlers registered: openai-realtime, gemini-live"); } else { logger.warn(`[ProviderRegistry] Realtime handlers partial: ${skipped.length} skipped`, { outcomes: realtimeOutcomes }); } } catch (realtimeError) { logger.warn("Failed to register Realtime handlers - Realtime functionality will be unavailable", { error: realtimeError instanceof Error ? realtimeError.message : String(realtimeError), }); } // ===== VIDEO HANDLER REGISTRATION ===== try { const { VideoProcessor } = await import("../utils/videoProcessor.js"); try { const { VertexVideoHandler } = await import("../adapters/video/vertexVideoHandler.js"); VideoProcessor.registerHandler("vertex", new VertexVideoHandler()); } catch (err) { logger.debug(`[ProviderRegistry] vertex video registration skipped: ${err instanceof Error ? err.message : String(err)}`); } try { const { KlingVideoHandler } = await import("../adapters/video/klingVideoHandler.js"); VideoProcessor.registerHandler("kling", new KlingVideoHandler()); } catch (err) { logger.debug(`[ProviderRegistry] kling video registration skipped: ${err instanceof Error ? err.message : String(err)}`); } try { const { RunwayVideoHandler } = await import("../adapters/video/runwayVideoHandler.js"); VideoProcessor.registerHandler("runway", new RunwayVideoHandler()); } catch (err) { logger.debug(`[ProviderRegistry] runway video registration skipped: ${err instanceof Error ? err.message : String(err)}`); } try { const { ReplicateVideoHandler } = await import("../adapters/video/replicateVideoHandler.js"); VideoProcessor.registerHandler("replicate", new ReplicateVideoHandler()); } catch (err) { logger.debug(`[ProviderRegistry] replicate video registration skipped: ${err instanceof Error ? err.message : String(err)}`); } logger.debug("Video handlers registered"); } catch (err) { logger.warn(`[ProviderRegistry] video registration block failed: ${err instanceof Error ? err.message : String(err)}`); } // ===== AVATAR HANDLER REGISTRATION ===== try { const { AvatarProcessor } = await import("../utils/avatarProcessor.js"); try { const { DIDAvatar } = await import("../avatar/providers/DIDAvatar.js"); AvatarProcessor.registerHandler("d-id", new DIDAvatar()); } catch (err) { logger.debug(`[ProviderRegistry] d-id avatar registration skipped: ${err instanceof Error ? err.message : String(err)}`); } try { const { ReplicateAvatar } = await import("../avatar/providers/ReplicateAvatar.js"); const replicateAvatar = new ReplicateAvatar(); AvatarProcessor.registerHandler("replicate", replicateAvatar); AvatarProcessor.registerHandler("musetalk", replicateAvatar); } catch (err) { logger.debug(`[ProviderRegistry] replicate avatar registration skipped: ${err instanceof Error ? err.message : String(err)}`); } try { const { HeyGenAvatar } = await import("../avatar/providers/HeyGenAvatar.js"); AvatarProcessor.registerHandler("heygen", new HeyGenAvatar()); } catch (err) { logger.debug(`[ProviderRegistry] heygen avatar registration skipped: ${err instanceof Error ? err.message : String(err)}`); } logger.debug("Avatar handlers registered"); } catch (avatarError) { logger.warn("Failed to register Avatar handlers - Avatar functionality will be unavailable", { error: avatarError instanceof Error ? avatarError.message : String(avatarError), }); } // ===== MUSIC HANDLER REGISTRATION ===== try { const { MusicProcessor } = await import("../utils/musicProcessor.js"); try { const { BeatovenMusic } = await import("../music/providers/BeatovenMusic.js"); MusicProcessor.registerHandler("beatoven", new BeatovenMusic()); } catch (err) { logger.debug(`[ProviderRegistry] beatoven music registration skipped: ${err instanceof Error ? err.message : String(err)}`); } try { const { ReplicateMusic } = await import("../music/providers/ReplicateMusic.js"); const replicateMusic = new ReplicateMusic(); MusicProcessor.registerHandler("replicate", replicateMusic); MusicProcessor.registerHandler("musicgen", replicateMusic); } catch (err) { logger.debug(`[ProviderRegistry] replicate music registration skipped: ${err instanceof Error ? err.message : String(err)}`); } try { const { ElevenLabsMusic } = await import("../music/providers/ElevenLabsMusic.js"); const elevenLabsMusic = new ElevenLabsMusic(); MusicProcessor.registerHandler("elevenlabs-music", elevenLabsMusic); MusicProcessor.registerHandler("elevenlabs-sound", elevenLabsMusic); } catch (err) { logger.debug(`[ProviderRegistry] elevenlabs-music registration skipped: ${err instanceof Error ? err.message : String(err)}`); } try { const { LyriaMusic } = await import("../music/providers/LyriaMusic.js"); MusicProcessor.registerHandler("lyria", new LyriaMusic()); } catch (err) { logger.debug(`[ProviderRegistry] lyria music registration skipped: ${err instanceof Error ? err.message : String(err)}`); } logger.debug("Music handlers registered"); } catch (musicError) { logger.warn("Failed to register Music handlers - Music functionality will be unavailable", { error: musicError instanceof Error ? musicError.message : String(musicError), }); } // Mark registered ONLY after all blocks (AI + voice) attempted, so a // subsequent registerAllProviders() call does not short-circuit when an // optional handler block silently failed. this.registered = true; } catch (error) { logger.error("Failed to register providers:", error); throw error; } } /** * Check if providers are registered */ static isRegistered() { return this.registered; } /** * Clear registrations (for testing) */ static clearRegistrations() { ProviderFactory.clearRegistrations(); this.registered = false; this.registrationPromise = null; // Reset realtime registration too — otherwise getRegistrationReport() // can surface stale data from a previous run if the realtime block // failed before reaching `realtimeRegistration = realtimeOutcomes`. ProviderRegistry.realtimeRegistration = {}; } /** * Set registry options (should be called before initialization) */ static setOptions(options) { this.options = { ...this.options, ...options }; logger.debug("Provider registry options updated:", this.options); } /** * Get current registry options */ static getOptions() { return { ...this.options }; } } // Note: Providers are registered explicitly when needed to avoid circular dependencies