Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 50 additions & 29 deletions packages/sdk/server-ai/src/api/providers/AIProviderFactory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,58 +94,79 @@ export class AIProviderFactory {
aiConfig: LDAIConfigKind,
logger?: LDLogger,
): Promise<AIProvider | undefined> {
let getProviderClass: () => Promise<typeof AIProvider | undefined>;

switch (providerType) {
case 'openai':
return this._createProvider(
'@launchdarkly/server-sdk-ai-openai',
'OpenAIProvider',
aiConfig,
logger,
);
// Lambda with hardcoded import - webpack can statically analyze this
getProviderClass = async () => {
// eslint-disable-next-line import/no-extraneous-dependencies
const module = await import('@launchdarkly/server-sdk-ai-openai');
return module.OpenAIProvider as unknown as typeof AIProvider;
};
break;
case 'langchain':
return this._createProvider(
'@launchdarkly/server-sdk-ai-langchain',
'LangChainProvider',
aiConfig,
logger,
);
// Lambda with hardcoded import - webpack can statically analyze this
getProviderClass = async () => {
// eslint-disable-next-line import/no-extraneous-dependencies
const module = await import('@launchdarkly/server-sdk-ai-langchain');
return module.LangChainProvider as unknown as typeof AIProvider;
};
break;
case 'vercel':
return this._createProvider(
'@launchdarkly/server-sdk-ai-vercel',
'VercelProvider',
aiConfig,
logger,
);
// Lambda with hardcoded import - webpack can statically analyze this
getProviderClass = async () => {
// eslint-disable-next-line import/no-extraneous-dependencies
const module = await import('@launchdarkly/server-sdk-ai-vercel');
return module.VercelProvider as unknown as typeof AIProvider;
};
break;
default:
return undefined;
}

return this._createProvider(getProviderClass, providerType, aiConfig, logger);
}

/**
* Create a provider instance dynamically.
* @param getProviderClass Lambda function that imports the module and returns the provider class
* @param providerType Provider type name for error messages
* @param aiConfig The AI configuration
* @param logger Optional logger
*/
private static async _createProvider(
packageName: string,
providerClassName: string,
getProviderClass: () => Promise<typeof AIProvider | undefined>,
providerType: SupportedAIProvider,
aiConfig: LDAIConfigKind,
logger?: LDLogger,
): Promise<AIProvider | undefined> {
try {
// Try to dynamically import the provider
// This will work if the package is installed
// eslint-disable-next-line import/no-extraneous-dependencies, global-require, import/no-dynamic-require
const { [providerClassName]: ProviderClass } = require(packageName);
const ProviderClass = await getProviderClass();

if (!ProviderClass) {
logger?.warn(`Provider class not found for provider ${providerType}`);
return undefined;
}

const provider = await ProviderClass.create(aiConfig, logger);
logger?.debug(
`Successfully created AIProvider for: ${aiConfig.provider?.name} with package ${packageName}`,
`Successfully created AIProvider for: ${aiConfig.provider?.name} with provider ${providerType}`,
);
return provider;
} catch (error) {
// If the provider is not available or creation fails, return undefined
logger?.warn(
`Error creating AIProvider for: ${aiConfig.provider?.name} with package ${packageName}: ${error}`,
);
// Provide helpful error message if module is not found
const err = error as Error & { code?: string };
if (err.code === 'ERR_MODULE_NOT_FOUND' || err.message?.includes('Cannot find module')) {
logger?.warn(
`Error creating AIProvider for: ${aiConfig.provider?.name} with provider ${providerType}: ${err.message}. ` +
`Please install the required package with your preferred package manager.`,
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Error Message: Don't Give Absolute Solutions (Bugbot Rules)

The error message instructs users to install the required package with their preferred package manager, but as noted in the PR discussion, the resolution depends on the project configuration and shouldn't be stated so definitively here.

Fix in Cursor Fix in Web

);
} else {
logger?.warn(
`Error creating AIProvider for: ${aiConfig.provider?.name} with provider ${providerType}: ${error}`,
);
}
return undefined;
}
}
Expand Down
Loading