@juspay/neurolink
Version:
Universal AI Development Platform with working MCP integration, multi-provider support, and professional CLI. Built-in tools operational, 58+ external MCP servers discoverable. Connect to filesystem, GitHub, database operations, and more. Build, test, and
235 lines (234 loc) • 11 kB
JavaScript
// ✅ CIRCULAR DEPENDENCY FIX: Remove barrel export import
// Providers are now managed via ProviderFactory instead of direct imports
import { ProviderFactory } from "../factories/providerFactory.js";
import { ProviderRegistry } from "../factories/providerRegistry.js";
import { getBestProvider } from "../utils/providerUtils.js";
import { logger } from "../utils/logger.js";
import { dynamicModelProvider } from "./dynamicModels.js";
const componentIdentifier = "aiProviderFactory";
/**
* Factory for creating AI provider instances with centralized configuration
*/
export class AIProviderFactory {
/**
* Normalize provider name using ProviderFactory
*/
static normalizeProviderName(providerName) {
// Use ProviderFactory registration - no more legacy switch statements
const normalized = ProviderFactory.normalizeProviderName(providerName);
if (normalized) {
return normalized;
}
// If not found in factory, return as-is (will be handled by factory error handling)
return providerName.toLowerCase();
}
/**
* Create a provider instance for the specified provider type
* @param providerName - Name of the provider ('vertex', 'bedrock', 'openai')
* @param modelName - Optional model name override
* @param enableMCP - Optional flag to enable MCP integration (default: true)
* @returns AIProvider instance
*/
static async createProvider(providerName, modelName, enableMCP = true, sdk) {
const functionTag = "AIawait ProviderFactory.createProvider";
// Providers are registered via ProviderFactory.initialize() on first use
logger.debug(`[${functionTag}] Provider creation started`, {
providerName,
modelName: modelName || "default",
enableMCP,
});
try {
// DYNAMIC MODEL PROVIDER STATUS (2025): Disabled due to reliability issues
//
// Root Cause: Dynamic model provider initialization can hang when:
// - Local model server (localhost:3001) is not running or responding
// - GitHub raw URL requests timeout due to network issues
// - Local config file doesn't exist
//
// Current Behavior: Static model resolution works reliably
// Impact: No functionality loss - providers use built-in model defaults
//
// Implementation Requirements (if re-enabling):
// 1. Add robust timeout handling (3s max per source)
// 2. Implement exponential backoff for network requests
// 3. Add graceful degradation when all sources fail
// 4. Create health check for localhost:3001 before attempting connection
// 5. Add comprehensive error handling and logging
//
// Until these improvements are implemented, dynamic model provider remains disabled
// for system reliability. Static model defaults provide stable functionality.
// COMPREHENSIVE FIX: Disable dynamic model resolution completely until provider is fixed
// This prevents stale gemini-1.5-pro-latest from overriding correct gemini-2.5-pro defaults
const resolvedModelName = modelName;
// COMMENTED OUT: Dynamic model resolution causing 1.5 vs 2.5 Pro issues
// if (!modelName || modelName === "default") {
// try {
// const normalizedProvider = this.normalizeProviderName(providerName);
// const dynamicModel = dynamicModelProvider.resolveModel(
// normalizedProvider,
// modelName || undefined,
// );
// if (dynamicModel) {
// resolvedModelName = dynamicModel.id;
// logger.debug(`[${functionTag}] Resolved dynamic model`, {
// provider: normalizedProvider,
// requestedModel: modelName || "default",
// resolvedModel: resolvedModelName,
// displayName: dynamicModel.displayName,
// pricing: dynamicModel.pricing.input,
// });
// }
// } catch (resolveError) {
// logger.debug(
// `[${functionTag}] Dynamic model resolution failed, using fallback`,
// {
// error:
// resolveError instanceof Error
// ? resolveError.message
// : String(resolveError),
// },
// );
// }
// }
// CRITICAL FIX: Initialize providers before using them
await ProviderRegistry.registerAllProviders();
// PURE FACTORY PATTERN: No switch statements - use ProviderFactory exclusively
const normalizedName = this.normalizeProviderName(providerName);
const finalModelName = resolvedModelName === "default" || resolvedModelName === null
? undefined
: resolvedModelName;
const provider = await ProviderFactory.createProvider(normalizedName, finalModelName, sdk);
logger.debug(componentIdentifier, "Pure factory pattern provider created", {
providerName: normalizedName,
modelName: finalModelName,
factoryUsed: true,
});
// PURE FACTORY PATTERN: All providers handled by ProviderFactory - no switch statements needed
// Wrap with MCP if enabled
if (enableMCP) {
try {
logger.debug(`[${functionTag}] MCP wrapping disabled - functionCalling removed`);
// MCP wrapping simplified - removed functionCalling dependency
}
catch (mcpError) {
logger.warn(`[${functionTag}] Failed to wrap with MCP, using base provider`, {
error: mcpError instanceof Error ? mcpError.message : String(mcpError),
});
}
}
logger.debug(`[${functionTag}] Provider creation succeeded`, {
providerName,
modelName: finalModelName || "default",
providerType: provider.constructor.name,
mcpEnabled: enableMCP,
});
return provider;
}
catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error);
logger.debug(`[${functionTag}] Provider creation failed`, {
providerName,
modelName: modelName || "default",
error: errorMessage,
});
throw error;
}
}
/**
* Create a provider instance with specific provider enum and model
* @param provider - Provider enum value
* @param model - Specific model enum value
* @returns AIProvider instance
*/
static async createProviderWithModel(provider, model) {
const functionTag = "AIawait ProviderFactory.createProviderWithModel";
logger.debug(`[${functionTag}] Provider model creation started`, {
provider,
model,
});
try {
const providerInstance = await this.createProvider(provider, model);
logger.debug(`[${functionTag}] Provider model creation succeeded`, {
provider,
model,
providerType: providerInstance.constructor.name,
});
return providerInstance;
}
catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error);
logger.debug(`[${functionTag}] Provider model creation failed`, {
provider,
model,
error: errorMessage,
});
throw error;
}
}
/**
* Create the best available provider automatically
* @param requestedProvider - Optional preferred provider
* @param modelName - Optional model name override
* @param enableMCP - Optional flag to enable MCP integration (default: true)
* @returns AIProvider instance
*/
static async createBestProvider(requestedProvider, modelName, enableMCP = true, sdk) {
const functionTag = "AIProviderFactory.createBestProvider";
try {
const bestProvider = await getBestProvider(requestedProvider);
logger.debug(`[${functionTag}] Best provider selected`, {
requestedProvider: requestedProvider || "auto",
selectedProvider: bestProvider,
modelName: modelName || "default",
enableMCP,
});
return await this.createProvider(bestProvider, modelName, enableMCP, sdk);
}
catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error);
logger.debug(`[${functionTag}] Best provider selection failed`, {
requestedProvider: requestedProvider || "auto",
error: errorMessage,
});
throw error;
}
}
/**
* Create primary and fallback provider instances
* @param primaryProvider - Primary provider name
* @param fallbackProvider - Fallback provider name
* @param modelName - Optional model name override
* @param enableMCP - Optional flag to enable MCP integration (default: true)
* @returns Object with primary and fallback providers
*/
static async createProviderWithFallback(primaryProvider, fallbackProvider, modelName, enableMCP = true) {
const functionTag = "AIawait ProviderFactory.createProviderWithFallback";
logger.debug(`[${functionTag}] Fallback provider setup started`, {
primaryProvider,
fallbackProvider,
modelName: modelName || "default",
enableMCP,
});
try {
const primary = await this.createProvider(primaryProvider, modelName, enableMCP);
const fallback = await this.createProvider(fallbackProvider, modelName, enableMCP);
logger.debug(`[${functionTag}] Fallback provider setup succeeded`, {
primaryProvider,
fallbackProvider,
modelName: modelName || "default",
enableMCP,
});
return { primary, fallback };
}
catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error);
logger.debug(`[${functionTag}] Fallback provider setup failed`, {
primaryProvider,
fallbackProvider,
error: errorMessage,
});
throw error;
}
}
}
export { componentIdentifier };