@launchdarkly/server-sdk-ai 0.14.0 → 0.15.0

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 +18 -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 +22 -5
  9. package/__tests__/Judge.test.ts +0 -496
  10. package/__tests__/LDAIClientImpl.test.ts +0 -589
  11. package/__tests__/LDAIConfigTrackerImpl.test.ts +0 -815
  12. package/__tests__/TokenUsage.test.ts +0 -119
  13. package/__tests__/TrackedChat.test.ts +0 -230
  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 -73
  20. package/dist/src/LDAIConfigTrackerImpl.d.ts.map +0 -1
  21. package/dist/src/LDAIConfigTrackerImpl.js +0 -203
  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 -203
  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 -141
  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 -202
  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 -149
  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 -35
  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 -129
  141. package/docs/interfaces/LDAIAgentConfig.html +0 -167
  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 -167
  146. package/docs/interfaces/LDAICompletionConfigDefault.html +0 -155
  147. package/docs/interfaces/LDAIConfig.html +0 -148
  148. package/docs/interfaces/LDAIConfigDefault.html +0 -133
  149. package/docs/interfaces/LDAIConfigTracker.html +0 -510
  150. package/docs/interfaces/LDAIJudgeConfig.html +0 -167
  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 -278
  169. package/src/LDClientMin.ts +0 -18
  170. package/src/api/LDAIClient.ts +0 -325
  171. package/src/api/chat/TrackedChat.ts +0 -159
  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 -231
  175. package/src/api/config/LDAIConfigUtils.ts +0 -201
  176. package/src/api/config/index.ts +0 -3
  177. package/src/api/config/types.ts +0 -256
  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 -216
  181. package/src/api/judge/index.ts +0 -2
  182. package/src/api/judge/types.ts +0 -39
  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
- });