@@ -10,30 +10,50 @@ import type {
1010 LDTokenUsage ,
1111} from '@launchdarkly/server-sdk-ai' ;
1212
13+ import type {
14+ VercelAIModelParameters ,
15+ VercelAISDKConfig ,
16+ VercelAISDKMapOptions ,
17+ VercelAISDKProvider ,
18+ } from './types' ;
19+
1320/**
1421 * Vercel AI implementation of AIProvider.
1522 * This provider integrates Vercel AI SDK with LaunchDarkly's tracking capabilities.
1623 */
1724export class VercelProvider extends AIProvider {
1825 private _model : LanguageModel ;
19- private _parameters : Record < string , unknown > ;
26+ private _parameters : VercelAIModelParameters ;
2027
21- constructor ( model : LanguageModel , parameters : Record < string , unknown > , logger ?: LDLogger ) {
28+ /**
29+ * Constructor for the VercelProvider.
30+ * @param model - The Vercel AI model to use.
31+ * @param parameters - The Vercel AI model parameters.
32+ * @param logger - The logger to use for the Vercel AI provider.
33+ */
34+ constructor ( model : LanguageModel , parameters : VercelAIModelParameters , logger ?: LDLogger ) {
2235 super ( logger ) ;
2336 this . _model = model ;
2437 this . _parameters = parameters ;
2538 }
2639
2740 // =============================================================================
28- // MAIN FACTORY METHOD
41+ // MAIN FACTORY METHODS
2942 // =============================================================================
3043
3144 /**
3245 * Static factory method to create a Vercel AIProvider from an AI configuration.
46+ * This method auto-detects the provider and creates the model.
47+ * Note: Messages from the AI config are not included in the provider - messages
48+ * should be passed at invocation time via invokeModel().
49+ *
50+ * @param aiConfig The LaunchDarkly AI configuration
51+ * @param logger Optional logger
52+ * @returns A Promise that resolves to a configured VercelProvider
3353 */
3454 static async create ( aiConfig : LDAIConfig , logger ?: LDLogger ) : Promise < VercelProvider > {
3555 const model = await VercelProvider . createVercelModel ( aiConfig ) ;
36- const parameters = aiConfig . model ?. parameters || { } ;
56+ const parameters = VercelProvider . mapParameters ( aiConfig . model ?. parameters ) ;
3757 return new VercelProvider ( model , parameters , logger ) ;
3858 }
3959
@@ -46,8 +66,6 @@ export class VercelProvider extends AIProvider {
4666 */
4767 async invokeModel ( messages : LDMessage [ ] ) : Promise < ChatResponse > {
4868 // Call Vercel AI generateText
49- // Type assertion: our MinLanguageModel is compatible with the expected LanguageModel interface
50- // The generateText function will work with any object that has the required properties
5169 const result = await generateText ( {
5270 model : this . _model ,
5371 messages,
@@ -121,19 +139,151 @@ export class VercelProvider extends AIProvider {
121139 } ;
122140 }
123141
142+ /**
143+ * Create a metrics extractor for Vercel AI SDK streaming results.
144+ * Use this with tracker.trackStreamMetricsOf() for streaming operations like streamText.
145+ *
146+ * The extractor waits for the stream's response promise to resolve, then extracts
147+ * metrics from the completed response.
148+ *
149+ * @returns A metrics extractor function for streaming results
150+ *
151+ * @example
152+ * const stream = aiConfig.tracker.trackStreamMetricsOf(
153+ * () => streamText(vercelConfig),
154+ * VercelProvider.createStreamMetricsExtractor()
155+ * );
156+ *
157+ * for await (const chunk of stream.textStream) {
158+ * process.stdout.write(chunk);
159+ * }
160+ */
161+ static createStreamMetricsExtractor ( ) {
162+ return async ( stream : any ) : Promise < LDAIMetrics > => {
163+ // Wait for stream to complete
164+ const result = await stream . response ;
165+ // Extract metrics from completed response
166+ return VercelProvider . createAIMetrics ( result ) ;
167+ } ;
168+ }
169+
170+ /**
171+ * Map LaunchDarkly model parameters to Vercel AI SDK parameters.
172+ *
173+ * Parameter mappings:
174+ * - max_tokens → maxTokens
175+ * - max_completion_tokens → maxOutputTokens
176+ * - temperature → temperature
177+ * - top_p → topP
178+ * - top_k → topK
179+ * - presence_penalty → presencePenalty
180+ * - frequency_penalty → frequencyPenalty
181+ * - stop → stopSequences
182+ * - seed → seed
183+ *
184+ * @param parameters The LaunchDarkly model parameters to map
185+ * @returns An object containing mapped Vercel AI SDK parameters
186+ */
187+ static mapParameters ( parameters ?: { [ index : string ] : unknown } ) : VercelAIModelParameters {
188+ if ( ! parameters ) {
189+ return { } ;
190+ }
191+
192+ const params : VercelAIModelParameters = { } ;
193+
194+ // Map token limits
195+ if ( parameters . max_tokens !== undefined ) {
196+ params . maxTokens = parameters . max_tokens as number ;
197+ }
198+ if ( parameters . max_completion_tokens !== undefined ) {
199+ params . maxOutputTokens = parameters . max_completion_tokens as number ;
200+ }
201+
202+ // Map remaining parameters
203+ if ( parameters . temperature !== undefined ) {
204+ params . temperature = parameters . temperature as number ;
205+ }
206+ if ( parameters . top_p !== undefined ) {
207+ params . topP = parameters . top_p as number ;
208+ }
209+ if ( parameters . top_k !== undefined ) {
210+ params . topK = parameters . top_k as number ;
211+ }
212+ if ( parameters . presence_penalty !== undefined ) {
213+ params . presencePenalty = parameters . presence_penalty as number ;
214+ }
215+ if ( parameters . frequency_penalty !== undefined ) {
216+ params . frequencyPenalty = parameters . frequency_penalty as number ;
217+ }
218+ if ( parameters . stop !== undefined ) {
219+ params . stopSequences = parameters . stop as string [ ] ;
220+ }
221+ if ( parameters . seed !== undefined ) {
222+ params . seed = parameters . seed as number ;
223+ }
224+
225+ return params ;
226+ }
227+
228+ /**
229+ * Convert an AI configuration to Vercel AI SDK parameters.
230+ * This static method allows converting an LDAIConfig to VercelAISDKConfig without
231+ * requiring an instance of VercelProvider.
232+ *
233+ * @param aiConfig The LaunchDarkly AI configuration
234+ * @param provider A Vercel AI SDK Provider or a map of provider names to Vercel AI SDK Providers
235+ * @param options Optional mapping options
236+ * @returns A configuration directly usable in Vercel AI SDK generateText() and streamText()
237+ * @throws {Error } if a Vercel AI SDK model cannot be determined from the given provider parameter
238+ */
239+ static toVercelAISDK < TMod > (
240+ aiConfig : LDAIConfig ,
241+ provider : VercelAISDKProvider < TMod > | Record < string , VercelAISDKProvider < TMod > > ,
242+ options ?: VercelAISDKMapOptions | undefined ,
243+ ) : VercelAISDKConfig < TMod > {
244+ // Determine the model from the provider
245+ let model : TMod | undefined ;
246+ if ( typeof provider === 'function' ) {
247+ model = provider ( aiConfig . model ?. name ?? '' ) ;
248+ } else {
249+ model = provider [ aiConfig . provider ?. name ?? '' ] ?.( aiConfig . model ?. name ?? '' ) ;
250+ }
251+ if ( ! model ) {
252+ throw new Error (
253+ 'Vercel AI SDK model cannot be determined from the supplied provider parameter.' ,
254+ ) ;
255+ }
256+
257+ // Merge messages from config and options
258+ let messages : LDMessage [ ] | undefined ;
259+ const configMessages = ( 'messages' in aiConfig ? aiConfig . messages : undefined ) as
260+ | LDMessage [ ]
261+ | undefined ;
262+ if ( configMessages || options ?. nonInterpolatedMessages ) {
263+ messages = [ ...( configMessages ?? [ ] ) , ...( options ?. nonInterpolatedMessages ?? [ ] ) ] ;
264+ }
265+
266+ // Map parameters using the shared mapping method
267+ const params = VercelProvider . mapParameters ( aiConfig . model ?. parameters ) ;
268+
269+ // Build and return the Vercel AI SDK configuration
270+ return {
271+ model,
272+ messages,
273+ ...params ,
274+ } ;
275+ }
276+
124277 /**
125278 * Create a Vercel AI model from an AI configuration.
126- * This method creates a Vercel AI model based on the provider configuration .
279+ * This method auto-detects the provider and creates the model instance .
127280 *
128281 * @param aiConfig The LaunchDarkly AI configuration
129282 * @returns A Promise that resolves to a configured Vercel AI model
130283 */
131284 static async createVercelModel ( aiConfig : LDAIConfig ) : Promise < LanguageModel > {
132285 const providerName = VercelProvider . mapProvider ( aiConfig . provider ?. name || '' ) ;
133286 const modelName = aiConfig . model ?. name || '' ;
134- // Parameters are not used in model creation but kept for future use
135- // eslint-disable-next-line @typescript-eslint/no-unused-vars
136- const parameters = aiConfig . model ?. parameters || { } ;
137287
138288 // Map provider names to their corresponding Vercel AI SDK imports
139289 switch ( providerName ) {
0 commit comments