@launchdarkly/server-sdk-ai 0.10.1 → 0.11.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 +13 -0
- package/__tests__/LDAIClientImpl.test.ts +328 -1
- package/__tests__/LDAIConfigTrackerImpl.test.ts +94 -136
- package/dist/LDAIClientImpl.d.ts +7 -0
- package/dist/LDAIClientImpl.d.ts.map +1 -1
- package/dist/LDAIClientImpl.js +60 -11
- package/dist/LDAIClientImpl.js.map +1 -1
- package/dist/LDAIConfigTrackerImpl.d.ts +3 -1
- package/dist/LDAIConfigTrackerImpl.d.ts.map +1 -1
- package/dist/LDAIConfigTrackerImpl.js +5 -3
- package/dist/LDAIConfigTrackerImpl.js.map +1 -1
- package/dist/api/LDAIClient.d.ts +70 -0
- package/dist/api/LDAIClient.d.ts.map +1 -1
- package/dist/api/agents/LDAIAgent.d.ts +32 -0
- package/dist/api/agents/LDAIAgent.d.ts.map +1 -0
- package/dist/api/agents/LDAIAgent.js +3 -0
- package/dist/api/agents/LDAIAgent.js.map +1 -0
- package/dist/api/agents/index.d.ts +2 -0
- package/dist/api/agents/index.d.ts.map +1 -0
- package/dist/api/agents/index.js +18 -0
- package/dist/api/agents/index.js.map +1 -0
- package/dist/api/index.d.ts +1 -0
- package/dist/api/index.d.ts.map +1 -1
- package/dist/api/index.js +1 -0
- package/dist/api/index.js.map +1 -1
- package/docs/assets/highlight.css +15 -8
- package/docs/assets/search.js +1 -1
- package/docs/enums/LDFeedbackKind.html +11 -8
- package/docs/functions/createBedrockTokenUsage.html +9 -6
- package/docs/functions/createOpenAiUsage.html +9 -6
- package/docs/functions/createVercelAISDKTokenUsage.html +9 -6
- package/docs/functions/initAi.html +9 -6
- package/docs/index.html +12 -6
- package/docs/interfaces/LDAIAgent.html +177 -0
- package/docs/interfaces/LDAIAgentConfig.html +111 -0
- package/docs/interfaces/LDAIClient.html +96 -10
- package/docs/interfaces/LDAIConfig.html +15 -12
- package/docs/interfaces/LDAIConfigTracker.html +21 -18
- package/docs/interfaces/LDMessage.html +11 -8
- package/docs/interfaces/LDModelConfig.html +12 -9
- package/docs/interfaces/LDProviderConfig.html +10 -7
- package/docs/interfaces/LDTokenUsage.html +12 -9
- package/docs/interfaces/VercelAISDKConfig.html +19 -16
- package/docs/interfaces/VercelAISDKMapOptions.html +10 -7
- package/docs/types/LDAIAgentDefaults.html +63 -0
- package/docs/types/LDAIDefaults.html +9 -6
- package/docs/types/VercelAISDKProvider.html +9 -6
- package/package.json +1 -1
- package/src/LDAIClientImpl.ts +146 -12
- package/src/LDAIConfigTrackerImpl.ts +11 -3
- package/src/api/LDAIClient.ts +80 -0
- package/src/api/agents/LDAIAgent.ts +36 -0
- package/src/api/agents/index.ts +1 -0
- package/src/api/index.ts +1 -0
package/src/LDAIClientImpl.ts
CHANGED
|
@@ -2,8 +2,10 @@ import * as Mustache from 'mustache';
|
|
|
2
2
|
|
|
3
3
|
import { LDContext } from '@launchdarkly/js-server-sdk-common';
|
|
4
4
|
|
|
5
|
+
import { LDAIAgent, LDAIAgentConfig, LDAIAgentDefaults } from './api/agents';
|
|
5
6
|
import {
|
|
6
7
|
LDAIConfig,
|
|
8
|
+
LDAIConfigTracker,
|
|
7
9
|
LDAIDefaults,
|
|
8
10
|
LDMessage,
|
|
9
11
|
LDModelConfig,
|
|
@@ -17,13 +19,16 @@ import { LDAIConfigMapper } from './LDAIConfigMapper';
|
|
|
17
19
|
import { LDAIConfigTrackerImpl } from './LDAIConfigTrackerImpl';
|
|
18
20
|
import { LDClientMin } from './LDClientMin';
|
|
19
21
|
|
|
22
|
+
type Mode = 'completion' | 'agent';
|
|
23
|
+
|
|
20
24
|
/**
|
|
21
|
-
* Metadata
|
|
25
|
+
* Metadata associated with a model configuration variation.
|
|
22
26
|
*/
|
|
23
27
|
interface LDMeta {
|
|
24
28
|
variationKey: string;
|
|
25
29
|
enabled: boolean;
|
|
26
30
|
version?: number;
|
|
31
|
+
mode?: Mode;
|
|
27
32
|
}
|
|
28
33
|
|
|
29
34
|
/**
|
|
@@ -33,10 +38,24 @@ interface LDMeta {
|
|
|
33
38
|
interface VariationContent {
|
|
34
39
|
model?: LDModelConfig;
|
|
35
40
|
messages?: LDMessage[];
|
|
41
|
+
instructions?: string;
|
|
36
42
|
provider?: LDProviderConfig;
|
|
37
43
|
_ldMeta?: LDMeta;
|
|
38
44
|
}
|
|
39
45
|
|
|
46
|
+
/**
|
|
47
|
+
* The result of evaluating a configuration.
|
|
48
|
+
*/
|
|
49
|
+
interface EvaluationResult {
|
|
50
|
+
tracker: LDAIConfigTracker;
|
|
51
|
+
enabled: boolean;
|
|
52
|
+
model?: LDModelConfig;
|
|
53
|
+
provider?: LDProviderConfig;
|
|
54
|
+
messages?: LDMessage[];
|
|
55
|
+
instructions?: string;
|
|
56
|
+
mode?: string;
|
|
57
|
+
}
|
|
58
|
+
|
|
40
59
|
export class LDAIClientImpl implements LDAIClient {
|
|
41
60
|
constructor(private _ldClient: LDClientMin) {}
|
|
42
61
|
|
|
@@ -44,13 +63,13 @@ export class LDAIClientImpl implements LDAIClient {
|
|
|
44
63
|
return Mustache.render(template, variables, undefined, { escape: (item: any) => item });
|
|
45
64
|
}
|
|
46
65
|
|
|
47
|
-
async
|
|
66
|
+
private async _evaluate(
|
|
48
67
|
key: string,
|
|
49
68
|
context: LDContext,
|
|
50
69
|
defaultValue: LDAIDefaults,
|
|
51
|
-
|
|
52
|
-
): Promise<LDAIConfig> {
|
|
70
|
+
): Promise<EvaluationResult> {
|
|
53
71
|
const value: VariationContent = await this._ldClient.variation(key, context, defaultValue);
|
|
72
|
+
|
|
54
73
|
const tracker = new LDAIConfigTrackerImpl(
|
|
55
74
|
this._ldClient,
|
|
56
75
|
key,
|
|
@@ -58,26 +77,100 @@ export class LDAIClientImpl implements LDAIClient {
|
|
|
58
77
|
value._ldMeta?.variationKey ?? '',
|
|
59
78
|
// eslint-disable-next-line no-underscore-dangle
|
|
60
79
|
value._ldMeta?.version ?? 1,
|
|
80
|
+
value.model?.name ?? '',
|
|
81
|
+
value.provider?.name ?? '',
|
|
61
82
|
context,
|
|
62
83
|
);
|
|
84
|
+
|
|
63
85
|
// eslint-disable-next-line no-underscore-dangle
|
|
64
86
|
const enabled = !!value._ldMeta?.enabled;
|
|
87
|
+
|
|
88
|
+
return {
|
|
89
|
+
tracker,
|
|
90
|
+
enabled,
|
|
91
|
+
model: value.model,
|
|
92
|
+
provider: value.provider,
|
|
93
|
+
messages: value.messages,
|
|
94
|
+
instructions: value.instructions,
|
|
95
|
+
// eslint-disable-next-line no-underscore-dangle
|
|
96
|
+
mode: value._ldMeta?.mode ?? 'completion',
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
private async _evaluateAgent(
|
|
101
|
+
key: string,
|
|
102
|
+
context: LDContext,
|
|
103
|
+
defaultValue: LDAIAgentDefaults,
|
|
104
|
+
variables?: Record<string, unknown>,
|
|
105
|
+
): Promise<LDAIAgent> {
|
|
106
|
+
const { tracker, enabled, model, provider, instructions } = await this._evaluate(
|
|
107
|
+
key,
|
|
108
|
+
context,
|
|
109
|
+
defaultValue,
|
|
110
|
+
);
|
|
111
|
+
|
|
112
|
+
const mapper = new LDAIConfigMapper(model, provider, undefined);
|
|
113
|
+
const agent: Omit<LDAIAgent, 'toVercelAISDK'> = {
|
|
114
|
+
tracker,
|
|
115
|
+
enabled,
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
// We are going to modify the contents before returning them, so we make a copy.
|
|
119
|
+
// This isn't a deep copy and the application developer should not modify the returned content.
|
|
120
|
+
if (model) {
|
|
121
|
+
agent.model = { ...model };
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (provider) {
|
|
125
|
+
agent.provider = { ...provider };
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const allVariables = { ...variables, ldctx: context };
|
|
129
|
+
|
|
130
|
+
if (instructions) {
|
|
131
|
+
agent.instructions = this._interpolateTemplate(instructions, allVariables);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
return {
|
|
135
|
+
...agent,
|
|
136
|
+
toVercelAISDK: <TMod>(
|
|
137
|
+
sdkProvider: VercelAISDKProvider<TMod> | Record<string, VercelAISDKProvider<TMod>>,
|
|
138
|
+
options?: VercelAISDKMapOptions | undefined,
|
|
139
|
+
): VercelAISDKConfig<TMod> => mapper.toVercelAISDK(sdkProvider, options),
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
async config(
|
|
144
|
+
key: string,
|
|
145
|
+
context: LDContext,
|
|
146
|
+
defaultValue: LDAIDefaults,
|
|
147
|
+
variables?: Record<string, unknown>,
|
|
148
|
+
): Promise<LDAIConfig> {
|
|
149
|
+
const {
|
|
150
|
+
tracker,
|
|
151
|
+
enabled,
|
|
152
|
+
model,
|
|
153
|
+
provider: configProvider,
|
|
154
|
+
messages,
|
|
155
|
+
} = await this._evaluate(key, context, defaultValue);
|
|
156
|
+
|
|
65
157
|
const config: Omit<LDAIConfig, 'toVercelAISDK'> = {
|
|
66
158
|
tracker,
|
|
67
159
|
enabled,
|
|
68
160
|
};
|
|
161
|
+
|
|
69
162
|
// We are going to modify the contents before returning them, so we make a copy.
|
|
70
163
|
// This isn't a deep copy and the application developer should not modify the returned content.
|
|
71
|
-
if (
|
|
72
|
-
config.model = { ...
|
|
164
|
+
if (model) {
|
|
165
|
+
config.model = { ...model };
|
|
73
166
|
}
|
|
74
|
-
if (
|
|
75
|
-
config.provider = { ...
|
|
167
|
+
if (configProvider) {
|
|
168
|
+
config.provider = { ...configProvider };
|
|
76
169
|
}
|
|
77
170
|
const allVariables = { ...variables, ldctx: context };
|
|
78
171
|
|
|
79
|
-
if (
|
|
80
|
-
config.messages =
|
|
172
|
+
if (messages) {
|
|
173
|
+
config.messages = messages.map((entry: any) => ({
|
|
81
174
|
...entry,
|
|
82
175
|
content: this._interpolateTemplate(entry.content, allVariables),
|
|
83
176
|
}));
|
|
@@ -88,9 +181,50 @@ export class LDAIClientImpl implements LDAIClient {
|
|
|
88
181
|
return {
|
|
89
182
|
...config,
|
|
90
183
|
toVercelAISDK: <TMod>(
|
|
91
|
-
|
|
184
|
+
sdkProvider: VercelAISDKProvider<TMod> | Record<string, VercelAISDKProvider<TMod>>,
|
|
92
185
|
options?: VercelAISDKMapOptions | undefined,
|
|
93
|
-
): VercelAISDKConfig<TMod> => mapper.toVercelAISDK(
|
|
186
|
+
): VercelAISDKConfig<TMod> => mapper.toVercelAISDK(sdkProvider, options),
|
|
94
187
|
};
|
|
95
188
|
}
|
|
189
|
+
|
|
190
|
+
async agent(
|
|
191
|
+
key: string,
|
|
192
|
+
context: LDContext,
|
|
193
|
+
defaultValue: LDAIAgentDefaults,
|
|
194
|
+
variables?: Record<string, unknown>,
|
|
195
|
+
): Promise<LDAIAgent> {
|
|
196
|
+
// Track agent usage
|
|
197
|
+
this._ldClient.track('$ld:ai:agent:function:single', context, key, 1);
|
|
198
|
+
|
|
199
|
+
return this._evaluateAgent(key, context, defaultValue, variables);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
async agents<const T extends readonly (LDAIAgentConfig & { defaultValue: LDAIAgentDefaults })[]>(
|
|
203
|
+
agentConfigs: T,
|
|
204
|
+
context: LDContext,
|
|
205
|
+
): Promise<Record<T[number]['key'], LDAIAgent>> {
|
|
206
|
+
// Track multiple agents usage
|
|
207
|
+
this._ldClient.track(
|
|
208
|
+
'$ld:ai:agent:function:multiple',
|
|
209
|
+
context,
|
|
210
|
+
agentConfigs.length,
|
|
211
|
+
agentConfigs.length,
|
|
212
|
+
);
|
|
213
|
+
|
|
214
|
+
const agents = {} as Record<T[number]['key'], LDAIAgent>;
|
|
215
|
+
|
|
216
|
+
await Promise.all(
|
|
217
|
+
agentConfigs.map(async (config) => {
|
|
218
|
+
const agent = await this._evaluateAgent(
|
|
219
|
+
config.key,
|
|
220
|
+
context,
|
|
221
|
+
config.defaultValue,
|
|
222
|
+
config.variables,
|
|
223
|
+
);
|
|
224
|
+
agents[config.key as T[number]['key']] = agent;
|
|
225
|
+
}),
|
|
226
|
+
);
|
|
227
|
+
|
|
228
|
+
return agents;
|
|
229
|
+
}
|
|
96
230
|
}
|
|
@@ -19,14 +19,24 @@ export class LDAIConfigTrackerImpl implements LDAIConfigTracker {
|
|
|
19
19
|
private _configKey: string,
|
|
20
20
|
private _variationKey: string,
|
|
21
21
|
private _version: number,
|
|
22
|
+
private _modelName: string,
|
|
23
|
+
private _providerName: string,
|
|
22
24
|
private _context: LDContext,
|
|
23
25
|
) {}
|
|
24
26
|
|
|
25
|
-
private _getTrackData(): {
|
|
27
|
+
private _getTrackData(): {
|
|
28
|
+
variationKey: string;
|
|
29
|
+
configKey: string;
|
|
30
|
+
version: number;
|
|
31
|
+
modelName: string;
|
|
32
|
+
providerName: string;
|
|
33
|
+
} {
|
|
26
34
|
return {
|
|
27
35
|
variationKey: this._variationKey,
|
|
28
36
|
configKey: this._configKey,
|
|
29
37
|
version: this._version,
|
|
38
|
+
modelName: this._modelName,
|
|
39
|
+
providerName: this._providerName,
|
|
30
40
|
};
|
|
31
41
|
}
|
|
32
42
|
|
|
@@ -69,13 +79,11 @@ export class LDAIConfigTrackerImpl implements LDAIConfigTracker {
|
|
|
69
79
|
|
|
70
80
|
trackSuccess(): void {
|
|
71
81
|
this._trackedMetrics.success = true;
|
|
72
|
-
this._ldClient.track('$ld:ai:generation', this._context, this._getTrackData(), 1);
|
|
73
82
|
this._ldClient.track('$ld:ai:generation:success', this._context, this._getTrackData(), 1);
|
|
74
83
|
}
|
|
75
84
|
|
|
76
85
|
trackError(): void {
|
|
77
86
|
this._trackedMetrics.success = false;
|
|
78
|
-
this._ldClient.track('$ld:ai:generation', this._context, this._getTrackData(), 1);
|
|
79
87
|
this._ldClient.track('$ld:ai:generation:error', this._context, this._getTrackData(), 1);
|
|
80
88
|
}
|
|
81
89
|
|
package/src/api/LDAIClient.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { LDContext } from '@launchdarkly/js-server-sdk-common';
|
|
2
2
|
|
|
3
|
+
import { LDAIAgent, LDAIAgentConfig, LDAIAgentDefaults } from './agents';
|
|
3
4
|
import { LDAIConfig, LDAIDefaults } from './config/LDAIConfig';
|
|
4
5
|
|
|
5
6
|
/**
|
|
@@ -63,4 +64,83 @@ export interface LDAIClient {
|
|
|
63
64
|
defaultValue: LDAIDefaults,
|
|
64
65
|
variables?: Record<string, unknown>,
|
|
65
66
|
): Promise<LDAIConfig>;
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Retrieves and processes a single AI Config agent based on the provided key, LaunchDarkly context,
|
|
70
|
+
* and variables. This includes the model configuration and the customized instructions.
|
|
71
|
+
*
|
|
72
|
+
* @param key The key of the AI Config agent.
|
|
73
|
+
* @param context The LaunchDarkly context object that contains relevant information about the
|
|
74
|
+
* current environment, user, or session. This context may influence how the configuration is
|
|
75
|
+
* processed or personalized.
|
|
76
|
+
* @param defaultValue A fallback value containing model configuration and instructions.
|
|
77
|
+
* @param variables A map of key-value pairs representing dynamic variables to be injected into
|
|
78
|
+
* the instructions. The keys correspond to placeholders within the template, and the values
|
|
79
|
+
* are the corresponding replacements.
|
|
80
|
+
*
|
|
81
|
+
* @returns An AI agent with customized `instructions` and a `tracker`. If the configuration
|
|
82
|
+
* cannot be accessed from LaunchDarkly, then the return value will include information from the
|
|
83
|
+
* `defaultValue`. The returned `tracker` can be used to track AI operation metrics (latency, token usage, etc.).
|
|
84
|
+
*
|
|
85
|
+
* @example
|
|
86
|
+
* ```
|
|
87
|
+
* const key = "research_agent";
|
|
88
|
+
* const context = {...};
|
|
89
|
+
* const variables = { topic: 'climate change' };
|
|
90
|
+
* const agent = await client.agent(key, context, {
|
|
91
|
+
* enabled: true,
|
|
92
|
+
* instructions: 'You are a research assistant.',
|
|
93
|
+
* }, variables);
|
|
94
|
+
*
|
|
95
|
+
* const researchResult = agent.instructions; // Interpolated instructions
|
|
96
|
+
* agent.tracker.trackSuccess();
|
|
97
|
+
* ```
|
|
98
|
+
*/
|
|
99
|
+
agent(
|
|
100
|
+
key: string,
|
|
101
|
+
context: LDContext,
|
|
102
|
+
defaultValue: LDAIAgentDefaults,
|
|
103
|
+
variables?: Record<string, unknown>,
|
|
104
|
+
): Promise<LDAIAgent>;
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Retrieves and processes multiple AI Config agents based on the provided agent configurations
|
|
108
|
+
* and LaunchDarkly context. This includes the model configuration and the customized instructions.
|
|
109
|
+
*
|
|
110
|
+
* @param agentConfigs An array of agent configurations, each containing the agent key, default configuration,
|
|
111
|
+
* and variables for instructions interpolation.
|
|
112
|
+
* @param context The LaunchDarkly context object that contains relevant information about the
|
|
113
|
+
* current environment, user, or session. This context may influence how the configuration is
|
|
114
|
+
* processed or personalized.
|
|
115
|
+
*
|
|
116
|
+
* @returns A map of agent keys to their respective AI agents with customized `instructions` and `tracker`.
|
|
117
|
+
* If a configuration cannot be accessed from LaunchDarkly, then the return value will include information
|
|
118
|
+
* from the respective `defaultValue`. The returned `tracker` can be used to track AI operation metrics
|
|
119
|
+
* (latency, token usage, etc.).
|
|
120
|
+
*
|
|
121
|
+
* @example
|
|
122
|
+
* ```
|
|
123
|
+
* const agentConfigs = [
|
|
124
|
+
* {
|
|
125
|
+
* key: 'research_agent',
|
|
126
|
+
* defaultValue: { enabled: true, instructions: 'You are a research assistant.' },
|
|
127
|
+
* variables: { topic: 'climate change' }
|
|
128
|
+
* },
|
|
129
|
+
* {
|
|
130
|
+
* key: 'writing_agent',
|
|
131
|
+
* defaultValue: { enabled: true, instructions: 'You are a writing assistant.' },
|
|
132
|
+
* variables: { style: 'academic' }
|
|
133
|
+
* }
|
|
134
|
+
* ] as const;
|
|
135
|
+
* const context = {...};
|
|
136
|
+
*
|
|
137
|
+
* const agents = await client.agents(agentConfigs, context);
|
|
138
|
+
* const researchResult = agents["research_agent"].instructions; // Interpolated instructions
|
|
139
|
+
* agents["research_agent"].tracker.trackSuccess();
|
|
140
|
+
* ```
|
|
141
|
+
*/
|
|
142
|
+
agents<const T extends readonly LDAIAgentConfig[]>(
|
|
143
|
+
agentConfigs: T,
|
|
144
|
+
context: LDContext,
|
|
145
|
+
): Promise<Record<T[number]['key'], LDAIAgent>>;
|
|
66
146
|
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { LDAIConfig } from '../config';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* AI Config agent and tracker.
|
|
5
|
+
*/
|
|
6
|
+
export interface LDAIAgent extends Omit<LDAIConfig, 'messages'> {
|
|
7
|
+
/**
|
|
8
|
+
* Instructions for the agent.
|
|
9
|
+
*/
|
|
10
|
+
instructions?: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Configuration for a single agent request.
|
|
15
|
+
*/
|
|
16
|
+
export interface LDAIAgentConfig {
|
|
17
|
+
/**
|
|
18
|
+
* The agent key to retrieve.
|
|
19
|
+
*/
|
|
20
|
+
key: string;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Default configuration for the agent.
|
|
24
|
+
*/
|
|
25
|
+
defaultValue: LDAIAgentDefaults;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Variables for instructions interpolation.
|
|
29
|
+
*/
|
|
30
|
+
variables?: Record<string, unknown>;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Default values for an agent.
|
|
35
|
+
*/
|
|
36
|
+
export type LDAIAgentDefaults = Omit<LDAIAgent, 'tracker'>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './LDAIAgent';
|
package/src/api/index.ts
CHANGED