Skip to content

Commit e46769b

Browse files
authored
fix: Make defaultValue optional with a disabled default (#1144)
1 parent 11e4a59 commit e46769b

10 files changed

Lines changed: 181 additions & 84 deletions

File tree

packages/sdk/server-ai/README.md

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -56,13 +56,9 @@ const defaultConfig = {
5656
};
5757
```
5858

59-
### Disabled Default
59+
### Default value
6060

61-
```typescript
62-
const defaultConfig = {
63-
enabled: false
64-
};
65-
```
61+
The `defaultValue` parameter is optional. When omitted, a disabled default is used.
6662

6763
## Retrieving AI Configurations
6864

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

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -740,3 +740,62 @@ describe('createJudge method', () => {
740740
judgeConfigSpy.mockRestore();
741741
});
742742
});
743+
744+
describe('optional default values', () => {
745+
it('uses a disabled completion config when no default is provided', async () => {
746+
const client = new LDAIClientImpl(mockLdClient);
747+
const key = 'test-flag';
748+
const disabledFlagValue = {
749+
_ldMeta: { variationKey: '', enabled: false, version: 1, mode: 'completion' },
750+
};
751+
mockLdClient.variation.mockResolvedValue(disabledFlagValue);
752+
753+
const result = await client.completionConfig(key, testContext);
754+
755+
expect(mockLdClient.variation).toHaveBeenCalledWith(
756+
key,
757+
testContext,
758+
expect.objectContaining({ _ldMeta: expect.objectContaining({ enabled: false }) }),
759+
);
760+
expect(result.enabled).toBe(false);
761+
});
762+
763+
it('uses a disabled agent config when no default is provided', async () => {
764+
const client = new LDAIClientImpl(mockLdClient);
765+
const key = 'test-agent';
766+
const disabledFlagValue = {
767+
_ldMeta: { variationKey: '', enabled: false, version: 1, mode: 'agent' },
768+
instructions: '',
769+
};
770+
mockLdClient.variation.mockResolvedValue(disabledFlagValue);
771+
772+
const result = await client.agentConfig(key, testContext);
773+
774+
expect(mockLdClient.variation).toHaveBeenCalledWith(
775+
key,
776+
testContext,
777+
expect.objectContaining({ _ldMeta: expect.objectContaining({ enabled: false }) }),
778+
);
779+
expect(result.enabled).toBe(false);
780+
});
781+
782+
it('uses a disabled judge config when no default is provided', async () => {
783+
const client = new LDAIClientImpl(mockLdClient);
784+
const key = 'test-judge';
785+
const disabledFlagValue = {
786+
_ldMeta: { variationKey: '', enabled: false, version: 1, mode: 'judge' },
787+
messages: [],
788+
evaluationMetricKeys: [],
789+
};
790+
mockLdClient.variation.mockResolvedValue(disabledFlagValue);
791+
792+
const result = await client.judgeConfig(key, testContext);
793+
794+
expect(mockLdClient.variation).toHaveBeenCalledWith(
795+
key,
796+
testContext,
797+
expect.objectContaining({ _ldMeta: expect.objectContaining({ enabled: false }) }),
798+
);
799+
expect(result.enabled).toBe(false);
800+
});
801+
});

packages/sdk/server-ai/examples/chat-observability/src/index.ts

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -38,14 +38,19 @@ async function main() {
3838
}
3939

4040
const aiClient = initAi(ldClient);
41-
const chat = await aiClient.createChat(
42-
aiConfigKey,
43-
context,
44-
{ enabled: false },
45-
{
46-
example_type: 'observability_demo',
47-
},
48-
);
41+
42+
// Pass a defaultValue for improved resiliency when the flag is unavailable or LaunchDarkly is unreachable; omit for a disabled default.
43+
// Example:
44+
// const defaultValue = {
45+
// enabled: true,
46+
// model: { name: 'gpt-4' },
47+
// provider: { name: 'openai' },
48+
// messages: [...]
49+
// };
50+
// const chat = await aiClient.createChat(aiConfigKey, context, defaultValue, { example_type: 'observability_demo' });
51+
const chat = await aiClient.createChat(aiConfigKey, context, undefined, {
52+
example_type: 'observability_demo',
53+
});
4954

5055
if (!chat) {
5156
console.log('*** AI chat configuration is not enabled');

packages/sdk/server-ai/examples/direct-judge/src/index.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,18 @@ async function main() {
3939
const aiClient = initAi(ldClient);
4040

4141
try {
42-
const judge = await aiClient.createJudge(judgeKey, context, { enabled: false });
42+
// Example using the judge functionality with direct input and output.
43+
//
44+
// Pass a defaultValue for improved resiliency when the flag is unavailable or LaunchDarkly is unreachable; omit for a disabled default.
45+
// Example:
46+
// const defaultValue = {
47+
// enabled: true,
48+
// model: { name: 'gpt-4' },
49+
// provider: { name: 'openai' },
50+
// messages: [...]
51+
// };
52+
// const judge = await aiClient.createJudge(judgeKey, context, defaultValue, { companyName: 'LaunchDarkly' })
53+
const judge = await aiClient.createJudge(judgeKey, context);
4354

4455
if (!judge) {
4556
console.log('*** AI judge configuration is not enabled');

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

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -47,17 +47,18 @@ async function main() {
4747

4848
const aiClient = initAi(ldClient);
4949

50-
const aiConfig = await aiClient.completionConfig(
51-
aiConfigKey,
52-
context,
53-
{
54-
model: {
55-
name: 'gpt-4',
56-
},
57-
enabled: false,
58-
},
59-
{ myVariable: 'My User Defined Variable' },
60-
);
50+
// Pass a defaultValue for improved resiliency when the flag is unavailable or LaunchDarkly is unreachable; omit for a disabled default.
51+
// Example:
52+
// const defaultValue = {
53+
// enabled: true,
54+
// model: { name: 'gpt-4' },
55+
// provider: { name: 'openai' },
56+
// messages: [...]
57+
// };
58+
// const aiConfig = await aiClient.completionConfig(aiConfigKey, context, defaultValue, { myVariable: '...' });
59+
const aiConfig = await aiClient.completionConfig(aiConfigKey, context, undefined, {
60+
myVariable: 'My User Defined Variable',
61+
});
6162

6263
if (!aiConfig.enabled || !aiConfig.tracker) {
6364
console.log('*** AI configuration is not enabled');

packages/sdk/server-ai/examples/tracked-chat/src/index.ts

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -35,20 +35,19 @@ async function main() {
3535
}
3636

3737
const aiClient = initAi(ldClient);
38-
const defaultValue = {
39-
enabled: true,
40-
model: { name: 'gpt-3.5-turbo' },
41-
messages: [{ role: 'system' as const, content: 'You are a helpful assistant.' }],
42-
provider: { name: 'openai' },
43-
};
4438

45-
// You provide a disabled default value
46-
// const defaultValue = {
47-
// enabled: false,
48-
// };
49-
50-
// Get AI chat configuration from LaunchDarkly
51-
const chat = await aiClient.createChat(aiConfigKey, context, defaultValue, {
39+
// Get AI chat configuration from LaunchDarkly.
40+
//
41+
// Pass a defaultValue for improved resiliency when the flag is unavailable or LaunchDarkly is unreachable; omit for a disabled default.
42+
// Example:
43+
// const defaultValue = {
44+
// enabled: true,
45+
// model: { name: 'gpt-4' },
46+
// provider: { name: 'openai' },
47+
// messages: [...]
48+
// };
49+
// const chat = await aiClient.createChat(aiConfigKey, context, defaultValue, { companyName: 'LaunchDarkly' });
50+
const chat = await aiClient.createChat(aiConfigKey, context, undefined, {
5251
companyName: 'LaunchDarkly',
5352
});
5453

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

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,18 @@ async function main() {
3939

4040
const aiClient = initAi(client);
4141

42-
// Get AI configuration from LaunchDarkly
43-
const aiConfig = await aiClient.completionConfig(aiConfigKey, context, {
44-
enabled: false,
45-
});
42+
// Get AI configuration from LaunchDarkly.
43+
//
44+
// Pass a defaultValue for improved resiliency when the flag is unavailable or LaunchDarkly is unreachable; omit for a disabled default.
45+
// Example:
46+
// const defaultValue = {
47+
// enabled: true,
48+
// model: { name: 'gpt-4' },
49+
// provider: { name: 'openai' },
50+
// messages: [...]
51+
// };
52+
// const aiConfig = await aiClient.completionConfig(aiConfigKey, context, defaultValue);
53+
const aiConfig = await aiClient.completionConfig(aiConfigKey, context);
4654

4755
if (!aiConfig.enabled || !aiConfig.tracker) {
4856
console.log('*** AI configuration is not enabled');

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

Lines changed: 34 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99
LDAIAgentRequestConfig,
1010
LDAICompletionConfig,
1111
LDAICompletionConfigDefault,
12+
LDAIConfigDefault,
1213
LDAIConfigDefaultKind,
1314
LDAIConfigKind,
1415
LDAIConfigMode,
@@ -42,6 +43,8 @@ const INIT_TRACK_CONTEXT: LDContext = {
4243
anonymous: true,
4344
};
4445

46+
const disabledAIConfig: LDAIConfigDefault = { enabled: false };
47+
4548
export class LDAIClientImpl implements LDAIClient {
4649
private _logger?: LDLogger;
4750

@@ -141,7 +144,7 @@ export class LDAIClientImpl implements LDAIClient {
141144
const judge = await this.createJudge(
142145
judgeConfig.key,
143146
context,
144-
{ enabled: false },
147+
undefined,
145148
variables,
146149
defaultAiProvider,
147150
);
@@ -171,12 +174,11 @@ export class LDAIClientImpl implements LDAIClient {
171174
async completionConfig(
172175
key: string,
173176
context: LDContext,
174-
defaultValue: LDAICompletionConfigDefault,
177+
defaultValue?: LDAICompletionConfigDefault,
175178
variables?: Record<string, unknown>,
176179
): Promise<LDAICompletionConfig> {
177180
this._ldClient.track(TRACK_USAGE_COMPLETION_CONFIG, context, key, 1);
178-
179-
return this._completionConfig(key, context, defaultValue, variables);
181+
return this._completionConfig(key, context, defaultValue ?? disabledAIConfig, variables);
180182
}
181183

182184
/**
@@ -185,7 +187,7 @@ export class LDAIClientImpl implements LDAIClient {
185187
async config(
186188
key: string,
187189
context: LDContext,
188-
defaultValue: LDAICompletionConfigDefault,
190+
defaultValue?: LDAICompletionConfigDefault,
189191
variables?: Record<string, unknown>,
190192
): Promise<LDAICompletionConfig> {
191193
return this.completionConfig(key, context, defaultValue, variables);
@@ -204,23 +206,27 @@ export class LDAIClientImpl implements LDAIClient {
204206
async judgeConfig(
205207
key: string,
206208
context: LDContext,
207-
defaultValue: LDAIJudgeConfigDefault,
209+
defaultValue?: LDAIJudgeConfigDefault,
208210
variables?: Record<string, unknown>,
209211
): Promise<LDAIJudgeConfig> {
210212
this._ldClient.track(TRACK_USAGE_JUDGE_CONFIG, context, key, 1);
211-
212-
return this._judgeConfig(key, context, defaultValue, variables);
213+
return this._judgeConfig(key, context, defaultValue ?? disabledAIConfig, variables);
213214
}
214215

215216
async agentConfig(
216217
key: string,
217218
context: LDContext,
218-
defaultValue: LDAIAgentConfigDefault,
219+
defaultValue?: LDAIAgentConfigDefault,
219220
variables?: Record<string, unknown>,
220221
): Promise<LDAIAgentConfig> {
221222
this._ldClient.track(TRACK_USAGE_AGENT_CONFIG, context, key, 1);
222-
223-
const config = await this._evaluate(key, context, defaultValue, 'agent', variables);
223+
const config = await this._evaluate(
224+
key,
225+
context,
226+
defaultValue ?? disabledAIConfig,
227+
'agent',
228+
variables,
229+
);
224230
return config as LDAIAgentConfig;
225231
}
226232

@@ -230,7 +236,7 @@ export class LDAIClientImpl implements LDAIClient {
230236
async agent(
231237
key: string,
232238
context: LDContext,
233-
defaultValue: LDAIAgentConfigDefault,
239+
defaultValue?: LDAIAgentConfigDefault,
234240
variables?: Record<string, unknown>,
235241
): Promise<LDAIAgentConfig> {
236242
return this.agentConfig(key, context, defaultValue, variables);
@@ -254,7 +260,7 @@ export class LDAIClientImpl implements LDAIClient {
254260
const agent = await this._evaluate(
255261
config.key,
256262
context,
257-
config.defaultValue,
263+
config.defaultValue ?? disabledAIConfig,
258264
'agent',
259265
config.variables,
260266
);
@@ -278,13 +284,17 @@ export class LDAIClientImpl implements LDAIClient {
278284
async createChat(
279285
key: string,
280286
context: LDContext,
281-
defaultValue: LDAICompletionConfigDefault,
287+
defaultValue?: LDAICompletionConfigDefault,
282288
variables?: Record<string, unknown>,
283289
defaultAiProvider?: SupportedAIProvider,
284290
): Promise<TrackedChat | undefined> {
285291
this._ldClient.track(TRACK_USAGE_CREATE_CHAT, context, key, 1);
286-
287-
const config = await this._completionConfig(key, context, defaultValue, variables);
292+
const config = await this._completionConfig(
293+
key,
294+
context,
295+
defaultValue ?? disabledAIConfig,
296+
variables,
297+
);
288298

289299
if (!config.enabled || !config.tracker) {
290300
this._logger?.info(`Chat configuration is disabled: ${key}`);
@@ -309,7 +319,7 @@ export class LDAIClientImpl implements LDAIClient {
309319
async createJudge(
310320
key: string,
311321
context: LDContext,
312-
defaultValue: LDAIJudgeConfigDefault,
322+
defaultValue?: LDAIJudgeConfigDefault,
313323
variables?: Record<string, unknown>,
314324
defaultAiProvider?: SupportedAIProvider,
315325
): Promise<Judge | undefined> {
@@ -334,7 +344,12 @@ export class LDAIClientImpl implements LDAIClient {
334344
response_to_evaluate: '{{response_to_evaluate}}',
335345
};
336346

337-
const judgeConfig = await this._judgeConfig(key, context, defaultValue, extendedVariables);
347+
const judgeConfig = await this._judgeConfig(
348+
key,
349+
context,
350+
defaultValue ?? disabledAIConfig,
351+
extendedVariables,
352+
);
338353

339354
if (!judgeConfig.enabled || !judgeConfig.tracker) {
340355
this._logger?.info(`Judge configuration is disabled: ${key}`);
@@ -359,7 +374,7 @@ export class LDAIClientImpl implements LDAIClient {
359374
async initChat(
360375
key: string,
361376
context: LDContext,
362-
defaultValue: LDAICompletionConfigDefault,
377+
defaultValue?: LDAICompletionConfigDefault,
363378
variables?: Record<string, unknown>,
364379
defaultAiProvider?: SupportedAIProvider,
365380
): Promise<TrackedChat | undefined> {

0 commit comments

Comments
 (0)