@@ -5,6 +5,21 @@ import { LDAIConfigTracker } from '../config/LDAIConfigTracker';
55import { AIProvider } from '../providers/AIProvider' ;
66import { TrackedChat } from './TrackedChat' ;
77
8+ /**
9+ * List of supported AI providers.
10+ */
11+ export const SUPPORTED_AI_PROVIDERS = [
12+ 'openai' ,
13+ // Multi-provider packages should be last in the list
14+ 'langchain' ,
15+ 'vercel' ,
16+ ] as const ;
17+
18+ /**
19+ * Type representing the supported AI providers.
20+ */
21+ export type SupportedAIProvider = ( typeof SUPPORTED_AI_PROVIDERS ) [ number ] ;
22+
823/**
924 * Factory for creating TrackedChat instances based on the provider configuration.
1025 */
@@ -17,21 +32,22 @@ export class TrackedChatFactory {
1732 * @param aiConfig The AI configuration
1833 * @param tracker The tracker for AI operations
1934 * @param logger Optional logger for logging provider initialization
35+ * @param defaultAiProvider Optional default AI provider to use
2036 */
2137 static async create (
2238 aiConfig : LDAIConfig ,
2339 tracker : LDAIConfigTracker ,
2440 logger ?: LDLogger ,
41+ defaultAiProvider ?: SupportedAIProvider ,
2542 ) : Promise < TrackedChat | undefined > {
26- const provider = await this . _createAIProvider ( aiConfig , logger ) ;
43+ const provider = await this . _createAIProvider ( aiConfig , logger , defaultAiProvider ) ;
2744 if ( ! provider ) {
2845 logger ?. warn (
2946 `Provider is not supported or failed to initialize: ${ aiConfig . provider ?. name ?? 'unknown' } ` ,
3047 ) ;
3148 return undefined ;
3249 }
3350
34- logger ?. debug ( `Successfully created TrackedChat for provider: ${ aiConfig . provider ?. name } ` ) ;
3551 return new TrackedChat ( aiConfig , tracker , provider ) ;
3652 }
3753
@@ -42,53 +58,114 @@ export class TrackedChatFactory {
4258 private static async _createAIProvider (
4359 aiConfig : LDAIConfig ,
4460 logger ?: LDLogger ,
61+ defaultAiProvider ?: SupportedAIProvider ,
4562 ) : Promise < AIProvider | undefined > {
4663 const providerName = aiConfig . provider ?. name ?. toLowerCase ( ) ;
47- logger ?. debug ( `Attempting to create AI provider: ${ providerName ?? 'unknown' } ` ) ;
48- let provider : AIProvider | undefined ;
64+ // Determine which providers to try based on defaultAiProvider
65+ const providersToTry = this . _getProvidersToTry ( defaultAiProvider , providerName ) ;
4966
50- // Try specific implementations for the provider
51- switch ( providerName ) {
52- case 'openai' :
53- // TODO: Return OpenAI AIProvider implementation when available
54- provider = undefined ;
55- break ;
56- case 'bedrock' :
57- // TODO: Return Bedrock AIProvider implementation when available
58- provider = undefined ;
59- break ;
60- default :
61- provider = undefined ;
67+ // Try each provider in order
68+ // eslint-disable-next-line no-restricted-syntax
69+ for ( const providerType of providersToTry ) {
70+ // eslint-disable-next-line no-await-in-loop
71+ const provider = await this . _tryCreateProvider ( providerType , aiConfig , logger ) ;
72+ if ( provider ) {
73+ return provider ;
74+ }
6275 }
6376
64- // If no specific implementation worked, try the multi-provider packages
65- if ( ! provider ) {
66- provider = await this . _createLangChainProvider ( aiConfig , logger ) ;
77+ return undefined ;
78+ }
79+
80+ /**
81+ * Determine which providers to try based on defaultAiProvider and providerName.
82+ */
83+ private static _getProvidersToTry (
84+ defaultAiProvider ?: SupportedAIProvider ,
85+ providerName ?: string ,
86+ ) : SupportedAIProvider [ ] {
87+ // If defaultAiProvider is set, only try that specific provider
88+ if ( defaultAiProvider ) {
89+ return [ defaultAiProvider ] ;
90+ }
91+
92+ // If no defaultAiProvider is set, try all providers in order
93+ const providerSet = new Set < SupportedAIProvider > ( ) ;
94+
95+ // First try the specific provider if it's supported
96+ if ( providerName && SUPPORTED_AI_PROVIDERS . includes ( providerName as SupportedAIProvider ) ) {
97+ providerSet . add ( providerName as SupportedAIProvider ) ;
6798 }
6899
69- return provider ;
100+ // Then try multi-provider packages, but avoid duplicates
101+ const multiProviderPackages : SupportedAIProvider [ ] = [ 'langchain' , 'vercel' ] ;
102+ multiProviderPackages . forEach ( ( provider ) => {
103+ providerSet . add ( provider ) ;
104+ } ) ;
105+
106+ return Array . from ( providerSet ) ;
70107 }
71108
72109 /**
73- * Create a LangChain AIProvider instance if the LangChain provider is available .
110+ * Try to create a provider of the specified type .
74111 */
75- private static async _createLangChainProvider (
112+ private static async _tryCreateProvider (
113+ providerType : SupportedAIProvider ,
114+ aiConfig : LDAIConfig ,
115+ logger ?: LDLogger ,
116+ ) : Promise < AIProvider | undefined > {
117+ switch ( providerType ) {
118+ case 'openai' :
119+ return this . _createProvider (
120+ '@launchdarkly/server-sdk-ai-openai' ,
121+ 'OpenAIProvider' ,
122+ aiConfig ,
123+ logger ,
124+ ) ;
125+ case 'langchain' :
126+ return this . _createProvider (
127+ '@launchdarkly/server-sdk-ai-langchain' ,
128+ 'LangChainProvider' ,
129+ aiConfig ,
130+ logger ,
131+ ) ;
132+ case 'vercel' :
133+ return this . _createProvider (
134+ '@launchdarkly/server-sdk-ai-vercel' ,
135+ 'VercelProvider' ,
136+ aiConfig ,
137+ logger ,
138+ ) ;
139+ default :
140+ return undefined ;
141+ }
142+ }
143+
144+ /**
145+ * Create a provider instance dynamically.
146+ */
147+ private static async _createProvider (
148+ packageName : string ,
149+ providerClassName : string ,
76150 aiConfig : LDAIConfig ,
77151 logger ?: LDLogger ,
78152 ) : Promise < AIProvider | undefined > {
79153 try {
80- logger ?. debug ( 'Attempting to load LangChain provider' ) ;
81- // Try to dynamically import the LangChain provider
82- // This will work if @launchdarkly /server-sdk-ai-langchain is installed
83- // eslint-disable-next-line import/no-extraneous-dependencies, global-require
84- const { LangChainProvider } = require ( '@launchdarkly/server-sdk-ai-langchain' ) ;
85-
86- const provider = await LangChainProvider . create ( aiConfig , logger ) ;
87- logger ?. debug ( 'Successfully created LangChain provider' ) ;
154+ // Try to dynamically import the provider
155+ // This will work if the package is installed
156+ // eslint-disable-next-line import/no-extraneous-dependencies, global-require, import/no-dynamic-require
157+ const { [ providerClassName ] : ProviderClass } = require ( packageName ) ;
158+
159+ const provider = await ProviderClass . create ( aiConfig , logger ) ;
160+ logger ?. debug (
161+ `Successfully created AIProvider for: ${ aiConfig . provider ?. name } with package ${ packageName } ` ,
162+ ) ;
88163 return provider ;
89164 } catch ( error ) {
90- // If the LangChain provider is not available or creation fails, return undefined
91- logger ?. error ( `Error creating LangChain provider: ${ error } ` ) ;
165+ // If the provider is not available or creation fails, return undefined
166+ logger ?. warn (
167+ `Error creating AIProvider for: ${ aiConfig . provider ?. name } with package ${ packageName } : ${ error } ` ,
168+ ) ;
92169 return undefined ;
93170 }
94171 }
0 commit comments