diff --git a/packages/sdk/browser/contract-tests/adapter/tsconfig.json b/packages/sdk/browser/contract-tests/adapter/tsconfig.json index 8e235feac..f6ad77fb4 100644 --- a/packages/sdk/browser/contract-tests/adapter/tsconfig.json +++ b/packages/sdk/browser/contract-tests/adapter/tsconfig.json @@ -7,7 +7,8 @@ "strict": true, "moduleResolution": "node", "outDir": "dist", - "sourceMap": true + "sourceMap": true, + "skipLibCheck": true }, "lib": ["ES6"], "exclude": ["**/*.test.ts", "dist", "node_modules"] diff --git a/packages/sdk/react-native/example/package.json b/packages/sdk/react-native/example/package.json index a79b3d473..a4c9e3a16 100644 --- a/packages/sdk/react-native/example/package.json +++ b/packages/sdk/react-native/example/package.json @@ -23,10 +23,10 @@ "dependencies": { "@launchdarkly/react-native-client-sdk": "workspace:^", "@react-native-async-storage/async-storage": "^1.21.0", - "expo": "51.0.31", + "expo": "52.0.14", "expo-status-bar": "~1.11.1", - "react": "18.2.0", - "react-native": "0.74.3", + "react": "18.3.1", + "react-native": "0.76.3", "react-native-dotenv": "^3.4.9" }, "devDependencies": { diff --git a/packages/sdk/react-universal/example/package.json b/packages/sdk/react-universal/example/package.json index 64b67d8ac..1101d1ffb 100644 --- a/packages/sdk/react-universal/example/package.json +++ b/packages/sdk/react-universal/example/package.json @@ -20,7 +20,7 @@ "@next/eslint-plugin-next": "^14.2.4", "@trivago/prettier-plugin-sort-imports": "^4.3.0", "@types/node": "^20", - "@types/react": "^18", + "@types/react": "18.3.13", "@types/react-dom": "^18", "autoprefixer": "^10.0.1", "eslint": "^8", diff --git a/packages/sdk/react-universal/package.json b/packages/sdk/react-universal/package.json index c60b35f20..39e341e7c 100644 --- a/packages/sdk/react-universal/package.json +++ b/packages/sdk/react-universal/package.json @@ -48,7 +48,7 @@ "devDependencies": { "@trivago/prettier-plugin-sort-imports": "^4.1.1", "@types/jest": "^29.5.0", - "@types/react": "^18", + "@types/react": "18.3.13", "@typescript-eslint/eslint-plugin": "^6.20.0", "@typescript-eslint/parser": "^6.20.0", "eslint": "^8.45.0", diff --git a/packages/sdk/server-ai/__tests__/LDAIConfigTrackerImpl.test.ts b/packages/sdk/server-ai/__tests__/LDAIConfigTrackerImpl.test.ts index 5787dcc06..532002dba 100644 --- a/packages/sdk/server-ai/__tests__/LDAIConfigTrackerImpl.test.ts +++ b/packages/sdk/server-ai/__tests__/LDAIConfigTrackerImpl.test.ts @@ -268,3 +268,39 @@ it('only tracks non-zero token counts', () => { expect.anything(), ); }); + +it('returns empty summary when no metrics tracked', () => { + const tracker = new LDAIConfigTrackerImpl(mockLdClient, configKey, versionKey, testContext); + + const summary = tracker.getSummary(); + + expect(summary).toEqual({}); +}); + +it('summarizes tracked metrics', () => { + const tracker = new LDAIConfigTrackerImpl(mockLdClient, configKey, versionKey, testContext); + + tracker.trackDuration(1000); + tracker.trackTokens({ + total: 100, + input: 40, + output: 60, + }); + tracker.trackFeedback({ kind: LDFeedbackKind.Positive }); + tracker.trackSuccess(); + + const summary = tracker.getSummary(); + + expect(summary).toEqual({ + durationMs: 1000, + tokens: { + total: 100, + input: 40, + output: 60, + }, + feedback: { + kind: 'positive', + }, + success: true, + }); +}); diff --git a/packages/sdk/server-ai/src/LDAIConfigTrackerImpl.ts b/packages/sdk/server-ai/src/LDAIConfigTrackerImpl.ts index b43fe69ae..2894f965e 100644 --- a/packages/sdk/server-ai/src/LDAIConfigTrackerImpl.ts +++ b/packages/sdk/server-ai/src/LDAIConfigTrackerImpl.ts @@ -1,11 +1,14 @@ import { LDContext } from '@launchdarkly/js-server-sdk-common'; import { LDAIConfigTracker } from './api/config'; +import { LDAIMetricSummary } from './api/config/LDAIConfigTracker'; import { createBedrockTokenUsage, LDFeedbackKind, LDTokenUsage } from './api/metrics'; import { createOpenAiUsage } from './api/metrics/OpenAiUsage'; import { LDClientMin } from './LDClientMin'; export class LDAIConfigTrackerImpl implements LDAIConfigTracker { + private _trackedMetrics: LDAIMetricSummary = {}; + constructor( private _ldClient: LDClientMin, private _configKey: string, @@ -21,6 +24,7 @@ export class LDAIConfigTrackerImpl implements LDAIConfigTracker { } trackDuration(duration: number): void { + this._trackedMetrics.durationMs = duration; this._ldClient.track('$ld:ai:duration:total', this._context, this._getTrackData(), duration); } @@ -34,6 +38,7 @@ export class LDAIConfigTrackerImpl implements LDAIConfigTracker { } trackFeedback(feedback: { kind: LDFeedbackKind }): void { + this._trackedMetrics.feedback = feedback; if (feedback.kind === LDFeedbackKind.Positive) { this._ldClient.track('$ld:ai:feedback:user:positive', this._context, this._getTrackData(), 1); } else if (feedback.kind === LDFeedbackKind.Negative) { @@ -42,6 +47,7 @@ export class LDAIConfigTrackerImpl implements LDAIConfigTracker { } trackSuccess(): void { + this._trackedMetrics.success = true; this._ldClient.track('$ld:ai:generation', this._context, this._getTrackData(), 1); } @@ -88,6 +94,7 @@ export class LDAIConfigTrackerImpl implements LDAIConfigTracker { } trackTokens(tokens: LDTokenUsage): void { + this._trackedMetrics.tokens = tokens; const trackData = this._getTrackData(); if (tokens.total > 0) { this._ldClient.track('$ld:ai:tokens:total', this._context, trackData, tokens.total); @@ -99,4 +106,11 @@ export class LDAIConfigTrackerImpl implements LDAIConfigTracker { this._ldClient.track('$ld:ai:tokens:output', this._context, trackData, tokens.output); } } + + /** + * Get a summary of the tracked metrics. + */ + getSummary(): LDAIMetricSummary { + return { ...this._trackedMetrics }; + } } diff --git a/packages/sdk/server-ai/src/api/config/LDAIConfigTracker.ts b/packages/sdk/server-ai/src/api/config/LDAIConfigTracker.ts index f92dfa4d9..3348a13d1 100644 --- a/packages/sdk/server-ai/src/api/config/LDAIConfigTracker.ts +++ b/packages/sdk/server-ai/src/api/config/LDAIConfigTracker.ts @@ -1,5 +1,30 @@ import { LDFeedbackKind, LDTokenUsage } from '../metrics'; +/** + * Metrics which have been tracked. + */ +export interface LDAIMetricSummary { + /** + * The duration of generation. + */ + durationMs?: number; + + /** + * Information about token usage. + */ + tokens?: LDTokenUsage; + + /** + * Was generation successful. + */ + success?: boolean; + + /** + * Any sentiment about the generation. + */ + feedback?: { kind: LDFeedbackKind }; +} + /** * The LDAIConfigTracker is used to track various details about AI operations. */ @@ -76,4 +101,9 @@ export interface LDAIConfigTracker { >( res: TRes, ): TRes; + + /** + * Get a summary of the tracked metrics. + */ + getSummary(): LDAIMetricSummary; } diff --git a/packages/shared/sdk-server/src/LDClientImpl.ts b/packages/shared/sdk-server/src/LDClientImpl.ts index 6bbc3b74e..44a355158 100644 --- a/packages/shared/sdk-server/src/LDClientImpl.ts +++ b/packages/shared/sdk-server/src/LDClientImpl.ts @@ -32,11 +32,11 @@ import { BigSegmentStoreMembership } from './api/interfaces'; import { LDWaitForInitializationOptions } from './api/LDWaitForInitializationOptions'; import BigSegmentsManager from './BigSegmentsManager'; import BigSegmentStoreStatusProvider from './BigSegmentStatusProviderImpl'; -import { createPayloadListener } from './data_sources/createStreamListenersFDv2'; +import { createStreamListeners } from './data_sources/createStreamListeners'; import DataSourceUpdates from './data_sources/DataSourceUpdates'; import PollingProcessor from './data_sources/PollingProcessor'; import Requestor from './data_sources/Requestor'; -import StreamingProcessorFDv2 from './data_sources/StreamingProcessorFDv2'; +import StreamingProcessor from './data_sources/StreamingProcessor'; import createDiagnosticsInitConfig from './diagnostics/createDiagnosticsInitConfig'; import { allAsync } from './evaluation/collection'; import { Flag } from './evaluation/data/Flag'; @@ -216,17 +216,16 @@ export default class LDClientImpl implements LDClient { }; this._evaluator = new Evaluator(this._platform, queries); - const payloadListener = createPayloadListener(dataSourceUpdates, this.logger, () => - this._initSuccess(), - ); - + const listeners = createStreamListeners(dataSourceUpdates, this._logger, { + put: () => this._initSuccess(), + }); const makeDefaultProcessor = () => config.stream - ? new StreamingProcessorFDv2( + ? new StreamingProcessor( clientContext, '/all', [], - payloadListener, + listeners, baseHeaders, this._diagnosticsManager, (e) => this._dataSourceErrorHandler(e),