@launchdarkly/server-sdk-ai 0.14.1 → 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 +11 -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 -521
  10. package/__tests__/LDAIClientImpl.test.ts +0 -594
  11. package/__tests__/LDAIConfigTrackerImpl.test.ts +0 -815
  12. package/__tests__/TokenUsage.test.ts +0 -119
  13. package/__tests__/TrackedChat.test.ts +0 -231
  14. package/dist/package.json +0 -53
  15. package/dist/src/LDAIClientImpl.d.ts +0 -39
  16. package/dist/src/LDAIClientImpl.d.ts.map +0 -1
  17. package/dist/src/LDAIClientImpl.js +0 -164
  18. package/dist/src/LDAIClientImpl.js.map +0 -1
  19. package/dist/src/LDAIConfigTrackerImpl.d.ts +0 -74
  20. package/dist/src/LDAIConfigTrackerImpl.d.ts.map +0 -1
  21. package/dist/src/LDAIConfigTrackerImpl.js +0 -207
  22. package/dist/src/LDAIConfigTrackerImpl.js.map +0 -1
  23. package/dist/src/LDClientMin.d.ts +0 -11
  24. package/dist/src/LDClientMin.d.ts.map +0 -1
  25. package/dist/src/LDClientMin.js +0 -3
  26. package/dist/src/LDClientMin.js.map +0 -1
  27. package/dist/src/api/LDAIClient.d.ts +0 -258
  28. package/dist/src/api/LDAIClient.d.ts.map +0 -1
  29. package/dist/src/api/LDAIClient.js +0 -3
  30. package/dist/src/api/LDAIClient.js.map +0 -1
  31. package/dist/src/api/chat/TrackedChat.d.ts +0 -72
  32. package/dist/src/api/chat/TrackedChat.d.ts.map +0 -1
  33. package/dist/src/api/chat/TrackedChat.js +0 -125
  34. package/dist/src/api/chat/TrackedChat.js.map +0 -1
  35. package/dist/src/api/chat/index.d.ts +0 -3
  36. package/dist/src/api/chat/index.d.ts.map +0 -1
  37. package/dist/src/api/chat/index.js +0 -19
  38. package/dist/src/api/chat/index.js.map +0 -1
  39. package/dist/src/api/chat/types.d.ts +0 -22
  40. package/dist/src/api/chat/types.d.ts.map +0 -1
  41. package/dist/src/api/chat/types.js +0 -3
  42. package/dist/src/api/chat/types.js.map +0 -1
  43. package/dist/src/api/config/LDAIConfigTracker.d.ts +0 -209
  44. package/dist/src/api/config/LDAIConfigTracker.d.ts.map +0 -1
  45. package/dist/src/api/config/LDAIConfigTracker.js +0 -3
  46. package/dist/src/api/config/LDAIConfigTracker.js.map +0 -1
  47. package/dist/src/api/config/LDAIConfigUtils.d.ts +0 -2
  48. package/dist/src/api/config/LDAIConfigUtils.d.ts.map +0 -1
  49. package/dist/src/api/config/LDAIConfigUtils.js +0 -145
  50. package/dist/src/api/config/LDAIConfigUtils.js.map +0 -1
  51. package/dist/src/api/config/index.d.ts +0 -3
  52. package/dist/src/api/config/index.d.ts.map +0 -1
  53. package/dist/src/api/config/index.js +0 -18
  54. package/dist/src/api/config/index.js.map +0 -1
  55. package/dist/src/api/config/types.d.ts +0 -206
  56. package/dist/src/api/config/types.d.ts.map +0 -1
  57. package/dist/src/api/config/types.js +0 -3
  58. package/dist/src/api/config/types.js.map +0 -1
  59. package/dist/src/api/index.d.ts +0 -7
  60. package/dist/src/api/index.d.ts.map +0 -1
  61. package/dist/src/api/index.js +0 -23
  62. package/dist/src/api/index.js.map +0 -1
  63. package/dist/src/api/judge/EvaluationSchemaBuilder.d.ts +0 -11
  64. package/dist/src/api/judge/EvaluationSchemaBuilder.d.ts.map +0 -1
  65. package/dist/src/api/judge/EvaluationSchemaBuilder.js +0 -52
  66. package/dist/src/api/judge/EvaluationSchemaBuilder.js.map +0 -1
  67. package/dist/src/api/judge/Judge.d.ts +0 -63
  68. package/dist/src/api/judge/Judge.d.ts.map +0 -1
  69. package/dist/src/api/judge/Judge.js +0 -151
  70. package/dist/src/api/judge/Judge.js.map +0 -1
  71. package/dist/src/api/judge/index.d.ts +0 -3
  72. package/dist/src/api/judge/index.d.ts.map +0 -1
  73. package/dist/src/api/judge/index.js +0 -6
  74. package/dist/src/api/judge/index.js.map +0 -1
  75. package/dist/src/api/judge/types.d.ts +0 -37
  76. package/dist/src/api/judge/types.d.ts.map +0 -1
  77. package/dist/src/api/judge/types.js +0 -3
  78. package/dist/src/api/judge/types.js.map +0 -1
  79. package/dist/src/api/metrics/BedrockTokenUsage.d.ts +0 -7
  80. package/dist/src/api/metrics/BedrockTokenUsage.d.ts.map +0 -1
  81. package/dist/src/api/metrics/BedrockTokenUsage.js +0 -12
  82. package/dist/src/api/metrics/BedrockTokenUsage.js.map +0 -1
  83. package/dist/src/api/metrics/LDAIMetrics.d.ts +0 -17
  84. package/dist/src/api/metrics/LDAIMetrics.d.ts.map +0 -1
  85. package/dist/src/api/metrics/LDAIMetrics.js +0 -3
  86. package/dist/src/api/metrics/LDAIMetrics.js.map +0 -1
  87. package/dist/src/api/metrics/LDFeedbackKind.d.ts +0 -14
  88. package/dist/src/api/metrics/LDFeedbackKind.d.ts.map +0 -1
  89. package/dist/src/api/metrics/LDFeedbackKind.js +0 -18
  90. package/dist/src/api/metrics/LDFeedbackKind.js.map +0 -1
  91. package/dist/src/api/metrics/LDTokenUsage.d.ts +0 -18
  92. package/dist/src/api/metrics/LDTokenUsage.d.ts.map +0 -1
  93. package/dist/src/api/metrics/LDTokenUsage.js +0 -3
  94. package/dist/src/api/metrics/LDTokenUsage.js.map +0 -1
  95. package/dist/src/api/metrics/OpenAiUsage.d.ts +0 -7
  96. package/dist/src/api/metrics/OpenAiUsage.d.ts.map +0 -1
  97. package/dist/src/api/metrics/OpenAiUsage.js +0 -13
  98. package/dist/src/api/metrics/OpenAiUsage.js.map +0 -1
  99. package/dist/src/api/metrics/VercelAISDKTokenUsage.d.ts +0 -9
  100. package/dist/src/api/metrics/VercelAISDKTokenUsage.d.ts.map +0 -1
  101. package/dist/src/api/metrics/VercelAISDKTokenUsage.js +0 -13
  102. package/dist/src/api/metrics/VercelAISDKTokenUsage.js.map +0 -1
  103. package/dist/src/api/metrics/index.d.ts +0 -7
  104. package/dist/src/api/metrics/index.d.ts.map +0 -1
  105. package/dist/src/api/metrics/index.js +0 -23
  106. package/dist/src/api/metrics/index.js.map +0 -1
  107. package/dist/src/api/providers/AIProvider.d.ts +0 -52
  108. package/dist/src/api/providers/AIProvider.d.ts.map +0 -1
  109. package/dist/src/api/providers/AIProvider.js +0 -88
  110. package/dist/src/api/providers/AIProvider.js.map +0 -1
  111. package/dist/src/api/providers/AIProviderFactory.d.ts +0 -39
  112. package/dist/src/api/providers/AIProviderFactory.d.ts.map +0 -1
  113. package/dist/src/api/providers/AIProviderFactory.js +0 -102
  114. package/dist/src/api/providers/AIProviderFactory.js.map +0 -1
  115. package/dist/src/api/providers/index.d.ts +0 -3
  116. package/dist/src/api/providers/index.d.ts.map +0 -1
  117. package/dist/src/api/providers/index.js +0 -19
  118. package/dist/src/api/providers/index.js.map +0 -1
  119. package/dist/src/index.d.ts +0 -19
  120. package/dist/src/index.d.ts.map +0 -1
  121. package/dist/src/index.js +0 -29
  122. package/dist/src/index.js.map +0 -1
  123. package/docs/.nojekyll +0 -1
  124. package/docs/assets/highlight.css +0 -92
  125. package/docs/assets/main.js +0 -58
  126. package/docs/assets/search.js +0 -1
  127. package/docs/assets/style.css +0 -1379
  128. package/docs/classes/AIProvider.html +0 -210
  129. package/docs/classes/AIProviderFactory.html +0 -208
  130. package/docs/classes/Judge.html +0 -322
  131. package/docs/classes/TrackedChat.html +0 -322
  132. package/docs/enums/LDFeedbackKind.html +0 -115
  133. package/docs/functions/createBedrockTokenUsage.html +0 -94
  134. package/docs/functions/createOpenAiUsage.html +0 -94
  135. package/docs/functions/createVercelAISDKTokenUsage.html +0 -98
  136. package/docs/functions/initAi.html +0 -93
  137. package/docs/index.html +0 -136
  138. package/docs/interfaces/ChatResponse.html +0 -130
  139. package/docs/interfaces/EvalScore.html +0 -119
  140. package/docs/interfaces/JudgeResponse.html +0 -139
  141. package/docs/interfaces/LDAIAgentConfig.html +0 -178
  142. package/docs/interfaces/LDAIAgentConfigDefault.html +0 -155
  143. package/docs/interfaces/LDAIAgentRequestConfig.html +0 -129
  144. package/docs/interfaces/LDAIClient.html +0 -449
  145. package/docs/interfaces/LDAICompletionConfig.html +0 -178
  146. package/docs/interfaces/LDAICompletionConfigDefault.html +0 -155
  147. package/docs/interfaces/LDAIConfig.html +0 -158
  148. package/docs/interfaces/LDAIConfigDefault.html +0 -133
  149. package/docs/interfaces/LDAIConfigTracker.html +0 -530
  150. package/docs/interfaces/LDAIJudgeConfig.html +0 -178
  151. package/docs/interfaces/LDAIJudgeConfigDefault.html +0 -155
  152. package/docs/interfaces/LDAIMetrics.html +0 -121
  153. package/docs/interfaces/LDJudge.html +0 -119
  154. package/docs/interfaces/LDJudgeConfiguration.html +0 -109
  155. package/docs/interfaces/LDLogger.html +0 -189
  156. package/docs/interfaces/LDMessage.html +0 -119
  157. package/docs/interfaces/LDModelConfig.html +0 -139
  158. package/docs/interfaces/LDProviderConfig.html +0 -105
  159. package/docs/interfaces/LDTokenUsage.html +0 -129
  160. package/docs/interfaces/StructuredResponse.html +0 -129
  161. package/docs/types/LDAIConfigDefaultKind.html +0 -81
  162. package/docs/types/LDAIConfigKind.html +0 -81
  163. package/docs/types/LDAIConfigMode.html +0 -81
  164. package/docs/types/SupportedAIProvider.html +0 -81
  165. package/docs/variables/SUPPORTED_AI_PROVIDERS.html +0 -81
  166. package/jest.config.js +0 -7
  167. package/src/LDAIClientImpl.ts +0 -327
  168. package/src/LDAIConfigTrackerImpl.ts +0 -288
  169. package/src/LDClientMin.ts +0 -18
  170. package/src/api/LDAIClient.ts +0 -325
  171. package/src/api/chat/TrackedChat.ts +0 -163
  172. package/src/api/chat/index.ts +0 -2
  173. package/src/api/chat/types.ts +0 -24
  174. package/src/api/config/LDAIConfigTracker.ts +0 -238
  175. package/src/api/config/LDAIConfigUtils.ts +0 -212
  176. package/src/api/config/index.ts +0 -3
  177. package/src/api/config/types.ts +0 -260
  178. package/src/api/index.ts +0 -6
  179. package/src/api/judge/EvaluationSchemaBuilder.ts +0 -54
  180. package/src/api/judge/Judge.ts +0 -218
  181. package/src/api/judge/index.ts +0 -2
  182. package/src/api/judge/types.ts +0 -41
  183. package/src/api/metrics/BedrockTokenUsage.ts +0 -13
  184. package/src/api/metrics/LDAIMetrics.ts +0 -18
  185. package/src/api/metrics/LDFeedbackKind.ts +0 -13
  186. package/src/api/metrics/LDTokenUsage.ts +0 -19
  187. package/src/api/metrics/OpenAiUsage.ts +0 -13
  188. package/src/api/metrics/VercelAISDKTokenUsage.ts +0 -15
  189. package/src/api/metrics/index.ts +0 -6
  190. package/src/api/providers/AIProvider.ts +0 -94
  191. package/src/api/providers/AIProviderFactory.ts +0 -152
  192. package/src/api/providers/index.ts +0 -2
  193. package/src/index.ts +0 -24
  194. package/tsconfig.eslint.json +0 -5
  195. package/tsconfig.json +0 -21
  196. package/tsconfig.ref.json +0 -7
  197. package/typedoc.json +0 -5
@@ -1,594 +0,0 @@
1
- import { LDContext } from '@launchdarkly/js-server-sdk-common';
2
-
3
- import {
4
- LDAIAgentConfigDefault,
5
- LDAICompletionConfigDefault,
6
- LDAIJudgeConfigDefault,
7
- } from '../src/api/config/types';
8
- import { Judge } from '../src/api/judge/Judge';
9
- import { AIProviderFactory } from '../src/api/providers/AIProviderFactory';
10
- import { LDAIClientImpl } from '../src/LDAIClientImpl';
11
- import { LDClientMin } from '../src/LDClientMin';
12
-
13
- // Mock Judge and AIProviderFactory
14
- jest.mock('../src/api/judge/Judge');
15
- jest.mock('../src/api/providers/AIProviderFactory');
16
-
17
- const mockLdClient: jest.Mocked<LDClientMin> = {
18
- variation: jest.fn(),
19
- track: jest.fn(),
20
- };
21
-
22
- // Reset mocks before each test
23
- beforeEach(() => {
24
- jest.clearAllMocks();
25
- });
26
-
27
- const testContext: LDContext = { kind: 'user', key: 'test-user' };
28
-
29
- describe('config evaluation', () => {
30
- it('evaluates completion config successfully with variable interpolation', async () => {
31
- const client = new LDAIClientImpl(mockLdClient);
32
- const key = 'test-flag';
33
- const defaultValue: LDAICompletionConfigDefault = {
34
- enabled: false,
35
- };
36
-
37
- const mockVariation = {
38
- model: {
39
- name: 'example-model',
40
- parameters: { name: 'imagination', temperature: 0.7, maxTokens: 4096 },
41
- },
42
- provider: {
43
- name: 'example-provider',
44
- },
45
- messages: [
46
- { role: 'system', content: 'Hello {{name}}' },
47
- { role: 'user', content: 'Score: {{score}}' },
48
- ],
49
- _ldMeta: {
50
- variationKey: 'v1',
51
- enabled: true,
52
- mode: 'completion',
53
- },
54
- };
55
-
56
- mockLdClient.variation.mockResolvedValue(mockVariation);
57
-
58
- const variables = { name: 'John', score: 42 };
59
- const evaluateSpy = jest.spyOn(client as any, '_evaluate');
60
- const result = await client.completionConfig(key, testContext, defaultValue, variables);
61
-
62
- expect(evaluateSpy).toHaveBeenCalledWith(
63
- key,
64
- testContext,
65
- defaultValue,
66
- 'completion',
67
- variables,
68
- );
69
- expect(result.messages).toEqual([
70
- { role: 'system', content: 'Hello John' },
71
- { role: 'user', content: 'Score: 42' },
72
- ]);
73
- expect(result.tracker).toBeDefined();
74
- expect(result.enabled).toBe(true);
75
- evaluateSpy.mockRestore();
76
- });
77
-
78
- it('includes context (ldctx) in variables for message interpolation', async () => {
79
- const client = new LDAIClientImpl(mockLdClient);
80
- const key = 'test-flag';
81
- const defaultValue: LDAICompletionConfigDefault = {
82
- enabled: false,
83
- };
84
-
85
- const mockVariation = {
86
- messages: [{ role: 'system', content: 'User key: {{ldctx.key}}' }],
87
- _ldMeta: { variationKey: 'v1', enabled: true, mode: 'completion' },
88
- };
89
-
90
- mockLdClient.variation.mockResolvedValue(mockVariation);
91
-
92
- const result = await client.completionConfig(key, testContext, defaultValue);
93
-
94
- expect(result.messages?.[0].content).toBe('User key: test-user');
95
- });
96
-
97
- it('evaluates agent config successfully with instruction interpolation', async () => {
98
- const client = new LDAIClientImpl(mockLdClient);
99
- const key = 'test-agent';
100
- const defaultValue: LDAIAgentConfigDefault = {
101
- enabled: false,
102
- };
103
-
104
- const mockVariation = {
105
- model: {
106
- name: 'example-model',
107
- parameters: { temperature: 0.7, maxTokens: 4096 },
108
- },
109
- provider: {
110
- name: 'example-provider',
111
- },
112
- instructions:
113
- 'You are a helpful assistant. Your name is {{name}} and your score is {{score}}',
114
- _ldMeta: {
115
- variationKey: 'v1',
116
- enabled: true,
117
- mode: 'agent',
118
- },
119
- };
120
-
121
- mockLdClient.variation.mockResolvedValue(mockVariation);
122
-
123
- const variables = { name: 'John', score: 42 };
124
- const evaluateSpy = jest.spyOn(client as any, '_evaluate');
125
- const result = await client.agentConfig(key, testContext, defaultValue, variables);
126
-
127
- expect(evaluateSpy).toHaveBeenCalledWith(key, testContext, defaultValue, 'agent', variables);
128
- expect(result.instructions).toBe(
129
- 'You are a helpful assistant. Your name is John and your score is 42',
130
- );
131
- expect(result.tracker).toBeDefined();
132
- expect(result.enabled).toBe(true);
133
- evaluateSpy.mockRestore();
134
- });
135
-
136
- it('evaluates judge config successfully', async () => {
137
- const client = new LDAIClientImpl(mockLdClient);
138
- const key = 'test-judge';
139
- const defaultValue: LDAIJudgeConfigDefault = {
140
- enabled: false,
141
- };
142
-
143
- const mockVariation = {
144
- enabled: true,
145
- model: { name: 'gpt-4' },
146
- provider: { name: 'openai' },
147
- evaluationMetricKeys: ['relevance', 'accuracy'],
148
- messages: [{ role: 'system', content: 'You are a judge.' }],
149
- _ldMeta: {
150
- variationKey: 'v1',
151
- enabled: true,
152
- mode: 'judge',
153
- },
154
- };
155
-
156
- mockLdClient.variation.mockResolvedValue(mockVariation);
157
-
158
- const evaluateSpy = jest.spyOn(client as any, '_evaluate');
159
- const result = await client.judgeConfig(key, testContext, defaultValue);
160
-
161
- expect(evaluateSpy).toHaveBeenCalledWith(key, testContext, defaultValue, 'judge', undefined);
162
- expect(result.evaluationMetricKeys).toEqual(['relevance', 'accuracy']);
163
- expect(result.tracker).toBeDefined();
164
- expect(result.enabled).toBe(true);
165
- evaluateSpy.mockRestore();
166
- });
167
-
168
- it('handles mode mismatch by returning disabled config', async () => {
169
- const client = new LDAIClientImpl(mockLdClient);
170
- const key = 'test-flag';
171
- const defaultValue: LDAICompletionConfigDefault = {
172
- enabled: false,
173
- };
174
-
175
- const mockVariation = {
176
- model: { name: 'example-provider', parameters: { name: 'imagination' } },
177
- messages: [{ role: 'system', content: 'Hello' }],
178
- _ldMeta: { variationKey: 'v1', enabled: true, mode: 'agent' }, // Wrong mode
179
- };
180
-
181
- mockLdClient.variation.mockResolvedValue(mockVariation);
182
-
183
- const result = await client.completionConfig(key, testContext, defaultValue);
184
-
185
- expect(result.enabled).toBe(false);
186
- expect(result.tracker).toBeUndefined();
187
- });
188
-
189
- it('handles missing metadata mode by defaulting to completion mode', async () => {
190
- const client = new LDAIClientImpl(mockLdClient);
191
- const key = 'test-flag';
192
- const defaultValue: LDAICompletionConfigDefault = {
193
- enabled: false,
194
- };
195
-
196
- const mockVariation = {
197
- model: { name: 'example-provider', parameters: { name: 'imagination' } },
198
- messages: [{ role: 'system', content: 'Hello' }],
199
- // No _ldMeta - mode defaults to completion
200
- };
201
-
202
- mockLdClient.variation.mockResolvedValue(mockVariation);
203
-
204
- const result = await client.completionConfig(key, testContext, defaultValue);
205
-
206
- expect(result.enabled).toBe(false);
207
- expect(result.tracker).toBeDefined();
208
- expect(result.messages).toEqual([{ role: 'system', content: 'Hello' }]);
209
- expect(result.model).toEqual({ name: 'example-provider', parameters: { name: 'imagination' } });
210
- });
211
-
212
- it('uses default value when flag does not exist', async () => {
213
- const client = new LDAIClientImpl(mockLdClient);
214
- const key = 'non-existent-flag';
215
- const defaultValue: LDAICompletionConfigDefault = {
216
- model: { name: 'default-model', parameters: { name: 'default' } },
217
- provider: { name: 'default-provider' },
218
- messages: [{ role: 'system', content: 'Default messages' }],
219
- enabled: true,
220
- };
221
-
222
- const expectedLDFlagValue = {
223
- _ldMeta: { enabled: true, mode: 'completion', variationKey: '' },
224
- model: defaultValue.model,
225
- messages: defaultValue.messages,
226
- provider: defaultValue.provider,
227
- };
228
-
229
- mockLdClient.variation.mockResolvedValue(expectedLDFlagValue);
230
-
231
- const result = await client.completionConfig(key, testContext, defaultValue);
232
-
233
- expect(result.model).toEqual(defaultValue.model);
234
- expect(result.messages).toEqual(defaultValue.messages);
235
- expect(result.provider).toEqual(defaultValue.provider);
236
- expect(result.tracker).toBeDefined();
237
- expect(result.enabled).toBe(defaultValue.enabled);
238
- expect(mockLdClient.variation).toHaveBeenCalledWith(
239
- key,
240
- testContext,
241
- expect.objectContaining({
242
- model: defaultValue.model,
243
- provider: defaultValue.provider,
244
- }),
245
- );
246
- });
247
- });
248
-
249
- describe('completionConfig method', () => {
250
- it('calls _evaluate with correct parameters and tracks usage', async () => {
251
- const client = new LDAIClientImpl(mockLdClient);
252
- const key = 'test-flag';
253
- const defaultValue: LDAICompletionConfigDefault = {
254
- model: { name: 'test', parameters: { name: 'test-model' } },
255
- messages: [],
256
- enabled: true,
257
- };
258
- const variables = { var1: 'value1' };
259
-
260
- const mockConfig = {
261
- model: { name: 'test-model' },
262
- messages: [],
263
- tracker: {} as any,
264
- enabled: true,
265
- };
266
-
267
- const evaluateSpy = jest.spyOn(client as any, '_evaluate');
268
- evaluateSpy.mockResolvedValue(mockConfig);
269
-
270
- const result = await client.completionConfig(key, testContext, defaultValue, variables);
271
-
272
- expect(mockLdClient.track).toHaveBeenCalledWith(
273
- '$ld:ai:config:function:single',
274
- testContext,
275
- key,
276
- 1,
277
- );
278
- expect(evaluateSpy).toHaveBeenCalledWith(
279
- key,
280
- testContext,
281
- defaultValue,
282
- 'completion',
283
- variables,
284
- );
285
- expect(result).toBeDefined();
286
- evaluateSpy.mockRestore();
287
- });
288
- });
289
-
290
- describe('agentConfig method', () => {
291
- it('calls _evaluate with correct parameters and tracks usage', async () => {
292
- const client = new LDAIClientImpl(mockLdClient);
293
- const key = 'test-agent';
294
- const defaultValue: LDAIAgentConfigDefault = {
295
- model: { name: 'test', parameters: { name: 'test-model' } },
296
- instructions: 'You are a helpful assistant.',
297
- enabled: true,
298
- };
299
- const variables = { var1: 'value1' };
300
-
301
- const mockConfig = {
302
- model: { name: 'test-model' },
303
- instructions: 'You are a helpful assistant.',
304
- tracker: {} as any,
305
- enabled: true,
306
- };
307
-
308
- const evaluateSpy = jest.spyOn(client as any, '_evaluate');
309
- evaluateSpy.mockResolvedValue(mockConfig);
310
-
311
- const result = await client.agentConfig(key, testContext, defaultValue, variables);
312
-
313
- expect(mockLdClient.track).toHaveBeenCalledWith(
314
- '$ld:ai:agent:function:single',
315
- testContext,
316
- key,
317
- 1,
318
- );
319
- expect(evaluateSpy).toHaveBeenCalledWith(key, testContext, defaultValue, 'agent', variables);
320
- expect(result).toBe(mockConfig);
321
- evaluateSpy.mockRestore();
322
- });
323
- });
324
-
325
- describe('agents method', () => {
326
- it('retrieves multiple agent configs with interpolated instructions', async () => {
327
- const client = new LDAIClientImpl(mockLdClient);
328
-
329
- const agentConfigs = [
330
- {
331
- key: 'research-agent',
332
- defaultValue: {
333
- enabled: false,
334
- },
335
- variables: { topic: 'climate change' },
336
- },
337
- {
338
- key: 'writing-agent',
339
- defaultValue: {
340
- enabled: false,
341
- },
342
- variables: { style: 'academic' },
343
- },
344
- ] as const;
345
-
346
- const mockVariations = {
347
- 'research-agent': {
348
- model: {
349
- name: 'research-model',
350
- parameters: { temperature: 0.3, maxTokens: 2048 },
351
- },
352
- provider: { name: 'openai' },
353
- instructions: 'You are a research assistant specializing in {{topic}}.',
354
- _ldMeta: { variationKey: 'v1', enabled: true, mode: 'agent' },
355
- },
356
- 'writing-agent': {
357
- model: {
358
- name: 'writing-model',
359
- parameters: { temperature: 0.7, maxTokens: 1024 },
360
- },
361
- provider: { name: 'anthropic' },
362
- instructions: 'You are a writing assistant with {{style}} style.',
363
- _ldMeta: { variationKey: 'v2', enabled: true, mode: 'agent' },
364
- },
365
- };
366
-
367
- mockLdClient.variation.mockImplementation((key) =>
368
- Promise.resolve(mockVariations[key as keyof typeof mockVariations]),
369
- );
370
-
371
- const result = await client.agentConfigs(agentConfigs, testContext);
372
-
373
- expect(result).toEqual({
374
- 'research-agent': {
375
- key: 'research-agent',
376
- model: {
377
- name: 'research-model',
378
- parameters: { temperature: 0.3, maxTokens: 2048 },
379
- },
380
- provider: { name: 'openai' },
381
- instructions: 'You are a research assistant specializing in climate change.',
382
- tracker: expect.any(Object),
383
- enabled: true,
384
- },
385
- 'writing-agent': {
386
- key: 'writing-agent',
387
- model: {
388
- name: 'writing-model',
389
- parameters: { temperature: 0.7, maxTokens: 1024 },
390
- },
391
- provider: { name: 'anthropic' },
392
- instructions: 'You are a writing assistant with academic style.',
393
- tracker: expect.any(Object),
394
- enabled: true,
395
- },
396
- });
397
-
398
- expect(mockLdClient.track).toHaveBeenCalledWith(
399
- '$ld:ai:agent:function:multiple',
400
- testContext,
401
- agentConfigs.length,
402
- agentConfigs.length,
403
- );
404
- });
405
-
406
- it('handles empty agent configs array', async () => {
407
- const client = new LDAIClientImpl(mockLdClient);
408
-
409
- const result = await client.agentConfigs([], testContext);
410
-
411
- expect(result).toEqual({});
412
-
413
- expect(mockLdClient.track).toHaveBeenCalledWith(
414
- '$ld:ai:agent:function:multiple',
415
- testContext,
416
- 0,
417
- 0,
418
- );
419
- });
420
- });
421
-
422
- describe('judgeConfig method', () => {
423
- it('calls _evaluate with correct parameters and tracks usage', async () => {
424
- const client = new LDAIClientImpl(mockLdClient);
425
- const key = 'test-judge';
426
- const defaultValue: LDAIJudgeConfigDefault = {
427
- enabled: false,
428
- };
429
- const variables = { metric: 'relevance' };
430
-
431
- const mockJudgeConfig = {
432
- enabled: true,
433
- model: { name: 'gpt-4' },
434
- provider: { name: 'openai' },
435
- evaluationMetricKeys: ['relevance'],
436
- messages: [{ role: 'system' as const, content: 'You are a judge for {{metric}}.' }],
437
- tracker: {} as any,
438
- toVercelAISDK: jest.fn(),
439
- };
440
-
441
- const evaluateSpy = jest.spyOn(client as any, '_evaluate');
442
- evaluateSpy.mockResolvedValue(mockJudgeConfig);
443
-
444
- const result = await client.judgeConfig(key, testContext, defaultValue, variables);
445
-
446
- expect(mockLdClient.track).toHaveBeenCalledWith(
447
- '$ld:ai:judge:function:single',
448
- testContext,
449
- key,
450
- 1,
451
- );
452
- expect(evaluateSpy).toHaveBeenCalledWith(key, testContext, defaultValue, 'judge', variables);
453
- expect(result).toBe(mockJudgeConfig);
454
- evaluateSpy.mockRestore();
455
- });
456
- });
457
-
458
- describe('createJudge method', () => {
459
- let mockProvider: jest.Mocked<any>;
460
- let mockJudge: jest.Mocked<Judge>;
461
-
462
- beforeEach(() => {
463
- mockProvider = {
464
- invokeStructuredModel: jest.fn(),
465
- };
466
-
467
- mockJudge = {
468
- evaluate: jest.fn(),
469
- evaluateMessages: jest.fn(),
470
- } as any;
471
-
472
- // Mock AIProviderFactory.create
473
- (AIProviderFactory.create as jest.Mock).mockResolvedValue(mockProvider);
474
-
475
- // Mock Judge constructor
476
- (Judge as jest.MockedClass<typeof Judge>).mockImplementation(() => mockJudge);
477
- });
478
-
479
- it('initializes judge successfully', async () => {
480
- const client = new LDAIClientImpl(mockLdClient);
481
- const key = 'test-judge';
482
- const defaultValue: LDAIJudgeConfigDefault = {
483
- enabled: false,
484
- };
485
-
486
- const mockJudgeConfig = {
487
- key: 'test-judge',
488
- enabled: true,
489
- model: { name: 'gpt-4' },
490
- provider: { name: 'openai' },
491
- evaluationMetricKeys: ['relevance', 'accuracy'],
492
- messages: [{ role: 'system' as const, content: 'You are a judge.' }],
493
- tracker: {} as any,
494
- toVercelAISDK: jest.fn(),
495
- };
496
-
497
- const judgeConfigSpy = jest.spyOn(client, 'judgeConfig');
498
- judgeConfigSpy.mockResolvedValue(mockJudgeConfig);
499
-
500
- const result = await client.createJudge(key, testContext, defaultValue);
501
-
502
- expect(mockLdClient.track).toHaveBeenCalledWith(
503
- '$ld:ai:judge:function:createJudge',
504
- testContext,
505
- key,
506
- 1,
507
- );
508
- expect(judgeConfigSpy).toHaveBeenCalledWith(key, testContext, defaultValue, {
509
- message_history: '{{message_history}}',
510
- response_to_evaluate: '{{response_to_evaluate}}',
511
- });
512
- expect(AIProviderFactory.create).toHaveBeenCalledWith(mockJudgeConfig, undefined, undefined);
513
- expect(Judge).toHaveBeenCalledWith(
514
- mockJudgeConfig,
515
- mockJudgeConfig.tracker,
516
- mockProvider,
517
- undefined,
518
- );
519
- expect(result).toBe(mockJudge);
520
- judgeConfigSpy.mockRestore();
521
- });
522
-
523
- it('returns undefined when judge configuration is disabled', async () => {
524
- const client = new LDAIClientImpl(mockLdClient);
525
- const key = 'test-judge';
526
- const defaultValue: LDAIJudgeConfigDefault = {
527
- enabled: false,
528
- };
529
-
530
- const mockJudgeConfig = {
531
- key: 'test-judge',
532
- enabled: false,
533
- evaluationMetricKeys: [],
534
- };
535
-
536
- const judgeConfigSpy = jest.spyOn(client, 'judgeConfig');
537
- judgeConfigSpy.mockResolvedValue(mockJudgeConfig);
538
-
539
- const result = await client.createJudge(key, testContext, defaultValue);
540
-
541
- expect(result).toBeUndefined();
542
- expect(AIProviderFactory.create).not.toHaveBeenCalled();
543
- expect(Judge).not.toHaveBeenCalled();
544
- judgeConfigSpy.mockRestore();
545
- });
546
-
547
- it('returns undefined when AIProviderFactory.create fails', async () => {
548
- const client = new LDAIClientImpl(mockLdClient);
549
- const key = 'test-judge';
550
- const defaultValue: LDAIJudgeConfigDefault = {
551
- enabled: false,
552
- };
553
-
554
- const mockJudgeConfig = {
555
- key: 'test-judge',
556
- enabled: true,
557
- model: { name: 'gpt-4' },
558
- provider: { name: 'openai' },
559
- evaluationMetricKeys: ['relevance'],
560
- messages: [{ role: 'system' as const, content: 'You are a judge.' }],
561
- tracker: {} as any,
562
- toVercelAISDK: jest.fn(),
563
- };
564
-
565
- const judgeConfigSpy = jest.spyOn(client, 'judgeConfig');
566
- judgeConfigSpy.mockResolvedValue(mockJudgeConfig);
567
-
568
- (AIProviderFactory.create as jest.Mock).mockResolvedValue(undefined);
569
-
570
- const result = await client.createJudge(key, testContext, defaultValue);
571
-
572
- expect(result).toBeUndefined();
573
- expect(AIProviderFactory.create).toHaveBeenCalledWith(mockJudgeConfig, undefined, undefined);
574
- expect(Judge).not.toHaveBeenCalled();
575
- judgeConfigSpy.mockRestore();
576
- });
577
-
578
- it('handles errors gracefully', async () => {
579
- const client = new LDAIClientImpl(mockLdClient);
580
- const key = 'test-judge';
581
- const defaultValue: LDAIJudgeConfigDefault = {
582
- enabled: false,
583
- };
584
-
585
- const error = new Error('Judge configuration error');
586
- const judgeConfigSpy = jest.spyOn(client, 'judgeConfig');
587
- judgeConfigSpy.mockRejectedValue(error);
588
-
589
- const result = await client.createJudge(key, testContext, defaultValue);
590
-
591
- expect(result).toBeUndefined();
592
- judgeConfigSpy.mockRestore();
593
- });
594
- });