From cb8d3c80c672b5475d46b3d4ec725d9e2a81ab88 Mon Sep 17 00:00:00 2001 From: jsonbailey Date: Thu, 30 Oct 2025 23:25:50 +0000 Subject: [PATCH 1/2] feat: Add support for trackStreamMetricsOf method fix: Deprecated toVercelAISDK, trackVercelAISDKStreamTextMetrics fix: Moved types VercelAISDKProvider, VercelAISDKMapOptions, and VercelAISDKConfig to `@launchdarkly/server-sdk-ai-vercel` package --- .../sdk/server-ai/src/LDAIConfigMapper.ts | 4 ++ .../server-ai/src/LDAIConfigTrackerImpl.ts | 54 +++++++++++++++++++ .../server-ai/src/api/config/LDAIConfig.ts | 3 ++ .../src/api/config/LDAIConfigTracker.ts | 29 ++++++++++ .../server-ai/src/api/config/VercelAISDK.ts | 12 +++++ 5 files changed, 102 insertions(+) diff --git a/packages/sdk/server-ai/src/LDAIConfigMapper.ts b/packages/sdk/server-ai/src/LDAIConfigMapper.ts index f7ed111152..827f4d01e4 100644 --- a/packages/sdk/server-ai/src/LDAIConfigMapper.ts +++ b/packages/sdk/server-ai/src/LDAIConfigMapper.ts @@ -27,6 +27,10 @@ export class LDAIConfigMapper { return undefined; } + /** + * @deprecated Use `VercelProvider.toVercelAISDK()` from the `@launchdarkly/server-sdk-ai-vercel` package instead. + * This method will be removed in a future version. + */ toVercelAISDK( provider: VercelAISDKProvider | Record>, options?: VercelAISDKMapOptions | undefined, diff --git a/packages/sdk/server-ai/src/LDAIConfigTrackerImpl.ts b/packages/sdk/server-ai/src/LDAIConfigTrackerImpl.ts index 8830cee4ea..47a87711d9 100644 --- a/packages/sdk/server-ai/src/LDAIConfigTrackerImpl.ts +++ b/packages/sdk/server-ai/src/LDAIConfigTrackerImpl.ts @@ -119,6 +119,60 @@ export class LDAIConfigTrackerImpl implements LDAIConfigTracker { return result; } + trackStreamMetricsOf( + streamCreator: () => TStream, + metricsExtractor: (stream: TStream) => Promise, + ): TStream { + const startTime = Date.now(); + + try { + // Create the stream synchronously + const stream = streamCreator(); + + // Start background metrics tracking (fire and forget) + this._trackStreamMetricsInBackground(stream, metricsExtractor, startTime); + + // Return stream immediately for consumption + return stream; + } catch (error) { + // Track error if stream creation fails + this.trackDuration(Date.now() - startTime); + this.trackError(); + throw error; + } + } + + private async _trackStreamMetricsInBackground( + stream: TStream, + metricsExtractor: (stream: TStream) => Promise, + startTime: number, + ): Promise { + try { + // Wait for metrics to be available + const metrics = await metricsExtractor(stream); + + // Track final duration + const duration = Date.now() - startTime; + this.trackDuration(duration); + + // Track success/error based on metrics + if (metrics.success) { + this.trackSuccess(); + } else { + this.trackError(); + } + + // Track token usage if available + if (metrics.usage) { + this.trackTokens(metrics.usage); + } + } catch (error) { + // If metrics extraction fails, track error + // but don't throw - stream consumption should not be affected + this.trackError(); + } + } + async trackOpenAIMetrics< TRes extends { usage?: { diff --git a/packages/sdk/server-ai/src/api/config/LDAIConfig.ts b/packages/sdk/server-ai/src/api/config/LDAIConfig.ts index c5071a6d59..4f958f3d3a 100644 --- a/packages/sdk/server-ai/src/api/config/LDAIConfig.ts +++ b/packages/sdk/server-ai/src/api/config/LDAIConfig.ts @@ -76,6 +76,9 @@ export interface LDAIConfig { * * WARNING: this method can throw an exception if a Vercel AI SDK model cannot be determined. * + * @deprecated Use `VercelProvider.toVercelAISDK()` from the `@launchdarkly/server-sdk-ai-vercel` package instead. + * This method will be removed in a future version. + * * @param provider A Vercel AI SDK Provider or a map of provider names to Vercel AI SDK Providers. * @param options Optional mapping options. * @returns A configuration directly usable in Vercel AI SDK generateText() and streamText() diff --git a/packages/sdk/server-ai/src/api/config/LDAIConfigTracker.ts b/packages/sdk/server-ai/src/api/config/LDAIConfigTracker.ts index 7f0b3f5797..491315e02b 100644 --- a/packages/sdk/server-ai/src/api/config/LDAIConfigTracker.ts +++ b/packages/sdk/server-ai/src/api/config/LDAIConfigTracker.ts @@ -106,6 +106,32 @@ export interface LDAIConfigTracker { func: () => Promise, ): Promise; + /** + * Track metrics for a streaming AI operation. + * + * This function will track the duration of the operation, extract metrics using the provided + * metrics extractor function, and track success or error status accordingly. + * + * Unlike trackMetricsOf, this method is designed for streaming operations where: + * - The stream is created and returned immediately (synchronously) + * - Metrics are extracted asynchronously in the background once the stream completes + * - Duration is tracked from stream creation to metrics extraction completion + * + * The stream is returned immediately so the caller can begin consuming it without waiting. + * Metrics extraction happens in the background and does not block stream consumption. + * + * If the stream creator throws, then this method will also throw and record an error. + * If metrics extraction fails, the error is logged but does not affect stream consumption. + * + * @param streamCreator Function that creates and returns the stream (synchronous) + * @param metricsExtractor Function that asynchronously extracts metrics from the stream + * @returns The stream result (returned immediately, not a Promise) + */ + trackStreamMetricsOf( + streamCreator: () => TStream, + metricsExtractor: (stream: TStream) => Promise, + ): TStream; + /** * Track an OpenAI operation. * @@ -187,6 +213,9 @@ export interface LDAIConfigTracker { * In the case the provided function throws, this function will record the duration and an error. * A failed operation will not have any token usage data. * + * @deprecated Use `trackStreamMetricsOf()` with `VercelProvider.createStreamMetricsExtractor()` from the + * `@launchdarkly/server-sdk-ai-vercel` package instead. This method will be removed in a future version. + * * @param func Function which executes the operation. * @returns The result of the operation. */ diff --git a/packages/sdk/server-ai/src/api/config/VercelAISDK.ts b/packages/sdk/server-ai/src/api/config/VercelAISDK.ts index 8796eb5c95..d8491a6810 100644 --- a/packages/sdk/server-ai/src/api/config/VercelAISDK.ts +++ b/packages/sdk/server-ai/src/api/config/VercelAISDK.ts @@ -1,11 +1,23 @@ import { type LDMessage } from './LDAIConfig'; +/** + * @deprecated Use `VercelAISDKProvider` from the `@launchdarkly/server-sdk-ai-vercel` package instead. + * This type will be removed in a future version. + */ export type VercelAISDKProvider = (modelName: string) => TMod; +/** + * @deprecated Use `VercelAISDKMapOptions` from the `@launchdarkly/server-sdk-ai-vercel` package instead. + * This type will be removed in a future version. + */ export interface VercelAISDKMapOptions { nonInterpolatedMessages?: LDMessage[] | undefined; } +/** + * @deprecated Use `VercelAISDKConfig` from the `@launchdarkly/server-sdk-ai-vercel` package instead. + * This type will be removed in a future version. + */ export interface VercelAISDKConfig { model: TMod; messages?: LDMessage[] | undefined; From ff14518b076936245868ededf08c944bcbe28ac0 Mon Sep 17 00:00:00 2001 From: jsonbailey Date: Tue, 4 Nov 2025 14:27:27 +0000 Subject: [PATCH 2/2] ensure we always track duration --- packages/sdk/server-ai/src/LDAIConfigTrackerImpl.ts | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/packages/sdk/server-ai/src/LDAIConfigTrackerImpl.ts b/packages/sdk/server-ai/src/LDAIConfigTrackerImpl.ts index 47a87711d9..578ef1f8da 100644 --- a/packages/sdk/server-ai/src/LDAIConfigTrackerImpl.ts +++ b/packages/sdk/server-ai/src/LDAIConfigTrackerImpl.ts @@ -151,10 +151,6 @@ export class LDAIConfigTrackerImpl implements LDAIConfigTracker { // Wait for metrics to be available const metrics = await metricsExtractor(stream); - // Track final duration - const duration = Date.now() - startTime; - this.trackDuration(duration); - // Track success/error based on metrics if (metrics.success) { this.trackSuccess(); @@ -168,8 +164,10 @@ export class LDAIConfigTrackerImpl implements LDAIConfigTracker { } } catch (error) { // If metrics extraction fails, track error - // but don't throw - stream consumption should not be affected this.trackError(); + } finally { + // Track duration regardless of success/error + this.trackDuration(Date.now() - startTime); } }