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

188 lines 8.13 kB
import { logger } from "../utils/logger.js"; // Pure factory pattern with no hardcoded imports // All providers loaded dynamically via registry to avoid circular dependencies /** * True Factory Pattern implementation for AI Providers * Uses registration-based approach to eliminate switch statements * and enable dynamic provider registration */ export class ProviderFactory { static providers = new Map(); static initialized = false; /** * Register a provider with the factory */ static registerProvider(name, constructor, defaultModel, // Optional - provider can read from env aliases = []) { const registration = { constructor, defaultModel, aliases, }; // Register main name ProviderFactory.providers.set(name.toLowerCase(), registration); // Register aliases aliases.forEach((alias) => { ProviderFactory.providers.set(alias.toLowerCase(), registration); }); logger.debug(`Registered provider: ${name} with model ${defaultModel || "from-env"}`); } /** * Create a provider instance * @param providerName - Provider name (optional, uses NEUROLINK_PROVIDER env var or 'vertex' as default) * @param modelName - Model name (optional, uses provider-specific env var or registry default) */ static async createProvider(providerName, modelName, sdk, region, credentials) { // Note: Providers are registered explicitly by ProviderRegistry to avoid circular dependencies // Use environment variable or default if not specified const resolvedProviderName = providerName || process.env.NEUROLINK_PROVIDER || process.env.AI_PROVIDER || "vertex"; const normalizedName = resolvedProviderName.toLowerCase(); const registration = ProviderFactory.providers.get(normalizedName); if (!registration) { throw new Error(`Unknown provider: ${resolvedProviderName}. Available providers: ${ProviderFactory.getAvailableProviders().join(", ")}`); } // Respect environment variables before falling back to registry default let model = modelName; if (!model) { // Check for provider-specific environment variables if (resolvedProviderName.toLowerCase().includes("vertex")) { // Use gemini-2.5-flash as default - latest GA model with best price-performance model = process.env.VERTEX_MODEL || "gemini-2.5-flash"; } else if (resolvedProviderName.toLowerCase().includes("bedrock")) { model = process.env.BEDROCK_MODEL || process.env.BEDROCK_MODEL_ID; } // Fallback to registry default if no env var model = model || registration.defaultModel; } // Map registered provider names to NeurolinkCredentials keys. // Most names match (openai, anthropic, vertex, bedrock, etc.) // but every kebab-case provider whose canonical credentials key is // camelCase MUST be mapped here — otherwise per-call credential // overrides silently get dropped (the factory looks up // credentials["lm-studio"] which is undefined while the user wrote // credentials.lmStudio). const credentialKeyMap = { "google-ai": "googleAiStudio", "openai-compatible": "openaiCompatible", huggingface: "huggingFace", "lm-studio": "lmStudio", "nvidia-nim": "nvidiaNim", }; const credKey = credentialKeyMap[normalizedName] ?? normalizedName; // Extract provider-scoped credential slice (e.g. credentials.openai for OpenAI) const scopedCredentials = credentials ? credentials[credKey] : undefined; try { if (typeof registration.constructor !== "function") { throw new Error(`Invalid constructor for provider ${providerName}: not a function`); } let result; try { const factoryResult = registration.constructor(model, resolvedProviderName, sdk, region, scopedCredentials); // Handle both sync and async results result = factoryResult instanceof Promise ? await factoryResult : factoryResult; } catch (factoryError) { if (registration.constructor.prototype && registration.constructor.prototype.constructor === registration.constructor) { try { result = new registration.constructor(model, resolvedProviderName, sdk, region, scopedCredentials); } catch (constructorError) { throw new Error(`Both factory function and constructor failed. Factory error: ${factoryError}. Constructor error: ${constructorError}`, { cause: constructorError }); } } else { throw factoryError; } } return result; } catch (error) { logger.error(`Failed to create provider ${resolvedProviderName}:`, error); throw new Error(`Failed to create provider ${resolvedProviderName}: ${error}`, { cause: error }); } } /** * Check if a provider is registered */ static hasProvider(providerName) { return ProviderFactory.providers.has(providerName.toLowerCase()); } /** * Get list of available providers */ static getAvailableProviders() { return Array.from(ProviderFactory.providers.keys()).filter((name, index, arr) => arr.indexOf(name) === index); } /** * Get provider registration info */ static getProviderInfo(providerName) { return ProviderFactory.providers.get(providerName.toLowerCase()); } /** * Normalize provider names using aliases (PHASE 1: Factory Pattern) */ static normalizeProviderName(providerName) { const normalized = providerName.toLowerCase(); // Check direct registration if (ProviderFactory.providers.has(normalized)) { return normalized; } // Check aliases from all registrations for (const [name, registration] of ProviderFactory.providers.entries()) { if (registration.aliases?.includes(normalized)) { return name; } } return null; } /** * Clear all registrations (mainly for testing) */ static clearRegistrations() { ProviderFactory.providers.clear(); ProviderFactory.initialized = false; } /** * Ensure providers are initialized */ static ensureInitialized() { if (!ProviderFactory.initialized) { ProviderFactory.initializeDefaultProviders(); ProviderFactory.initialized = true; } } /** * Initialize default providers * NOTE: Providers are now registered by ProviderRegistry to avoid circular dependencies */ static initializeDefaultProviders() { logger.debug("BaseProvider factory pattern ready - providers registered by ProviderRegistry"); // No hardcoded registrations - all done dynamically by ProviderRegistry } /** * Create the best available provider for the given name * Used by NeuroLink SDK for streaming and generation */ static async createBestProvider(providerName, modelName, enableMCP, sdk, credentials) { return await ProviderFactory.createProvider(providerName, modelName, sdk, undefined, credentials); } } /** * Helper function to create providers with backward compatibility */ export async function createAIProvider(providerName, modelName, credentials) { return await ProviderFactory.createProvider(providerName, modelName, undefined, undefined, credentials); } //# sourceMappingURL=providerFactory.js.map