@launchdarkly/server-sdk-ai 0.19.1 → 1.0.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 +67 -0
- package/README.md +13 -16
- package/dist/index.cjs +617 -478
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +680 -443
- package/dist/index.d.ts +680 -443
- package/dist/index.js +613 -473
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -31,147 +31,127 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
31
31
|
var src_exports = {};
|
|
32
32
|
__export(src_exports, {
|
|
33
33
|
AIProvider: () => AIProvider,
|
|
34
|
-
AIProviderFactory: () => AIProviderFactory,
|
|
35
34
|
AgentGraphDefinition: () => AgentGraphDefinition,
|
|
36
35
|
AgentGraphNode: () => AgentGraphNode,
|
|
37
36
|
Judge: () => Judge,
|
|
38
37
|
LDFeedbackKind: () => LDFeedbackKind,
|
|
39
38
|
LDGraphTrackerImpl: () => LDGraphTrackerImpl,
|
|
39
|
+
ManagedAgent: () => ManagedAgent,
|
|
40
|
+
ManagedAgentGraph: () => ManagedAgentGraph,
|
|
41
|
+
ManagedModel: () => ManagedModel,
|
|
42
|
+
RunnerFactory: () => RunnerFactory,
|
|
40
43
|
SUPPORTED_AI_PROVIDERS: () => SUPPORTED_AI_PROVIDERS,
|
|
41
|
-
TrackedChat: () => TrackedChat,
|
|
42
|
-
createBedrockTokenUsage: () => createBedrockTokenUsage,
|
|
43
|
-
createOpenAiUsage: () => createOpenAiUsage,
|
|
44
|
-
createVercelAISDKTokenUsage: () => createVercelAISDKTokenUsage,
|
|
45
44
|
initAi: () => initAi
|
|
46
45
|
});
|
|
47
46
|
module.exports = __toCommonJS(src_exports);
|
|
48
47
|
|
|
49
48
|
// src/LDAIClientImpl.ts
|
|
50
|
-
var
|
|
49
|
+
var import_mustache = __toESM(require("mustache"), 1);
|
|
51
50
|
var import_node_crypto = require("crypto");
|
|
52
51
|
|
|
53
|
-
// src/api/
|
|
54
|
-
var
|
|
55
|
-
constructor(
|
|
56
|
-
this.
|
|
57
|
-
this.
|
|
58
|
-
this.judges = judges;
|
|
52
|
+
// src/api/ManagedAgent.ts
|
|
53
|
+
var ManagedAgent = class {
|
|
54
|
+
constructor(aiAgentConfig, runner, _logger) {
|
|
55
|
+
this.aiAgentConfig = aiAgentConfig;
|
|
56
|
+
this.runner = runner;
|
|
59
57
|
this._logger = _logger;
|
|
60
|
-
this.messages = [];
|
|
61
58
|
}
|
|
62
59
|
/**
|
|
63
|
-
* Invoke the
|
|
64
|
-
*
|
|
60
|
+
* Invoke the agent with a prompt string and return a ManagedResult.
|
|
61
|
+
*
|
|
62
|
+
* `run()` resolves before `ManagedResult.evaluations` resolves. Awaiting
|
|
63
|
+
* `evaluations` guarantees both judge evaluation and tracker.trackJudgeResult()
|
|
64
|
+
* are complete.
|
|
65
|
+
*
|
|
66
|
+
* @param prompt The user input to send to the agent.
|
|
67
|
+
* @returns Promise resolving to ManagedResult (before evaluations settle).
|
|
65
68
|
*/
|
|
66
|
-
async
|
|
67
|
-
const tracker = this.
|
|
68
|
-
const
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
};
|
|
72
|
-
this.messages.push(userMessage);
|
|
73
|
-
const configMessages = this.aiConfig.messages || [];
|
|
74
|
-
const allMessages = [...configMessages, ...this.messages];
|
|
75
|
-
const response = await tracker.trackMetricsOf(
|
|
76
|
-
(result) => result.metrics,
|
|
77
|
-
() => this.provider.invokeModel(allMessages)
|
|
69
|
+
async run(prompt) {
|
|
70
|
+
const tracker = this.aiAgentConfig.createTracker();
|
|
71
|
+
const result = await tracker.trackMetricsOf(
|
|
72
|
+
(r) => r.metrics,
|
|
73
|
+
() => this.runner.run(prompt)
|
|
78
74
|
);
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
return evaluations;
|
|
75
|
+
const metrics = tracker.getSummary();
|
|
76
|
+
const output = result.content;
|
|
77
|
+
const evaluations = this.aiAgentConfig.evaluator.evaluate(prompt, output).then((results) => {
|
|
78
|
+
results.forEach((judgeResult) => {
|
|
79
|
+
if (!judgeResult.sampled) {
|
|
80
|
+
return;
|
|
86
81
|
}
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
* Evaluates the response with all configured judges.
|
|
94
|
-
* Returns a promise that resolves to an array of evaluation results.
|
|
95
|
-
*
|
|
96
|
-
* @param messages Array of messages representing the conversation history
|
|
97
|
-
* @param response The AI response to be evaluated
|
|
98
|
-
* @returns Promise resolving to array of judge evaluation results
|
|
99
|
-
*/
|
|
100
|
-
async _evaluateWithJudges(messages, response) {
|
|
101
|
-
const judgeConfigs = this.aiConfig.judgeConfiguration.judges;
|
|
102
|
-
const evaluationPromises = judgeConfigs.map(async (judgeConfig) => {
|
|
103
|
-
const judge = this.judges[judgeConfig.key];
|
|
104
|
-
if (!judge) {
|
|
105
|
-
this._logger?.warn(
|
|
106
|
-
`Judge configuration is not enabled for ${judgeConfig.key} in ${this.aiConfig.key}`
|
|
107
|
-
);
|
|
108
|
-
const result = {
|
|
109
|
-
success: false,
|
|
110
|
-
sampled: true,
|
|
111
|
-
errorMessage: `Judge configuration is not enabled for ${judgeConfig.key}`
|
|
112
|
-
};
|
|
113
|
-
return result;
|
|
114
|
-
}
|
|
115
|
-
return judge.evaluateMessages(messages, response, judgeConfig.samplingRate);
|
|
116
|
-
});
|
|
117
|
-
const results = await Promise.allSettled(evaluationPromises);
|
|
118
|
-
return results.map((settled) => {
|
|
119
|
-
if (settled.status === "fulfilled") {
|
|
120
|
-
return settled.value;
|
|
121
|
-
}
|
|
122
|
-
const result = {
|
|
123
|
-
success: false,
|
|
124
|
-
sampled: true,
|
|
125
|
-
errorMessage: "Judge evaluation failed"
|
|
126
|
-
};
|
|
127
|
-
return result;
|
|
82
|
+
tracker.trackJudgeResult(judgeResult);
|
|
83
|
+
});
|
|
84
|
+
return results;
|
|
85
|
+
}).catch((err) => {
|
|
86
|
+
this._logger?.warn("Judge evaluation failed unexpectedly:", err);
|
|
87
|
+
return [];
|
|
128
88
|
});
|
|
89
|
+
return {
|
|
90
|
+
content: output,
|
|
91
|
+
metrics,
|
|
92
|
+
raw: result.raw,
|
|
93
|
+
parsed: result.parsed,
|
|
94
|
+
evaluations
|
|
95
|
+
};
|
|
129
96
|
}
|
|
130
97
|
/**
|
|
131
|
-
* Get the underlying AI configuration used to initialize this
|
|
98
|
+
* Get the underlying AI agent configuration used to initialize this ManagedAgent.
|
|
132
99
|
*/
|
|
133
100
|
getConfig() {
|
|
134
|
-
return this.
|
|
101
|
+
return this.aiAgentConfig;
|
|
135
102
|
}
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
* Get the judges associated with this TrackedChat.
|
|
145
|
-
* Returns a record of judge instances keyed by their configuration keys.
|
|
146
|
-
*/
|
|
147
|
-
getJudges() {
|
|
148
|
-
return this.judges;
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
// src/api/ManagedModel.ts
|
|
106
|
+
var ManagedModel = class {
|
|
107
|
+
constructor(aiConfig, runner, _logger) {
|
|
108
|
+
this.aiConfig = aiConfig;
|
|
109
|
+
this.runner = runner;
|
|
110
|
+
this._logger = _logger;
|
|
149
111
|
}
|
|
150
112
|
/**
|
|
151
|
-
*
|
|
152
|
-
*
|
|
153
|
-
*
|
|
113
|
+
* Invoke the model with a prompt string and return a ManagedResult.
|
|
114
|
+
*
|
|
115
|
+
* `run()` resolves before `ManagedResult.evaluations` resolves. Awaiting
|
|
116
|
+
* `evaluations` guarantees both judge evaluation and tracker.trackJudgeResult()
|
|
117
|
+
* are complete.
|
|
154
118
|
*
|
|
155
|
-
* @param
|
|
119
|
+
* @param prompt The user input to send to the model.
|
|
120
|
+
* @returns Promise resolving to ManagedResult (before evaluations settle).
|
|
156
121
|
*/
|
|
157
|
-
|
|
158
|
-
this.
|
|
122
|
+
async run(prompt) {
|
|
123
|
+
const tracker = this.aiConfig.createTracker();
|
|
124
|
+
const result = await tracker.trackMetricsOf(
|
|
125
|
+
(r) => r.metrics,
|
|
126
|
+
() => this.runner.run(prompt)
|
|
127
|
+
);
|
|
128
|
+
const metrics = tracker.getSummary();
|
|
129
|
+
const output = result.content;
|
|
130
|
+
const evaluations = this.aiConfig.evaluator.evaluate(prompt, output).then((results) => {
|
|
131
|
+
results.forEach((judgeResult) => {
|
|
132
|
+
if (!judgeResult.sampled) {
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
tracker.trackJudgeResult(judgeResult);
|
|
136
|
+
});
|
|
137
|
+
return results;
|
|
138
|
+
}).catch((err) => {
|
|
139
|
+
this._logger?.warn("Judge evaluation failed unexpectedly:", err);
|
|
140
|
+
return [];
|
|
141
|
+
});
|
|
142
|
+
return {
|
|
143
|
+
content: output,
|
|
144
|
+
metrics,
|
|
145
|
+
raw: result.raw,
|
|
146
|
+
parsed: result.parsed,
|
|
147
|
+
evaluations
|
|
148
|
+
};
|
|
159
149
|
}
|
|
160
150
|
/**
|
|
161
|
-
* Get
|
|
162
|
-
*
|
|
163
|
-
* @param includeConfigMessages Whether to include the config messages from the AIConfig.
|
|
164
|
-
* Defaults to false.
|
|
165
|
-
* @returns Array of messages. When includeConfigMessages is true, returns both config
|
|
166
|
-
* messages and conversation history with config messages prepended. When false,
|
|
167
|
-
* returns only the conversation history messages.
|
|
151
|
+
* Get the underlying AI configuration used to initialize this ManagedModel.
|
|
168
152
|
*/
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
const configMessages = this.aiConfig.messages || [];
|
|
172
|
-
return [...configMessages, ...this.messages];
|
|
173
|
-
}
|
|
174
|
-
return [...this.messages];
|
|
153
|
+
getConfig() {
|
|
154
|
+
return this.aiConfig;
|
|
175
155
|
}
|
|
176
156
|
};
|
|
177
157
|
|
|
@@ -206,9 +186,6 @@ var LDAIConfigUtils = class {
|
|
|
206
186
|
if ("evaluationMetricKey" in config && config.evaluationMetricKey !== void 0) {
|
|
207
187
|
flagValue.evaluationMetricKey = config.evaluationMetricKey;
|
|
208
188
|
}
|
|
209
|
-
if ("evaluationMetricKeys" in config && config.evaluationMetricKeys !== void 0) {
|
|
210
|
-
flagValue.evaluationMetricKeys = config.evaluationMetricKeys;
|
|
211
|
-
}
|
|
212
189
|
if ("judgeConfiguration" in config && config.judgeConfiguration !== void 0) {
|
|
213
190
|
flagValue.judgeConfiguration = config.judgeConfiguration;
|
|
214
191
|
}
|
|
@@ -222,47 +199,53 @@ var LDAIConfigUtils = class {
|
|
|
222
199
|
*
|
|
223
200
|
* @param key The configuration key
|
|
224
201
|
* @param flagValue The flag value from LaunchDarkly
|
|
225
|
-
* @param trackerFactory A factory function that creates a new tracker for each
|
|
202
|
+
* @param trackerFactory A factory function that creates a new tracker for each AI run
|
|
203
|
+
* @param evaluator The evaluator to attach to completion and agent configs
|
|
226
204
|
* @returns The appropriate AI configuration type
|
|
227
205
|
*/
|
|
228
|
-
static fromFlagValue(key, flagValue, trackerFactory) {
|
|
206
|
+
static fromFlagValue(key, flagValue, trackerFactory, evaluator) {
|
|
229
207
|
const flagValueMode = flagValue._ldMeta?.mode;
|
|
230
208
|
switch (flagValueMode) {
|
|
231
209
|
case "agent":
|
|
232
|
-
return this.toAgentConfig(key, flagValue, trackerFactory);
|
|
210
|
+
return this.toAgentConfig(key, flagValue, trackerFactory, evaluator);
|
|
233
211
|
case "judge":
|
|
234
212
|
return this.toJudgeConfig(key, flagValue, trackerFactory);
|
|
235
213
|
case "completion":
|
|
236
214
|
default:
|
|
237
|
-
return this.toCompletionConfig(key, flagValue, trackerFactory);
|
|
215
|
+
return this.toCompletionConfig(key, flagValue, trackerFactory, evaluator);
|
|
238
216
|
}
|
|
239
217
|
}
|
|
240
218
|
/**
|
|
241
219
|
* Creates a disabled configuration of the specified mode.
|
|
242
220
|
*
|
|
221
|
+
* @param key The configuration key
|
|
243
222
|
* @param mode The mode for the disabled config
|
|
223
|
+
* @param createTracker A factory function that creates a new tracker for each AI run
|
|
224
|
+
* @param evaluator The evaluator to attach to completion and agent configs
|
|
244
225
|
* @returns A disabled config of the appropriate type
|
|
245
226
|
*/
|
|
246
|
-
static createDisabledConfig(key, mode) {
|
|
227
|
+
static createDisabledConfig(key, mode, createTracker, evaluator) {
|
|
247
228
|
switch (mode) {
|
|
248
229
|
case "agent":
|
|
249
230
|
return {
|
|
250
231
|
key,
|
|
251
232
|
enabled: false,
|
|
252
|
-
createTracker
|
|
233
|
+
createTracker,
|
|
234
|
+
evaluator
|
|
253
235
|
};
|
|
254
236
|
case "judge":
|
|
255
237
|
return {
|
|
256
238
|
key,
|
|
257
239
|
enabled: false,
|
|
258
|
-
createTracker
|
|
240
|
+
createTracker
|
|
259
241
|
};
|
|
260
242
|
case "completion":
|
|
261
243
|
default:
|
|
262
244
|
return {
|
|
263
245
|
key,
|
|
264
246
|
enabled: false,
|
|
265
|
-
createTracker
|
|
247
|
+
createTracker,
|
|
248
|
+
evaluator
|
|
266
249
|
};
|
|
267
250
|
}
|
|
268
251
|
}
|
|
@@ -303,13 +286,15 @@ var LDAIConfigUtils = class {
|
|
|
303
286
|
*
|
|
304
287
|
* @param key The configuration key
|
|
305
288
|
* @param flagValue The flag value from LaunchDarkly
|
|
306
|
-
* @param trackerFactory A factory function that creates a new tracker for each
|
|
289
|
+
* @param trackerFactory A factory function that creates a new tracker for each AI run
|
|
290
|
+
* @param evaluator The evaluator for this completion config
|
|
307
291
|
* @returns A completion configuration
|
|
308
292
|
*/
|
|
309
|
-
static toCompletionConfig(key, flagValue, trackerFactory) {
|
|
293
|
+
static toCompletionConfig(key, flagValue, trackerFactory, evaluator) {
|
|
310
294
|
return {
|
|
311
295
|
...this._toBaseConfig(key, flagValue),
|
|
312
296
|
createTracker: trackerFactory,
|
|
297
|
+
evaluator,
|
|
313
298
|
messages: flagValue.messages,
|
|
314
299
|
judgeConfiguration: flagValue.judgeConfiguration,
|
|
315
300
|
tools: this._resolveTools(flagValue)
|
|
@@ -320,13 +305,15 @@ var LDAIConfigUtils = class {
|
|
|
320
305
|
*
|
|
321
306
|
* @param key The configuration key
|
|
322
307
|
* @param flagValue The flag value from LaunchDarkly
|
|
323
|
-
* @param trackerFactory A factory function that creates a new tracker for each
|
|
308
|
+
* @param trackerFactory A factory function that creates a new tracker for each AI run
|
|
309
|
+
* @param evaluator The evaluator for this agent config
|
|
324
310
|
* @returns An agent configuration
|
|
325
311
|
*/
|
|
326
|
-
static toAgentConfig(key, flagValue, trackerFactory) {
|
|
312
|
+
static toAgentConfig(key, flagValue, trackerFactory, evaluator) {
|
|
327
313
|
return {
|
|
328
314
|
...this._toBaseConfig(key, flagValue),
|
|
329
315
|
createTracker: trackerFactory,
|
|
316
|
+
evaluator,
|
|
330
317
|
instructions: flagValue.instructions,
|
|
331
318
|
judgeConfiguration: flagValue.judgeConfiguration,
|
|
332
319
|
tools: this._resolveTools(flagValue)
|
|
@@ -337,7 +324,7 @@ var LDAIConfigUtils = class {
|
|
|
337
324
|
*
|
|
338
325
|
* @param key The configuration key
|
|
339
326
|
* @param flagValue The flag value from LaunchDarkly
|
|
340
|
-
* @param trackerFactory A factory function that creates a new tracker for each
|
|
327
|
+
* @param trackerFactory A factory function that creates a new tracker for each AI run
|
|
341
328
|
* @returns A judge configuration
|
|
342
329
|
*/
|
|
343
330
|
static toJudgeConfig(key, flagValue, trackerFactory) {
|
|
@@ -470,10 +457,10 @@ var AgentGraphDefinition = class _AgentGraphDefinition {
|
|
|
470
457
|
return this._agentGraph;
|
|
471
458
|
}
|
|
472
459
|
/**
|
|
473
|
-
* Returns a new {@link LDGraphTracker} for
|
|
460
|
+
* Returns a new {@link LDGraphTracker} for a fresh graph run.
|
|
474
461
|
*
|
|
475
|
-
* Call this once per
|
|
476
|
-
* that groups all events for that
|
|
462
|
+
* Call this once per graph run. Each call produces a tracker with a fresh `runId`
|
|
463
|
+
* that groups all events for that run.
|
|
477
464
|
*/
|
|
478
465
|
createTracker() {
|
|
479
466
|
return this._createTracker();
|
|
@@ -591,8 +578,23 @@ var AgentGraphDefinition = class _AgentGraphDefinition {
|
|
|
591
578
|
}
|
|
592
579
|
};
|
|
593
580
|
|
|
581
|
+
// src/api/judge/Evaluator.ts
|
|
582
|
+
var Evaluator = class _Evaluator {
|
|
583
|
+
constructor(_judges) {
|
|
584
|
+
this._judges = _judges;
|
|
585
|
+
}
|
|
586
|
+
static noop() {
|
|
587
|
+
return new _Evaluator([]);
|
|
588
|
+
}
|
|
589
|
+
async evaluate(input, output) {
|
|
590
|
+
if (this._judges.length === 0) {
|
|
591
|
+
return [];
|
|
592
|
+
}
|
|
593
|
+
return Promise.all(this._judges.map((judge) => judge.evaluate(input, output)));
|
|
594
|
+
}
|
|
595
|
+
};
|
|
596
|
+
|
|
594
597
|
// src/api/judge/Judge.ts
|
|
595
|
-
var import_mustache = __toESM(require("mustache"), 1);
|
|
596
598
|
var EVALUATION_SCHEMA = {
|
|
597
599
|
type: "object",
|
|
598
600
|
properties: {
|
|
@@ -610,15 +612,27 @@ var EVALUATION_SCHEMA = {
|
|
|
610
612
|
required: ["score", "reasoning"],
|
|
611
613
|
additionalProperties: false
|
|
612
614
|
};
|
|
615
|
+
function stripLegacyJudgeMessages(messages) {
|
|
616
|
+
return messages.filter(
|
|
617
|
+
(msg) => msg.role === "system" || !msg.content.includes("{{message_history}}") && !msg.content.includes("{{response_to_evaluate}}")
|
|
618
|
+
);
|
|
619
|
+
}
|
|
613
620
|
var Judge = class {
|
|
614
|
-
constructor(_aiConfig,
|
|
621
|
+
constructor(_aiConfig, _runner, _sampleRate = 1, logger) {
|
|
615
622
|
this._aiConfig = _aiConfig;
|
|
616
|
-
this.
|
|
623
|
+
this._runner = _runner;
|
|
624
|
+
this._sampleRate = _sampleRate;
|
|
617
625
|
this._logger = logger;
|
|
618
626
|
}
|
|
619
627
|
/**
|
|
620
|
-
*
|
|
621
|
-
*
|
|
628
|
+
* The default sampling rate baked in at construction. Used by `evaluate` /
|
|
629
|
+
* `evaluateMessages` when no per-call rate is supplied.
|
|
630
|
+
*/
|
|
631
|
+
get sampleRate() {
|
|
632
|
+
return this._sampleRate;
|
|
633
|
+
}
|
|
634
|
+
/**
|
|
635
|
+
* Gets the evaluation metric key from the judge AI config.
|
|
622
636
|
* Treats empty strings and whitespace-only strings as invalid.
|
|
623
637
|
* @returns The evaluation metric key, or undefined if not available
|
|
624
638
|
*/
|
|
@@ -626,12 +640,6 @@ var Judge = class {
|
|
|
626
640
|
if (this._aiConfig.evaluationMetricKey && this._aiConfig.evaluationMetricKey.trim().length > 0) {
|
|
627
641
|
return this._aiConfig.evaluationMetricKey.trim();
|
|
628
642
|
}
|
|
629
|
-
if (this._aiConfig.evaluationMetricKeys && this._aiConfig.evaluationMetricKeys.length > 0) {
|
|
630
|
-
const validKey = this._aiConfig.evaluationMetricKeys.find(
|
|
631
|
-
(key) => key && key.trim().length > 0
|
|
632
|
-
);
|
|
633
|
-
return validKey ? validKey.trim() : void 0;
|
|
634
|
-
}
|
|
635
643
|
return void 0;
|
|
636
644
|
}
|
|
637
645
|
/**
|
|
@@ -639,10 +647,13 @@ var Judge = class {
|
|
|
639
647
|
*
|
|
640
648
|
* @param input The input prompt or question that was provided to the AI
|
|
641
649
|
* @param output The AI-generated response to be evaluated
|
|
642
|
-
* @param samplingRate Sampling rate (0-1) to determine if evaluation should be processed
|
|
650
|
+
* @param samplingRate Sampling rate (0-1) to determine if evaluation should be processed.
|
|
651
|
+
* When omitted, the Judge's constructor-default rate is used. An explicit `0` overrides
|
|
652
|
+
* the default — only `undefined` falls through.
|
|
643
653
|
* @returns Promise that resolves to evaluation results
|
|
644
654
|
*/
|
|
645
|
-
async evaluate(input, output, samplingRate
|
|
655
|
+
async evaluate(input, output, samplingRate) {
|
|
656
|
+
const effectiveRate = samplingRate ?? this._sampleRate;
|
|
646
657
|
const result = {
|
|
647
658
|
success: false,
|
|
648
659
|
sampled: false,
|
|
@@ -660,26 +671,20 @@ var Judge = class {
|
|
|
660
671
|
result.errorMessage = "Judge configuration is missing required evaluation metric key";
|
|
661
672
|
return result;
|
|
662
673
|
}
|
|
663
|
-
if (
|
|
664
|
-
this._logger?.
|
|
665
|
-
result.sampled = true;
|
|
666
|
-
result.errorMessage = "Judge configuration must include messages";
|
|
667
|
-
return result;
|
|
668
|
-
}
|
|
669
|
-
if (Math.random() > samplingRate) {
|
|
670
|
-
this._logger?.debug(`Judge evaluation skipped due to sampling rate: ${samplingRate}`);
|
|
674
|
+
if (Math.random() > effectiveRate) {
|
|
675
|
+
this._logger?.debug(`Judge evaluation skipped due to sampling rate: ${effectiveRate}`);
|
|
671
676
|
return result;
|
|
672
677
|
}
|
|
673
678
|
result.sampled = true;
|
|
674
|
-
const
|
|
679
|
+
const evaluationInput = this._buildEvaluationInput(input, output);
|
|
675
680
|
const response = await tracker.trackMetricsOf(
|
|
676
681
|
(r) => r.metrics,
|
|
677
|
-
() => this.
|
|
682
|
+
() => this._runner.run(evaluationInput, EVALUATION_SCHEMA)
|
|
678
683
|
);
|
|
679
|
-
const evalResult = this._parseEvaluationResponse(response.
|
|
684
|
+
const evalResult = this._parseEvaluationResponse(response.parsed);
|
|
680
685
|
if (!evalResult) {
|
|
681
686
|
this._logger?.warn(
|
|
682
|
-
`Could not parse evaluation response: ${JSON.stringify(response.
|
|
687
|
+
`Could not parse evaluation response: ${JSON.stringify(response.parsed)}`,
|
|
683
688
|
tracker.getTrackData()
|
|
684
689
|
);
|
|
685
690
|
return result;
|
|
@@ -699,16 +704,21 @@ var Judge = class {
|
|
|
699
704
|
}
|
|
700
705
|
}
|
|
701
706
|
/**
|
|
702
|
-
* Evaluates an AI response from chat messages and
|
|
707
|
+
* Evaluates an AI response from chat messages and a runner result.
|
|
708
|
+
*
|
|
709
|
+
* Each message is rendered as `<role>: <content>` so the judge model can
|
|
710
|
+
* distinguish speakers in the message history. Messages are joined with a
|
|
711
|
+
* single newline.
|
|
703
712
|
*
|
|
704
713
|
* @param messages Array of messages representing the conversation history
|
|
705
|
-
* @param response The AI
|
|
706
|
-
* @param samplingRatio Sampling ratio (0-1)
|
|
714
|
+
* @param response The runner result containing the AI-generated content to evaluate
|
|
715
|
+
* @param samplingRatio Sampling ratio (0-1). When omitted, the Judge's
|
|
716
|
+
* constructor-default rate is used.
|
|
707
717
|
* @returns Promise that resolves to evaluation results
|
|
708
718
|
*/
|
|
709
|
-
async evaluateMessages(messages, response, samplingRatio
|
|
710
|
-
const input = messages.length === 0 ? "" : messages.map((msg) => msg.content).join("\
|
|
711
|
-
const output = response.
|
|
719
|
+
async evaluateMessages(messages, response, samplingRatio) {
|
|
720
|
+
const input = messages.length === 0 ? "" : messages.map((msg) => `${msg.role}: ${msg.content}`).join("\n");
|
|
721
|
+
const output = response.content;
|
|
712
722
|
return this.evaluate(input, output, samplingRatio);
|
|
713
723
|
}
|
|
714
724
|
/**
|
|
@@ -718,29 +728,23 @@ var Judge = class {
|
|
|
718
728
|
return this._aiConfig;
|
|
719
729
|
}
|
|
720
730
|
/**
|
|
721
|
-
* Returns the
|
|
731
|
+
* Returns the runner used by this judge.
|
|
722
732
|
*/
|
|
723
|
-
|
|
724
|
-
return this.
|
|
725
|
-
}
|
|
726
|
-
/**
|
|
727
|
-
* Constructs evaluation messages by combining judge's config messages with input/output.
|
|
728
|
-
*/
|
|
729
|
-
_constructEvaluationMessages(input, output) {
|
|
730
|
-
const messages = this._aiConfig.messages.map((msg) => ({
|
|
731
|
-
...msg,
|
|
732
|
-
content: this._interpolateMessage(msg.content, {
|
|
733
|
-
message_history: input,
|
|
734
|
-
response_to_evaluate: output
|
|
735
|
-
})
|
|
736
|
-
}));
|
|
737
|
-
return messages;
|
|
733
|
+
getRunner() {
|
|
734
|
+
return this._runner;
|
|
738
735
|
}
|
|
739
736
|
/**
|
|
740
|
-
*
|
|
737
|
+
* Builds the evaluation input string passed to the runner.
|
|
738
|
+
*
|
|
739
|
+
* Combines the original prompt and the response into a single, well-known
|
|
740
|
+
* format the judge model is expected to evaluate.
|
|
741
741
|
*/
|
|
742
|
-
|
|
743
|
-
return
|
|
742
|
+
_buildEvaluationInput(input, output) {
|
|
743
|
+
return `MESSAGE HISTORY:
|
|
744
|
+
${input}
|
|
745
|
+
|
|
746
|
+
RESPONSE TO EVALUATE:
|
|
747
|
+
${output}`;
|
|
744
748
|
}
|
|
745
749
|
/**
|
|
746
750
|
* Parses the structured evaluation response. Expects top-level {score, reasoning}.
|
|
@@ -766,115 +770,105 @@ var Judge = class {
|
|
|
766
770
|
// src/api/providers/AIProvider.ts
|
|
767
771
|
var AIProvider = class {
|
|
768
772
|
constructor(logger) {
|
|
769
|
-
this.
|
|
773
|
+
this._logger = logger;
|
|
770
774
|
}
|
|
771
775
|
/**
|
|
772
|
-
*
|
|
773
|
-
* This method should convert messages to provider format, invoke the model,
|
|
774
|
-
* and return a ChatResponse with the result and metrics.
|
|
776
|
+
* Create a Runner for a completion or judge AI Config.
|
|
775
777
|
*
|
|
776
|
-
*
|
|
777
|
-
*
|
|
778
|
+
* Override in provider subclasses to return a configured {@link Runner}.
|
|
779
|
+
* Default implementation returns `undefined`.
|
|
778
780
|
*
|
|
779
|
-
* @param
|
|
780
|
-
* @
|
|
781
|
+
* @param config The completion or judge AI configuration.
|
|
782
|
+
* @param multiTurn Whether the runner should accumulate conversation history
|
|
783
|
+
* across successive `run()` calls. Defaults to `true` (chat semantics).
|
|
784
|
+
* Pass `false` for stateless runners such as judges where each call must
|
|
785
|
+
* start from the initial config messages.
|
|
786
|
+
* @returns Promise resolving to a {@link Runner}, or `undefined` if this
|
|
787
|
+
* provider does not support model creation.
|
|
781
788
|
*/
|
|
782
|
-
async
|
|
783
|
-
|
|
784
|
-
return {
|
|
785
|
-
message: {
|
|
786
|
-
role: "assistant",
|
|
787
|
-
content: ""
|
|
788
|
-
},
|
|
789
|
-
metrics: {
|
|
790
|
-
success: false,
|
|
791
|
-
usage: {
|
|
792
|
-
total: 0,
|
|
793
|
-
input: 0,
|
|
794
|
-
output: 0
|
|
795
|
-
}
|
|
796
|
-
}
|
|
797
|
-
};
|
|
789
|
+
async createModel(_config, _multiTurn = true) {
|
|
790
|
+
return void 0;
|
|
798
791
|
}
|
|
799
792
|
/**
|
|
800
|
-
*
|
|
801
|
-
* This method should convert messages to provider format, invoke the model with
|
|
802
|
-
* structured output configuration, and return a structured response.
|
|
793
|
+
* Create a Runner for an agent AI Config.
|
|
803
794
|
*
|
|
804
|
-
*
|
|
805
|
-
*
|
|
795
|
+
* Override in provider subclasses to return a configured {@link Runner}.
|
|
796
|
+
* Default implementation returns `undefined`.
|
|
806
797
|
*
|
|
807
|
-
* @param
|
|
808
|
-
* @param
|
|
809
|
-
* @returns Promise
|
|
798
|
+
* @param config The agent AI configuration.
|
|
799
|
+
* @param tools Optional registry of callable tools.
|
|
800
|
+
* @returns Promise resolving to a {@link Runner}, or `undefined` if this
|
|
801
|
+
* provider does not support agent creation.
|
|
810
802
|
*/
|
|
811
|
-
async
|
|
812
|
-
|
|
813
|
-
return {
|
|
814
|
-
data: {},
|
|
815
|
-
rawResponse: "",
|
|
816
|
-
metrics: {
|
|
817
|
-
success: false,
|
|
818
|
-
usage: {
|
|
819
|
-
total: 0,
|
|
820
|
-
input: 0,
|
|
821
|
-
output: 0
|
|
822
|
-
}
|
|
823
|
-
}
|
|
824
|
-
};
|
|
803
|
+
async createAgent(_config, _tools) {
|
|
804
|
+
return void 0;
|
|
825
805
|
}
|
|
826
806
|
/**
|
|
827
|
-
*
|
|
828
|
-
*
|
|
829
|
-
*
|
|
807
|
+
* Create an AgentGraphRunner for an agent graph definition.
|
|
808
|
+
*
|
|
809
|
+
* Override in provider subclasses to return a configured {@link AgentGraphRunner}.
|
|
810
|
+
* Default implementation returns `undefined`.
|
|
830
811
|
*
|
|
831
|
-
* @param
|
|
832
|
-
* @param
|
|
833
|
-
* @returns Promise
|
|
812
|
+
* @param graphDef The agent graph definition.
|
|
813
|
+
* @param tools Optional registry of callable tools.
|
|
814
|
+
* @returns Promise resolving to an {@link AgentGraphRunner}, or `undefined` if
|
|
815
|
+
* this provider does not support graph execution.
|
|
834
816
|
*/
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
throw new Error("Provider implementations must override the static create method");
|
|
817
|
+
async createAgentGraph(_graphDef, _tools) {
|
|
818
|
+
return void 0;
|
|
838
819
|
}
|
|
839
820
|
};
|
|
840
821
|
|
|
841
|
-
// src/api/providers/
|
|
822
|
+
// src/api/providers/RunnerFactory.ts
|
|
842
823
|
var SUPPORTED_AI_PROVIDERS = [
|
|
843
824
|
"openai",
|
|
844
825
|
// Multi-provider packages should be last in the list
|
|
845
826
|
"langchain",
|
|
846
827
|
"vercel"
|
|
847
828
|
];
|
|
848
|
-
var
|
|
829
|
+
var RunnerFactory = class _RunnerFactory {
|
|
849
830
|
/**
|
|
850
|
-
*
|
|
851
|
-
* This method attempts to load provider-specific implementations dynamically.
|
|
852
|
-
* Returns undefined if the provider is not supported.
|
|
831
|
+
* Load and return the AIProvider factory for the given provider type.
|
|
853
832
|
*
|
|
854
|
-
*
|
|
855
|
-
*
|
|
856
|
-
* @
|
|
833
|
+
* This is the single place in the codebase that knows provider package names.
|
|
834
|
+
* Each supported provider package exports a `*RunnerFactory` class that
|
|
835
|
+
* extends {@link AIProvider}; this method instantiates it directly.
|
|
836
|
+
*
|
|
837
|
+
* @param providerType One of the {@link SUPPORTED_AI_PROVIDERS} values.
|
|
838
|
+
* @param logger Optional logger forwarded to the provider factory.
|
|
839
|
+
* @returns A configured {@link AIProvider} instance, or `undefined` if the
|
|
840
|
+
* package cannot be loaded.
|
|
857
841
|
*/
|
|
858
|
-
static async
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
842
|
+
static async _getProviderFactory(providerType, logger) {
|
|
843
|
+
try {
|
|
844
|
+
let module2;
|
|
845
|
+
switch (providerType) {
|
|
846
|
+
case "openai": {
|
|
847
|
+
module2 = await import("@launchdarkly/server-sdk-ai-openai");
|
|
848
|
+
return new module2.OpenAIRunnerFactory(logger);
|
|
849
|
+
}
|
|
850
|
+
case "langchain": {
|
|
851
|
+
module2 = await import("@launchdarkly/server-sdk-ai-langchain");
|
|
852
|
+
return new module2.LangChainRunnerFactory(logger);
|
|
853
|
+
}
|
|
854
|
+
case "vercel": {
|
|
855
|
+
module2 = await import("@launchdarkly/server-sdk-ai-vercel");
|
|
856
|
+
return new module2.VercelRunnerFactory(logger);
|
|
857
|
+
}
|
|
858
|
+
default:
|
|
859
|
+
return void 0;
|
|
869
860
|
}
|
|
861
|
+
} catch (error) {
|
|
862
|
+
logger?.warn(
|
|
863
|
+
`Unable to load provider package. Check that you have installed the correct package. ${error.message}`
|
|
864
|
+
);
|
|
865
|
+
return void 0;
|
|
870
866
|
}
|
|
871
|
-
logger?.warn(
|
|
872
|
-
`Provider is not supported or failed to initialize: ${aiConfig.provider?.name ?? "unknown"}`
|
|
873
|
-
);
|
|
874
|
-
return void 0;
|
|
875
867
|
}
|
|
876
868
|
/**
|
|
877
869
|
* Determine which providers to try based on defaultAiProvider and providerName.
|
|
870
|
+
*
|
|
871
|
+
* Mirrors Python's `_get_providers_to_try` helper.
|
|
878
872
|
*/
|
|
879
873
|
static _getProvidersToTry(defaultAiProvider, providerName) {
|
|
880
874
|
if (defaultAiProvider) {
|
|
@@ -891,57 +885,118 @@ var AIProviderFactory = class {
|
|
|
891
885
|
return Array.from(providerSet);
|
|
892
886
|
}
|
|
893
887
|
/**
|
|
894
|
-
* Try
|
|
888
|
+
* Try each provider in order and return the first non-undefined result.
|
|
889
|
+
*
|
|
890
|
+
* Mirrors Python's `_with_fallback` helper. Loads each provider factory via
|
|
891
|
+
* {@link _getProviderFactory} and calls `fn` with it. Returns the first
|
|
892
|
+
* truthy result, or `undefined` if no provider succeeds.
|
|
893
|
+
*
|
|
894
|
+
* @param providers Ordered list of provider types to try.
|
|
895
|
+
* @param fn Callback that calls the appropriate factory method on the provider.
|
|
896
|
+
* @param logger Optional logger forwarded to each provider factory.
|
|
895
897
|
*/
|
|
896
|
-
static async
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
case "langchain": {
|
|
906
|
-
module2 = await import("@launchdarkly/server-sdk-ai-langchain");
|
|
907
|
-
const provider = await module2.LangChainProvider.create(aiConfig, logger);
|
|
908
|
-
return provider;
|
|
898
|
+
static async _withFallback(providers, fn, logger) {
|
|
899
|
+
for (const providerType of providers) {
|
|
900
|
+
logger?.debug(`Attempting to create runner with provider: ${providerType}`);
|
|
901
|
+
const factory = await _RunnerFactory._getProviderFactory(providerType, logger);
|
|
902
|
+
if (factory) {
|
|
903
|
+
const result = await fn(factory);
|
|
904
|
+
if (result) {
|
|
905
|
+
logger?.debug(`Successfully created runner with provider: ${providerType}`);
|
|
906
|
+
return result;
|
|
909
907
|
}
|
|
910
|
-
case "vercel": {
|
|
911
|
-
module2 = await import("@launchdarkly/server-sdk-ai-vercel");
|
|
912
|
-
const provider = await module2.VercelProvider.create(aiConfig, logger);
|
|
913
|
-
return provider;
|
|
914
|
-
}
|
|
915
|
-
default:
|
|
916
|
-
return void 0;
|
|
917
908
|
}
|
|
918
|
-
}
|
|
909
|
+
}
|
|
910
|
+
return void 0;
|
|
911
|
+
}
|
|
912
|
+
/**
|
|
913
|
+
* Create a Runner for the given AI configuration.
|
|
914
|
+
*
|
|
915
|
+
* Suitable for completion, judge, and agent config modes. Dynamically
|
|
916
|
+
* loads the matching provider package via {@link _getProviderFactory} and
|
|
917
|
+
* delegates to its {@link AIProvider.createModel} method.
|
|
918
|
+
*
|
|
919
|
+
* @param config The AI configuration (completion, agent, or judge).
|
|
920
|
+
* @param logger Optional logger forwarded to the underlying provider.
|
|
921
|
+
* @param defaultAiProvider Optional provider override
|
|
922
|
+
* ('openai', 'langchain', 'vercel', …). When set, only that provider is
|
|
923
|
+
* tried. When omitted, providers are tried in priority order based on the
|
|
924
|
+
* provider name in the config.
|
|
925
|
+
* @param multiTurn Whether the runner should accumulate conversation history
|
|
926
|
+
* across successive `run()` calls. Defaults to `true` (chat semantics).
|
|
927
|
+
* Judges pass `false` so each evaluation starts from the initial config
|
|
928
|
+
* messages.
|
|
929
|
+
* @returns A configured {@link Runner} ready to invoke the model, or
|
|
930
|
+
* `undefined` if no suitable provider could be loaded.
|
|
931
|
+
*/
|
|
932
|
+
static async createModel(config, logger, defaultAiProvider, multiTurn = true) {
|
|
933
|
+
const providerName = config.provider?.name?.toLowerCase();
|
|
934
|
+
const providers = _RunnerFactory._getProvidersToTry(defaultAiProvider, providerName);
|
|
935
|
+
const runner = await _RunnerFactory._withFallback(
|
|
936
|
+
providers,
|
|
937
|
+
(factory) => factory.createModel(config, multiTurn),
|
|
938
|
+
logger
|
|
939
|
+
);
|
|
940
|
+
if (!runner) {
|
|
919
941
|
logger?.warn(
|
|
920
|
-
`
|
|
942
|
+
`Provider is not supported or failed to initialize: ${config.provider?.name ?? "unknown"}`
|
|
921
943
|
);
|
|
922
|
-
return void 0;
|
|
923
944
|
}
|
|
945
|
+
return runner;
|
|
946
|
+
}
|
|
947
|
+
/**
|
|
948
|
+
* Create a Runner for an agent AI Config.
|
|
949
|
+
*
|
|
950
|
+
* Delegates to the provider factory's {@link AIProvider.createAgent} method.
|
|
951
|
+
*
|
|
952
|
+
* @param config The agent AI configuration.
|
|
953
|
+
* @param tools Optional registry of callable tools.
|
|
954
|
+
* @param logger Optional logger forwarded to the underlying provider.
|
|
955
|
+
* @param defaultAiProvider Optional provider override.
|
|
956
|
+
* @returns A configured {@link Runner}, or `undefined` if no suitable
|
|
957
|
+
* provider could be loaded.
|
|
958
|
+
*/
|
|
959
|
+
static async createAgent(config, tools, logger, defaultAiProvider) {
|
|
960
|
+
const providerName = config.provider?.name?.toLowerCase();
|
|
961
|
+
const providers = _RunnerFactory._getProvidersToTry(defaultAiProvider, providerName);
|
|
962
|
+
const runner = await _RunnerFactory._withFallback(
|
|
963
|
+
providers,
|
|
964
|
+
(factory) => factory.createAgent(config, tools),
|
|
965
|
+
logger
|
|
966
|
+
);
|
|
967
|
+
if (!runner) {
|
|
968
|
+
logger?.warn(
|
|
969
|
+
`Provider is not supported or failed to initialize: ${config.provider?.name ?? "unknown"}`
|
|
970
|
+
);
|
|
971
|
+
}
|
|
972
|
+
return runner;
|
|
973
|
+
}
|
|
974
|
+
/**
|
|
975
|
+
* Create an AgentGraphRunner for the given agent graph definition.
|
|
976
|
+
*
|
|
977
|
+
* Delegates to the provider factory's {@link AIProvider.createAgentGraph} method.
|
|
978
|
+
*
|
|
979
|
+
* @param graphDef The agent graph definition.
|
|
980
|
+
* @param tools Optional registry of callable tools.
|
|
981
|
+
* @param logger Optional logger forwarded to the underlying provider.
|
|
982
|
+
* @param defaultAiProvider Optional provider override.
|
|
983
|
+
* @returns A configured {@link AgentGraphRunner}, or `undefined` if no
|
|
984
|
+
* suitable provider could be loaded.
|
|
985
|
+
*/
|
|
986
|
+
static async createAgentGraph(graphDef, tools, logger, defaultAiProvider) {
|
|
987
|
+
const providers = _RunnerFactory._getProvidersToTry(defaultAiProvider);
|
|
988
|
+
const runner = await _RunnerFactory._withFallback(
|
|
989
|
+
providers,
|
|
990
|
+
(factory) => factory.createAgentGraph(graphDef, tools),
|
|
991
|
+
logger
|
|
992
|
+
);
|
|
993
|
+
if (!runner) {
|
|
994
|
+
logger?.warn(`No provider could create an AgentGraphRunner for the given graph definition.`);
|
|
995
|
+
}
|
|
996
|
+
return runner;
|
|
924
997
|
}
|
|
925
998
|
};
|
|
926
999
|
|
|
927
|
-
// src/api/metrics/BedrockTokenUsage.ts
|
|
928
|
-
function createBedrockTokenUsage(data) {
|
|
929
|
-
return {
|
|
930
|
-
total: data.totalTokens || 0,
|
|
931
|
-
input: data.inputTokens || 0,
|
|
932
|
-
output: data.outputTokens || 0
|
|
933
|
-
};
|
|
934
|
-
}
|
|
935
|
-
|
|
936
|
-
// src/api/metrics/OpenAiUsage.ts
|
|
937
|
-
function createOpenAiUsage(data) {
|
|
938
|
-
return {
|
|
939
|
-
total: data.total_tokens ?? 0,
|
|
940
|
-
input: data.prompt_tokens ?? 0,
|
|
941
|
-
output: data.completion_tokens ?? 0
|
|
942
|
-
};
|
|
943
|
-
}
|
|
944
|
-
|
|
945
1000
|
// src/api/metrics/LDFeedbackKind.ts
|
|
946
1001
|
var LDFeedbackKind = /* @__PURE__ */ ((LDFeedbackKind2) => {
|
|
947
1002
|
LDFeedbackKind2["Positive"] = "positive";
|
|
@@ -949,15 +1004,6 @@ var LDFeedbackKind = /* @__PURE__ */ ((LDFeedbackKind2) => {
|
|
|
949
1004
|
return LDFeedbackKind2;
|
|
950
1005
|
})(LDFeedbackKind || {});
|
|
951
1006
|
|
|
952
|
-
// src/api/metrics/VercelAISDKTokenUsage.ts
|
|
953
|
-
function createVercelAISDKTokenUsage(data) {
|
|
954
|
-
return {
|
|
955
|
-
total: data.totalTokens ?? 0,
|
|
956
|
-
input: data.inputTokens ?? data.promptTokens ?? 0,
|
|
957
|
-
output: data.outputTokens ?? data.completionTokens ?? 0
|
|
958
|
-
};
|
|
959
|
-
}
|
|
960
|
-
|
|
961
1007
|
// src/LDAIConfigTrackerImpl.ts
|
|
962
1008
|
var LDAIConfigTrackerImpl = class _LDAIConfigTrackerImpl {
|
|
963
1009
|
constructor(_ldClient, _runId, _configKey, _variationKey, _version, _modelName, _providerName, _context, _graphKey) {
|
|
@@ -971,6 +1017,7 @@ var LDAIConfigTrackerImpl = class _LDAIConfigTrackerImpl {
|
|
|
971
1017
|
this._context = _context;
|
|
972
1018
|
this._graphKey = _graphKey;
|
|
973
1019
|
this._trackedMetrics = {};
|
|
1020
|
+
this._trackedMetrics.resumptionToken = this.resumptionToken;
|
|
974
1021
|
}
|
|
975
1022
|
getTrackData() {
|
|
976
1023
|
return {
|
|
@@ -1011,7 +1058,7 @@ var LDAIConfigTrackerImpl = class _LDAIConfigTrackerImpl {
|
|
|
1011
1058
|
trackDuration(duration) {
|
|
1012
1059
|
if (this._trackedMetrics.durationMs !== void 0) {
|
|
1013
1060
|
this._ldClient.logger?.warn(
|
|
1014
|
-
"
|
|
1061
|
+
"Skipping trackDuration: duration already recorded on this tracker. Call createTracker on the AI Config for a new run."
|
|
1015
1062
|
);
|
|
1016
1063
|
return;
|
|
1017
1064
|
}
|
|
@@ -1032,7 +1079,7 @@ var LDAIConfigTrackerImpl = class _LDAIConfigTrackerImpl {
|
|
|
1032
1079
|
trackTimeToFirstToken(timeToFirstTokenMs) {
|
|
1033
1080
|
if (this._trackedMetrics.timeToFirstTokenMs !== void 0) {
|
|
1034
1081
|
this._ldClient.logger?.warn(
|
|
1035
|
-
"
|
|
1082
|
+
"Skipping trackTimeToFirstToken: time-to-first-token already recorded on this tracker. Call createTracker on the AI Config for a new run."
|
|
1036
1083
|
);
|
|
1037
1084
|
return;
|
|
1038
1085
|
}
|
|
@@ -1054,6 +1101,10 @@ var LDAIConfigTrackerImpl = class _LDAIConfigTrackerImpl {
|
|
|
1054
1101
|
}
|
|
1055
1102
|
}
|
|
1056
1103
|
trackToolCall(toolKey) {
|
|
1104
|
+
if (!this._trackedMetrics.toolCalls) {
|
|
1105
|
+
this._trackedMetrics.toolCalls = [];
|
|
1106
|
+
}
|
|
1107
|
+
this._trackedMetrics.toolCalls.push(toolKey);
|
|
1057
1108
|
this._ldClient.track("$ld:ai:tool_call", this._context, { ...this.getTrackData(), toolKey }, 1);
|
|
1058
1109
|
}
|
|
1059
1110
|
trackToolCalls(toolKeys) {
|
|
@@ -1064,7 +1115,7 @@ var LDAIConfigTrackerImpl = class _LDAIConfigTrackerImpl {
|
|
|
1064
1115
|
trackFeedback(feedback) {
|
|
1065
1116
|
if (this._trackedMetrics.feedback !== void 0) {
|
|
1066
1117
|
this._ldClient.logger?.warn(
|
|
1067
|
-
"
|
|
1118
|
+
"Skipping trackFeedback: feedback already recorded on this tracker. Call createTracker on the AI Config for a new run."
|
|
1068
1119
|
);
|
|
1069
1120
|
return;
|
|
1070
1121
|
}
|
|
@@ -1078,7 +1129,7 @@ var LDAIConfigTrackerImpl = class _LDAIConfigTrackerImpl {
|
|
|
1078
1129
|
trackSuccess() {
|
|
1079
1130
|
if (this._trackedMetrics.success !== void 0) {
|
|
1080
1131
|
this._ldClient.logger?.warn(
|
|
1081
|
-
"
|
|
1132
|
+
"Skipping trackSuccess: success/error already recorded on this tracker. Call createTracker on the AI Config for a new run."
|
|
1082
1133
|
);
|
|
1083
1134
|
return;
|
|
1084
1135
|
}
|
|
@@ -1088,7 +1139,7 @@ var LDAIConfigTrackerImpl = class _LDAIConfigTrackerImpl {
|
|
|
1088
1139
|
trackError() {
|
|
1089
1140
|
if (this._trackedMetrics.success !== void 0) {
|
|
1090
1141
|
this._ldClient.logger?.warn(
|
|
1091
|
-
"
|
|
1142
|
+
"Skipping trackError: success/error already recorded on this tracker. Call createTracker on the AI Config for a new run."
|
|
1092
1143
|
);
|
|
1093
1144
|
return;
|
|
1094
1145
|
}
|
|
@@ -1109,8 +1160,11 @@ var LDAIConfigTrackerImpl = class _LDAIConfigTrackerImpl {
|
|
|
1109
1160
|
} else {
|
|
1110
1161
|
this.trackError();
|
|
1111
1162
|
}
|
|
1112
|
-
if (metrics.
|
|
1113
|
-
this.trackTokens(metrics.
|
|
1163
|
+
if (metrics.tokens) {
|
|
1164
|
+
this.trackTokens(metrics.tokens);
|
|
1165
|
+
}
|
|
1166
|
+
if (metrics.toolCalls?.length) {
|
|
1167
|
+
this.trackToolCalls(metrics.toolCalls);
|
|
1114
1168
|
}
|
|
1115
1169
|
return result;
|
|
1116
1170
|
}
|
|
@@ -1134,8 +1188,11 @@ var LDAIConfigTrackerImpl = class _LDAIConfigTrackerImpl {
|
|
|
1134
1188
|
} else {
|
|
1135
1189
|
this.trackError();
|
|
1136
1190
|
}
|
|
1137
|
-
if (metrics.
|
|
1138
|
-
this.trackTokens(metrics.
|
|
1191
|
+
if (metrics.tokens) {
|
|
1192
|
+
this.trackTokens(metrics.tokens);
|
|
1193
|
+
}
|
|
1194
|
+
if (metrics.toolCalls?.length) {
|
|
1195
|
+
this.trackToolCalls(metrics.toolCalls);
|
|
1139
1196
|
}
|
|
1140
1197
|
} catch (error) {
|
|
1141
1198
|
this.trackError();
|
|
@@ -1143,50 +1200,10 @@ var LDAIConfigTrackerImpl = class _LDAIConfigTrackerImpl {
|
|
|
1143
1200
|
this.trackDuration(Date.now() - startTime);
|
|
1144
1201
|
}
|
|
1145
1202
|
}
|
|
1146
|
-
async trackOpenAIMetrics(func) {
|
|
1147
|
-
try {
|
|
1148
|
-
const result = await this.trackDurationOf(func);
|
|
1149
|
-
this.trackSuccess();
|
|
1150
|
-
if (result.usage) {
|
|
1151
|
-
this.trackTokens(createOpenAiUsage(result.usage));
|
|
1152
|
-
}
|
|
1153
|
-
return result;
|
|
1154
|
-
} catch (err) {
|
|
1155
|
-
this.trackError();
|
|
1156
|
-
throw err;
|
|
1157
|
-
}
|
|
1158
|
-
}
|
|
1159
|
-
trackBedrockConverseMetrics(res) {
|
|
1160
|
-
if (res.$metadata?.httpStatusCode === 200) {
|
|
1161
|
-
this.trackSuccess();
|
|
1162
|
-
} else if (res.$metadata?.httpStatusCode && res.$metadata.httpStatusCode >= 400) {
|
|
1163
|
-
this.trackError();
|
|
1164
|
-
}
|
|
1165
|
-
if (res.metrics && res.metrics.latencyMs) {
|
|
1166
|
-
this.trackDuration(res.metrics.latencyMs);
|
|
1167
|
-
}
|
|
1168
|
-
if (res.usage) {
|
|
1169
|
-
this.trackTokens(createBedrockTokenUsage(res.usage));
|
|
1170
|
-
}
|
|
1171
|
-
return res;
|
|
1172
|
-
}
|
|
1173
|
-
async trackVercelAISDKGenerateTextMetrics(func) {
|
|
1174
|
-
try {
|
|
1175
|
-
const result = await this.trackDurationOf(func);
|
|
1176
|
-
this.trackSuccess();
|
|
1177
|
-
if (result.usage) {
|
|
1178
|
-
this.trackTokens(createVercelAISDKTokenUsage(result.usage));
|
|
1179
|
-
}
|
|
1180
|
-
return result;
|
|
1181
|
-
} catch (err) {
|
|
1182
|
-
this.trackError();
|
|
1183
|
-
throw err;
|
|
1184
|
-
}
|
|
1185
|
-
}
|
|
1186
1203
|
trackTokens(tokens) {
|
|
1187
1204
|
if (this._trackedMetrics.tokens !== void 0) {
|
|
1188
1205
|
this._ldClient.logger?.warn(
|
|
1189
|
-
"
|
|
1206
|
+
"Skipping trackTokens: token usage already recorded on this tracker. Call createTracker on the AI Config for a new run."
|
|
1190
1207
|
);
|
|
1191
1208
|
return;
|
|
1192
1209
|
}
|
|
@@ -1220,6 +1237,7 @@ var LDGraphTrackerImpl = class _LDGraphTrackerImpl {
|
|
|
1220
1237
|
this._version = _version;
|
|
1221
1238
|
this._context = _context;
|
|
1222
1239
|
this._summary = {};
|
|
1240
|
+
this._summary.resumptionToken = this.resumptionToken;
|
|
1223
1241
|
}
|
|
1224
1242
|
/**
|
|
1225
1243
|
* Reconstructs an {@link LDGraphTrackerImpl} from a resumption token, preserving
|
|
@@ -1245,15 +1263,12 @@ var LDGraphTrackerImpl = class _LDGraphTrackerImpl {
|
|
|
1245
1263
|
);
|
|
1246
1264
|
}
|
|
1247
1265
|
getTrackData() {
|
|
1248
|
-
|
|
1266
|
+
return {
|
|
1249
1267
|
runId: this._runId,
|
|
1250
1268
|
graphKey: this._graphKey,
|
|
1251
|
-
version: this._version
|
|
1269
|
+
version: this._version,
|
|
1270
|
+
...this._variationKey !== void 0 ? { variationKey: this._variationKey } : {}
|
|
1252
1271
|
};
|
|
1253
|
-
if (this._variationKey !== void 0) {
|
|
1254
|
-
data.variationKey = this._variationKey;
|
|
1255
|
-
}
|
|
1256
|
-
return data;
|
|
1257
1272
|
}
|
|
1258
1273
|
getSummary() {
|
|
1259
1274
|
return { ...this._summary };
|
|
@@ -1273,7 +1288,7 @@ var LDGraphTrackerImpl = class _LDGraphTrackerImpl {
|
|
|
1273
1288
|
trackInvocationSuccess() {
|
|
1274
1289
|
if (this._summary.success !== void 0) {
|
|
1275
1290
|
this._ldClient.logger?.warn(
|
|
1276
|
-
"
|
|
1291
|
+
"Skipping trackInvocationSuccess: invocation result already recorded on this graph tracker. Call createTracker on the agent graph for a new run."
|
|
1277
1292
|
);
|
|
1278
1293
|
return;
|
|
1279
1294
|
}
|
|
@@ -1283,7 +1298,7 @@ var LDGraphTrackerImpl = class _LDGraphTrackerImpl {
|
|
|
1283
1298
|
trackInvocationFailure() {
|
|
1284
1299
|
if (this._summary.success !== void 0) {
|
|
1285
1300
|
this._ldClient.logger?.warn(
|
|
1286
|
-
"
|
|
1301
|
+
"Skipping trackInvocationFailure: invocation result already recorded on this graph tracker. Call createTracker on the agent graph for a new run."
|
|
1287
1302
|
);
|
|
1288
1303
|
return;
|
|
1289
1304
|
}
|
|
@@ -1293,7 +1308,7 @@ var LDGraphTrackerImpl = class _LDGraphTrackerImpl {
|
|
|
1293
1308
|
trackDuration(durationMs) {
|
|
1294
1309
|
if (this._summary.durationMs !== void 0) {
|
|
1295
1310
|
this._ldClient.logger?.warn(
|
|
1296
|
-
"
|
|
1311
|
+
"Skipping trackDuration: duration already recorded on this graph tracker. Call createTracker on the agent graph for a new run."
|
|
1297
1312
|
);
|
|
1298
1313
|
return;
|
|
1299
1314
|
}
|
|
@@ -1308,7 +1323,7 @@ var LDGraphTrackerImpl = class _LDGraphTrackerImpl {
|
|
|
1308
1323
|
trackTotalTokens(tokens) {
|
|
1309
1324
|
if (this._summary.tokens !== void 0) {
|
|
1310
1325
|
this._ldClient.logger?.warn(
|
|
1311
|
-
"
|
|
1326
|
+
"Skipping trackTotalTokens: tokens already recorded on this graph tracker. Call createTracker on the agent graph for a new run."
|
|
1312
1327
|
);
|
|
1313
1328
|
return;
|
|
1314
1329
|
}
|
|
@@ -1323,7 +1338,7 @@ var LDGraphTrackerImpl = class _LDGraphTrackerImpl {
|
|
|
1323
1338
|
trackPath(path) {
|
|
1324
1339
|
if (this._summary.path !== void 0) {
|
|
1325
1340
|
this._ldClient.logger?.warn(
|
|
1326
|
-
"
|
|
1341
|
+
"Skipping trackPath: path already recorded on this graph tracker. Call createTracker on the agent graph for a new run."
|
|
1327
1342
|
);
|
|
1328
1343
|
return;
|
|
1329
1344
|
}
|
|
@@ -1358,13 +1373,14 @@ var LDGraphTrackerImpl = class _LDGraphTrackerImpl {
|
|
|
1358
1373
|
|
|
1359
1374
|
// src/sdkInfo.ts
|
|
1360
1375
|
var aiSdkName = "@launchdarkly/server-sdk-ai";
|
|
1361
|
-
var aiSdkVersion = "0.
|
|
1376
|
+
var aiSdkVersion = "1.0.0";
|
|
1362
1377
|
var aiSdkLanguage = "javascript";
|
|
1363
1378
|
|
|
1364
1379
|
// src/LDAIClientImpl.ts
|
|
1365
1380
|
var TRACK_SDK_INFO = "$ld:ai:sdk:info";
|
|
1366
1381
|
var TRACK_USAGE_COMPLETION_CONFIG = "$ld:ai:usage:completion-config";
|
|
1367
1382
|
var TRACK_USAGE_CREATE_CHAT = "$ld:ai:usage:create-chat";
|
|
1383
|
+
var TRACK_USAGE_CREATE_AGENT = "$ld:ai:usage:create-agent";
|
|
1368
1384
|
var TRACK_USAGE_JUDGE_CONFIG = "$ld:ai:usage:judge-config";
|
|
1369
1385
|
var TRACK_USAGE_CREATE_JUDGE = "$ld:ai:usage:create-judge";
|
|
1370
1386
|
var TRACK_USAGE_AGENT_CONFIG = "$ld:ai:usage:agent-config";
|
|
@@ -1392,18 +1408,11 @@ var LDAIClientImpl = class {
|
|
|
1392
1408
|
);
|
|
1393
1409
|
}
|
|
1394
1410
|
_interpolateTemplate(template, variables) {
|
|
1395
|
-
return
|
|
1411
|
+
return import_mustache.default.render(template, variables, void 0, { escape: (item) => item });
|
|
1396
1412
|
}
|
|
1397
|
-
async _evaluate(key, context, defaultValue, mode, variables, graphKey) {
|
|
1413
|
+
async _evaluate(key, context, defaultValue, mode, variables, graphKey, defaultAiProvider) {
|
|
1398
1414
|
const ldFlagValue = LDAIConfigUtils.toFlagValue(defaultValue, mode);
|
|
1399
1415
|
const value = await this._ldClient.variation(key, context, ldFlagValue);
|
|
1400
|
-
const flagMode = value._ldMeta?.mode ?? "completion";
|
|
1401
|
-
if (flagMode !== mode) {
|
|
1402
|
-
this._logger?.warn(
|
|
1403
|
-
`AI Config mode mismatch for ${key}: expected ${mode}, got ${flagMode}. Returning disabled config.`
|
|
1404
|
-
);
|
|
1405
|
-
return LDAIConfigUtils.createDisabledConfig(key, mode);
|
|
1406
|
-
}
|
|
1407
1416
|
const trackerFactory = () => new LDAIConfigTrackerImpl(
|
|
1408
1417
|
this._ldClient,
|
|
1409
1418
|
(0, import_node_crypto.randomUUID)(),
|
|
@@ -1417,7 +1426,23 @@ var LDAIClientImpl = class {
|
|
|
1417
1426
|
context,
|
|
1418
1427
|
graphKey
|
|
1419
1428
|
);
|
|
1420
|
-
const
|
|
1429
|
+
const flagMode = value._ldMeta?.mode ?? "completion";
|
|
1430
|
+
let evaluator = Evaluator.noop();
|
|
1431
|
+
if (flagMode !== mode) {
|
|
1432
|
+
this._logger?.warn(
|
|
1433
|
+
`AI Config mode mismatch for ${key}: expected ${mode}, got ${flagMode}. Returning disabled config.`
|
|
1434
|
+
);
|
|
1435
|
+
return LDAIConfigUtils.createDisabledConfig(key, mode, trackerFactory, evaluator);
|
|
1436
|
+
}
|
|
1437
|
+
if (flagMode !== "judge") {
|
|
1438
|
+
evaluator = await this._buildEvaluator(
|
|
1439
|
+
value.judgeConfiguration?.judges ?? [],
|
|
1440
|
+
context,
|
|
1441
|
+
variables,
|
|
1442
|
+
defaultAiProvider
|
|
1443
|
+
);
|
|
1444
|
+
}
|
|
1445
|
+
const config = LDAIConfigUtils.fromFlagValue(key, value, trackerFactory, evaluator);
|
|
1421
1446
|
return this._applyInterpolation(config, context, variables);
|
|
1422
1447
|
}
|
|
1423
1448
|
_applyInterpolation(config, context, variables) {
|
|
@@ -1439,61 +1464,98 @@ var LDAIClientImpl = class {
|
|
|
1439
1464
|
}
|
|
1440
1465
|
return config;
|
|
1441
1466
|
}
|
|
1442
|
-
async
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1467
|
+
async _buildEvaluator(judgeConfigs, context, variables, defaultAiProvider) {
|
|
1468
|
+
if (judgeConfigs.length === 0) {
|
|
1469
|
+
return Evaluator.noop();
|
|
1470
|
+
}
|
|
1471
|
+
const judgeInstances = (await Promise.all(
|
|
1472
|
+
judgeConfigs.map(
|
|
1473
|
+
(jc) => this._createJudgeInstance(
|
|
1474
|
+
jc.key,
|
|
1475
|
+
context,
|
|
1476
|
+
void 0,
|
|
1477
|
+
variables,
|
|
1478
|
+
defaultAiProvider,
|
|
1479
|
+
jc.samplingRate
|
|
1480
|
+
)
|
|
1481
|
+
)
|
|
1482
|
+
)).filter((j) => j !== void 0);
|
|
1483
|
+
return new Evaluator(judgeInstances);
|
|
1484
|
+
}
|
|
1485
|
+
async _completionConfig(key, context, defaultValue, variables, defaultAiProvider) {
|
|
1486
|
+
return await this._evaluate(
|
|
1487
|
+
key,
|
|
1488
|
+
context,
|
|
1489
|
+
defaultValue,
|
|
1490
|
+
"completion",
|
|
1491
|
+
variables,
|
|
1492
|
+
void 0,
|
|
1493
|
+
defaultAiProvider
|
|
1494
|
+
);
|
|
1465
1495
|
}
|
|
1466
|
-
async completionConfig(key, context, defaultValue, variables) {
|
|
1496
|
+
async completionConfig(key, context, defaultValue, variables, defaultAiProvider) {
|
|
1467
1497
|
this._ldClient.track(TRACK_USAGE_COMPLETION_CONFIG, context, key, 1);
|
|
1468
|
-
return this._completionConfig(
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1498
|
+
return this._completionConfig(
|
|
1499
|
+
key,
|
|
1500
|
+
context,
|
|
1501
|
+
defaultValue ?? disabledAIConfig,
|
|
1502
|
+
variables,
|
|
1503
|
+
defaultAiProvider
|
|
1504
|
+
);
|
|
1475
1505
|
}
|
|
1476
1506
|
async _judgeConfig(key, context, defaultValue, variables) {
|
|
1477
|
-
|
|
1507
|
+
if (variables?.message_history !== void 0) {
|
|
1508
|
+
this._logger?.warn(
|
|
1509
|
+
"The variable 'message_history' is reserved by the judge and will be ignored."
|
|
1510
|
+
);
|
|
1511
|
+
}
|
|
1512
|
+
if (variables?.response_to_evaluate !== void 0) {
|
|
1513
|
+
this._logger?.warn(
|
|
1514
|
+
"The variable 'response_to_evaluate' is reserved by the judge and will be ignored."
|
|
1515
|
+
);
|
|
1516
|
+
}
|
|
1517
|
+
const extendedVariables = {
|
|
1518
|
+
...variables,
|
|
1519
|
+
message_history: "{{message_history}}",
|
|
1520
|
+
response_to_evaluate: "{{response_to_evaluate}}"
|
|
1521
|
+
};
|
|
1522
|
+
const config = await this._evaluate(
|
|
1523
|
+
key,
|
|
1524
|
+
context,
|
|
1525
|
+
defaultValue,
|
|
1526
|
+
"judge",
|
|
1527
|
+
extendedVariables
|
|
1528
|
+
);
|
|
1529
|
+
if (config.messages) {
|
|
1530
|
+
return { ...config, messages: stripLegacyJudgeMessages(config.messages) };
|
|
1531
|
+
}
|
|
1478
1532
|
return config;
|
|
1479
1533
|
}
|
|
1480
1534
|
async judgeConfig(key, context, defaultValue, variables) {
|
|
1481
1535
|
this._ldClient.track(TRACK_USAGE_JUDGE_CONFIG, context, key, 1);
|
|
1482
1536
|
return this._judgeConfig(key, context, defaultValue ?? disabledAIConfig, variables);
|
|
1483
1537
|
}
|
|
1484
|
-
async _agentConfig(key, context, defaultValue, variables, graphKey) {
|
|
1485
|
-
|
|
1486
|
-
|
|
1538
|
+
async _agentConfig(key, context, defaultValue, variables, graphKey, defaultAiProvider) {
|
|
1539
|
+
return await this._evaluate(
|
|
1540
|
+
key,
|
|
1541
|
+
context,
|
|
1542
|
+
defaultValue,
|
|
1543
|
+
"agent",
|
|
1544
|
+
variables,
|
|
1545
|
+
graphKey,
|
|
1546
|
+
defaultAiProvider
|
|
1547
|
+
);
|
|
1487
1548
|
}
|
|
1488
|
-
async agentConfig(key, context, defaultValue, variables) {
|
|
1549
|
+
async agentConfig(key, context, defaultValue, variables, defaultAiProvider) {
|
|
1489
1550
|
this._ldClient.track(TRACK_USAGE_AGENT_CONFIG, context, key, 1);
|
|
1490
|
-
return this._agentConfig(
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1551
|
+
return this._agentConfig(
|
|
1552
|
+
key,
|
|
1553
|
+
context,
|
|
1554
|
+
defaultValue ?? disabledAIConfig,
|
|
1555
|
+
variables,
|
|
1556
|
+
void 0,
|
|
1557
|
+
defaultAiProvider
|
|
1558
|
+
);
|
|
1497
1559
|
}
|
|
1498
1560
|
async agentConfigs(agentConfigs, context) {
|
|
1499
1561
|
this._ldClient.track(
|
|
@@ -1516,79 +1578,82 @@ var LDAIClientImpl = class {
|
|
|
1516
1578
|
);
|
|
1517
1579
|
return agents;
|
|
1518
1580
|
}
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
async agents(agentConfigs, context) {
|
|
1523
|
-
return this.agentConfigs(agentConfigs, context);
|
|
1524
|
-
}
|
|
1525
|
-
async createChat(key, context, defaultValue, variables, defaultAiProvider) {
|
|
1526
|
-
this._ldClient.track(TRACK_USAGE_CREATE_CHAT, context, key, 1);
|
|
1527
|
-
const config = await this._completionConfig(
|
|
1581
|
+
async createJudge(key, context, defaultValue, variables, defaultAiProvider, sampleRate = 1) {
|
|
1582
|
+
this._ldClient.track(TRACK_USAGE_CREATE_JUDGE, context, key, 1);
|
|
1583
|
+
return this._createJudgeInstance(
|
|
1528
1584
|
key,
|
|
1529
1585
|
context,
|
|
1530
|
-
defaultValue
|
|
1531
|
-
variables
|
|
1532
|
-
);
|
|
1533
|
-
if (!config.enabled) {
|
|
1534
|
-
this._logger?.info(`Chat configuration is disabled: ${key}`);
|
|
1535
|
-
return void 0;
|
|
1536
|
-
}
|
|
1537
|
-
const provider = await AIProviderFactory.create(config, this._logger, defaultAiProvider);
|
|
1538
|
-
if (!provider) {
|
|
1539
|
-
return void 0;
|
|
1540
|
-
}
|
|
1541
|
-
const judges = await this._initializeJudges(
|
|
1542
|
-
config.judgeConfiguration?.judges ?? [],
|
|
1543
|
-
context,
|
|
1586
|
+
defaultValue,
|
|
1544
1587
|
variables,
|
|
1545
|
-
defaultAiProvider
|
|
1588
|
+
defaultAiProvider,
|
|
1589
|
+
sampleRate
|
|
1546
1590
|
);
|
|
1547
|
-
return new TrackedChat(config, provider, judges, this._logger);
|
|
1548
1591
|
}
|
|
1549
|
-
async
|
|
1550
|
-
this._ldClient.track(TRACK_USAGE_CREATE_JUDGE, context, key, 1);
|
|
1592
|
+
async _createJudgeInstance(key, context, defaultValue, variables, defaultAiProvider, sampleRate = 1) {
|
|
1551
1593
|
try {
|
|
1552
|
-
if (variables?.message_history !== void 0) {
|
|
1553
|
-
this._logger?.warn(
|
|
1554
|
-
"The variable 'message_history' is reserved by the judge and will be ignored."
|
|
1555
|
-
);
|
|
1556
|
-
}
|
|
1557
|
-
if (variables?.response_to_evaluate !== void 0) {
|
|
1558
|
-
this._logger?.warn(
|
|
1559
|
-
"The variable 'response_to_evaluate' is reserved by the judge and will be ignored."
|
|
1560
|
-
);
|
|
1561
|
-
}
|
|
1562
|
-
const extendedVariables = {
|
|
1563
|
-
...variables,
|
|
1564
|
-
message_history: "{{message_history}}",
|
|
1565
|
-
response_to_evaluate: "{{response_to_evaluate}}"
|
|
1566
|
-
};
|
|
1567
1594
|
const judgeConfig = await this._judgeConfig(
|
|
1568
1595
|
key,
|
|
1569
1596
|
context,
|
|
1570
1597
|
defaultValue ?? disabledAIConfig,
|
|
1571
|
-
|
|
1598
|
+
variables
|
|
1572
1599
|
);
|
|
1573
1600
|
if (!judgeConfig.enabled) {
|
|
1574
1601
|
this._logger?.info(`Judge configuration is disabled: ${key}`);
|
|
1575
1602
|
return void 0;
|
|
1576
1603
|
}
|
|
1577
|
-
const
|
|
1578
|
-
|
|
1604
|
+
const runner = await RunnerFactory.createModel(
|
|
1605
|
+
judgeConfig,
|
|
1606
|
+
this._logger,
|
|
1607
|
+
defaultAiProvider,
|
|
1608
|
+
false
|
|
1609
|
+
);
|
|
1610
|
+
if (!runner) {
|
|
1579
1611
|
return void 0;
|
|
1580
1612
|
}
|
|
1581
|
-
return new Judge(judgeConfig,
|
|
1613
|
+
return new Judge(judgeConfig, runner, sampleRate, this._logger);
|
|
1582
1614
|
} catch (error) {
|
|
1583
1615
|
this._logger?.error(`Failed to initialize judge ${key}:`, error);
|
|
1584
1616
|
return void 0;
|
|
1585
1617
|
}
|
|
1586
1618
|
}
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1619
|
+
async createModel(key, context, defaultValue, variables, defaultAiProvider) {
|
|
1620
|
+
this._ldClient.track(TRACK_USAGE_CREATE_CHAT, context, key, 1);
|
|
1621
|
+
const config = await this._completionConfig(
|
|
1622
|
+
key,
|
|
1623
|
+
context,
|
|
1624
|
+
defaultValue ?? disabledAIConfig,
|
|
1625
|
+
variables,
|
|
1626
|
+
defaultAiProvider
|
|
1627
|
+
);
|
|
1628
|
+
if (!config.enabled) {
|
|
1629
|
+
this._logger?.info(`Completion configuration is disabled: ${key}`);
|
|
1630
|
+
return void 0;
|
|
1631
|
+
}
|
|
1632
|
+
const runner = await RunnerFactory.createModel(config, this._logger, defaultAiProvider);
|
|
1633
|
+
if (!runner) {
|
|
1634
|
+
return void 0;
|
|
1635
|
+
}
|
|
1636
|
+
return new ManagedModel(config, runner, this._logger);
|
|
1637
|
+
}
|
|
1638
|
+
async createAgent(key, context, defaultValue, variables, defaultAiProvider) {
|
|
1639
|
+
this._ldClient.track(TRACK_USAGE_CREATE_AGENT, context, key, 1);
|
|
1640
|
+
const config = await this._agentConfig(
|
|
1641
|
+
key,
|
|
1642
|
+
context,
|
|
1643
|
+
defaultValue ?? disabledAIConfig,
|
|
1644
|
+
variables,
|
|
1645
|
+
void 0,
|
|
1646
|
+
defaultAiProvider
|
|
1647
|
+
);
|
|
1648
|
+
if (!config.enabled) {
|
|
1649
|
+
this._logger?.info(`Agent configuration is disabled: ${key}`);
|
|
1650
|
+
return void 0;
|
|
1651
|
+
}
|
|
1652
|
+
const runner = await RunnerFactory.createAgent(config, void 0, this._logger, defaultAiProvider);
|
|
1653
|
+
if (!runner) {
|
|
1654
|
+
return void 0;
|
|
1655
|
+
}
|
|
1656
|
+
return new ManagedAgent(config, runner, this._logger);
|
|
1592
1657
|
}
|
|
1593
1658
|
createTracker(token, context) {
|
|
1594
1659
|
return LDAIConfigTrackerImpl.fromResumptionToken(token, this._ldClient, context);
|
|
@@ -1667,6 +1732,81 @@ var LDAIClientImpl = class {
|
|
|
1667
1732
|
}
|
|
1668
1733
|
};
|
|
1669
1734
|
|
|
1735
|
+
// src/api/ManagedAgentGraph.ts
|
|
1736
|
+
var ManagedAgentGraph = class {
|
|
1737
|
+
constructor(_graphDefinition, _logger) {
|
|
1738
|
+
this._graphDefinition = _graphDefinition;
|
|
1739
|
+
this._logger = _logger;
|
|
1740
|
+
}
|
|
1741
|
+
/**
|
|
1742
|
+
* Runs the agent graph using the provided runner function and returns a ManagedGraphResult.
|
|
1743
|
+
*
|
|
1744
|
+
* The runner function receives the graph tracker and AgentGraphDefinition,
|
|
1745
|
+
* executes the graph, and returns an AgentGraphRunnerResult.
|
|
1746
|
+
*
|
|
1747
|
+
* run() returns before ManagedGraphResult.evaluations resolves.
|
|
1748
|
+
*
|
|
1749
|
+
* @param runner Async function that executes the graph and returns AgentGraphRunnerResult.
|
|
1750
|
+
* @returns ManagedGraphResult with LDAIGraphMetricSummary and evaluations promise.
|
|
1751
|
+
*/
|
|
1752
|
+
async run(runner) {
|
|
1753
|
+
const graphTracker = this._graphDefinition.createTracker();
|
|
1754
|
+
const runnerResult = await runner(this._graphDefinition, graphTracker);
|
|
1755
|
+
const metrics = {
|
|
1756
|
+
success: runnerResult.metrics.success,
|
|
1757
|
+
path: runnerResult.metrics.path,
|
|
1758
|
+
durationMs: runnerResult.metrics.durationMs,
|
|
1759
|
+
tokens: runnerResult.metrics.tokens,
|
|
1760
|
+
nodeMetrics: this._trackNodeMetrics(runnerResult.metrics.nodeMetrics),
|
|
1761
|
+
resumptionToken: graphTracker.resumptionToken
|
|
1762
|
+
};
|
|
1763
|
+
const evaluations = Promise.resolve([]);
|
|
1764
|
+
return {
|
|
1765
|
+
content: runnerResult.content,
|
|
1766
|
+
metrics,
|
|
1767
|
+
raw: runnerResult.raw,
|
|
1768
|
+
evaluations
|
|
1769
|
+
};
|
|
1770
|
+
}
|
|
1771
|
+
/**
|
|
1772
|
+
* Converts per-node LDAIMetrics from the runner into LDAIMetricSummary by
|
|
1773
|
+
* creating a per-node tracker, firing tracking events, and calling getSummary().
|
|
1774
|
+
*/
|
|
1775
|
+
_trackNodeMetrics(nodeMetrics) {
|
|
1776
|
+
const summaries = {};
|
|
1777
|
+
for (const [nodeKey, metrics] of Object.entries(nodeMetrics)) {
|
|
1778
|
+
const node = this._graphDefinition.getNode(nodeKey);
|
|
1779
|
+
if (!node) {
|
|
1780
|
+
this._logger?.warn(`ManagedAgentGraph: no node found for key "${nodeKey}", skipping metrics`);
|
|
1781
|
+
continue;
|
|
1782
|
+
}
|
|
1783
|
+
const tracker = node.getConfig().createTracker();
|
|
1784
|
+
if (metrics.tokens) {
|
|
1785
|
+
tracker.trackTokens(metrics.tokens);
|
|
1786
|
+
}
|
|
1787
|
+
if (metrics.durationMs !== void 0) {
|
|
1788
|
+
tracker.trackDuration(metrics.durationMs);
|
|
1789
|
+
}
|
|
1790
|
+
if (metrics.toolCalls?.length) {
|
|
1791
|
+
tracker.trackToolCalls(metrics.toolCalls);
|
|
1792
|
+
}
|
|
1793
|
+
if (metrics.success) {
|
|
1794
|
+
tracker.trackSuccess();
|
|
1795
|
+
} else {
|
|
1796
|
+
tracker.trackError();
|
|
1797
|
+
}
|
|
1798
|
+
summaries[nodeKey] = tracker.getSummary();
|
|
1799
|
+
}
|
|
1800
|
+
return summaries;
|
|
1801
|
+
}
|
|
1802
|
+
/**
|
|
1803
|
+
* Returns the underlying AgentGraphDefinition.
|
|
1804
|
+
*/
|
|
1805
|
+
getGraphDefinition() {
|
|
1806
|
+
return this._graphDefinition;
|
|
1807
|
+
}
|
|
1808
|
+
};
|
|
1809
|
+
|
|
1670
1810
|
// src/index.ts
|
|
1671
1811
|
function initAi(ldClient) {
|
|
1672
1812
|
return new LDAIClientImpl(ldClient);
|
|
@@ -1674,17 +1814,16 @@ function initAi(ldClient) {
|
|
|
1674
1814
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1675
1815
|
0 && (module.exports = {
|
|
1676
1816
|
AIProvider,
|
|
1677
|
-
AIProviderFactory,
|
|
1678
1817
|
AgentGraphDefinition,
|
|
1679
1818
|
AgentGraphNode,
|
|
1680
1819
|
Judge,
|
|
1681
1820
|
LDFeedbackKind,
|
|
1682
1821
|
LDGraphTrackerImpl,
|
|
1822
|
+
ManagedAgent,
|
|
1823
|
+
ManagedAgentGraph,
|
|
1824
|
+
ManagedModel,
|
|
1825
|
+
RunnerFactory,
|
|
1683
1826
|
SUPPORTED_AI_PROVIDERS,
|
|
1684
|
-
TrackedChat,
|
|
1685
|
-
createBedrockTokenUsage,
|
|
1686
|
-
createOpenAiUsage,
|
|
1687
|
-
createVercelAISDKTokenUsage,
|
|
1688
1827
|
initAi
|
|
1689
1828
|
});
|
|
1690
1829
|
//# sourceMappingURL=index.cjs.map
|