@launchdarkly/server-sdk-ai 0.14.1 → 0.15.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (197) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/dist/index.cjs +1117 -0
  3. package/dist/index.cjs.map +1 -0
  4. package/dist/index.d.cts +1022 -0
  5. package/dist/index.d.ts +1022 -0
  6. package/dist/index.js +1071 -0
  7. package/dist/index.js.map +1 -0
  8. package/package.json +23 -6
  9. package/__tests__/Judge.test.ts +0 -521
  10. package/__tests__/LDAIClientImpl.test.ts +0 -594
  11. package/__tests__/LDAIConfigTrackerImpl.test.ts +0 -815
  12. package/__tests__/TokenUsage.test.ts +0 -119
  13. package/__tests__/TrackedChat.test.ts +0 -231
  14. package/dist/package.json +0 -53
  15. package/dist/src/LDAIClientImpl.d.ts +0 -39
  16. package/dist/src/LDAIClientImpl.d.ts.map +0 -1
  17. package/dist/src/LDAIClientImpl.js +0 -164
  18. package/dist/src/LDAIClientImpl.js.map +0 -1
  19. package/dist/src/LDAIConfigTrackerImpl.d.ts +0 -74
  20. package/dist/src/LDAIConfigTrackerImpl.d.ts.map +0 -1
  21. package/dist/src/LDAIConfigTrackerImpl.js +0 -207
  22. package/dist/src/LDAIConfigTrackerImpl.js.map +0 -1
  23. package/dist/src/LDClientMin.d.ts +0 -11
  24. package/dist/src/LDClientMin.d.ts.map +0 -1
  25. package/dist/src/LDClientMin.js +0 -3
  26. package/dist/src/LDClientMin.js.map +0 -1
  27. package/dist/src/api/LDAIClient.d.ts +0 -258
  28. package/dist/src/api/LDAIClient.d.ts.map +0 -1
  29. package/dist/src/api/LDAIClient.js +0 -3
  30. package/dist/src/api/LDAIClient.js.map +0 -1
  31. package/dist/src/api/chat/TrackedChat.d.ts +0 -72
  32. package/dist/src/api/chat/TrackedChat.d.ts.map +0 -1
  33. package/dist/src/api/chat/TrackedChat.js +0 -125
  34. package/dist/src/api/chat/TrackedChat.js.map +0 -1
  35. package/dist/src/api/chat/index.d.ts +0 -3
  36. package/dist/src/api/chat/index.d.ts.map +0 -1
  37. package/dist/src/api/chat/index.js +0 -19
  38. package/dist/src/api/chat/index.js.map +0 -1
  39. package/dist/src/api/chat/types.d.ts +0 -22
  40. package/dist/src/api/chat/types.d.ts.map +0 -1
  41. package/dist/src/api/chat/types.js +0 -3
  42. package/dist/src/api/chat/types.js.map +0 -1
  43. package/dist/src/api/config/LDAIConfigTracker.d.ts +0 -209
  44. package/dist/src/api/config/LDAIConfigTracker.d.ts.map +0 -1
  45. package/dist/src/api/config/LDAIConfigTracker.js +0 -3
  46. package/dist/src/api/config/LDAIConfigTracker.js.map +0 -1
  47. package/dist/src/api/config/LDAIConfigUtils.d.ts +0 -2
  48. package/dist/src/api/config/LDAIConfigUtils.d.ts.map +0 -1
  49. package/dist/src/api/config/LDAIConfigUtils.js +0 -145
  50. package/dist/src/api/config/LDAIConfigUtils.js.map +0 -1
  51. package/dist/src/api/config/index.d.ts +0 -3
  52. package/dist/src/api/config/index.d.ts.map +0 -1
  53. package/dist/src/api/config/index.js +0 -18
  54. package/dist/src/api/config/index.js.map +0 -1
  55. package/dist/src/api/config/types.d.ts +0 -206
  56. package/dist/src/api/config/types.d.ts.map +0 -1
  57. package/dist/src/api/config/types.js +0 -3
  58. package/dist/src/api/config/types.js.map +0 -1
  59. package/dist/src/api/index.d.ts +0 -7
  60. package/dist/src/api/index.d.ts.map +0 -1
  61. package/dist/src/api/index.js +0 -23
  62. package/dist/src/api/index.js.map +0 -1
  63. package/dist/src/api/judge/EvaluationSchemaBuilder.d.ts +0 -11
  64. package/dist/src/api/judge/EvaluationSchemaBuilder.d.ts.map +0 -1
  65. package/dist/src/api/judge/EvaluationSchemaBuilder.js +0 -52
  66. package/dist/src/api/judge/EvaluationSchemaBuilder.js.map +0 -1
  67. package/dist/src/api/judge/Judge.d.ts +0 -63
  68. package/dist/src/api/judge/Judge.d.ts.map +0 -1
  69. package/dist/src/api/judge/Judge.js +0 -151
  70. package/dist/src/api/judge/Judge.js.map +0 -1
  71. package/dist/src/api/judge/index.d.ts +0 -3
  72. package/dist/src/api/judge/index.d.ts.map +0 -1
  73. package/dist/src/api/judge/index.js +0 -6
  74. package/dist/src/api/judge/index.js.map +0 -1
  75. package/dist/src/api/judge/types.d.ts +0 -37
  76. package/dist/src/api/judge/types.d.ts.map +0 -1
  77. package/dist/src/api/judge/types.js +0 -3
  78. package/dist/src/api/judge/types.js.map +0 -1
  79. package/dist/src/api/metrics/BedrockTokenUsage.d.ts +0 -7
  80. package/dist/src/api/metrics/BedrockTokenUsage.d.ts.map +0 -1
  81. package/dist/src/api/metrics/BedrockTokenUsage.js +0 -12
  82. package/dist/src/api/metrics/BedrockTokenUsage.js.map +0 -1
  83. package/dist/src/api/metrics/LDAIMetrics.d.ts +0 -17
  84. package/dist/src/api/metrics/LDAIMetrics.d.ts.map +0 -1
  85. package/dist/src/api/metrics/LDAIMetrics.js +0 -3
  86. package/dist/src/api/metrics/LDAIMetrics.js.map +0 -1
  87. package/dist/src/api/metrics/LDFeedbackKind.d.ts +0 -14
  88. package/dist/src/api/metrics/LDFeedbackKind.d.ts.map +0 -1
  89. package/dist/src/api/metrics/LDFeedbackKind.js +0 -18
  90. package/dist/src/api/metrics/LDFeedbackKind.js.map +0 -1
  91. package/dist/src/api/metrics/LDTokenUsage.d.ts +0 -18
  92. package/dist/src/api/metrics/LDTokenUsage.d.ts.map +0 -1
  93. package/dist/src/api/metrics/LDTokenUsage.js +0 -3
  94. package/dist/src/api/metrics/LDTokenUsage.js.map +0 -1
  95. package/dist/src/api/metrics/OpenAiUsage.d.ts +0 -7
  96. package/dist/src/api/metrics/OpenAiUsage.d.ts.map +0 -1
  97. package/dist/src/api/metrics/OpenAiUsage.js +0 -13
  98. package/dist/src/api/metrics/OpenAiUsage.js.map +0 -1
  99. package/dist/src/api/metrics/VercelAISDKTokenUsage.d.ts +0 -9
  100. package/dist/src/api/metrics/VercelAISDKTokenUsage.d.ts.map +0 -1
  101. package/dist/src/api/metrics/VercelAISDKTokenUsage.js +0 -13
  102. package/dist/src/api/metrics/VercelAISDKTokenUsage.js.map +0 -1
  103. package/dist/src/api/metrics/index.d.ts +0 -7
  104. package/dist/src/api/metrics/index.d.ts.map +0 -1
  105. package/dist/src/api/metrics/index.js +0 -23
  106. package/dist/src/api/metrics/index.js.map +0 -1
  107. package/dist/src/api/providers/AIProvider.d.ts +0 -52
  108. package/dist/src/api/providers/AIProvider.d.ts.map +0 -1
  109. package/dist/src/api/providers/AIProvider.js +0 -88
  110. package/dist/src/api/providers/AIProvider.js.map +0 -1
  111. package/dist/src/api/providers/AIProviderFactory.d.ts +0 -39
  112. package/dist/src/api/providers/AIProviderFactory.d.ts.map +0 -1
  113. package/dist/src/api/providers/AIProviderFactory.js +0 -102
  114. package/dist/src/api/providers/AIProviderFactory.js.map +0 -1
  115. package/dist/src/api/providers/index.d.ts +0 -3
  116. package/dist/src/api/providers/index.d.ts.map +0 -1
  117. package/dist/src/api/providers/index.js +0 -19
  118. package/dist/src/api/providers/index.js.map +0 -1
  119. package/dist/src/index.d.ts +0 -19
  120. package/dist/src/index.d.ts.map +0 -1
  121. package/dist/src/index.js +0 -29
  122. package/dist/src/index.js.map +0 -1
  123. package/docs/.nojekyll +0 -1
  124. package/docs/assets/highlight.css +0 -92
  125. package/docs/assets/main.js +0 -58
  126. package/docs/assets/search.js +0 -1
  127. package/docs/assets/style.css +0 -1379
  128. package/docs/classes/AIProvider.html +0 -210
  129. package/docs/classes/AIProviderFactory.html +0 -208
  130. package/docs/classes/Judge.html +0 -322
  131. package/docs/classes/TrackedChat.html +0 -322
  132. package/docs/enums/LDFeedbackKind.html +0 -115
  133. package/docs/functions/createBedrockTokenUsage.html +0 -94
  134. package/docs/functions/createOpenAiUsage.html +0 -94
  135. package/docs/functions/createVercelAISDKTokenUsage.html +0 -98
  136. package/docs/functions/initAi.html +0 -93
  137. package/docs/index.html +0 -136
  138. package/docs/interfaces/ChatResponse.html +0 -130
  139. package/docs/interfaces/EvalScore.html +0 -119
  140. package/docs/interfaces/JudgeResponse.html +0 -139
  141. package/docs/interfaces/LDAIAgentConfig.html +0 -178
  142. package/docs/interfaces/LDAIAgentConfigDefault.html +0 -155
  143. package/docs/interfaces/LDAIAgentRequestConfig.html +0 -129
  144. package/docs/interfaces/LDAIClient.html +0 -449
  145. package/docs/interfaces/LDAICompletionConfig.html +0 -178
  146. package/docs/interfaces/LDAICompletionConfigDefault.html +0 -155
  147. package/docs/interfaces/LDAIConfig.html +0 -158
  148. package/docs/interfaces/LDAIConfigDefault.html +0 -133
  149. package/docs/interfaces/LDAIConfigTracker.html +0 -530
  150. package/docs/interfaces/LDAIJudgeConfig.html +0 -178
  151. package/docs/interfaces/LDAIJudgeConfigDefault.html +0 -155
  152. package/docs/interfaces/LDAIMetrics.html +0 -121
  153. package/docs/interfaces/LDJudge.html +0 -119
  154. package/docs/interfaces/LDJudgeConfiguration.html +0 -109
  155. package/docs/interfaces/LDLogger.html +0 -189
  156. package/docs/interfaces/LDMessage.html +0 -119
  157. package/docs/interfaces/LDModelConfig.html +0 -139
  158. package/docs/interfaces/LDProviderConfig.html +0 -105
  159. package/docs/interfaces/LDTokenUsage.html +0 -129
  160. package/docs/interfaces/StructuredResponse.html +0 -129
  161. package/docs/types/LDAIConfigDefaultKind.html +0 -81
  162. package/docs/types/LDAIConfigKind.html +0 -81
  163. package/docs/types/LDAIConfigMode.html +0 -81
  164. package/docs/types/SupportedAIProvider.html +0 -81
  165. package/docs/variables/SUPPORTED_AI_PROVIDERS.html +0 -81
  166. package/jest.config.js +0 -7
  167. package/src/LDAIClientImpl.ts +0 -327
  168. package/src/LDAIConfigTrackerImpl.ts +0 -288
  169. package/src/LDClientMin.ts +0 -18
  170. package/src/api/LDAIClient.ts +0 -325
  171. package/src/api/chat/TrackedChat.ts +0 -163
  172. package/src/api/chat/index.ts +0 -2
  173. package/src/api/chat/types.ts +0 -24
  174. package/src/api/config/LDAIConfigTracker.ts +0 -238
  175. package/src/api/config/LDAIConfigUtils.ts +0 -212
  176. package/src/api/config/index.ts +0 -3
  177. package/src/api/config/types.ts +0 -260
  178. package/src/api/index.ts +0 -6
  179. package/src/api/judge/EvaluationSchemaBuilder.ts +0 -54
  180. package/src/api/judge/Judge.ts +0 -218
  181. package/src/api/judge/index.ts +0 -2
  182. package/src/api/judge/types.ts +0 -41
  183. package/src/api/metrics/BedrockTokenUsage.ts +0 -13
  184. package/src/api/metrics/LDAIMetrics.ts +0 -18
  185. package/src/api/metrics/LDFeedbackKind.ts +0 -13
  186. package/src/api/metrics/LDTokenUsage.ts +0 -19
  187. package/src/api/metrics/OpenAiUsage.ts +0 -13
  188. package/src/api/metrics/VercelAISDKTokenUsage.ts +0 -15
  189. package/src/api/metrics/index.ts +0 -6
  190. package/src/api/providers/AIProvider.ts +0 -94
  191. package/src/api/providers/AIProviderFactory.ts +0 -152
  192. package/src/api/providers/index.ts +0 -2
  193. package/src/index.ts +0 -24
  194. package/tsconfig.eslint.json +0 -5
  195. package/tsconfig.json +0 -21
  196. package/tsconfig.ref.json +0 -7
  197. package/typedoc.json +0 -5
@@ -1,815 +0,0 @@
1
- import { LDContext } from '@launchdarkly/js-server-sdk-common';
2
-
3
- import { name as aiSdkName, version as aiSdkVersion } from '../package.json';
4
- import { LDFeedbackKind } from '../src/api/metrics';
5
- import { LDAIConfigTrackerImpl } from '../src/LDAIConfigTrackerImpl';
6
- import { LDClientMin } from '../src/LDClientMin';
7
-
8
- const mockTrack = jest.fn();
9
- const mockVariation = jest.fn();
10
- const mockLdClient: LDClientMin = {
11
- track: mockTrack,
12
- variation: mockVariation,
13
- };
14
-
15
- const testContext: LDContext = { kind: 'user', key: 'test-user' };
16
- const configKey = 'test-config';
17
- const variationKey = 'v1';
18
- const version = 1;
19
- const modelName = 'test-model';
20
- const providerName = 'test-provider';
21
-
22
- const getExpectedTrackData = () => ({
23
- configKey,
24
- variationKey,
25
- version,
26
- modelName,
27
- providerName,
28
- aiSdkName,
29
- aiSdkVersion,
30
- });
31
-
32
- beforeEach(() => {
33
- jest.clearAllMocks();
34
- });
35
-
36
- it('tracks duration', () => {
37
- const tracker = new LDAIConfigTrackerImpl(
38
- mockLdClient,
39
- configKey,
40
- variationKey,
41
- version,
42
- modelName,
43
- providerName,
44
- testContext,
45
- );
46
- tracker.trackDuration(1000);
47
-
48
- expect(mockTrack).toHaveBeenCalledWith(
49
- '$ld:ai:duration:total',
50
- testContext,
51
- getExpectedTrackData(),
52
- 1000,
53
- );
54
- });
55
-
56
- it('tracks duration of async function', async () => {
57
- const tracker = new LDAIConfigTrackerImpl(
58
- mockLdClient,
59
- configKey,
60
- variationKey,
61
- version,
62
- modelName,
63
- providerName,
64
- testContext,
65
- );
66
- jest.spyOn(global.Date, 'now').mockReturnValueOnce(1000).mockReturnValueOnce(2000);
67
-
68
- const result = await tracker.trackDurationOf(async () => 'test-result');
69
-
70
- expect(result).toBe('test-result');
71
- expect(mockTrack).toHaveBeenCalledWith(
72
- '$ld:ai:duration:total',
73
- testContext,
74
- getExpectedTrackData(),
75
- 1000,
76
- );
77
- });
78
-
79
- it('tracks time to first token', () => {
80
- const tracker = new LDAIConfigTrackerImpl(
81
- mockLdClient,
82
- configKey,
83
- variationKey,
84
- version,
85
- modelName,
86
- providerName,
87
- testContext,
88
- );
89
- tracker.trackTimeToFirstToken(1000);
90
-
91
- expect(mockTrack).toHaveBeenCalledWith(
92
- '$ld:ai:tokens:ttf',
93
- testContext,
94
- getExpectedTrackData(),
95
- 1000,
96
- );
97
- });
98
-
99
- it('tracks positive feedback', () => {
100
- const tracker = new LDAIConfigTrackerImpl(
101
- mockLdClient,
102
- configKey,
103
- variationKey,
104
- version,
105
- modelName,
106
- providerName,
107
- testContext,
108
- );
109
- tracker.trackFeedback({ kind: LDFeedbackKind.Positive });
110
-
111
- expect(mockTrack).toHaveBeenCalledWith(
112
- '$ld:ai:feedback:user:positive',
113
- testContext,
114
- getExpectedTrackData(),
115
- 1,
116
- );
117
- });
118
-
119
- it('tracks negative feedback', () => {
120
- const tracker = new LDAIConfigTrackerImpl(
121
- mockLdClient,
122
- configKey,
123
- variationKey,
124
- version,
125
- modelName,
126
- providerName,
127
- testContext,
128
- );
129
- tracker.trackFeedback({ kind: LDFeedbackKind.Negative });
130
-
131
- expect(mockTrack).toHaveBeenCalledWith(
132
- '$ld:ai:feedback:user:negative',
133
- testContext,
134
- getExpectedTrackData(),
135
- 1,
136
- );
137
- });
138
-
139
- it('tracks success', () => {
140
- const tracker = new LDAIConfigTrackerImpl(
141
- mockLdClient,
142
- configKey,
143
- variationKey,
144
- version,
145
- modelName,
146
- providerName,
147
- testContext,
148
- );
149
- tracker.trackSuccess();
150
-
151
- expect(mockTrack).toHaveBeenCalledWith(
152
- '$ld:ai:generation:success',
153
- testContext,
154
- getExpectedTrackData(),
155
- 1,
156
- );
157
- });
158
-
159
- it('tracks OpenAI usage', async () => {
160
- const tracker = new LDAIConfigTrackerImpl(
161
- mockLdClient,
162
- configKey,
163
- variationKey,
164
- version,
165
- modelName,
166
- providerName,
167
- testContext,
168
- );
169
- jest.spyOn(global.Date, 'now').mockReturnValueOnce(1000).mockReturnValueOnce(2000);
170
-
171
- const TOTAL_TOKENS = 100;
172
- const PROMPT_TOKENS = 49;
173
- const COMPLETION_TOKENS = 51;
174
-
175
- await tracker.trackOpenAIMetrics(async () => ({
176
- usage: {
177
- total_tokens: TOTAL_TOKENS,
178
- prompt_tokens: PROMPT_TOKENS,
179
- completion_tokens: COMPLETION_TOKENS,
180
- },
181
- }));
182
-
183
- expect(mockTrack).toHaveBeenCalledWith(
184
- '$ld:ai:duration:total',
185
- testContext,
186
- getExpectedTrackData(),
187
- 1000,
188
- );
189
-
190
- expect(mockTrack).toHaveBeenCalledWith(
191
- '$ld:ai:generation:success',
192
- testContext,
193
- getExpectedTrackData(),
194
- 1,
195
- );
196
-
197
- expect(mockTrack).not.toHaveBeenCalledWith(
198
- '$ld:ai:generation:error',
199
- expect.anything(),
200
- expect.anything(),
201
- expect.anything(),
202
- );
203
-
204
- expect(mockTrack).toHaveBeenCalledWith(
205
- '$ld:ai:tokens:total',
206
- testContext,
207
- getExpectedTrackData(),
208
- TOTAL_TOKENS,
209
- );
210
-
211
- expect(mockTrack).toHaveBeenCalledWith(
212
- '$ld:ai:tokens:input',
213
- testContext,
214
- getExpectedTrackData(),
215
- PROMPT_TOKENS,
216
- );
217
-
218
- expect(mockTrack).toHaveBeenCalledWith(
219
- '$ld:ai:tokens:output',
220
- testContext,
221
- getExpectedTrackData(),
222
- COMPLETION_TOKENS,
223
- );
224
- });
225
-
226
- it('tracks error when OpenAI metrics function throws', async () => {
227
- const tracker = new LDAIConfigTrackerImpl(
228
- mockLdClient,
229
- configKey,
230
- variationKey,
231
- version,
232
- modelName,
233
- providerName,
234
- testContext,
235
- );
236
- jest.spyOn(global.Date, 'now').mockReturnValueOnce(1000).mockReturnValueOnce(2000);
237
-
238
- const error = new Error('OpenAI API error');
239
- await expect(
240
- tracker.trackOpenAIMetrics(async () => {
241
- throw error;
242
- }),
243
- ).rejects.toThrow(error);
244
-
245
- expect(mockTrack).toHaveBeenCalledWith(
246
- '$ld:ai:duration:total',
247
- testContext,
248
- getExpectedTrackData(),
249
- 1000,
250
- );
251
-
252
- expect(mockTrack).toHaveBeenCalledWith(
253
- '$ld:ai:generation:error',
254
- testContext,
255
- getExpectedTrackData(),
256
- 1,
257
- );
258
-
259
- expect(mockTrack).not.toHaveBeenCalledWith(
260
- expect.stringMatching(/^\$ld:ai:tokens:/),
261
- expect.anything(),
262
- expect.anything(),
263
- expect.anything(),
264
- );
265
- });
266
-
267
- it('tracks Bedrock conversation with successful response', () => {
268
- const tracker = new LDAIConfigTrackerImpl(
269
- mockLdClient,
270
- configKey,
271
- variationKey,
272
- version,
273
- modelName,
274
- providerName,
275
- testContext,
276
- );
277
-
278
- const TOTAL_TOKENS = 100;
279
- const PROMPT_TOKENS = 49;
280
- const COMPLETION_TOKENS = 51;
281
-
282
- const response = {
283
- $metadata: { httpStatusCode: 200 },
284
- metrics: { latencyMs: 500 },
285
- usage: {
286
- inputTokens: PROMPT_TOKENS,
287
- outputTokens: COMPLETION_TOKENS,
288
- totalTokens: TOTAL_TOKENS,
289
- },
290
- };
291
-
292
- tracker.trackBedrockConverseMetrics(response);
293
-
294
- expect(mockTrack).toHaveBeenCalledWith(
295
- '$ld:ai:generation:success',
296
- testContext,
297
- getExpectedTrackData(),
298
- 1,
299
- );
300
-
301
- expect(mockTrack).not.toHaveBeenCalledWith(
302
- '$ld:ai:generation:error',
303
- expect.anything(),
304
- expect.anything(),
305
- expect.anything(),
306
- );
307
-
308
- expect(mockTrack).toHaveBeenCalledWith(
309
- '$ld:ai:duration:total',
310
- testContext,
311
- getExpectedTrackData(),
312
- 500,
313
- );
314
-
315
- expect(mockTrack).toHaveBeenCalledWith(
316
- '$ld:ai:tokens:total',
317
- testContext,
318
- getExpectedTrackData(),
319
- TOTAL_TOKENS,
320
- );
321
-
322
- expect(mockTrack).toHaveBeenCalledWith(
323
- '$ld:ai:tokens:input',
324
- testContext,
325
- getExpectedTrackData(),
326
- PROMPT_TOKENS,
327
- );
328
-
329
- expect(mockTrack).toHaveBeenCalledWith(
330
- '$ld:ai:tokens:output',
331
- testContext,
332
- getExpectedTrackData(),
333
- COMPLETION_TOKENS,
334
- );
335
- });
336
-
337
- it('tracks Bedrock conversation with error response', () => {
338
- const tracker = new LDAIConfigTrackerImpl(
339
- mockLdClient,
340
- configKey,
341
- variationKey,
342
- version,
343
- modelName,
344
- providerName,
345
- testContext,
346
- );
347
-
348
- const response = {
349
- $metadata: { httpStatusCode: 400 },
350
- };
351
-
352
- tracker.trackBedrockConverseMetrics(response);
353
-
354
- expect(mockTrack).toHaveBeenCalledTimes(1);
355
-
356
- expect(mockTrack).toHaveBeenCalledWith(
357
- '$ld:ai:generation:error',
358
- testContext,
359
- getExpectedTrackData(),
360
- 1,
361
- );
362
-
363
- expect(mockTrack).not.toHaveBeenCalledWith(
364
- expect.stringMatching(/^\$ld:ai:tokens:/),
365
- expect.anything(),
366
- expect.anything(),
367
- expect.anything(),
368
- );
369
- });
370
-
371
- describe('Vercel AI SDK generateText', () => {
372
- it('tracks Vercel AI SDK usage', async () => {
373
- const tracker = new LDAIConfigTrackerImpl(
374
- mockLdClient,
375
- configKey,
376
- variationKey,
377
- version,
378
- modelName,
379
- providerName,
380
- testContext,
381
- );
382
- jest.spyOn(global.Date, 'now').mockReturnValueOnce(1000).mockReturnValueOnce(2000);
383
-
384
- const TOTAL_TOKENS = 100;
385
- const PROMPT_TOKENS = 49;
386
- const COMPLETION_TOKENS = 51;
387
-
388
- await tracker.trackVercelAISDKGenerateTextMetrics(async () => ({
389
- usage: {
390
- totalTokens: TOTAL_TOKENS,
391
- promptTokens: PROMPT_TOKENS,
392
- completionTokens: COMPLETION_TOKENS,
393
- },
394
- }));
395
-
396
- expect(mockTrack).toHaveBeenCalledWith(
397
- '$ld:ai:duration:total',
398
- testContext,
399
- getExpectedTrackData(),
400
- 1000,
401
- );
402
-
403
- expect(mockTrack).toHaveBeenCalledWith(
404
- '$ld:ai:generation:success',
405
- testContext,
406
- getExpectedTrackData(),
407
- 1,
408
- );
409
-
410
- expect(mockTrack).not.toHaveBeenCalledWith(
411
- '$ld:ai:generation:error',
412
- expect.anything(),
413
- expect.anything(),
414
- expect.anything(),
415
- );
416
-
417
- expect(mockTrack).toHaveBeenCalledWith(
418
- '$ld:ai:tokens:total',
419
- testContext,
420
- getExpectedTrackData(),
421
- TOTAL_TOKENS,
422
- );
423
-
424
- expect(mockTrack).toHaveBeenCalledWith(
425
- '$ld:ai:tokens:input',
426
- testContext,
427
- getExpectedTrackData(),
428
- PROMPT_TOKENS,
429
- );
430
-
431
- expect(mockTrack).toHaveBeenCalledWith(
432
- '$ld:ai:tokens:output',
433
- testContext,
434
- getExpectedTrackData(),
435
- COMPLETION_TOKENS,
436
- );
437
- });
438
-
439
- it('tracks error when Vercel AI SDK metrics function throws', async () => {
440
- const tracker = new LDAIConfigTrackerImpl(
441
- mockLdClient,
442
- configKey,
443
- variationKey,
444
- version,
445
- modelName,
446
- providerName,
447
- testContext,
448
- );
449
- jest.spyOn(global.Date, 'now').mockReturnValueOnce(1000).mockReturnValueOnce(2000);
450
-
451
- const error = new Error('Vercel AI SDK API error');
452
- await expect(
453
- tracker.trackVercelAISDKGenerateTextMetrics(async () => {
454
- throw error;
455
- }),
456
- ).rejects.toThrow(error);
457
-
458
- expect(mockTrack).toHaveBeenCalledWith(
459
- '$ld:ai:duration:total',
460
- testContext,
461
- getExpectedTrackData(),
462
- 1000,
463
- );
464
-
465
- expect(mockTrack).toHaveBeenCalledWith(
466
- '$ld:ai:generation:error',
467
- testContext,
468
- getExpectedTrackData(),
469
- 1,
470
- );
471
-
472
- expect(mockTrack).not.toHaveBeenCalledWith(
473
- expect.stringMatching(/^\$ld:ai:tokens:/),
474
- expect.anything(),
475
- expect.anything(),
476
- expect.anything(),
477
- );
478
- });
479
- });
480
-
481
- it('tracks tokens', () => {
482
- const tracker = new LDAIConfigTrackerImpl(
483
- mockLdClient,
484
- configKey,
485
- variationKey,
486
- version,
487
- modelName,
488
- providerName,
489
- testContext,
490
- );
491
-
492
- const TOTAL_TOKENS = 100;
493
- const PROMPT_TOKENS = 49;
494
- const COMPLETION_TOKENS = 51;
495
-
496
- tracker.trackTokens({
497
- total: TOTAL_TOKENS,
498
- input: PROMPT_TOKENS,
499
- output: COMPLETION_TOKENS,
500
- });
501
-
502
- expect(mockTrack).toHaveBeenCalledWith(
503
- '$ld:ai:tokens:total',
504
- testContext,
505
- getExpectedTrackData(),
506
- TOTAL_TOKENS,
507
- );
508
-
509
- expect(mockTrack).toHaveBeenCalledWith(
510
- '$ld:ai:tokens:input',
511
- testContext,
512
- getExpectedTrackData(),
513
- PROMPT_TOKENS,
514
- );
515
-
516
- expect(mockTrack).toHaveBeenCalledWith(
517
- '$ld:ai:tokens:output',
518
- testContext,
519
- getExpectedTrackData(),
520
- COMPLETION_TOKENS,
521
- );
522
- });
523
-
524
- it('only tracks non-zero token counts', () => {
525
- const tracker = new LDAIConfigTrackerImpl(
526
- mockLdClient,
527
- configKey,
528
- variationKey,
529
- version,
530
- modelName,
531
- providerName,
532
- testContext,
533
- );
534
-
535
- tracker.trackTokens({
536
- total: 0,
537
- input: 50,
538
- output: 0,
539
- });
540
-
541
- expect(mockTrack).not.toHaveBeenCalledWith(
542
- '$ld:ai:tokens:total',
543
- expect.anything(),
544
- expect.anything(),
545
- expect.anything(),
546
- );
547
-
548
- expect(mockTrack).toHaveBeenCalledWith(
549
- '$ld:ai:tokens:input',
550
- testContext,
551
- getExpectedTrackData(),
552
- 50,
553
- );
554
-
555
- expect(mockTrack).not.toHaveBeenCalledWith(
556
- '$ld:ai:tokens:output',
557
- expect.anything(),
558
- expect.anything(),
559
- expect.anything(),
560
- );
561
- });
562
-
563
- it('returns empty summary when no metrics tracked', () => {
564
- const tracker = new LDAIConfigTrackerImpl(
565
- mockLdClient,
566
- configKey,
567
- variationKey,
568
- version,
569
- modelName,
570
- providerName,
571
- testContext,
572
- );
573
-
574
- const summary = tracker.getSummary();
575
-
576
- expect(summary).toEqual({});
577
- });
578
-
579
- it('summarizes tracked metrics', () => {
580
- const tracker = new LDAIConfigTrackerImpl(
581
- mockLdClient,
582
- configKey,
583
- variationKey,
584
- version,
585
- modelName,
586
- providerName,
587
- testContext,
588
- );
589
-
590
- tracker.trackDuration(1000);
591
- tracker.trackTokens({
592
- total: 100,
593
- input: 40,
594
- output: 60,
595
- });
596
- tracker.trackFeedback({ kind: LDFeedbackKind.Positive });
597
- tracker.trackSuccess();
598
-
599
- const summary = tracker.getSummary();
600
-
601
- expect(summary).toEqual({
602
- durationMs: 1000,
603
- tokens: {
604
- total: 100,
605
- input: 40,
606
- output: 60,
607
- },
608
- feedback: {
609
- kind: 'positive',
610
- },
611
- success: true,
612
- });
613
- });
614
-
615
- it('tracks duration when async function throws', async () => {
616
- const tracker = new LDAIConfigTrackerImpl(
617
- mockLdClient,
618
- configKey,
619
- variationKey,
620
- version,
621
- modelName,
622
- providerName,
623
- testContext,
624
- );
625
- jest.spyOn(global.Date, 'now').mockReturnValueOnce(1000).mockReturnValueOnce(2000);
626
-
627
- const error = new Error('test error');
628
- await expect(
629
- tracker.trackDurationOf(async () => {
630
- throw error;
631
- }),
632
- ).rejects.toThrow(error);
633
-
634
- expect(mockTrack).toHaveBeenCalledWith(
635
- '$ld:ai:duration:total',
636
- testContext,
637
- getExpectedTrackData(),
638
- 1000,
639
- );
640
- });
641
-
642
- it('tracks error', () => {
643
- const tracker = new LDAIConfigTrackerImpl(
644
- mockLdClient,
645
- configKey,
646
- variationKey,
647
- version,
648
- modelName,
649
- providerName,
650
- testContext,
651
- );
652
- tracker.trackError();
653
-
654
- expect(mockTrack).toHaveBeenCalledWith(
655
- '$ld:ai:generation:error',
656
- testContext,
657
- getExpectedTrackData(),
658
- 1,
659
- );
660
- });
661
-
662
- describe('trackMetricsOf', () => {
663
- it('tracks success and token usage from metrics', async () => {
664
- const tracker = new LDAIConfigTrackerImpl(
665
- mockLdClient,
666
- configKey,
667
- variationKey,
668
- version,
669
- modelName,
670
- providerName,
671
- testContext,
672
- );
673
-
674
- const mockResult = { response: 'test' };
675
- const mockMetrics = {
676
- success: true,
677
- usage: { total: 100, input: 50, output: 50 },
678
- };
679
-
680
- const metricsExtractor = jest.fn().mockReturnValue(mockMetrics);
681
- const operation = jest.fn().mockResolvedValue(mockResult);
682
-
683
- const result = await tracker.trackMetricsOf(metricsExtractor, operation);
684
-
685
- expect(result).toBe(mockResult);
686
- expect(metricsExtractor).toHaveBeenCalledWith(mockResult);
687
- expect(operation).toHaveBeenCalled();
688
-
689
- // Should track success
690
- expect(mockTrack).toHaveBeenCalledWith(
691
- '$ld:ai:generation:success',
692
- testContext,
693
- getExpectedTrackData(),
694
- 1,
695
- );
696
-
697
- // Should track token usage
698
- expect(mockTrack).toHaveBeenCalledWith(
699
- '$ld:ai:tokens:total',
700
- testContext,
701
- getExpectedTrackData(),
702
- 100,
703
- );
704
- expect(mockTrack).toHaveBeenCalledWith(
705
- '$ld:ai:tokens:input',
706
- testContext,
707
- getExpectedTrackData(),
708
- 50,
709
- );
710
- expect(mockTrack).toHaveBeenCalledWith(
711
- '$ld:ai:tokens:output',
712
- testContext,
713
- getExpectedTrackData(),
714
- 50,
715
- );
716
- });
717
-
718
- it('tracks failure when metrics indicate failure', async () => {
719
- const tracker = new LDAIConfigTrackerImpl(
720
- mockLdClient,
721
- configKey,
722
- variationKey,
723
- version,
724
- modelName,
725
- providerName,
726
- testContext,
727
- );
728
-
729
- const mockResult = { response: 'test' };
730
- const mockMetrics = {
731
- success: false,
732
- };
733
-
734
- const metricsExtractor = jest.fn().mockReturnValue(mockMetrics);
735
- const operation = jest.fn().mockResolvedValue(mockResult);
736
-
737
- await tracker.trackMetricsOf(metricsExtractor, operation);
738
-
739
- // Should track error
740
- expect(mockTrack).toHaveBeenCalledWith(
741
- '$ld:ai:generation:error',
742
- testContext,
743
- getExpectedTrackData(),
744
- 1,
745
- );
746
- });
747
-
748
- it('tracks failure when operation throws', async () => {
749
- const tracker = new LDAIConfigTrackerImpl(
750
- mockLdClient,
751
- configKey,
752
- variationKey,
753
- version,
754
- modelName,
755
- providerName,
756
- testContext,
757
- );
758
-
759
- const error = new Error('Operation failed');
760
- const metricsExtractor = jest.fn();
761
- const operation = jest.fn().mockRejectedValue(error);
762
-
763
- await expect(tracker.trackMetricsOf(metricsExtractor, operation)).rejects.toThrow(error);
764
-
765
- // Should track error
766
- expect(mockTrack).toHaveBeenCalledWith(
767
- '$ld:ai:generation:error',
768
- testContext,
769
- getExpectedTrackData(),
770
- 1,
771
- );
772
-
773
- // Should not call metrics extractor when operation fails
774
- expect(metricsExtractor).not.toHaveBeenCalled();
775
- });
776
-
777
- it('tracks metrics without token usage', async () => {
778
- const tracker = new LDAIConfigTrackerImpl(
779
- mockLdClient,
780
- configKey,
781
- variationKey,
782
- version,
783
- modelName,
784
- providerName,
785
- testContext,
786
- );
787
-
788
- const mockResult = { response: 'test' };
789
- const mockMetrics = {
790
- success: true,
791
- // No usage provided
792
- };
793
-
794
- const metricsExtractor = jest.fn().mockReturnValue(mockMetrics);
795
- const operation = jest.fn().mockResolvedValue(mockResult);
796
-
797
- await tracker.trackMetricsOf(metricsExtractor, operation);
798
-
799
- // Should track success but not token usage
800
- expect(mockTrack).toHaveBeenCalledWith(
801
- '$ld:ai:generation:success',
802
- testContext,
803
- getExpectedTrackData(),
804
- 1,
805
- );
806
-
807
- // Should not track token usage
808
- expect(mockTrack).not.toHaveBeenCalledWith(
809
- '$ld:ai:tokens:total',
810
- expect.any(Object),
811
- expect.any(Object),
812
- expect.any(Number),
813
- );
814
- });
815
- });