@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,7 +1,9 @@
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 { LDAIConfigTracker } from './api/config';
4
5
  import { LDAIMetricSummary } from './api/config/LDAIConfigTracker';
6
+ import { EvalScore } from './api/judge/types';
5
7
  import {
6
8
  createBedrockTokenUsage,
7
9
  createOpenAiUsage,
@@ -25,12 +27,14 @@ export class LDAIConfigTrackerImpl implements LDAIConfigTracker {
25
27
  private _context: LDContext,
26
28
  ) {}
27
29
 
28
- private _getTrackData(): {
30
+ getTrackData(): {
29
31
  variationKey: string;
30
32
  configKey: string;
31
33
  version: number;
32
34
  modelName: string;
33
35
  providerName: string;
36
+ aiSdkName: string;
37
+ aiSdkVersion: string;
34
38
  } {
35
39
  return {
36
40
  variationKey: this._variationKey,
@@ -38,12 +42,14 @@ export class LDAIConfigTrackerImpl implements LDAIConfigTracker {
38
42
  version: this._version,
39
43
  modelName: this._modelName,
40
44
  providerName: this._providerName,
45
+ aiSdkName,
46
+ aiSdkVersion,
41
47
  };
42
48
  }
43
49
 
44
50
  trackDuration(duration: number): void {
45
51
  this._trackedMetrics.durationMs = duration;
46
- this._ldClient.track('$ld:ai:duration:total', this._context, this._getTrackData(), duration);
52
+ this._ldClient.track('$ld:ai:duration:total', this._context, this.getTrackData(), duration);
47
53
  }
48
54
 
49
55
  async trackDurationOf<TRes>(func: () => Promise<TRes>): Promise<TRes> {
@@ -64,28 +70,35 @@ export class LDAIConfigTrackerImpl implements LDAIConfigTracker {
64
70
  this._ldClient.track(
65
71
  '$ld:ai:tokens:ttf',
66
72
  this._context,
67
- this._getTrackData(),
73
+ this.getTrackData(),
68
74
  timeToFirstTokenMs,
69
75
  );
70
76
  }
71
77
 
78
+ trackEvalScores(scores: Record<string, EvalScore>) {
79
+ // Track each evaluation score individually
80
+ Object.entries(scores).forEach(([metricKey, evalScore]) => {
81
+ this._ldClient.track(metricKey, this._context, this.getTrackData(), evalScore.score);
82
+ });
83
+ }
84
+
72
85
  trackFeedback(feedback: { kind: LDFeedbackKind }): void {
73
86
  this._trackedMetrics.feedback = feedback;
74
87
  if (feedback.kind === LDFeedbackKind.Positive) {
75
- this._ldClient.track('$ld:ai:feedback:user:positive', this._context, this._getTrackData(), 1);
88
+ this._ldClient.track('$ld:ai:feedback:user:positive', this._context, this.getTrackData(), 1);
76
89
  } else if (feedback.kind === LDFeedbackKind.Negative) {
77
- this._ldClient.track('$ld:ai:feedback:user:negative', this._context, this._getTrackData(), 1);
90
+ this._ldClient.track('$ld:ai:feedback:user:negative', this._context, this.getTrackData(), 1);
78
91
  }
79
92
  }
80
93
 
81
94
  trackSuccess(): void {
82
95
  this._trackedMetrics.success = true;
83
- this._ldClient.track('$ld:ai:generation:success', this._context, this._getTrackData(), 1);
96
+ this._ldClient.track('$ld:ai:generation:success', this._context, this.getTrackData(), 1);
84
97
  }
85
98
 
86
99
  trackError(): void {
87
100
  this._trackedMetrics.success = false;
88
- this._ldClient.track('$ld:ai:generation:error', this._context, this._getTrackData(), 1);
101
+ this._ldClient.track('$ld:ai:generation:error', this._context, this.getTrackData(), 1);
89
102
  }
90
103
 
91
104
  async trackMetricsOf<TRes>(
@@ -119,6 +132,58 @@ export class LDAIConfigTrackerImpl implements LDAIConfigTracker {
119
132
  return result;
120
133
  }
121
134
 
135
+ trackStreamMetricsOf<TStream>(
136
+ streamCreator: () => TStream,
137
+ metricsExtractor: (stream: TStream) => Promise<LDAIMetrics>,
138
+ ): TStream {
139
+ const startTime = Date.now();
140
+
141
+ try {
142
+ // Create the stream synchronously
143
+ const stream = streamCreator();
144
+
145
+ // Start background metrics tracking (fire and forget)
146
+ this._trackStreamMetricsInBackground(stream, metricsExtractor, startTime);
147
+
148
+ // Return stream immediately for consumption
149
+ return stream;
150
+ } catch (error) {
151
+ // Track error if stream creation fails
152
+ this.trackDuration(Date.now() - startTime);
153
+ this.trackError();
154
+ throw error;
155
+ }
156
+ }
157
+
158
+ private async _trackStreamMetricsInBackground<TStream>(
159
+ stream: TStream,
160
+ metricsExtractor: (stream: TStream) => Promise<LDAIMetrics>,
161
+ startTime: number,
162
+ ): Promise<void> {
163
+ try {
164
+ // Wait for metrics to be available
165
+ const metrics = await metricsExtractor(stream);
166
+
167
+ // Track success/error based on metrics
168
+ if (metrics.success) {
169
+ this.trackSuccess();
170
+ } else {
171
+ this.trackError();
172
+ }
173
+
174
+ // Track token usage if available
175
+ if (metrics.usage) {
176
+ this.trackTokens(metrics.usage);
177
+ }
178
+ } catch (error) {
179
+ // If metrics extraction fails, track error
180
+ this.trackError();
181
+ } finally {
182
+ // Track duration regardless of success/error
183
+ this.trackDuration(Date.now() - startTime);
184
+ }
185
+ }
186
+
122
187
  async trackOpenAIMetrics<
123
188
  TRes extends {
124
189
  usage?: {
@@ -190,55 +255,9 @@ export class LDAIConfigTrackerImpl implements LDAIConfigTracker {
190
255
  }
191
256
  }
192
257
 
193
- trackVercelAISDKStreamTextMetrics<
194
- TRes extends {
195
- finishReason?: Promise<string>;
196
- usage?: Promise<{
197
- totalTokens?: number;
198
- inputTokens?: number;
199
- promptTokens?: number;
200
- outputTokens?: number;
201
- completionTokens?: number;
202
- }>;
203
- },
204
- >(func: () => TRes): TRes {
205
- const startTime = Date.now();
206
- try {
207
- const result = func();
208
- result.finishReason
209
- ?.then(async (finishReason) => {
210
- const endTime = Date.now();
211
- this.trackDuration(endTime - startTime);
212
- if (finishReason === 'error') {
213
- this.trackError();
214
- } else {
215
- this.trackSuccess();
216
- if (result.usage) {
217
- try {
218
- this.trackTokens(createVercelAISDKTokenUsage(await result.usage));
219
- } catch {
220
- // Intentionally squashing this error
221
- }
222
- }
223
- }
224
- })
225
- .catch(() => {
226
- const endTime = Date.now();
227
- this.trackDuration(endTime - startTime);
228
- this.trackError();
229
- });
230
- return result;
231
- } catch (err) {
232
- const endTime = Date.now();
233
- this.trackDuration(endTime - startTime);
234
- this.trackError();
235
- throw err;
236
- }
237
- }
238
-
239
258
  trackTokens(tokens: LDTokenUsage): void {
240
259
  this._trackedMetrics.tokens = tokens;
241
- const trackData = this._getTrackData();
260
+ const trackData = this.getTrackData();
242
261
  if (tokens.total > 0) {
243
262
  this._ldClient.track('$ld:ai:tokens:total', this._context, trackData, tokens.total);
244
263
  }
@@ -1,8 +1,16 @@
1
1
  import { LDContext } from '@launchdarkly/js-server-sdk-common';
2
2
 
3
- import { LDAIAgent, LDAIAgentConfig, LDAIAgentDefaults } from './agents';
4
3
  import { TrackedChat } from './chat';
5
- import { LDAIConfig, LDAIDefaults } from './config/LDAIConfig';
4
+ import {
5
+ LDAIAgentConfig,
6
+ LDAIAgentConfigDefault,
7
+ LDAIAgentRequestConfig,
8
+ LDAICompletionConfig,
9
+ LDAICompletionConfigDefault,
10
+ LDAIJudgeConfig,
11
+ LDAIJudgeConfigDefault,
12
+ } from './config';
13
+ import { Judge } from './judge/Judge';
6
14
  import { SupportedAIProvider } from './providers';
7
15
 
8
16
  /**
@@ -10,7 +18,7 @@ import { SupportedAIProvider } from './providers';
10
18
  */
11
19
  export interface LDAIClient {
12
20
  /**
13
- * Retrieves and processes an AI Config based on the provided key, LaunchDarkly context,
21
+ * Retrieves and processes a completion AI Config based on the provided key, LaunchDarkly context,
14
22
  * and variables. This includes the model configuration and the customized messages.
15
23
  *
16
24
  * @param key The key of the AI Config.
@@ -34,9 +42,11 @@ export interface LDAIClient {
34
42
  * const variables = {username: 'john'};
35
43
  * const defaultValue = {
36
44
  * enabled: false,
45
+ * model: { name: 'gpt-4' },
46
+ * provider: { name: 'openai' },
37
47
  * };
38
48
  *
39
- * const result = config(key, context, defaultValue, variables);
49
+ * const result = completionConfig(key, context, defaultValue, variables);
40
50
  * // Output:
41
51
  * {
42
52
  * enabled: true,
@@ -60,12 +70,22 @@ export interface LDAIClient {
60
70
  * }
61
71
  * ```
62
72
  */
73
+ completionConfig(
74
+ key: string,
75
+ context: LDContext,
76
+ defaultValue: LDAICompletionConfigDefault,
77
+ variables?: Record<string, unknown>,
78
+ ): Promise<LDAICompletionConfig>;
79
+
80
+ /**
81
+ * @deprecated Use `completionConfig` instead. This method will be removed in a future version.
82
+ */
63
83
  config(
64
84
  key: string,
65
85
  context: LDContext,
66
- defaultValue: LDAIDefaults,
86
+ defaultValue: LDAICompletionConfigDefault,
67
87
  variables?: Record<string, unknown>,
68
- ): Promise<LDAIConfig>;
88
+ ): Promise<LDAICompletionConfig>;
69
89
 
70
90
  /**
71
91
  * Retrieves and processes a single AI Config agent based on the provided key, LaunchDarkly context,
@@ -89,21 +109,67 @@ export interface LDAIClient {
89
109
  * const key = "research_agent";
90
110
  * const context = {...};
91
111
  * const variables = { topic: 'climate change' };
92
- * const agent = await client.agent(key, context, {
112
+ * const agentConfig = await client.agentConfig(key, context, {
93
113
  * enabled: true,
114
+ * model: { name: 'gpt-4' },
115
+ * provider: { name: 'openai' },
94
116
  * instructions: 'You are a research assistant.',
95
117
  * }, variables);
96
118
  *
97
- * const researchResult = agent.instructions; // Interpolated instructions
98
- * agent.tracker.trackSuccess();
119
+ * const researchResult = agentConfig.instructions; // Interpolated instructions
120
+ * agentConfig.tracker.trackSuccess();
99
121
  * ```
100
122
  */
123
+ agentConfig(
124
+ key: string,
125
+ context: LDContext,
126
+ defaultValue: LDAIAgentConfigDefault,
127
+ variables?: Record<string, unknown>,
128
+ ): Promise<LDAIAgentConfig>;
129
+
130
+ /**
131
+ * @deprecated Use `agentConfig` instead. This method will be removed in a future version.
132
+ */
101
133
  agent(
102
134
  key: string,
103
135
  context: LDContext,
104
- defaultValue: LDAIAgentDefaults,
136
+ defaultValue: LDAIAgentConfigDefault,
137
+ variables?: Record<string, unknown>,
138
+ ): Promise<LDAIAgentConfig>;
139
+
140
+ /**
141
+ * Retrieves and processes a Judge AI Config based on the provided key, LaunchDarkly context,
142
+ * and variables. This includes the model configuration and the customized messages for evaluation.
143
+ *
144
+ * @param key The key of the Judge AI Config.
145
+ * @param context The LaunchDarkly context object that contains relevant information about the
146
+ * current environment, user, or session. This context may influence how the configuration is
147
+ * processed or personalized.
148
+ * @param defaultValue A fallback value containing model configuration and messages. This will
149
+ * be used if the configuration is not available from LaunchDarkly.
150
+ * @param variables Optional variables for template interpolation in messages and instructions.
151
+ * @returns A promise that resolves to a tracked judge configuration.
152
+ *
153
+ * @example
154
+ * ```typescript
155
+ * const judgeConf = await client.judgeConfig(key, context, {
156
+ * enabled: true,
157
+ * model: { name: 'gpt-4' },
158
+ * provider: { name: 'openai' },
159
+ * evaluationMetricKeys: ['$ld:ai:judge:relevance'],
160
+ * messages: [{ role: 'system', content: 'You are a relevance judge.' }]
161
+ * }, variables);
162
+ *
163
+ * const config = judgeConf.config; // Interpolated configuration
164
+ * judgeConf.tracker.trackSuccess();
165
+ * ```
166
+ */
167
+ judgeConfig(
168
+ key: string,
169
+ context: LDContext,
170
+ defaultValue: LDAIJudgeConfigDefault,
105
171
  variables?: Record<string, unknown>,
106
- ): Promise<LDAIAgent>;
172
+ ): Promise<LDAIJudgeConfig>;
107
173
 
108
174
  /**
109
175
  * Retrieves and processes multiple AI Config agents based on the provided agent configurations
@@ -122,38 +188,59 @@ export interface LDAIClient {
122
188
  *
123
189
  * @example
124
190
  * ```
125
- * const agentConfigs = [
191
+ * const agentConfigsList = [
126
192
  * {
127
193
  * key: 'research_agent',
128
- * defaultValue: { enabled: true, instructions: 'You are a research assistant.' },
194
+ * defaultValue: {
195
+ * enabled: true,
196
+ * model: { name: 'gpt-4' },
197
+ * provider: { name: 'openai' },
198
+ * instructions: 'You are a research assistant.'
199
+ * },
129
200
  * variables: { topic: 'climate change' }
130
201
  * },
131
202
  * {
132
203
  * key: 'writing_agent',
133
- * defaultValue: { enabled: true, instructions: 'You are a writing assistant.' },
204
+ * defaultValue: {
205
+ * enabled: true,
206
+ * model: { name: 'gpt-4' },
207
+ * provider: { name: 'openai' },
208
+ * instructions: 'You are a writing assistant.'
209
+ * },
134
210
  * variables: { style: 'academic' }
135
211
  * }
136
212
  * ] as const;
137
213
  * const context = {...};
138
214
  *
139
- * const agents = await client.agents(agentConfigs, context);
140
- * const researchResult = agents["research_agent"].instructions; // Interpolated instructions
141
- * agents["research_agent"].tracker.trackSuccess();
215
+ * const configs = await client.agentConfigs(agentConfigsList, context);
216
+ * const researchResult = configs["research_agent"].instructions; // Interpolated instructions
217
+ * configs["research_agent"].tracker.trackSuccess();
142
218
  * ```
143
219
  */
144
- agents<const T extends readonly LDAIAgentConfig[]>(
220
+ agentConfigs<const T extends readonly LDAIAgentRequestConfig[]>(
221
+ agentConfigs: T,
222
+ context: LDContext,
223
+ ): Promise<Record<T[number]['key'], LDAIAgentConfig>>;
224
+
225
+ /**
226
+ * @deprecated Use `agentConfigs` instead. This method will be removed in a future version.
227
+ */
228
+ agents<const T extends readonly LDAIAgentRequestConfig[]>(
145
229
  agentConfigs: T,
146
230
  context: LDContext,
147
- ): Promise<Record<T[number]['key'], LDAIAgent>>;
231
+ ): Promise<Record<T[number]['key'], LDAIAgentConfig>>;
148
232
 
149
233
  /**
150
- * Initializes and returns a new TrackedChat instance for chat interactions.
234
+ * Returns a TrackedChat instance for chat interactions.
151
235
  * This method serves as the primary entry point for creating TrackedChat instances from configuration.
152
236
  *
153
237
  * @param key The key identifying the AI chat configuration to use.
154
238
  * @param context The standard LDContext used when evaluating flags.
155
239
  * @param defaultValue A default value representing a standard AI chat config result.
156
240
  * @param variables Dictionary of values for instruction interpolation.
241
+ * The variables will also be used for judge evaluation. For the judge only, the variables
242
+ * `message_history` and `response_to_evaluate` are reserved and will be ignored.
243
+ * @param defaultAiProvider Optional default AI provider to use.
157
244
  * @returns A promise that resolves to the TrackedChat instance, or null if the configuration is disabled.
158
245
  *
159
246
  * @example
@@ -161,32 +248,78 @@ export interface LDAIClient {
161
248
  * const key = "customer_support_chat";
162
249
  * const context = {...};
163
250
  * const defaultValue = {
164
- * config: {
165
- * enabled: false,
166
- * model: { name: "gpt-4" },
167
- * messages: [
168
- * { role: "system", content: "You are a helpful customer support agent." }
169
- * ]
170
- * }
251
+ * enabled: false,
252
+ * model: { name: "gpt-4" },
253
+ * provider: { name: "openai" },
254
+ * messages: [
255
+ * { role: "system", content: "You are a helpful customer support agent." }
256
+ * ]
171
257
  * };
172
258
  * const variables = { customerName: 'John' };
173
259
  *
174
- * const chat = await client.initChat(key, context, defaultValue, variables);
260
+ * const chat = await client.createChat(key, context, defaultValue, variables);
175
261
  * if (chat) {
176
262
  * const response = await chat.invoke("I need help with my order");
177
263
  * console.log(response.message.content);
178
- *
179
- * // Access configuration and tracker if needed
180
- * console.log('Model:', chat.getConfig().model?.name);
181
- * chat.getTracker().trackSuccess();
182
264
  * }
183
265
  * ```
184
266
  */
267
+ createChat(
268
+ key: string,
269
+ context: LDContext,
270
+ defaultValue: LDAICompletionConfigDefault,
271
+ variables?: Record<string, unknown>,
272
+ defaultAiProvider?: SupportedAIProvider,
273
+ ): Promise<TrackedChat | undefined>;
274
+
275
+ /**
276
+ * @deprecated Use `createChat` instead. This method will be removed in a future version.
277
+ */
185
278
  initChat(
186
279
  key: string,
187
280
  context: LDContext,
188
- defaultValue: LDAIDefaults,
281
+ defaultValue: LDAICompletionConfigDefault,
189
282
  variables?: Record<string, unknown>,
190
283
  defaultAiProvider?: SupportedAIProvider,
191
284
  ): Promise<TrackedChat | undefined>;
285
+
286
+ /**
287
+ * Creates and returns a new Judge instance for AI evaluation.
288
+ *
289
+ * @param key The key identifying the AI judge configuration to use
290
+ * @param context Standard LDContext used when evaluating flags
291
+ * @param defaultValue A default value representing a standard AI config result
292
+ * @param variables Dictionary of values for instruction interpolation.
293
+ * The variables `message_history` and `response_to_evaluate` are reserved for the judge and will be ignored.
294
+ * @param defaultAiProvider Optional default AI provider to use.
295
+ * @returns Promise that resolves to a Judge instance or undefined if disabled/unsupported
296
+ *
297
+ * @example
298
+ * ```
299
+ * const judge = await client.createJudge(
300
+ * "relevance-judge",
301
+ * context,
302
+ * {
303
+ * enabled: true,
304
+ * model: { name: "gpt-4" },
305
+ * provider: { name: "openai" },
306
+ * evaluationMetricKeys: ['$ld:ai:judge:relevance'],
307
+ * messages: [{ role: 'system', content: 'You are a relevance judge.' }]
308
+ * },
309
+ * { metric: "relevance" }
310
+ * );
311
+ *
312
+ * if (judge) {
313
+ * const result = await judge.evaluate("User question", "AI response");
314
+ * console.log('Relevance score:', result.evals.relevance?.score);
315
+ * }
316
+ * ```
317
+ */
318
+ createJudge(
319
+ key: string,
320
+ context: LDContext,
321
+ defaultValue: LDAIJudgeConfigDefault,
322
+ variables?: Record<string, unknown>,
323
+ defaultAiProvider?: SupportedAIProvider,
324
+ ): Promise<Judge | undefined>;
192
325
  }
@@ -1,5 +1,9 @@
1
- import { LDAIConfig, LDMessage } from '../config/LDAIConfig';
1
+ import { LDLogger } from '@launchdarkly/js-server-sdk-common';
2
+
2
3
  import { LDAIConfigTracker } from '../config/LDAIConfigTracker';
4
+ import { LDAICompletionConfig, LDMessage } from '../config/types';
5
+ import { Judge } from '../judge/Judge';
6
+ import { JudgeResponse } from '../judge/types';
3
7
  import { AIProvider } from '../providers/AIProvider';
4
8
  import { ChatResponse } from './types';
5
9
 
@@ -13,9 +17,11 @@ export class TrackedChat {
13
17
  protected messages: LDMessage[];
14
18
 
15
19
  constructor(
16
- protected readonly aiConfig: LDAIConfig,
20
+ protected readonly aiConfig: LDAICompletionConfig,
17
21
  protected readonly tracker: LDAIConfigTracker,
18
22
  protected readonly provider: AIProvider,
23
+ protected readonly judges: Record<string, Judge> = {},
24
+ private readonly _logger?: LDLogger,
19
25
  ) {
20
26
  this.messages = [];
21
27
  }
@@ -42,16 +48,61 @@ export class TrackedChat {
42
48
  () => this.provider.invokeModel(allMessages),
43
49
  );
44
50
 
45
- // Add the assistant response to the conversation history
46
- this.messages.push(response.message);
51
+ if (
52
+ this.aiConfig.judgeConfiguration?.judges &&
53
+ this.aiConfig.judgeConfiguration.judges.length > 0
54
+ ) {
55
+ response.evaluations = this._evaluateWithJudges(this.messages, response);
56
+ }
47
57
 
58
+ this.messages.push(response.message);
48
59
  return response;
49
60
  }
50
61
 
62
+ /**
63
+ * Evaluates the response with all configured judges.
64
+ * Returns a promise that resolves to an array of evaluation results.
65
+ *
66
+ * @param messages Array of messages representing the conversation history
67
+ * @param response The AI response to be evaluated
68
+ * @returns Promise resolving to array of judge evaluation results
69
+ */
70
+ private async _evaluateWithJudges(
71
+ messages: LDMessage[],
72
+ response: ChatResponse,
73
+ ): Promise<Array<JudgeResponse | undefined>> {
74
+ const judgeConfigs = this.aiConfig.judgeConfiguration!.judges;
75
+
76
+ // Start all judge evaluations in parallel
77
+ const evaluationPromises = judgeConfigs.map(async (judgeConfig) => {
78
+ const judge = this.judges[judgeConfig.key];
79
+ if (!judge) {
80
+ this._logger?.warn(
81
+ `Judge configuration is not enabled: ${judgeConfig.key}`,
82
+ this.tracker.getTrackData(),
83
+ );
84
+ return undefined;
85
+ }
86
+
87
+ const evalResult = await judge.evaluateMessages(messages, response, judgeConfig.samplingRate);
88
+
89
+ if (evalResult && evalResult.success) {
90
+ this.tracker.trackEvalScores(evalResult.evals);
91
+ }
92
+
93
+ return evalResult;
94
+ });
95
+
96
+ // ensure all evaluations complete even if some fail
97
+ const results = await Promise.allSettled(evaluationPromises);
98
+
99
+ return results.map((result) => (result.status === 'fulfilled' ? result.value : undefined));
100
+ }
101
+
51
102
  /**
52
103
  * Get the underlying AI configuration used to initialize this TrackedChat.
53
104
  */
54
- getConfig(): LDAIConfig {
105
+ getConfig(): LDAICompletionConfig {
55
106
  return this.aiConfig;
56
107
  }
57
108
 
@@ -70,6 +121,14 @@ export class TrackedChat {
70
121
  return this.provider;
71
122
  }
72
123
 
124
+ /**
125
+ * Get the judges associated with this TrackedChat.
126
+ * Returns a record of judge instances keyed by their configuration keys.
127
+ */
128
+ getJudges(): Record<string, Judge> {
129
+ return this.judges;
130
+ }
131
+
73
132
  /**
74
133
  * Append messages to the conversation history.
75
134
  * Adds messages to the conversation history without invoking the model,
@@ -1,4 +1,5 @@
1
- import { LDMessage } from '../config/LDAIConfig';
1
+ import { LDMessage } from '../config/types';
2
+ import { JudgeResponse } from '../judge/types';
2
3
  import { LDAIMetrics } from '../metrics/LDAIMetrics';
3
4
 
4
5
  /**
@@ -14,4 +15,10 @@ export interface ChatResponse {
14
15
  * Metrics information including success status and token usage.
15
16
  */
16
17
  metrics: LDAIMetrics;
18
+
19
+ /**
20
+ * Promise that resolves to judge evaluation results.
21
+ * Only present when judges are configured for evaluation.
22
+ */
23
+ evaluations?: Promise<Array<JudgeResponse | undefined>>;
17
24
  }