@launchdarkly/server-sdk-ai 0.12.3 → 0.14.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 (242) hide show
  1. package/CHANGELOG.md +44 -0
  2. package/README.md +2 -2
  3. package/__tests__/Judge.test.ts +496 -0
  4. package/__tests__/LDAIClientImpl.test.ts +530 -323
  5. package/__tests__/LDAIConfigTrackerImpl.test.ts +50 -290
  6. package/__tests__/TrackedChat.test.ts +4 -5
  7. package/dist/package.json +53 -0
  8. package/dist/src/LDAIClientImpl.d.ts +39 -0
  9. package/dist/src/LDAIClientImpl.d.ts.map +1 -0
  10. package/dist/src/LDAIClientImpl.js +164 -0
  11. package/dist/src/LDAIClientImpl.js.map +1 -0
  12. package/dist/{LDAIConfigTrackerImpl.d.ts → src/LDAIConfigTrackerImpl.d.ts} +13 -11
  13. package/dist/src/LDAIConfigTrackerImpl.d.ts.map +1 -0
  14. package/dist/{LDAIConfigTrackerImpl.js → src/LDAIConfigTrackerImpl.js} +59 -44
  15. package/dist/src/LDAIConfigTrackerImpl.js.map +1 -0
  16. package/dist/src/LDClientMin.d.ts.map +1 -0
  17. package/dist/{LDClientMin.js.map → src/LDClientMin.js.map} +1 -1
  18. package/dist/src/api/LDAIClient.d.ts +258 -0
  19. package/dist/src/api/LDAIClient.d.ts.map +1 -0
  20. package/dist/{api → src/api}/LDAIClient.js.map +1 -1
  21. package/dist/{api → src/api}/chat/TrackedChat.d.ts +22 -4
  22. package/dist/src/api/chat/TrackedChat.d.ts.map +1 -0
  23. package/dist/{api → src/api}/chat/TrackedChat.js +43 -2
  24. package/dist/src/api/chat/TrackedChat.js.map +1 -0
  25. package/dist/src/api/chat/index.d.ts.map +1 -0
  26. package/dist/src/api/chat/index.js.map +1 -0
  27. package/dist/src/api/chat/types.d.ts +22 -0
  28. package/dist/src/api/chat/types.d.ts.map +1 -0
  29. package/dist/{api → src/api}/chat/types.js.map +1 -1
  30. package/dist/{api → src/api}/config/LDAIConfigTracker.d.ts +41 -22
  31. package/dist/src/api/config/LDAIConfigTracker.d.ts.map +1 -0
  32. package/dist/src/api/config/LDAIConfigTracker.js.map +1 -0
  33. package/dist/src/api/config/LDAIConfigUtils.d.ts +2 -0
  34. package/dist/src/api/config/LDAIConfigUtils.d.ts.map +1 -0
  35. package/dist/src/api/config/LDAIConfigUtils.js +141 -0
  36. package/dist/src/api/config/LDAIConfigUtils.js.map +1 -0
  37. package/dist/src/api/config/index.d.ts +3 -0
  38. package/dist/src/api/config/index.d.ts.map +1 -0
  39. package/dist/{api/agents → src/api/config}/index.js +1 -1
  40. package/dist/src/api/config/index.js.map +1 -0
  41. package/dist/src/api/config/types.d.ts +202 -0
  42. package/dist/src/api/config/types.d.ts.map +1 -0
  43. package/dist/{api/agents/LDAIAgent.js → src/api/config/types.js} +1 -1
  44. package/dist/src/api/config/types.js.map +1 -0
  45. package/dist/{api → src/api}/index.d.ts +1 -1
  46. package/dist/src/api/index.d.ts.map +1 -0
  47. package/dist/{api → src/api}/index.js +1 -1
  48. package/dist/src/api/index.js.map +1 -0
  49. package/dist/src/api/judge/EvaluationSchemaBuilder.d.ts +11 -0
  50. package/dist/src/api/judge/EvaluationSchemaBuilder.d.ts.map +1 -0
  51. package/dist/src/api/judge/EvaluationSchemaBuilder.js +52 -0
  52. package/dist/src/api/judge/EvaluationSchemaBuilder.js.map +1 -0
  53. package/dist/src/api/judge/Judge.d.ts +63 -0
  54. package/dist/src/api/judge/Judge.d.ts.map +1 -0
  55. package/dist/src/api/judge/Judge.js +149 -0
  56. package/dist/src/api/judge/Judge.js.map +1 -0
  57. package/dist/src/api/judge/index.d.ts +3 -0
  58. package/dist/src/api/judge/index.d.ts.map +1 -0
  59. package/dist/src/api/judge/index.js +6 -0
  60. package/dist/src/api/judge/index.js.map +1 -0
  61. package/dist/src/api/judge/types.d.ts +35 -0
  62. package/dist/src/api/judge/types.d.ts.map +1 -0
  63. package/dist/{api/config/LDAIConfig.js → src/api/judge/types.js} +1 -1
  64. package/dist/src/api/judge/types.js.map +1 -0
  65. package/dist/src/api/metrics/BedrockTokenUsage.d.ts.map +1 -0
  66. package/dist/src/api/metrics/BedrockTokenUsage.js.map +1 -0
  67. package/dist/src/api/metrics/LDAIMetrics.d.ts.map +1 -0
  68. package/dist/src/api/metrics/LDAIMetrics.js.map +1 -0
  69. package/dist/src/api/metrics/LDFeedbackKind.d.ts.map +1 -0
  70. package/dist/src/api/metrics/LDFeedbackKind.js.map +1 -0
  71. package/dist/src/api/metrics/LDTokenUsage.d.ts.map +1 -0
  72. package/dist/src/api/metrics/LDTokenUsage.js.map +1 -0
  73. package/dist/src/api/metrics/OpenAiUsage.d.ts.map +1 -0
  74. package/dist/src/api/metrics/OpenAiUsage.js.map +1 -0
  75. package/dist/src/api/metrics/VercelAISDKTokenUsage.d.ts.map +1 -0
  76. package/dist/src/api/metrics/VercelAISDKTokenUsage.js.map +1 -0
  77. package/dist/src/api/metrics/index.d.ts.map +1 -0
  78. package/dist/src/api/metrics/index.js.map +1 -0
  79. package/dist/{api → src/api}/providers/AIProvider.d.ts +20 -3
  80. package/dist/src/api/providers/AIProvider.d.ts.map +1 -0
  81. package/dist/src/api/providers/AIProvider.js +88 -0
  82. package/dist/src/api/providers/AIProvider.js.map +1 -0
  83. package/dist/{api → src/api}/providers/AIProviderFactory.d.ts +2 -2
  84. package/dist/src/api/providers/AIProviderFactory.d.ts.map +1 -0
  85. package/dist/src/api/providers/AIProviderFactory.js.map +1 -0
  86. package/dist/src/api/providers/index.d.ts.map +1 -0
  87. package/dist/src/api/providers/index.js.map +1 -0
  88. package/dist/src/index.d.ts.map +1 -0
  89. package/dist/src/index.js.map +1 -0
  90. package/docs/assets/search.js +1 -1
  91. package/docs/classes/AIProvider.html +55 -20
  92. package/docs/classes/AIProviderFactory.html +27 -17
  93. package/docs/classes/Judge.html +322 -0
  94. package/docs/classes/TrackedChat.html +97 -29
  95. package/docs/enums/LDFeedbackKind.html +22 -12
  96. package/docs/functions/createBedrockTokenUsage.html +20 -10
  97. package/docs/functions/createOpenAiUsage.html +20 -10
  98. package/docs/functions/createVercelAISDKTokenUsage.html +20 -10
  99. package/docs/functions/initAi.html +20 -10
  100. package/docs/index.html +36 -16
  101. package/docs/interfaces/ChatResponse.html +35 -14
  102. package/docs/interfaces/EvalScore.html +119 -0
  103. package/docs/interfaces/JudgeResponse.html +129 -0
  104. package/docs/interfaces/LDAIAgentConfig.html +81 -33
  105. package/docs/interfaces/{LDAIAgent.html → LDAIAgentConfigDefault.html} +51 -41
  106. package/docs/interfaces/LDAIAgentRequestConfig.html +129 -0
  107. package/docs/interfaces/LDAIClient.html +234 -40
  108. package/docs/interfaces/{VercelAISDKConfig.html → LDAICompletionConfig.html} +86 -86
  109. package/docs/interfaces/LDAICompletionConfigDefault.html +155 -0
  110. package/docs/interfaces/LDAIConfig.html +45 -75
  111. package/docs/interfaces/LDAIConfigDefault.html +133 -0
  112. package/docs/interfaces/LDAIConfigTracker.html +140 -59
  113. package/docs/interfaces/LDAIJudgeConfig.html +167 -0
  114. package/docs/interfaces/LDAIJudgeConfigDefault.html +155 -0
  115. package/docs/interfaces/LDAIMetrics.html +22 -12
  116. package/docs/interfaces/LDJudge.html +119 -0
  117. package/docs/interfaces/{VercelAISDKMapOptions.html → LDJudgeConfiguration.html} +36 -19
  118. package/docs/interfaces/LDLogger.html +19 -9
  119. package/docs/interfaces/LDMessage.html +22 -12
  120. package/docs/interfaces/LDModelConfig.html +23 -13
  121. package/docs/interfaces/LDProviderConfig.html +21 -11
  122. package/docs/interfaces/LDTokenUsage.html +23 -13
  123. package/docs/interfaces/StructuredResponse.html +129 -0
  124. package/docs/types/{VercelAISDKProvider.html → LDAIConfigDefaultKind.html} +26 -31
  125. package/docs/types/{LDAIAgentDefaults.html → LDAIConfigKind.html} +24 -14
  126. package/docs/types/{LDAIDefaults.html → LDAIConfigMode.html} +24 -24
  127. package/docs/types/SupportedAIProvider.html +20 -10
  128. package/docs/variables/SUPPORTED_AI_PROVIDERS.html +20 -10
  129. package/package.json +3 -3
  130. package/src/LDAIClientImpl.ts +222 -176
  131. package/src/LDAIConfigTrackerImpl.ts +73 -54
  132. package/src/api/LDAIClient.ts +166 -33
  133. package/src/api/chat/TrackedChat.ts +64 -5
  134. package/src/api/chat/types.ts +8 -1
  135. package/src/api/config/LDAIConfigTracker.ts +46 -27
  136. package/src/api/config/LDAIConfigUtils.ts +201 -0
  137. package/src/api/config/index.ts +2 -2
  138. package/src/api/config/types.ts +256 -0
  139. package/src/api/index.ts +1 -1
  140. package/src/api/judge/EvaluationSchemaBuilder.ts +54 -0
  141. package/src/api/judge/Judge.ts +216 -0
  142. package/src/api/judge/index.ts +2 -0
  143. package/src/api/judge/types.ts +39 -0
  144. package/src/api/providers/AIProvider.ts +54 -3
  145. package/src/api/providers/AIProviderFactory.ts +4 -4
  146. package/tsconfig.json +3 -3
  147. package/tsconfig.ref.json +1 -1
  148. package/__tests__/LDAIConfigMapper.test.ts +0 -159
  149. package/dist/LDAIClientImpl.d.ts +0 -23
  150. package/dist/LDAIClientImpl.d.ts.map +0 -1
  151. package/dist/LDAIClientImpl.js +0 -128
  152. package/dist/LDAIClientImpl.js.map +0 -1
  153. package/dist/LDAIConfigMapper.d.ts +0 -10
  154. package/dist/LDAIConfigMapper.d.ts.map +0 -1
  155. package/dist/LDAIConfigMapper.js +0 -55
  156. package/dist/LDAIConfigMapper.js.map +0 -1
  157. package/dist/LDAIConfigTrackerImpl.d.ts.map +0 -1
  158. package/dist/LDAIConfigTrackerImpl.js.map +0 -1
  159. package/dist/LDClientMin.d.ts.map +0 -1
  160. package/dist/api/LDAIClient.d.ts +0 -169
  161. package/dist/api/LDAIClient.d.ts.map +0 -1
  162. package/dist/api/agents/LDAIAgent.d.ts +0 -32
  163. package/dist/api/agents/LDAIAgent.d.ts.map +0 -1
  164. package/dist/api/agents/LDAIAgent.js.map +0 -1
  165. package/dist/api/agents/index.d.ts +0 -2
  166. package/dist/api/agents/index.d.ts.map +0 -1
  167. package/dist/api/agents/index.js.map +0 -1
  168. package/dist/api/chat/TrackedChat.d.ts.map +0 -1
  169. package/dist/api/chat/TrackedChat.js.map +0 -1
  170. package/dist/api/chat/index.d.ts.map +0 -1
  171. package/dist/api/chat/index.js.map +0 -1
  172. package/dist/api/chat/types.d.ts +0 -16
  173. package/dist/api/chat/types.d.ts.map +0 -1
  174. package/dist/api/config/LDAIConfig.d.ts +0 -92
  175. package/dist/api/config/LDAIConfig.d.ts.map +0 -1
  176. package/dist/api/config/LDAIConfig.js.map +0 -1
  177. package/dist/api/config/LDAIConfigTracker.d.ts.map +0 -1
  178. package/dist/api/config/LDAIConfigTracker.js.map +0 -1
  179. package/dist/api/config/VercelAISDK.d.ts +0 -19
  180. package/dist/api/config/VercelAISDK.d.ts.map +0 -1
  181. package/dist/api/config/VercelAISDK.js +0 -3
  182. package/dist/api/config/VercelAISDK.js.map +0 -1
  183. package/dist/api/config/index.d.ts +0 -4
  184. package/dist/api/config/index.d.ts.map +0 -1
  185. package/dist/api/config/index.js +0 -19
  186. package/dist/api/config/index.js.map +0 -1
  187. package/dist/api/index.d.ts.map +0 -1
  188. package/dist/api/index.js.map +0 -1
  189. package/dist/api/metrics/BedrockTokenUsage.d.ts.map +0 -1
  190. package/dist/api/metrics/BedrockTokenUsage.js.map +0 -1
  191. package/dist/api/metrics/LDAIMetrics.d.ts.map +0 -1
  192. package/dist/api/metrics/LDAIMetrics.js.map +0 -1
  193. package/dist/api/metrics/LDFeedbackKind.d.ts.map +0 -1
  194. package/dist/api/metrics/LDFeedbackKind.js.map +0 -1
  195. package/dist/api/metrics/LDTokenUsage.d.ts.map +0 -1
  196. package/dist/api/metrics/LDTokenUsage.js.map +0 -1
  197. package/dist/api/metrics/OpenAiUsage.d.ts.map +0 -1
  198. package/dist/api/metrics/OpenAiUsage.js.map +0 -1
  199. package/dist/api/metrics/VercelAISDKTokenUsage.d.ts.map +0 -1
  200. package/dist/api/metrics/VercelAISDKTokenUsage.js.map +0 -1
  201. package/dist/api/metrics/index.d.ts.map +0 -1
  202. package/dist/api/metrics/index.js.map +0 -1
  203. package/dist/api/providers/AIProvider.d.ts.map +0 -1
  204. package/dist/api/providers/AIProvider.js +0 -31
  205. package/dist/api/providers/AIProvider.js.map +0 -1
  206. package/dist/api/providers/AIProviderFactory.d.ts.map +0 -1
  207. package/dist/api/providers/AIProviderFactory.js.map +0 -1
  208. package/dist/api/providers/index.d.ts.map +0 -1
  209. package/dist/api/providers/index.js.map +0 -1
  210. package/dist/index.d.ts.map +0 -1
  211. package/dist/index.js.map +0 -1
  212. package/src/LDAIConfigMapper.ts +0 -65
  213. package/src/api/agents/LDAIAgent.ts +0 -36
  214. package/src/api/agents/index.ts +0 -1
  215. package/src/api/config/LDAIConfig.ts +0 -101
  216. package/src/api/config/VercelAISDK.ts +0 -21
  217. /package/dist/{LDClientMin.d.ts → src/LDClientMin.d.ts} +0 -0
  218. /package/dist/{LDClientMin.js → src/LDClientMin.js} +0 -0
  219. /package/dist/{api → src/api}/LDAIClient.js +0 -0
  220. /package/dist/{api → src/api}/chat/index.d.ts +0 -0
  221. /package/dist/{api → src/api}/chat/index.js +0 -0
  222. /package/dist/{api → src/api}/chat/types.js +0 -0
  223. /package/dist/{api → src/api}/config/LDAIConfigTracker.js +0 -0
  224. /package/dist/{api → src/api}/metrics/BedrockTokenUsage.d.ts +0 -0
  225. /package/dist/{api → src/api}/metrics/BedrockTokenUsage.js +0 -0
  226. /package/dist/{api → src/api}/metrics/LDAIMetrics.d.ts +0 -0
  227. /package/dist/{api → src/api}/metrics/LDAIMetrics.js +0 -0
  228. /package/dist/{api → src/api}/metrics/LDFeedbackKind.d.ts +0 -0
  229. /package/dist/{api → src/api}/metrics/LDFeedbackKind.js +0 -0
  230. /package/dist/{api → src/api}/metrics/LDTokenUsage.d.ts +0 -0
  231. /package/dist/{api → src/api}/metrics/LDTokenUsage.js +0 -0
  232. /package/dist/{api → src/api}/metrics/OpenAiUsage.d.ts +0 -0
  233. /package/dist/{api → src/api}/metrics/OpenAiUsage.js +0 -0
  234. /package/dist/{api → src/api}/metrics/VercelAISDKTokenUsage.d.ts +0 -0
  235. /package/dist/{api → src/api}/metrics/VercelAISDKTokenUsage.js +0 -0
  236. /package/dist/{api → src/api}/metrics/index.d.ts +0 -0
  237. /package/dist/{api → src/api}/metrics/index.js +0 -0
  238. /package/dist/{api → src/api}/providers/AIProviderFactory.js +0 -0
  239. /package/dist/{api → src/api}/providers/index.d.ts +0 -0
  240. /package/dist/{api → src/api}/providers/index.js +0 -0
  241. /package/dist/{index.d.ts → src/index.d.ts} +0 -0
  242. /package/dist/{index.js → src/index.js} +0 -0
@@ -1,5 +1,6 @@
1
1
  import { LDContext } from '@launchdarkly/js-server-sdk-common';
2
2
 
3
+ import { name as aiSdkName, version as aiSdkVersion } from '../package.json';
3
4
  import { LDFeedbackKind } from '../src/api/metrics';
4
5
  import { LDAIConfigTrackerImpl } from '../src/LDAIConfigTrackerImpl';
5
6
  import { LDClientMin } from '../src/LDClientMin';
@@ -18,6 +19,16 @@ const version = 1;
18
19
  const modelName = 'test-model';
19
20
  const providerName = 'test-provider';
20
21
 
22
+ const getExpectedTrackData = () => ({
23
+ configKey,
24
+ variationKey,
25
+ version,
26
+ modelName,
27
+ providerName,
28
+ aiSdkName,
29
+ aiSdkVersion,
30
+ });
31
+
21
32
  beforeEach(() => {
22
33
  jest.clearAllMocks();
23
34
  });
@@ -37,7 +48,7 @@ it('tracks duration', () => {
37
48
  expect(mockTrack).toHaveBeenCalledWith(
38
49
  '$ld:ai:duration:total',
39
50
  testContext,
40
- { configKey, variationKey, version, modelName, providerName },
51
+ getExpectedTrackData(),
41
52
  1000,
42
53
  );
43
54
  });
@@ -60,7 +71,7 @@ it('tracks duration of async function', async () => {
60
71
  expect(mockTrack).toHaveBeenCalledWith(
61
72
  '$ld:ai:duration:total',
62
73
  testContext,
63
- { configKey, variationKey, version, modelName, providerName },
74
+ getExpectedTrackData(),
64
75
  1000,
65
76
  );
66
77
  });
@@ -80,7 +91,7 @@ it('tracks time to first token', () => {
80
91
  expect(mockTrack).toHaveBeenCalledWith(
81
92
  '$ld:ai:tokens:ttf',
82
93
  testContext,
83
- { configKey, variationKey, version, modelName, providerName },
94
+ getExpectedTrackData(),
84
95
  1000,
85
96
  );
86
97
  });
@@ -100,7 +111,7 @@ it('tracks positive feedback', () => {
100
111
  expect(mockTrack).toHaveBeenCalledWith(
101
112
  '$ld:ai:feedback:user:positive',
102
113
  testContext,
103
- { configKey, variationKey, version, modelName, providerName },
114
+ getExpectedTrackData(),
104
115
  1,
105
116
  );
106
117
  });
@@ -120,7 +131,7 @@ it('tracks negative feedback', () => {
120
131
  expect(mockTrack).toHaveBeenCalledWith(
121
132
  '$ld:ai:feedback:user:negative',
122
133
  testContext,
123
- { configKey, variationKey, version, modelName, providerName },
134
+ getExpectedTrackData(),
124
135
  1,
125
136
  );
126
137
  });
@@ -140,7 +151,7 @@ it('tracks success', () => {
140
151
  expect(mockTrack).toHaveBeenCalledWith(
141
152
  '$ld:ai:generation:success',
142
153
  testContext,
143
- { configKey, variationKey, version, modelName, providerName },
154
+ getExpectedTrackData(),
144
155
  1,
145
156
  );
146
157
  });
@@ -172,14 +183,14 @@ it('tracks OpenAI usage', async () => {
172
183
  expect(mockTrack).toHaveBeenCalledWith(
173
184
  '$ld:ai:duration:total',
174
185
  testContext,
175
- { configKey, variationKey, version, modelName, providerName },
186
+ getExpectedTrackData(),
176
187
  1000,
177
188
  );
178
189
 
179
190
  expect(mockTrack).toHaveBeenCalledWith(
180
191
  '$ld:ai:generation:success',
181
192
  testContext,
182
- { configKey, variationKey, version, modelName, providerName },
193
+ getExpectedTrackData(),
183
194
  1,
184
195
  );
185
196
 
@@ -193,21 +204,21 @@ it('tracks OpenAI usage', async () => {
193
204
  expect(mockTrack).toHaveBeenCalledWith(
194
205
  '$ld:ai:tokens:total',
195
206
  testContext,
196
- { configKey, variationKey, version, modelName, providerName },
207
+ getExpectedTrackData(),
197
208
  TOTAL_TOKENS,
198
209
  );
199
210
 
200
211
  expect(mockTrack).toHaveBeenCalledWith(
201
212
  '$ld:ai:tokens:input',
202
213
  testContext,
203
- { configKey, variationKey, version, modelName, providerName },
214
+ getExpectedTrackData(),
204
215
  PROMPT_TOKENS,
205
216
  );
206
217
 
207
218
  expect(mockTrack).toHaveBeenCalledWith(
208
219
  '$ld:ai:tokens:output',
209
220
  testContext,
210
- { configKey, variationKey, version, modelName, providerName },
221
+ getExpectedTrackData(),
211
222
  COMPLETION_TOKENS,
212
223
  );
213
224
  });
@@ -234,14 +245,14 @@ it('tracks error when OpenAI metrics function throws', async () => {
234
245
  expect(mockTrack).toHaveBeenCalledWith(
235
246
  '$ld:ai:duration:total',
236
247
  testContext,
237
- { configKey, variationKey, version, modelName, providerName },
248
+ getExpectedTrackData(),
238
249
  1000,
239
250
  );
240
251
 
241
252
  expect(mockTrack).toHaveBeenCalledWith(
242
253
  '$ld:ai:generation:error',
243
254
  testContext,
244
- { configKey, variationKey, version, modelName, providerName },
255
+ getExpectedTrackData(),
245
256
  1,
246
257
  );
247
258
 
@@ -283,7 +294,7 @@ it('tracks Bedrock conversation with successful response', () => {
283
294
  expect(mockTrack).toHaveBeenCalledWith(
284
295
  '$ld:ai:generation:success',
285
296
  testContext,
286
- { configKey, variationKey, version, modelName, providerName },
297
+ getExpectedTrackData(),
287
298
  1,
288
299
  );
289
300
 
@@ -297,28 +308,28 @@ it('tracks Bedrock conversation with successful response', () => {
297
308
  expect(mockTrack).toHaveBeenCalledWith(
298
309
  '$ld:ai:duration:total',
299
310
  testContext,
300
- { configKey, variationKey, version, modelName, providerName },
311
+ getExpectedTrackData(),
301
312
  500,
302
313
  );
303
314
 
304
315
  expect(mockTrack).toHaveBeenCalledWith(
305
316
  '$ld:ai:tokens:total',
306
317
  testContext,
307
- { configKey, variationKey, version, modelName, providerName },
318
+ getExpectedTrackData(),
308
319
  TOTAL_TOKENS,
309
320
  );
310
321
 
311
322
  expect(mockTrack).toHaveBeenCalledWith(
312
323
  '$ld:ai:tokens:input',
313
324
  testContext,
314
- { configKey, variationKey, version, modelName, providerName },
325
+ getExpectedTrackData(),
315
326
  PROMPT_TOKENS,
316
327
  );
317
328
 
318
329
  expect(mockTrack).toHaveBeenCalledWith(
319
330
  '$ld:ai:tokens:output',
320
331
  testContext,
321
- { configKey, variationKey, version, modelName, providerName },
332
+ getExpectedTrackData(),
322
333
  COMPLETION_TOKENS,
323
334
  );
324
335
  });
@@ -345,7 +356,7 @@ it('tracks Bedrock conversation with error response', () => {
345
356
  expect(mockTrack).toHaveBeenCalledWith(
346
357
  '$ld:ai:generation:error',
347
358
  testContext,
348
- { configKey, variationKey, version, modelName, providerName },
359
+ getExpectedTrackData(),
349
360
  1,
350
361
  );
351
362
 
@@ -385,14 +396,14 @@ describe('Vercel AI SDK generateText', () => {
385
396
  expect(mockTrack).toHaveBeenCalledWith(
386
397
  '$ld:ai:duration:total',
387
398
  testContext,
388
- { configKey, variationKey, version, modelName, providerName },
399
+ getExpectedTrackData(),
389
400
  1000,
390
401
  );
391
402
 
392
403
  expect(mockTrack).toHaveBeenCalledWith(
393
404
  '$ld:ai:generation:success',
394
405
  testContext,
395
- { configKey, variationKey, version, modelName, providerName },
406
+ getExpectedTrackData(),
396
407
  1,
397
408
  );
398
409
 
@@ -406,21 +417,21 @@ describe('Vercel AI SDK generateText', () => {
406
417
  expect(mockTrack).toHaveBeenCalledWith(
407
418
  '$ld:ai:tokens:total',
408
419
  testContext,
409
- { configKey, variationKey, version, modelName, providerName },
420
+ getExpectedTrackData(),
410
421
  TOTAL_TOKENS,
411
422
  );
412
423
 
413
424
  expect(mockTrack).toHaveBeenCalledWith(
414
425
  '$ld:ai:tokens:input',
415
426
  testContext,
416
- { configKey, variationKey, version, modelName, providerName },
427
+ getExpectedTrackData(),
417
428
  PROMPT_TOKENS,
418
429
  );
419
430
 
420
431
  expect(mockTrack).toHaveBeenCalledWith(
421
432
  '$ld:ai:tokens:output',
422
433
  testContext,
423
- { configKey, variationKey, version, modelName, providerName },
434
+ getExpectedTrackData(),
424
435
  COMPLETION_TOKENS,
425
436
  );
426
437
  });
@@ -447,137 +458,14 @@ describe('Vercel AI SDK generateText', () => {
447
458
  expect(mockTrack).toHaveBeenCalledWith(
448
459
  '$ld:ai:duration:total',
449
460
  testContext,
450
- { configKey, variationKey, version, modelName, providerName },
451
- 1000,
452
- );
453
-
454
- expect(mockTrack).toHaveBeenCalledWith(
455
- '$ld:ai:generation:error',
456
- testContext,
457
- { configKey, variationKey, version, modelName, providerName },
458
- 1,
459
- );
460
-
461
- expect(mockTrack).not.toHaveBeenCalledWith(
462
- expect.stringMatching(/^\$ld:ai:tokens:/),
463
- expect.anything(),
464
- expect.anything(),
465
- expect.anything(),
466
- );
467
- });
468
- });
469
-
470
- describe('Vercel AI SDK streamText', () => {
471
- it('tracks Vercel AI SDK usage', async () => {
472
- const tracker = new LDAIConfigTrackerImpl(
473
- mockLdClient,
474
- configKey,
475
- variationKey,
476
- version,
477
- modelName,
478
- providerName,
479
- testContext,
480
- );
481
- jest.spyOn(global.Date, 'now').mockReturnValueOnce(1000).mockReturnValueOnce(2000);
482
-
483
- const TOTAL_TOKENS = 100;
484
- const PROMPT_TOKENS = 49;
485
- const COMPLETION_TOKENS = 51;
486
-
487
- let resolveDone: ((value: boolean) => void) | undefined;
488
- const donePromise = new Promise<boolean>((resolve) => {
489
- resolveDone = resolve;
490
- });
491
-
492
- const finishReason = Promise.resolve('stop');
493
- jest
494
- .spyOn(finishReason, 'then')
495
- .mockImplementationOnce((fn) => finishReason.then(fn).finally(() => resolveDone?.(true)));
496
-
497
- tracker.trackVercelAISDKStreamTextMetrics(() => ({
498
- finishReason,
499
- usage: Promise.resolve({
500
- totalTokens: TOTAL_TOKENS,
501
- promptTokens: PROMPT_TOKENS,
502
- completionTokens: COMPLETION_TOKENS,
503
- }),
504
- }));
505
-
506
- await donePromise;
507
-
508
- expect(mockTrack).toHaveBeenCalledWith(
509
- '$ld:ai:duration:total',
510
- testContext,
511
- { configKey, variationKey, version, modelName, providerName },
512
- 1000,
513
- );
514
-
515
- expect(mockTrack).toHaveBeenCalledWith(
516
- '$ld:ai:generation:success',
517
- testContext,
518
- { configKey, variationKey, version, modelName, providerName },
519
- 1,
520
- );
521
-
522
- expect(mockTrack).not.toHaveBeenCalledWith(
523
- '$ld:ai:generation:error',
524
- expect.anything(),
525
- expect.anything(),
526
- expect.anything(),
527
- );
528
-
529
- expect(mockTrack).toHaveBeenCalledWith(
530
- '$ld:ai:tokens:total',
531
- testContext,
532
- { configKey, variationKey, version, modelName, providerName },
533
- TOTAL_TOKENS,
534
- );
535
-
536
- expect(mockTrack).toHaveBeenCalledWith(
537
- '$ld:ai:tokens:input',
538
- testContext,
539
- { configKey, variationKey, version, modelName, providerName },
540
- PROMPT_TOKENS,
541
- );
542
-
543
- expect(mockTrack).toHaveBeenCalledWith(
544
- '$ld:ai:tokens:output',
545
- testContext,
546
- { configKey, variationKey, version, modelName, providerName },
547
- COMPLETION_TOKENS,
548
- );
549
- });
550
-
551
- it('tracks error when Vercel AI SDK metrics function throws', async () => {
552
- const tracker = new LDAIConfigTrackerImpl(
553
- mockLdClient,
554
- configKey,
555
- variationKey,
556
- version,
557
- modelName,
558
- providerName,
559
- testContext,
560
- );
561
- jest.spyOn(global.Date, 'now').mockReturnValueOnce(1000).mockReturnValueOnce(2000);
562
-
563
- const error = new Error('Vercel AI SDK API error');
564
- expect(() =>
565
- tracker.trackVercelAISDKStreamTextMetrics(() => {
566
- throw error;
567
- }),
568
- ).toThrow(error);
569
-
570
- expect(mockTrack).toHaveBeenCalledWith(
571
- '$ld:ai:duration:total',
572
- testContext,
573
- { configKey, variationKey, version, modelName, providerName },
461
+ getExpectedTrackData(),
574
462
  1000,
575
463
  );
576
464
 
577
465
  expect(mockTrack).toHaveBeenCalledWith(
578
466
  '$ld:ai:generation:error',
579
467
  testContext,
580
- { configKey, variationKey, version, modelName, providerName },
468
+ getExpectedTrackData(),
581
469
  1,
582
470
  );
583
471
 
@@ -588,134 +476,6 @@ describe('Vercel AI SDK streamText', () => {
588
476
  expect.anything(),
589
477
  );
590
478
  });
591
-
592
- it('tracks error when Vercel AI SDK finishes because of an error', async () => {
593
- const tracker = new LDAIConfigTrackerImpl(
594
- mockLdClient,
595
- configKey,
596
- variationKey,
597
- version,
598
- modelName,
599
- providerName,
600
- testContext,
601
- );
602
- jest.spyOn(global.Date, 'now').mockReturnValueOnce(1000).mockReturnValueOnce(2000);
603
-
604
- tracker.trackVercelAISDKStreamTextMetrics(() => ({
605
- finishReason: Promise.resolve('error'),
606
- }));
607
-
608
- await new Promise(process.nextTick);
609
-
610
- expect(mockTrack).toHaveBeenCalledWith(
611
- '$ld:ai:duration:total',
612
- testContext,
613
- { configKey, variationKey, version, modelName, providerName },
614
- 1000,
615
- );
616
-
617
- expect(mockTrack).toHaveBeenCalledWith(
618
- '$ld:ai:generation:error',
619
- testContext,
620
- { configKey, variationKey, version, modelName, providerName },
621
- 1,
622
- );
623
-
624
- expect(mockTrack).not.toHaveBeenCalledWith(
625
- expect.stringMatching(/^\$ld:ai:tokens:/),
626
- expect.anything(),
627
- expect.anything(),
628
- expect.anything(),
629
- );
630
- });
631
-
632
- it('tracks error when Vercel AI SDK finishReason promise rejects', async () => {
633
- const tracker = new LDAIConfigTrackerImpl(
634
- mockLdClient,
635
- configKey,
636
- variationKey,
637
- version,
638
- modelName,
639
- providerName,
640
- testContext,
641
- );
642
- jest.spyOn(global.Date, 'now').mockReturnValueOnce(1000).mockReturnValueOnce(2000);
643
-
644
- tracker.trackVercelAISDKStreamTextMetrics(() => ({
645
- finishReason: Promise.reject(new Error('Vercel AI SDK API error')),
646
- }));
647
-
648
- await new Promise(process.nextTick);
649
-
650
- expect(mockTrack).toHaveBeenCalledWith(
651
- '$ld:ai:duration:total',
652
- testContext,
653
- { configKey, variationKey, version, modelName, providerName },
654
- 1000,
655
- );
656
-
657
- expect(mockTrack).toHaveBeenCalledWith(
658
- '$ld:ai:generation:error',
659
- testContext,
660
- { configKey, variationKey, version, modelName, providerName },
661
- 1,
662
- );
663
-
664
- expect(mockTrack).not.toHaveBeenCalledWith(
665
- expect.stringMatching(/^\$ld:ai:tokens:/),
666
- expect.anything(),
667
- expect.anything(),
668
- expect.anything(),
669
- );
670
- });
671
-
672
- it('squashes error when Vercel AI SDK usage promise rejects', async () => {
673
- const tracker = new LDAIConfigTrackerImpl(
674
- mockLdClient,
675
- configKey,
676
- variationKey,
677
- version,
678
- modelName,
679
- providerName,
680
- testContext,
681
- );
682
- jest.spyOn(global.Date, 'now').mockReturnValueOnce(1000).mockReturnValueOnce(2000);
683
-
684
- tracker.trackVercelAISDKStreamTextMetrics(() => ({
685
- finishReason: Promise.resolve('stop'),
686
- usage: Promise.reject(new Error('Vercel AI SDK API error')),
687
- }));
688
-
689
- await new Promise(process.nextTick);
690
-
691
- expect(mockTrack).toHaveBeenCalledWith(
692
- '$ld:ai:duration:total',
693
- testContext,
694
- { configKey, variationKey, version, modelName, providerName },
695
- 1000,
696
- );
697
-
698
- expect(mockTrack).toHaveBeenCalledWith(
699
- '$ld:ai:generation:success',
700
- testContext,
701
- { configKey, variationKey, version, modelName, providerName },
702
- 1,
703
- );
704
-
705
- expect(mockTrack).not.toHaveBeenCalledWith(
706
- '$ld:ai:generation:error',
707
- expect.anything(),
708
- expect.anything(),
709
- expect.anything(),
710
- );
711
-
712
- expect(mockTrack).not.toHaveBeenCalledWith(
713
- expect.stringMatching(/^\$ld:ai:tokens:/),
714
- expect.anything(),
715
- expect.anything(),
716
- expect.anything(),
717
- );
718
- });
719
479
  });
720
480
 
721
481
  it('tracks tokens', () => {
@@ -742,21 +502,21 @@ it('tracks tokens', () => {
742
502
  expect(mockTrack).toHaveBeenCalledWith(
743
503
  '$ld:ai:tokens:total',
744
504
  testContext,
745
- { configKey, variationKey, version, modelName, providerName },
505
+ getExpectedTrackData(),
746
506
  TOTAL_TOKENS,
747
507
  );
748
508
 
749
509
  expect(mockTrack).toHaveBeenCalledWith(
750
510
  '$ld:ai:tokens:input',
751
511
  testContext,
752
- { configKey, variationKey, version, modelName, providerName },
512
+ getExpectedTrackData(),
753
513
  PROMPT_TOKENS,
754
514
  );
755
515
 
756
516
  expect(mockTrack).toHaveBeenCalledWith(
757
517
  '$ld:ai:tokens:output',
758
518
  testContext,
759
- { configKey, variationKey, version, modelName, providerName },
519
+ getExpectedTrackData(),
760
520
  COMPLETION_TOKENS,
761
521
  );
762
522
  });
@@ -788,7 +548,7 @@ it('only tracks non-zero token counts', () => {
788
548
  expect(mockTrack).toHaveBeenCalledWith(
789
549
  '$ld:ai:tokens:input',
790
550
  testContext,
791
- { configKey, variationKey, version, modelName, providerName },
551
+ getExpectedTrackData(),
792
552
  50,
793
553
  );
794
554
 
@@ -874,7 +634,7 @@ it('tracks duration when async function throws', async () => {
874
634
  expect(mockTrack).toHaveBeenCalledWith(
875
635
  '$ld:ai:duration:total',
876
636
  testContext,
877
- { configKey, variationKey, version, modelName, providerName },
637
+ getExpectedTrackData(),
878
638
  1000,
879
639
  );
880
640
  });
@@ -894,7 +654,7 @@ it('tracks error', () => {
894
654
  expect(mockTrack).toHaveBeenCalledWith(
895
655
  '$ld:ai:generation:error',
896
656
  testContext,
897
- { configKey, variationKey, version, modelName, providerName },
657
+ getExpectedTrackData(),
898
658
  1,
899
659
  );
900
660
  });
@@ -930,7 +690,7 @@ describe('trackMetricsOf', () => {
930
690
  expect(mockTrack).toHaveBeenCalledWith(
931
691
  '$ld:ai:generation:success',
932
692
  testContext,
933
- { configKey, variationKey, version, modelName, providerName },
693
+ getExpectedTrackData(),
934
694
  1,
935
695
  );
936
696
 
@@ -938,19 +698,19 @@ describe('trackMetricsOf', () => {
938
698
  expect(mockTrack).toHaveBeenCalledWith(
939
699
  '$ld:ai:tokens:total',
940
700
  testContext,
941
- { configKey, variationKey, version, modelName, providerName },
701
+ getExpectedTrackData(),
942
702
  100,
943
703
  );
944
704
  expect(mockTrack).toHaveBeenCalledWith(
945
705
  '$ld:ai:tokens:input',
946
706
  testContext,
947
- { configKey, variationKey, version, modelName, providerName },
707
+ getExpectedTrackData(),
948
708
  50,
949
709
  );
950
710
  expect(mockTrack).toHaveBeenCalledWith(
951
711
  '$ld:ai:tokens:output',
952
712
  testContext,
953
- { configKey, variationKey, version, modelName, providerName },
713
+ getExpectedTrackData(),
954
714
  50,
955
715
  );
956
716
  });
@@ -980,7 +740,7 @@ describe('trackMetricsOf', () => {
980
740
  expect(mockTrack).toHaveBeenCalledWith(
981
741
  '$ld:ai:generation:error',
982
742
  testContext,
983
- { configKey, variationKey, version, modelName, providerName },
743
+ getExpectedTrackData(),
984
744
  1,
985
745
  );
986
746
  });
@@ -1006,7 +766,7 @@ describe('trackMetricsOf', () => {
1006
766
  expect(mockTrack).toHaveBeenCalledWith(
1007
767
  '$ld:ai:generation:error',
1008
768
  testContext,
1009
- { configKey, variationKey, version, modelName, providerName },
769
+ getExpectedTrackData(),
1010
770
  1,
1011
771
  );
1012
772
 
@@ -1040,7 +800,7 @@ describe('trackMetricsOf', () => {
1040
800
  expect(mockTrack).toHaveBeenCalledWith(
1041
801
  '$ld:ai:generation:success',
1042
802
  testContext,
1043
- { configKey, variationKey, version, modelName, providerName },
803
+ getExpectedTrackData(),
1044
804
  1,
1045
805
  );
1046
806
 
@@ -1,13 +1,13 @@
1
1
  import { TrackedChat } from '../src/api/chat/TrackedChat';
2
2
  import { ChatResponse } from '../src/api/chat/types';
3
- import { LDAIConfig, LDMessage } from '../src/api/config/LDAIConfig';
4
3
  import { LDAIConfigTracker } from '../src/api/config/LDAIConfigTracker';
4
+ import { LDAICompletionConfig, LDMessage } from '../src/api/config/types';
5
5
  import { AIProvider } from '../src/api/providers/AIProvider';
6
6
 
7
7
  describe('TrackedChat', () => {
8
8
  let mockProvider: jest.Mocked<AIProvider>;
9
9
  let mockTracker: jest.Mocked<LDAIConfigTracker>;
10
- let aiConfig: LDAIConfig;
10
+ let aiConfig: LDAICompletionConfig;
11
11
 
12
12
  beforeEach(() => {
13
13
  // Mock the AIProvider
@@ -38,7 +38,6 @@ describe('TrackedChat', () => {
38
38
  model: { name: 'gpt-4' },
39
39
  provider: { name: 'openai' },
40
40
  tracker: mockTracker,
41
- toVercelAISDK: jest.fn(),
42
41
  };
43
42
  });
44
43
 
@@ -136,7 +135,7 @@ describe('TrackedChat', () => {
136
135
  });
137
136
 
138
137
  it('returns empty array when no messages exist and includeConfigMessages is false', () => {
139
- const configWithoutMessages: LDAIConfig = {
138
+ const configWithoutMessages: LDAICompletionConfig = {
140
139
  ...aiConfig,
141
140
  messages: [],
142
141
  };
@@ -167,7 +166,7 @@ describe('TrackedChat', () => {
167
166
  });
168
167
 
169
168
  it('handles undefined config messages gracefully', () => {
170
- const configWithoutMessages: LDAIConfig = {
169
+ const configWithoutMessages: LDAICompletionConfig = {
171
170
  ...aiConfig,
172
171
  messages: undefined,
173
172
  };
@@ -0,0 +1,53 @@
1
+ {
2
+ "name": "@launchdarkly/server-sdk-ai",
3
+ "version": "0.14.0",
4
+ "description": "LaunchDarkly AI SDK for Server-Side JavaScript",
5
+ "homepage": "https://github.com/launchdarkly/js-core/tree/main/packages/sdk/server-ai",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "https://github.com/launchdarkly/js-core.git"
9
+ },
10
+ "main": "dist/src/index.js",
11
+ "types": "dist/src/index.d.ts",
12
+ "type": "commonjs",
13
+ "scripts": {
14
+ "build": "npx tsc",
15
+ "lint": "npx eslint . --ext .ts",
16
+ "prettier": "prettier --write '**/*.@(js|ts|tsx|json|css)' --ignore-path ../../../.prettierignore",
17
+ "lint:fix": "yarn run lint --fix",
18
+ "check": "yarn prettier && yarn lint && yarn build && yarn test",
19
+ "test": "jest"
20
+ },
21
+ "keywords": [
22
+ "launchdarkly",
23
+ "ai",
24
+ "llm"
25
+ ],
26
+ "author": "LaunchDarkly",
27
+ "license": "Apache-2.0",
28
+ "dependencies": {
29
+ "mustache": "^4.2.0"
30
+ },
31
+ "devDependencies": {
32
+ "@launchdarkly/js-server-sdk-common": "2.16.2",
33
+ "@trivago/prettier-plugin-sort-imports": "^4.1.1",
34
+ "@types/jest": "^29.5.3",
35
+ "@types/mustache": "^4.2.5",
36
+ "@typescript-eslint/eslint-plugin": "^6.20.0",
37
+ "@typescript-eslint/parser": "^6.20.0",
38
+ "eslint": "^8.45.0",
39
+ "eslint-config-airbnb-base": "^15.0.0",
40
+ "eslint-config-airbnb-typescript": "^17.1.0",
41
+ "eslint-config-prettier": "^8.8.0",
42
+ "eslint-plugin-import": "^2.27.5",
43
+ "eslint-plugin-jest": "^27.6.3",
44
+ "eslint-plugin-prettier": "^5.0.0",
45
+ "jest": "^29.6.1",
46
+ "prettier": "^3.0.0",
47
+ "ts-jest": "^29.1.1",
48
+ "typescript": "5.1.6"
49
+ },
50
+ "peerDependencies": {
51
+ "@launchdarkly/js-server-sdk-common": "2.x"
52
+ }
53
+ }