Skip to content

Commit cd72ea8

Browse files
authored
feat!: Updated AI config interface. (#697)
1 parent 6524030 commit cd72ea8

File tree

10 files changed

+88
-91
lines changed

10 files changed

+88
-91
lines changed

packages/sdk/server-ai/__tests__/LDAIClientImpl.test.ts

Lines changed: 39 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -11,36 +11,24 @@ const mockLdClient: jest.Mocked<LDClientMin> = {
1111

1212
const testContext: LDContext = { kind: 'user', key: 'test-user' };
1313

14-
it('interpolates template variables', () => {
15-
const client = new LDAIClientImpl(mockLdClient);
16-
const template = 'Hello {{name}}, your score is {{score}}';
17-
const variables = { name: 'John', score: 42 };
18-
19-
const result = client.interpolateTemplate(template, variables);
20-
expect(result).toBe('Hello John, your score is 42');
21-
});
22-
23-
it('handles empty variables in template interpolation', () => {
24-
const client = new LDAIClientImpl(mockLdClient);
25-
const template = 'Hello {{name}}';
26-
const variables = {};
27-
28-
const result = client.interpolateTemplate(template, variables);
29-
expect(result).toBe('Hello ');
30-
});
31-
32-
it('returns model config with interpolated prompts', async () => {
14+
it('returns config with interpolated messagess', async () => {
3315
const client = new LDAIClientImpl(mockLdClient);
3416
const key = 'test-flag';
3517
const defaultValue: LDAIDefaults = {
36-
model: { modelId: 'test', name: 'test-model' },
37-
prompt: [],
18+
model: { id: 'test', parameters: { name: 'test-model' } },
19+
messages: [],
3820
enabled: true,
3921
};
4022

4123
const mockVariation = {
42-
model: { modelId: 'example-provider', name: 'imagination', temperature: 0.7, maxTokens: 4096 },
43-
prompt: [
24+
model: {
25+
id: 'example-model',
26+
parameters: { name: 'imagination', temperature: 0.7, maxTokens: 4096 },
27+
},
28+
provider: {
29+
id: 'example-provider',
30+
},
31+
messages: [
4432
{ role: 'system', content: 'Hello {{name}}' },
4533
{ role: 'user', content: 'Score: {{score}}' },
4634
],
@@ -53,11 +41,17 @@ it('returns model config with interpolated prompts', async () => {
5341
mockLdClient.variation.mockResolvedValue(mockVariation);
5442

5543
const variables = { name: 'John', score: 42 };
56-
const result = await client.modelConfig(key, testContext, defaultValue, variables);
44+
const result = await client.config(key, testContext, defaultValue, variables);
5745

5846
expect(result).toEqual({
59-
model: { modelId: 'example-provider', name: 'imagination', temperature: 0.7, maxTokens: 4096 },
60-
prompt: [
47+
model: {
48+
id: 'example-model',
49+
parameters: { name: 'imagination', temperature: 0.7, maxTokens: 4096 },
50+
},
51+
provider: {
52+
id: 'example-provider',
53+
},
54+
messages: [
6155
{ role: 'system', content: 'Hello John' },
6256
{ role: 'user', content: 'Score: 42' },
6357
],
@@ -66,46 +60,46 @@ it('returns model config with interpolated prompts', async () => {
6660
});
6761
});
6862

69-
it('includes context in variables for prompt interpolation', async () => {
63+
it('includes context in variables for messages interpolation', async () => {
7064
const client = new LDAIClientImpl(mockLdClient);
7165
const key = 'test-flag';
7266
const defaultValue: LDAIDefaults = {
73-
model: { modelId: 'test', name: 'test-model' },
74-
prompt: [],
67+
model: { id: 'test', parameters: { name: 'test-model' } },
68+
messages: [],
7569
};
7670

7771
const mockVariation = {
78-
prompt: [{ role: 'system', content: 'User key: {{ldctx.key}}' }],
72+
messages: [{ role: 'system', content: 'User key: {{ldctx.key}}' }],
7973
_ldMeta: { versionKey: 'v1', enabled: true },
8074
};
8175

8276
mockLdClient.variation.mockResolvedValue(mockVariation);
8377

84-
const result = await client.modelConfig(key, testContext, defaultValue);
78+
const result = await client.config(key, testContext, defaultValue);
8579

86-
expect(result.prompt?.[0].content).toBe('User key: test-user');
80+
expect(result.messages?.[0].content).toBe('User key: test-user');
8781
});
8882

8983
it('handles missing metadata in variation', async () => {
9084
const client = new LDAIClientImpl(mockLdClient);
9185
const key = 'test-flag';
9286
const defaultValue: LDAIDefaults = {
93-
model: { modelId: 'test', name: 'test-model' },
94-
prompt: [],
87+
model: { id: 'test', parameters: { name: 'test-model' } },
88+
messages: [],
9589
};
9690

9791
const mockVariation = {
98-
model: { modelId: 'example-provider', name: 'imagination' },
99-
prompt: [{ role: 'system', content: 'Hello' }],
92+
model: { id: 'example-provider', parameters: { name: 'imagination' } },
93+
messages: [{ role: 'system', content: 'Hello' }],
10094
};
10195

10296
mockLdClient.variation.mockResolvedValue(mockVariation);
10397

104-
const result = await client.modelConfig(key, testContext, defaultValue);
98+
const result = await client.config(key, testContext, defaultValue);
10599

106100
expect(result).toEqual({
107-
model: { modelId: 'example-provider', name: 'imagination' },
108-
prompt: [{ role: 'system', content: 'Hello' }],
101+
model: { id: 'example-provider', parameters: { name: 'imagination' } },
102+
messages: [{ role: 'system', content: 'Hello' }],
109103
tracker: expect.any(Object),
110104
enabled: false,
111105
});
@@ -115,18 +109,20 @@ it('passes the default value to the underlying client', async () => {
115109
const client = new LDAIClientImpl(mockLdClient);
116110
const key = 'non-existent-flag';
117111
const defaultValue: LDAIDefaults = {
118-
model: { modelId: 'default-model', name: 'default' },
119-
prompt: [{ role: 'system', content: 'Default prompt' }],
112+
model: { id: 'default-model', parameters: { name: 'default' } },
113+
provider: { id: 'default-provider' },
114+
messages: [{ role: 'system', content: 'Default messages' }],
120115
enabled: true,
121116
};
122117

123118
mockLdClient.variation.mockResolvedValue(defaultValue);
124119

125-
const result = await client.modelConfig(key, testContext, defaultValue);
120+
const result = await client.config(key, testContext, defaultValue);
126121

127122
expect(result).toEqual({
128123
model: defaultValue.model,
129-
prompt: defaultValue.prompt,
124+
messages: defaultValue.messages,
125+
provider: defaultValue.provider,
130126
tracker: expect.any(Object),
131127
enabled: false,
132128
});

packages/sdk/server-ai/__tests__/LDAIConfigTrackerImpl.test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ it('tracks OpenAI usage', async () => {
9090
const PROMPT_TOKENS = 49;
9191
const COMPLETION_TOKENS = 51;
9292

93-
await tracker.trackOpenAI(async () => ({
93+
await tracker.trackOpenAIMetrics(async () => ({
9494
usage: {
9595
total_tokens: TOTAL_TOKENS,
9696
prompt_tokens: PROMPT_TOKENS,
@@ -151,7 +151,7 @@ it('tracks Bedrock conversation with successful response', () => {
151151
},
152152
};
153153

154-
tracker.trackBedrockConverse(response);
154+
tracker.trackBedrockConverseMetrics(response);
155155

156156
expect(mockTrack).toHaveBeenCalledWith(
157157
'$ld:ai:generation',
@@ -198,7 +198,7 @@ it('tracks Bedrock conversation with error response', () => {
198198

199199
// TODO: We may want a track failure.
200200

201-
tracker.trackBedrockConverse(response);
201+
tracker.trackBedrockConverseMetrics(response);
202202

203203
expect(mockTrack).not.toHaveBeenCalled();
204204
});

packages/sdk/server-ai/examples/bedrock/src/index.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -48,12 +48,12 @@ async function main() {
4848

4949
const aiClient = initAi(ldClient);
5050

51-
const aiConfig = await aiClient.modelConfig(
51+
const aiConfig = await aiClient.config(
5252
aiConfigKey!,
5353
context,
5454
{
5555
model: {
56-
modelId: 'my-default-model',
56+
id: 'my-default-model',
5757
},
5858
enabled: true,
5959
},
@@ -63,14 +63,14 @@ async function main() {
6363
);
6464
const { tracker } = aiConfig;
6565

66-
const completion = tracker.trackBedrockConverse(
66+
const completion = tracker.trackBedrockConverseMetrics(
6767
await awsClient.send(
6868
new ConverseCommand({
69-
modelId: aiConfig.model?.modelId ?? 'no-model',
70-
messages: mapPromptToConversation(aiConfig.prompt ?? []),
69+
modelId: aiConfig.model?.id ?? 'no-model',
70+
messages: mapPromptToConversation(aiConfig.messages ?? []),
7171
inferenceConfig: {
72-
temperature: aiConfig.model?.temperature ?? 0.5,
73-
maxTokens: aiConfig.model?.maxTokens ?? 4096,
72+
temperature: (aiConfig.model?.parameters?.temperature as number) ?? 0.5,
73+
maxTokens: (aiConfig.model?.parameters?.maxTokens as number) ?? 4096,
7474
},
7575
}),
7676
),

packages/sdk/server-ai/examples/openai/src/index.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -46,24 +46,24 @@ async function main(): Promise<void> {
4646

4747
const aiClient = initAi(ldClient);
4848

49-
const aiConfig = await aiClient.modelConfig(
49+
const aiConfig = await aiClient.config(
5050
aiConfigKey,
5151
context,
5252
{
5353
model: {
54-
modelId: 'gpt-4',
54+
id: 'gpt-4',
5555
},
5656
},
5757
{ myVariable: 'My User Defined Variable' },
5858
);
5959

6060
const { tracker } = aiConfig;
61-
const completion = await tracker.trackOpenAI(async () =>
61+
const completion = await tracker.trackOpenAIMetrics(async () =>
6262
client.chat.completions.create({
63-
messages: aiConfig.prompt || [],
64-
model: aiConfig.model?.modelId || 'gpt-4',
65-
temperature: aiConfig.model?.temperature ?? 0.5,
66-
max_tokens: aiConfig.model?.maxTokens ?? 4096,
63+
messages: aiConfig.messages || [],
64+
model: aiConfig.model?.id || 'gpt-4',
65+
temperature: (aiConfig.model?.parameters?.temperature as number) ?? 0.5,
66+
max_tokens: (aiConfig.model?.parameters?.maxTokens as number) ?? 4096,
6767
}),
6868
);
6969

packages/sdk/server-ai/src/LDAIClientImpl.ts

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import * as Mustache from 'mustache';
22

33
import { LDContext } from '@launchdarkly/js-server-sdk-common';
44

5-
import { LDAIConfig, LDAIDefaults, LDMessage, LDModelConfig } from './api/config';
5+
import { LDAIConfig, LDAIDefaults, LDMessage, LDModelConfig, LDProviderConfig } from './api/config';
66
import { LDAIClient } from './api/LDAIClient';
77
import { LDAIConfigTrackerImpl } from './LDAIConfigTrackerImpl';
88
import { LDClientMin } from './LDClientMin';
@@ -21,18 +21,19 @@ interface LDMeta {
2121
*/
2222
interface VariationContent {
2323
model?: LDModelConfig;
24-
prompt?: LDMessage[];
24+
messages?: LDMessage[];
25+
provider?: LDProviderConfig;
2526
_ldMeta?: LDMeta;
2627
}
2728

2829
export class LDAIClientImpl implements LDAIClient {
2930
constructor(private _ldClient: LDClientMin) {}
3031

31-
interpolateTemplate(template: string, variables: Record<string, unknown>): string {
32+
private _interpolateTemplate(template: string, variables: Record<string, unknown>): string {
3233
return Mustache.render(template, variables, undefined, { escape: (item: any) => item });
3334
}
3435

35-
async modelConfig(
36+
async config(
3637
key: string,
3738
context: LDContext,
3839
defaultValue: LDAIDefaults,
@@ -57,12 +58,15 @@ export class LDAIClientImpl implements LDAIClient {
5758
if (value.model) {
5859
config.model = { ...value.model };
5960
}
61+
if (value.provider) {
62+
config.provider = { ...value.provider };
63+
}
6064
const allVariables = { ...variables, ldctx: context };
6165

62-
if (value.prompt) {
63-
config.prompt = value.prompt.map((entry: any) => ({
66+
if (value.messages) {
67+
config.messages = value.messages.map((entry: any) => ({
6468
...entry,
65-
content: this.interpolateTemplate(entry.content, allVariables),
69+
content: this._interpolateTemplate(entry.content, allVariables),
6670
}));
6771
}
6872

packages/sdk/server-ai/src/LDAIConfigTrackerImpl.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ export class LDAIConfigTrackerImpl implements LDAIConfigTracker {
4545
this._ldClient.track('$ld:ai:generation', this._context, this._getTrackData(), 1);
4646
}
4747

48-
async trackOpenAI<
48+
async trackOpenAIMetrics<
4949
TRes extends {
5050
usage?: {
5151
total_tokens?: number;
@@ -62,7 +62,7 @@ export class LDAIConfigTrackerImpl implements LDAIConfigTracker {
6262
return result;
6363
}
6464

65-
trackBedrockConverse<
65+
trackBedrockConverseMetrics<
6666
TRes extends {
6767
$metadata: { httpStatusCode?: number };
6868
metrics?: { latencyMs?: number };

packages/sdk/server-ai/src/api/LDAIClient.ts

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,6 @@ import { LDAIConfig, LDAIDefaults } from './config/LDAIConfig';
66
* Interface for performing AI operations using LaunchDarkly.
77
*/
88
export interface LDAIClient {
9-
/**
10-
* Parses and interpolates a template string with the provided variables.
11-
*
12-
* @param template The template string to be parsed and interpolated.
13-
* @param variables An object containing the variables to be used for interpolation.
14-
* @returns The interpolated string.
15-
*/
16-
interpolateTemplate(template: string, variables: Record<string, unknown>): string;
17-
189
/**
1910
* Retrieves and processes an AI configuration based on the provided key, LaunchDarkly context,
2011
* and variables. This includes the model configuration and the processed prompts.
@@ -67,7 +58,7 @@ export interface LDAIClient {
6758
* }
6859
* ```
6960
*/
70-
modelConfig(
61+
config(
7162
key: string,
7263
context: LDContext,
7364
defaultValue: LDAIDefaults,

packages/sdk/server-ai/src/api/config/LDAIConfig.ts

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,23 +7,24 @@ export interface LDModelConfig {
77
/**
88
* The ID of the model.
99
*/
10-
modelId: string;
10+
id: string;
1111

1212
/**
13-
* Tuning parameter for randomness versus determinism. Exact effect will be determined by the
14-
* model.
13+
* Model specific parameters.
1514
*/
16-
temperature?: number;
15+
parameters?: { [index: string]: unknown };
1716

1817
/**
19-
* The maximum number of tokens.
18+
* Additional user-specified parameters.
2019
*/
21-
maxTokens?: number;
20+
custom?: { [index: string]: unknown };
21+
}
2222

23+
export interface LDProviderConfig {
2324
/**
24-
* And additional model specific information.
25+
* The ID of the provider.
2526
*/
26-
[index: string]: unknown;
27+
id: string;
2728
}
2829

2930
/**
@@ -51,7 +52,12 @@ export interface LDAIConfig {
5152
/**
5253
* Optional prompt data.
5354
*/
54-
prompt?: LDMessage[];
55+
messages?: LDMessage[];
56+
57+
/**
58+
* Optional configuration for the provider.
59+
*/
60+
provider?: LDProviderConfig;
5561

5662
/**
5763
* A tracker which can be used to generate analytics.

0 commit comments

Comments
 (0)