@launchdarkly/server-sdk-ai 0.14.0 → 0.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +18 -0
- package/dist/index.cjs +1117 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +1022 -0
- package/dist/index.d.ts +1022 -0
- package/dist/index.js +1071 -0
- package/dist/index.js.map +1 -0
- package/package.json +22 -5
- package/__tests__/Judge.test.ts +0 -496
- package/__tests__/LDAIClientImpl.test.ts +0 -589
- package/__tests__/LDAIConfigTrackerImpl.test.ts +0 -815
- package/__tests__/TokenUsage.test.ts +0 -119
- package/__tests__/TrackedChat.test.ts +0 -230
- package/dist/package.json +0 -53
- package/dist/src/LDAIClientImpl.d.ts +0 -39
- package/dist/src/LDAIClientImpl.d.ts.map +0 -1
- package/dist/src/LDAIClientImpl.js +0 -164
- package/dist/src/LDAIClientImpl.js.map +0 -1
- package/dist/src/LDAIConfigTrackerImpl.d.ts +0 -73
- package/dist/src/LDAIConfigTrackerImpl.d.ts.map +0 -1
- package/dist/src/LDAIConfigTrackerImpl.js +0 -203
- package/dist/src/LDAIConfigTrackerImpl.js.map +0 -1
- package/dist/src/LDClientMin.d.ts +0 -11
- package/dist/src/LDClientMin.d.ts.map +0 -1
- package/dist/src/LDClientMin.js +0 -3
- package/dist/src/LDClientMin.js.map +0 -1
- package/dist/src/api/LDAIClient.d.ts +0 -258
- package/dist/src/api/LDAIClient.d.ts.map +0 -1
- package/dist/src/api/LDAIClient.js +0 -3
- package/dist/src/api/LDAIClient.js.map +0 -1
- package/dist/src/api/chat/TrackedChat.d.ts +0 -72
- package/dist/src/api/chat/TrackedChat.d.ts.map +0 -1
- package/dist/src/api/chat/TrackedChat.js +0 -125
- package/dist/src/api/chat/TrackedChat.js.map +0 -1
- package/dist/src/api/chat/index.d.ts +0 -3
- package/dist/src/api/chat/index.d.ts.map +0 -1
- package/dist/src/api/chat/index.js +0 -19
- package/dist/src/api/chat/index.js.map +0 -1
- package/dist/src/api/chat/types.d.ts +0 -22
- package/dist/src/api/chat/types.d.ts.map +0 -1
- package/dist/src/api/chat/types.js +0 -3
- package/dist/src/api/chat/types.js.map +0 -1
- package/dist/src/api/config/LDAIConfigTracker.d.ts +0 -203
- package/dist/src/api/config/LDAIConfigTracker.d.ts.map +0 -1
- package/dist/src/api/config/LDAIConfigTracker.js +0 -3
- package/dist/src/api/config/LDAIConfigTracker.js.map +0 -1
- package/dist/src/api/config/LDAIConfigUtils.d.ts +0 -2
- package/dist/src/api/config/LDAIConfigUtils.d.ts.map +0 -1
- package/dist/src/api/config/LDAIConfigUtils.js +0 -141
- package/dist/src/api/config/LDAIConfigUtils.js.map +0 -1
- package/dist/src/api/config/index.d.ts +0 -3
- package/dist/src/api/config/index.d.ts.map +0 -1
- package/dist/src/api/config/index.js +0 -18
- package/dist/src/api/config/index.js.map +0 -1
- package/dist/src/api/config/types.d.ts +0 -202
- package/dist/src/api/config/types.d.ts.map +0 -1
- package/dist/src/api/config/types.js +0 -3
- package/dist/src/api/config/types.js.map +0 -1
- package/dist/src/api/index.d.ts +0 -7
- package/dist/src/api/index.d.ts.map +0 -1
- package/dist/src/api/index.js +0 -23
- package/dist/src/api/index.js.map +0 -1
- package/dist/src/api/judge/EvaluationSchemaBuilder.d.ts +0 -11
- package/dist/src/api/judge/EvaluationSchemaBuilder.d.ts.map +0 -1
- package/dist/src/api/judge/EvaluationSchemaBuilder.js +0 -52
- package/dist/src/api/judge/EvaluationSchemaBuilder.js.map +0 -1
- package/dist/src/api/judge/Judge.d.ts +0 -63
- package/dist/src/api/judge/Judge.d.ts.map +0 -1
- package/dist/src/api/judge/Judge.js +0 -149
- package/dist/src/api/judge/Judge.js.map +0 -1
- package/dist/src/api/judge/index.d.ts +0 -3
- package/dist/src/api/judge/index.d.ts.map +0 -1
- package/dist/src/api/judge/index.js +0 -6
- package/dist/src/api/judge/index.js.map +0 -1
- package/dist/src/api/judge/types.d.ts +0 -35
- package/dist/src/api/judge/types.d.ts.map +0 -1
- package/dist/src/api/judge/types.js +0 -3
- package/dist/src/api/judge/types.js.map +0 -1
- package/dist/src/api/metrics/BedrockTokenUsage.d.ts +0 -7
- package/dist/src/api/metrics/BedrockTokenUsage.d.ts.map +0 -1
- package/dist/src/api/metrics/BedrockTokenUsage.js +0 -12
- package/dist/src/api/metrics/BedrockTokenUsage.js.map +0 -1
- package/dist/src/api/metrics/LDAIMetrics.d.ts +0 -17
- package/dist/src/api/metrics/LDAIMetrics.d.ts.map +0 -1
- package/dist/src/api/metrics/LDAIMetrics.js +0 -3
- package/dist/src/api/metrics/LDAIMetrics.js.map +0 -1
- package/dist/src/api/metrics/LDFeedbackKind.d.ts +0 -14
- package/dist/src/api/metrics/LDFeedbackKind.d.ts.map +0 -1
- package/dist/src/api/metrics/LDFeedbackKind.js +0 -18
- package/dist/src/api/metrics/LDFeedbackKind.js.map +0 -1
- package/dist/src/api/metrics/LDTokenUsage.d.ts +0 -18
- package/dist/src/api/metrics/LDTokenUsage.d.ts.map +0 -1
- package/dist/src/api/metrics/LDTokenUsage.js +0 -3
- package/dist/src/api/metrics/LDTokenUsage.js.map +0 -1
- package/dist/src/api/metrics/OpenAiUsage.d.ts +0 -7
- package/dist/src/api/metrics/OpenAiUsage.d.ts.map +0 -1
- package/dist/src/api/metrics/OpenAiUsage.js +0 -13
- package/dist/src/api/metrics/OpenAiUsage.js.map +0 -1
- package/dist/src/api/metrics/VercelAISDKTokenUsage.d.ts +0 -9
- package/dist/src/api/metrics/VercelAISDKTokenUsage.d.ts.map +0 -1
- package/dist/src/api/metrics/VercelAISDKTokenUsage.js +0 -13
- package/dist/src/api/metrics/VercelAISDKTokenUsage.js.map +0 -1
- package/dist/src/api/metrics/index.d.ts +0 -7
- package/dist/src/api/metrics/index.d.ts.map +0 -1
- package/dist/src/api/metrics/index.js +0 -23
- package/dist/src/api/metrics/index.js.map +0 -1
- package/dist/src/api/providers/AIProvider.d.ts +0 -52
- package/dist/src/api/providers/AIProvider.d.ts.map +0 -1
- package/dist/src/api/providers/AIProvider.js +0 -88
- package/dist/src/api/providers/AIProvider.js.map +0 -1
- package/dist/src/api/providers/AIProviderFactory.d.ts +0 -39
- package/dist/src/api/providers/AIProviderFactory.d.ts.map +0 -1
- package/dist/src/api/providers/AIProviderFactory.js +0 -102
- package/dist/src/api/providers/AIProviderFactory.js.map +0 -1
- package/dist/src/api/providers/index.d.ts +0 -3
- package/dist/src/api/providers/index.d.ts.map +0 -1
- package/dist/src/api/providers/index.js +0 -19
- package/dist/src/api/providers/index.js.map +0 -1
- package/dist/src/index.d.ts +0 -19
- package/dist/src/index.d.ts.map +0 -1
- package/dist/src/index.js +0 -29
- package/dist/src/index.js.map +0 -1
- package/docs/.nojekyll +0 -1
- package/docs/assets/highlight.css +0 -92
- package/docs/assets/main.js +0 -58
- package/docs/assets/search.js +0 -1
- package/docs/assets/style.css +0 -1379
- package/docs/classes/AIProvider.html +0 -210
- package/docs/classes/AIProviderFactory.html +0 -208
- package/docs/classes/Judge.html +0 -322
- package/docs/classes/TrackedChat.html +0 -322
- package/docs/enums/LDFeedbackKind.html +0 -115
- package/docs/functions/createBedrockTokenUsage.html +0 -94
- package/docs/functions/createOpenAiUsage.html +0 -94
- package/docs/functions/createVercelAISDKTokenUsage.html +0 -98
- package/docs/functions/initAi.html +0 -93
- package/docs/index.html +0 -136
- package/docs/interfaces/ChatResponse.html +0 -130
- package/docs/interfaces/EvalScore.html +0 -119
- package/docs/interfaces/JudgeResponse.html +0 -129
- package/docs/interfaces/LDAIAgentConfig.html +0 -167
- package/docs/interfaces/LDAIAgentConfigDefault.html +0 -155
- package/docs/interfaces/LDAIAgentRequestConfig.html +0 -129
- package/docs/interfaces/LDAIClient.html +0 -449
- package/docs/interfaces/LDAICompletionConfig.html +0 -167
- package/docs/interfaces/LDAICompletionConfigDefault.html +0 -155
- package/docs/interfaces/LDAIConfig.html +0 -148
- package/docs/interfaces/LDAIConfigDefault.html +0 -133
- package/docs/interfaces/LDAIConfigTracker.html +0 -510
- package/docs/interfaces/LDAIJudgeConfig.html +0 -167
- package/docs/interfaces/LDAIJudgeConfigDefault.html +0 -155
- package/docs/interfaces/LDAIMetrics.html +0 -121
- package/docs/interfaces/LDJudge.html +0 -119
- package/docs/interfaces/LDJudgeConfiguration.html +0 -109
- package/docs/interfaces/LDLogger.html +0 -189
- package/docs/interfaces/LDMessage.html +0 -119
- package/docs/interfaces/LDModelConfig.html +0 -139
- package/docs/interfaces/LDProviderConfig.html +0 -105
- package/docs/interfaces/LDTokenUsage.html +0 -129
- package/docs/interfaces/StructuredResponse.html +0 -129
- package/docs/types/LDAIConfigDefaultKind.html +0 -81
- package/docs/types/LDAIConfigKind.html +0 -81
- package/docs/types/LDAIConfigMode.html +0 -81
- package/docs/types/SupportedAIProvider.html +0 -81
- package/docs/variables/SUPPORTED_AI_PROVIDERS.html +0 -81
- package/jest.config.js +0 -7
- package/src/LDAIClientImpl.ts +0 -327
- package/src/LDAIConfigTrackerImpl.ts +0 -278
- package/src/LDClientMin.ts +0 -18
- package/src/api/LDAIClient.ts +0 -325
- package/src/api/chat/TrackedChat.ts +0 -159
- package/src/api/chat/index.ts +0 -2
- package/src/api/chat/types.ts +0 -24
- package/src/api/config/LDAIConfigTracker.ts +0 -231
- package/src/api/config/LDAIConfigUtils.ts +0 -201
- package/src/api/config/index.ts +0 -3
- package/src/api/config/types.ts +0 -256
- package/src/api/index.ts +0 -6
- package/src/api/judge/EvaluationSchemaBuilder.ts +0 -54
- package/src/api/judge/Judge.ts +0 -216
- package/src/api/judge/index.ts +0 -2
- package/src/api/judge/types.ts +0 -39
- package/src/api/metrics/BedrockTokenUsage.ts +0 -13
- package/src/api/metrics/LDAIMetrics.ts +0 -18
- package/src/api/metrics/LDFeedbackKind.ts +0 -13
- package/src/api/metrics/LDTokenUsage.ts +0 -19
- package/src/api/metrics/OpenAiUsage.ts +0 -13
- package/src/api/metrics/VercelAISDKTokenUsage.ts +0 -15
- package/src/api/metrics/index.ts +0 -6
- package/src/api/providers/AIProvider.ts +0 -94
- package/src/api/providers/AIProviderFactory.ts +0 -152
- package/src/api/providers/index.ts +0 -2
- package/src/index.ts +0 -24
- package/tsconfig.eslint.json +0 -5
- package/tsconfig.json +0 -21
- package/tsconfig.ref.json +0 -7
- package/typedoc.json +0 -5
|
@@ -1,589 +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
|
-
model: {
|
|
376
|
-
name: 'research-model',
|
|
377
|
-
parameters: { temperature: 0.3, maxTokens: 2048 },
|
|
378
|
-
},
|
|
379
|
-
provider: { name: 'openai' },
|
|
380
|
-
instructions: 'You are a research assistant specializing in climate change.',
|
|
381
|
-
tracker: expect.any(Object),
|
|
382
|
-
enabled: true,
|
|
383
|
-
},
|
|
384
|
-
'writing-agent': {
|
|
385
|
-
model: {
|
|
386
|
-
name: 'writing-model',
|
|
387
|
-
parameters: { temperature: 0.7, maxTokens: 1024 },
|
|
388
|
-
},
|
|
389
|
-
provider: { name: 'anthropic' },
|
|
390
|
-
instructions: 'You are a writing assistant with academic style.',
|
|
391
|
-
tracker: expect.any(Object),
|
|
392
|
-
enabled: true,
|
|
393
|
-
},
|
|
394
|
-
});
|
|
395
|
-
|
|
396
|
-
expect(mockLdClient.track).toHaveBeenCalledWith(
|
|
397
|
-
'$ld:ai:agent:function:multiple',
|
|
398
|
-
testContext,
|
|
399
|
-
agentConfigs.length,
|
|
400
|
-
agentConfigs.length,
|
|
401
|
-
);
|
|
402
|
-
});
|
|
403
|
-
|
|
404
|
-
it('handles empty agent configs array', async () => {
|
|
405
|
-
const client = new LDAIClientImpl(mockLdClient);
|
|
406
|
-
|
|
407
|
-
const result = await client.agentConfigs([], testContext);
|
|
408
|
-
|
|
409
|
-
expect(result).toEqual({});
|
|
410
|
-
|
|
411
|
-
expect(mockLdClient.track).toHaveBeenCalledWith(
|
|
412
|
-
'$ld:ai:agent:function:multiple',
|
|
413
|
-
testContext,
|
|
414
|
-
0,
|
|
415
|
-
0,
|
|
416
|
-
);
|
|
417
|
-
});
|
|
418
|
-
});
|
|
419
|
-
|
|
420
|
-
describe('judgeConfig method', () => {
|
|
421
|
-
it('calls _evaluate with correct parameters and tracks usage', async () => {
|
|
422
|
-
const client = new LDAIClientImpl(mockLdClient);
|
|
423
|
-
const key = 'test-judge';
|
|
424
|
-
const defaultValue: LDAIJudgeConfigDefault = {
|
|
425
|
-
enabled: false,
|
|
426
|
-
};
|
|
427
|
-
const variables = { metric: 'relevance' };
|
|
428
|
-
|
|
429
|
-
const mockJudgeConfig = {
|
|
430
|
-
enabled: true,
|
|
431
|
-
model: { name: 'gpt-4' },
|
|
432
|
-
provider: { name: 'openai' },
|
|
433
|
-
evaluationMetricKeys: ['relevance'],
|
|
434
|
-
messages: [{ role: 'system' as const, content: 'You are a judge for {{metric}}.' }],
|
|
435
|
-
tracker: {} as any,
|
|
436
|
-
toVercelAISDK: jest.fn(),
|
|
437
|
-
};
|
|
438
|
-
|
|
439
|
-
const evaluateSpy = jest.spyOn(client as any, '_evaluate');
|
|
440
|
-
evaluateSpy.mockResolvedValue(mockJudgeConfig);
|
|
441
|
-
|
|
442
|
-
const result = await client.judgeConfig(key, testContext, defaultValue, variables);
|
|
443
|
-
|
|
444
|
-
expect(mockLdClient.track).toHaveBeenCalledWith(
|
|
445
|
-
'$ld:ai:judge:function:single',
|
|
446
|
-
testContext,
|
|
447
|
-
key,
|
|
448
|
-
1,
|
|
449
|
-
);
|
|
450
|
-
expect(evaluateSpy).toHaveBeenCalledWith(key, testContext, defaultValue, 'judge', variables);
|
|
451
|
-
expect(result).toBe(mockJudgeConfig);
|
|
452
|
-
evaluateSpy.mockRestore();
|
|
453
|
-
});
|
|
454
|
-
});
|
|
455
|
-
|
|
456
|
-
describe('createJudge method', () => {
|
|
457
|
-
let mockProvider: jest.Mocked<any>;
|
|
458
|
-
let mockJudge: jest.Mocked<Judge>;
|
|
459
|
-
|
|
460
|
-
beforeEach(() => {
|
|
461
|
-
mockProvider = {
|
|
462
|
-
invokeStructuredModel: jest.fn(),
|
|
463
|
-
};
|
|
464
|
-
|
|
465
|
-
mockJudge = {
|
|
466
|
-
evaluate: jest.fn(),
|
|
467
|
-
evaluateMessages: jest.fn(),
|
|
468
|
-
} as any;
|
|
469
|
-
|
|
470
|
-
// Mock AIProviderFactory.create
|
|
471
|
-
(AIProviderFactory.create as jest.Mock).mockResolvedValue(mockProvider);
|
|
472
|
-
|
|
473
|
-
// Mock Judge constructor
|
|
474
|
-
(Judge as jest.MockedClass<typeof Judge>).mockImplementation(() => mockJudge);
|
|
475
|
-
});
|
|
476
|
-
|
|
477
|
-
it('initializes judge successfully', async () => {
|
|
478
|
-
const client = new LDAIClientImpl(mockLdClient);
|
|
479
|
-
const key = 'test-judge';
|
|
480
|
-
const defaultValue: LDAIJudgeConfigDefault = {
|
|
481
|
-
enabled: false,
|
|
482
|
-
};
|
|
483
|
-
|
|
484
|
-
const mockJudgeConfig = {
|
|
485
|
-
enabled: true,
|
|
486
|
-
model: { name: 'gpt-4' },
|
|
487
|
-
provider: { name: 'openai' },
|
|
488
|
-
evaluationMetricKeys: ['relevance', 'accuracy'],
|
|
489
|
-
messages: [{ role: 'system' as const, content: 'You are a judge.' }],
|
|
490
|
-
tracker: {} as any,
|
|
491
|
-
toVercelAISDK: jest.fn(),
|
|
492
|
-
};
|
|
493
|
-
|
|
494
|
-
const judgeConfigSpy = jest.spyOn(client, 'judgeConfig');
|
|
495
|
-
judgeConfigSpy.mockResolvedValue(mockJudgeConfig);
|
|
496
|
-
|
|
497
|
-
const result = await client.createJudge(key, testContext, defaultValue);
|
|
498
|
-
|
|
499
|
-
expect(mockLdClient.track).toHaveBeenCalledWith(
|
|
500
|
-
'$ld:ai:judge:function:createJudge',
|
|
501
|
-
testContext,
|
|
502
|
-
key,
|
|
503
|
-
1,
|
|
504
|
-
);
|
|
505
|
-
expect(judgeConfigSpy).toHaveBeenCalledWith(key, testContext, defaultValue, {
|
|
506
|
-
message_history: '{{message_history}}',
|
|
507
|
-
response_to_evaluate: '{{response_to_evaluate}}',
|
|
508
|
-
});
|
|
509
|
-
expect(AIProviderFactory.create).toHaveBeenCalledWith(mockJudgeConfig, undefined, undefined);
|
|
510
|
-
expect(Judge).toHaveBeenCalledWith(
|
|
511
|
-
mockJudgeConfig,
|
|
512
|
-
mockJudgeConfig.tracker,
|
|
513
|
-
mockProvider,
|
|
514
|
-
undefined,
|
|
515
|
-
);
|
|
516
|
-
expect(result).toBe(mockJudge);
|
|
517
|
-
judgeConfigSpy.mockRestore();
|
|
518
|
-
});
|
|
519
|
-
|
|
520
|
-
it('returns undefined when judge configuration is disabled', async () => {
|
|
521
|
-
const client = new LDAIClientImpl(mockLdClient);
|
|
522
|
-
const key = 'test-judge';
|
|
523
|
-
const defaultValue: LDAIJudgeConfigDefault = {
|
|
524
|
-
enabled: false,
|
|
525
|
-
};
|
|
526
|
-
|
|
527
|
-
const mockJudgeConfig = {
|
|
528
|
-
enabled: false,
|
|
529
|
-
evaluationMetricKeys: [],
|
|
530
|
-
};
|
|
531
|
-
|
|
532
|
-
const judgeConfigSpy = jest.spyOn(client, 'judgeConfig');
|
|
533
|
-
judgeConfigSpy.mockResolvedValue(mockJudgeConfig);
|
|
534
|
-
|
|
535
|
-
const result = await client.createJudge(key, testContext, defaultValue);
|
|
536
|
-
|
|
537
|
-
expect(result).toBeUndefined();
|
|
538
|
-
expect(AIProviderFactory.create).not.toHaveBeenCalled();
|
|
539
|
-
expect(Judge).not.toHaveBeenCalled();
|
|
540
|
-
judgeConfigSpy.mockRestore();
|
|
541
|
-
});
|
|
542
|
-
|
|
543
|
-
it('returns undefined when AIProviderFactory.create fails', async () => {
|
|
544
|
-
const client = new LDAIClientImpl(mockLdClient);
|
|
545
|
-
const key = 'test-judge';
|
|
546
|
-
const defaultValue: LDAIJudgeConfigDefault = {
|
|
547
|
-
enabled: false,
|
|
548
|
-
};
|
|
549
|
-
|
|
550
|
-
const mockJudgeConfig = {
|
|
551
|
-
enabled: true,
|
|
552
|
-
model: { name: 'gpt-4' },
|
|
553
|
-
provider: { name: 'openai' },
|
|
554
|
-
evaluationMetricKeys: ['relevance'],
|
|
555
|
-
messages: [{ role: 'system' as const, content: 'You are a judge.' }],
|
|
556
|
-
tracker: {} as any,
|
|
557
|
-
toVercelAISDK: jest.fn(),
|
|
558
|
-
};
|
|
559
|
-
|
|
560
|
-
const judgeConfigSpy = jest.spyOn(client, 'judgeConfig');
|
|
561
|
-
judgeConfigSpy.mockResolvedValue(mockJudgeConfig);
|
|
562
|
-
|
|
563
|
-
(AIProviderFactory.create as jest.Mock).mockResolvedValue(undefined);
|
|
564
|
-
|
|
565
|
-
const result = await client.createJudge(key, testContext, defaultValue);
|
|
566
|
-
|
|
567
|
-
expect(result).toBeUndefined();
|
|
568
|
-
expect(AIProviderFactory.create).toHaveBeenCalledWith(mockJudgeConfig, undefined, undefined);
|
|
569
|
-
expect(Judge).not.toHaveBeenCalled();
|
|
570
|
-
judgeConfigSpy.mockRestore();
|
|
571
|
-
});
|
|
572
|
-
|
|
573
|
-
it('handles errors gracefully', async () => {
|
|
574
|
-
const client = new LDAIClientImpl(mockLdClient);
|
|
575
|
-
const key = 'test-judge';
|
|
576
|
-
const defaultValue: LDAIJudgeConfigDefault = {
|
|
577
|
-
enabled: false,
|
|
578
|
-
};
|
|
579
|
-
|
|
580
|
-
const error = new Error('Judge configuration error');
|
|
581
|
-
const judgeConfigSpy = jest.spyOn(client, 'judgeConfig');
|
|
582
|
-
judgeConfigSpy.mockRejectedValue(error);
|
|
583
|
-
|
|
584
|
-
const result = await client.createJudge(key, testContext, defaultValue);
|
|
585
|
-
|
|
586
|
-
expect(result).toBeUndefined();
|
|
587
|
-
judgeConfigSpy.mockRestore();
|
|
588
|
-
});
|
|
589
|
-
});
|