@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.js
CHANGED
|
@@ -1,129 +1,110 @@
|
|
|
1
1
|
// src/LDAIClientImpl.ts
|
|
2
|
-
import
|
|
2
|
+
import Mustache from "mustache";
|
|
3
3
|
import { randomUUID } from "crypto";
|
|
4
4
|
|
|
5
|
-
// src/api/
|
|
6
|
-
var
|
|
7
|
-
constructor(
|
|
8
|
-
this.
|
|
9
|
-
this.
|
|
10
|
-
this.judges = judges;
|
|
5
|
+
// src/api/ManagedAgent.ts
|
|
6
|
+
var ManagedAgent = class {
|
|
7
|
+
constructor(aiAgentConfig, runner, _logger) {
|
|
8
|
+
this.aiAgentConfig = aiAgentConfig;
|
|
9
|
+
this.runner = runner;
|
|
11
10
|
this._logger = _logger;
|
|
12
|
-
this.messages = [];
|
|
13
11
|
}
|
|
14
12
|
/**
|
|
15
|
-
* Invoke the
|
|
16
|
-
*
|
|
13
|
+
* Invoke the agent with a prompt string and return a ManagedResult.
|
|
14
|
+
*
|
|
15
|
+
* `run()` resolves before `ManagedResult.evaluations` resolves. Awaiting
|
|
16
|
+
* `evaluations` guarantees both judge evaluation and tracker.trackJudgeResult()
|
|
17
|
+
* are complete.
|
|
18
|
+
*
|
|
19
|
+
* @param prompt The user input to send to the agent.
|
|
20
|
+
* @returns Promise resolving to ManagedResult (before evaluations settle).
|
|
17
21
|
*/
|
|
18
|
-
async
|
|
19
|
-
const tracker = this.
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
};
|
|
24
|
-
this.messages.push(userMessage);
|
|
25
|
-
const configMessages = this.aiConfig.messages || [];
|
|
26
|
-
const allMessages = [...configMessages, ...this.messages];
|
|
27
|
-
const response = await tracker.trackMetricsOf(
|
|
28
|
-
(result) => result.metrics,
|
|
29
|
-
() => this.provider.invokeModel(allMessages)
|
|
22
|
+
async run(prompt) {
|
|
23
|
+
const tracker = this.aiAgentConfig.createTracker();
|
|
24
|
+
const result = await tracker.trackMetricsOf(
|
|
25
|
+
(r) => r.metrics,
|
|
26
|
+
() => this.runner.run(prompt)
|
|
30
27
|
);
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
return evaluations;
|
|
28
|
+
const metrics = tracker.getSummary();
|
|
29
|
+
const output = result.content;
|
|
30
|
+
const evaluations = this.aiAgentConfig.evaluator.evaluate(prompt, output).then((results) => {
|
|
31
|
+
results.forEach((judgeResult) => {
|
|
32
|
+
if (!judgeResult.sampled) {
|
|
33
|
+
return;
|
|
38
34
|
}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
* Evaluates the response with all configured judges.
|
|
46
|
-
* Returns a promise that resolves to an array of evaluation results.
|
|
47
|
-
*
|
|
48
|
-
* @param messages Array of messages representing the conversation history
|
|
49
|
-
* @param response The AI response to be evaluated
|
|
50
|
-
* @returns Promise resolving to array of judge evaluation results
|
|
51
|
-
*/
|
|
52
|
-
async _evaluateWithJudges(messages, response) {
|
|
53
|
-
const judgeConfigs = this.aiConfig.judgeConfiguration.judges;
|
|
54
|
-
const evaluationPromises = judgeConfigs.map(async (judgeConfig) => {
|
|
55
|
-
const judge = this.judges[judgeConfig.key];
|
|
56
|
-
if (!judge) {
|
|
57
|
-
this._logger?.warn(
|
|
58
|
-
`Judge configuration is not enabled for ${judgeConfig.key} in ${this.aiConfig.key}`
|
|
59
|
-
);
|
|
60
|
-
const result = {
|
|
61
|
-
success: false,
|
|
62
|
-
sampled: true,
|
|
63
|
-
errorMessage: `Judge configuration is not enabled for ${judgeConfig.key}`
|
|
64
|
-
};
|
|
65
|
-
return result;
|
|
66
|
-
}
|
|
67
|
-
return judge.evaluateMessages(messages, response, judgeConfig.samplingRate);
|
|
68
|
-
});
|
|
69
|
-
const results = await Promise.allSettled(evaluationPromises);
|
|
70
|
-
return results.map((settled) => {
|
|
71
|
-
if (settled.status === "fulfilled") {
|
|
72
|
-
return settled.value;
|
|
73
|
-
}
|
|
74
|
-
const result = {
|
|
75
|
-
success: false,
|
|
76
|
-
sampled: true,
|
|
77
|
-
errorMessage: "Judge evaluation failed"
|
|
78
|
-
};
|
|
79
|
-
return result;
|
|
35
|
+
tracker.trackJudgeResult(judgeResult);
|
|
36
|
+
});
|
|
37
|
+
return results;
|
|
38
|
+
}).catch((err) => {
|
|
39
|
+
this._logger?.warn("Judge evaluation failed unexpectedly:", err);
|
|
40
|
+
return [];
|
|
80
41
|
});
|
|
42
|
+
return {
|
|
43
|
+
content: output,
|
|
44
|
+
metrics,
|
|
45
|
+
raw: result.raw,
|
|
46
|
+
parsed: result.parsed,
|
|
47
|
+
evaluations
|
|
48
|
+
};
|
|
81
49
|
}
|
|
82
50
|
/**
|
|
83
|
-
* Get the underlying AI configuration used to initialize this
|
|
51
|
+
* Get the underlying AI agent configuration used to initialize this ManagedAgent.
|
|
84
52
|
*/
|
|
85
53
|
getConfig() {
|
|
86
|
-
return this.
|
|
54
|
+
return this.aiAgentConfig;
|
|
87
55
|
}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
* Get the judges associated with this TrackedChat.
|
|
97
|
-
* Returns a record of judge instances keyed by their configuration keys.
|
|
98
|
-
*/
|
|
99
|
-
getJudges() {
|
|
100
|
-
return this.judges;
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
// src/api/ManagedModel.ts
|
|
59
|
+
var ManagedModel = class {
|
|
60
|
+
constructor(aiConfig, runner, _logger) {
|
|
61
|
+
this.aiConfig = aiConfig;
|
|
62
|
+
this.runner = runner;
|
|
63
|
+
this._logger = _logger;
|
|
101
64
|
}
|
|
102
65
|
/**
|
|
103
|
-
*
|
|
104
|
-
*
|
|
105
|
-
*
|
|
66
|
+
* Invoke the model with a prompt string and return a ManagedResult.
|
|
67
|
+
*
|
|
68
|
+
* `run()` resolves before `ManagedResult.evaluations` resolves. Awaiting
|
|
69
|
+
* `evaluations` guarantees both judge evaluation and tracker.trackJudgeResult()
|
|
70
|
+
* are complete.
|
|
106
71
|
*
|
|
107
|
-
* @param
|
|
72
|
+
* @param prompt The user input to send to the model.
|
|
73
|
+
* @returns Promise resolving to ManagedResult (before evaluations settle).
|
|
108
74
|
*/
|
|
109
|
-
|
|
110
|
-
this.
|
|
75
|
+
async run(prompt) {
|
|
76
|
+
const tracker = this.aiConfig.createTracker();
|
|
77
|
+
const result = await tracker.trackMetricsOf(
|
|
78
|
+
(r) => r.metrics,
|
|
79
|
+
() => this.runner.run(prompt)
|
|
80
|
+
);
|
|
81
|
+
const metrics = tracker.getSummary();
|
|
82
|
+
const output = result.content;
|
|
83
|
+
const evaluations = this.aiConfig.evaluator.evaluate(prompt, output).then((results) => {
|
|
84
|
+
results.forEach((judgeResult) => {
|
|
85
|
+
if (!judgeResult.sampled) {
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
tracker.trackJudgeResult(judgeResult);
|
|
89
|
+
});
|
|
90
|
+
return results;
|
|
91
|
+
}).catch((err) => {
|
|
92
|
+
this._logger?.warn("Judge evaluation failed unexpectedly:", err);
|
|
93
|
+
return [];
|
|
94
|
+
});
|
|
95
|
+
return {
|
|
96
|
+
content: output,
|
|
97
|
+
metrics,
|
|
98
|
+
raw: result.raw,
|
|
99
|
+
parsed: result.parsed,
|
|
100
|
+
evaluations
|
|
101
|
+
};
|
|
111
102
|
}
|
|
112
103
|
/**
|
|
113
|
-
* Get
|
|
114
|
-
*
|
|
115
|
-
* @param includeConfigMessages Whether to include the config messages from the AIConfig.
|
|
116
|
-
* Defaults to false.
|
|
117
|
-
* @returns Array of messages. When includeConfigMessages is true, returns both config
|
|
118
|
-
* messages and conversation history with config messages prepended. When false,
|
|
119
|
-
* returns only the conversation history messages.
|
|
104
|
+
* Get the underlying AI configuration used to initialize this ManagedModel.
|
|
120
105
|
*/
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
const configMessages = this.aiConfig.messages || [];
|
|
124
|
-
return [...configMessages, ...this.messages];
|
|
125
|
-
}
|
|
126
|
-
return [...this.messages];
|
|
106
|
+
getConfig() {
|
|
107
|
+
return this.aiConfig;
|
|
127
108
|
}
|
|
128
109
|
};
|
|
129
110
|
|
|
@@ -158,9 +139,6 @@ var LDAIConfigUtils = class {
|
|
|
158
139
|
if ("evaluationMetricKey" in config && config.evaluationMetricKey !== void 0) {
|
|
159
140
|
flagValue.evaluationMetricKey = config.evaluationMetricKey;
|
|
160
141
|
}
|
|
161
|
-
if ("evaluationMetricKeys" in config && config.evaluationMetricKeys !== void 0) {
|
|
162
|
-
flagValue.evaluationMetricKeys = config.evaluationMetricKeys;
|
|
163
|
-
}
|
|
164
142
|
if ("judgeConfiguration" in config && config.judgeConfiguration !== void 0) {
|
|
165
143
|
flagValue.judgeConfiguration = config.judgeConfiguration;
|
|
166
144
|
}
|
|
@@ -174,47 +152,53 @@ var LDAIConfigUtils = class {
|
|
|
174
152
|
*
|
|
175
153
|
* @param key The configuration key
|
|
176
154
|
* @param flagValue The flag value from LaunchDarkly
|
|
177
|
-
* @param trackerFactory A factory function that creates a new tracker for each
|
|
155
|
+
* @param trackerFactory A factory function that creates a new tracker for each AI run
|
|
156
|
+
* @param evaluator The evaluator to attach to completion and agent configs
|
|
178
157
|
* @returns The appropriate AI configuration type
|
|
179
158
|
*/
|
|
180
|
-
static fromFlagValue(key, flagValue, trackerFactory) {
|
|
159
|
+
static fromFlagValue(key, flagValue, trackerFactory, evaluator) {
|
|
181
160
|
const flagValueMode = flagValue._ldMeta?.mode;
|
|
182
161
|
switch (flagValueMode) {
|
|
183
162
|
case "agent":
|
|
184
|
-
return this.toAgentConfig(key, flagValue, trackerFactory);
|
|
163
|
+
return this.toAgentConfig(key, flagValue, trackerFactory, evaluator);
|
|
185
164
|
case "judge":
|
|
186
165
|
return this.toJudgeConfig(key, flagValue, trackerFactory);
|
|
187
166
|
case "completion":
|
|
188
167
|
default:
|
|
189
|
-
return this.toCompletionConfig(key, flagValue, trackerFactory);
|
|
168
|
+
return this.toCompletionConfig(key, flagValue, trackerFactory, evaluator);
|
|
190
169
|
}
|
|
191
170
|
}
|
|
192
171
|
/**
|
|
193
172
|
* Creates a disabled configuration of the specified mode.
|
|
194
173
|
*
|
|
174
|
+
* @param key The configuration key
|
|
195
175
|
* @param mode The mode for the disabled config
|
|
176
|
+
* @param createTracker A factory function that creates a new tracker for each AI run
|
|
177
|
+
* @param evaluator The evaluator to attach to completion and agent configs
|
|
196
178
|
* @returns A disabled config of the appropriate type
|
|
197
179
|
*/
|
|
198
|
-
static createDisabledConfig(key, mode) {
|
|
180
|
+
static createDisabledConfig(key, mode, createTracker, evaluator) {
|
|
199
181
|
switch (mode) {
|
|
200
182
|
case "agent":
|
|
201
183
|
return {
|
|
202
184
|
key,
|
|
203
185
|
enabled: false,
|
|
204
|
-
createTracker
|
|
186
|
+
createTracker,
|
|
187
|
+
evaluator
|
|
205
188
|
};
|
|
206
189
|
case "judge":
|
|
207
190
|
return {
|
|
208
191
|
key,
|
|
209
192
|
enabled: false,
|
|
210
|
-
createTracker
|
|
193
|
+
createTracker
|
|
211
194
|
};
|
|
212
195
|
case "completion":
|
|
213
196
|
default:
|
|
214
197
|
return {
|
|
215
198
|
key,
|
|
216
199
|
enabled: false,
|
|
217
|
-
createTracker
|
|
200
|
+
createTracker,
|
|
201
|
+
evaluator
|
|
218
202
|
};
|
|
219
203
|
}
|
|
220
204
|
}
|
|
@@ -255,13 +239,15 @@ var LDAIConfigUtils = class {
|
|
|
255
239
|
*
|
|
256
240
|
* @param key The configuration key
|
|
257
241
|
* @param flagValue The flag value from LaunchDarkly
|
|
258
|
-
* @param trackerFactory A factory function that creates a new tracker for each
|
|
242
|
+
* @param trackerFactory A factory function that creates a new tracker for each AI run
|
|
243
|
+
* @param evaluator The evaluator for this completion config
|
|
259
244
|
* @returns A completion configuration
|
|
260
245
|
*/
|
|
261
|
-
static toCompletionConfig(key, flagValue, trackerFactory) {
|
|
246
|
+
static toCompletionConfig(key, flagValue, trackerFactory, evaluator) {
|
|
262
247
|
return {
|
|
263
248
|
...this._toBaseConfig(key, flagValue),
|
|
264
249
|
createTracker: trackerFactory,
|
|
250
|
+
evaluator,
|
|
265
251
|
messages: flagValue.messages,
|
|
266
252
|
judgeConfiguration: flagValue.judgeConfiguration,
|
|
267
253
|
tools: this._resolveTools(flagValue)
|
|
@@ -272,13 +258,15 @@ var LDAIConfigUtils = class {
|
|
|
272
258
|
*
|
|
273
259
|
* @param key The configuration key
|
|
274
260
|
* @param flagValue The flag value from LaunchDarkly
|
|
275
|
-
* @param trackerFactory A factory function that creates a new tracker for each
|
|
261
|
+
* @param trackerFactory A factory function that creates a new tracker for each AI run
|
|
262
|
+
* @param evaluator The evaluator for this agent config
|
|
276
263
|
* @returns An agent configuration
|
|
277
264
|
*/
|
|
278
|
-
static toAgentConfig(key, flagValue, trackerFactory) {
|
|
265
|
+
static toAgentConfig(key, flagValue, trackerFactory, evaluator) {
|
|
279
266
|
return {
|
|
280
267
|
...this._toBaseConfig(key, flagValue),
|
|
281
268
|
createTracker: trackerFactory,
|
|
269
|
+
evaluator,
|
|
282
270
|
instructions: flagValue.instructions,
|
|
283
271
|
judgeConfiguration: flagValue.judgeConfiguration,
|
|
284
272
|
tools: this._resolveTools(flagValue)
|
|
@@ -289,7 +277,7 @@ var LDAIConfigUtils = class {
|
|
|
289
277
|
*
|
|
290
278
|
* @param key The configuration key
|
|
291
279
|
* @param flagValue The flag value from LaunchDarkly
|
|
292
|
-
* @param trackerFactory A factory function that creates a new tracker for each
|
|
280
|
+
* @param trackerFactory A factory function that creates a new tracker for each AI run
|
|
293
281
|
* @returns A judge configuration
|
|
294
282
|
*/
|
|
295
283
|
static toJudgeConfig(key, flagValue, trackerFactory) {
|
|
@@ -422,10 +410,10 @@ var AgentGraphDefinition = class _AgentGraphDefinition {
|
|
|
422
410
|
return this._agentGraph;
|
|
423
411
|
}
|
|
424
412
|
/**
|
|
425
|
-
* Returns a new {@link LDGraphTracker} for
|
|
413
|
+
* Returns a new {@link LDGraphTracker} for a fresh graph run.
|
|
426
414
|
*
|
|
427
|
-
* Call this once per
|
|
428
|
-
* that groups all events for that
|
|
415
|
+
* Call this once per graph run. Each call produces a tracker with a fresh `runId`
|
|
416
|
+
* that groups all events for that run.
|
|
429
417
|
*/
|
|
430
418
|
createTracker() {
|
|
431
419
|
return this._createTracker();
|
|
@@ -543,8 +531,23 @@ var AgentGraphDefinition = class _AgentGraphDefinition {
|
|
|
543
531
|
}
|
|
544
532
|
};
|
|
545
533
|
|
|
534
|
+
// src/api/judge/Evaluator.ts
|
|
535
|
+
var Evaluator = class _Evaluator {
|
|
536
|
+
constructor(_judges) {
|
|
537
|
+
this._judges = _judges;
|
|
538
|
+
}
|
|
539
|
+
static noop() {
|
|
540
|
+
return new _Evaluator([]);
|
|
541
|
+
}
|
|
542
|
+
async evaluate(input, output) {
|
|
543
|
+
if (this._judges.length === 0) {
|
|
544
|
+
return [];
|
|
545
|
+
}
|
|
546
|
+
return Promise.all(this._judges.map((judge) => judge.evaluate(input, output)));
|
|
547
|
+
}
|
|
548
|
+
};
|
|
549
|
+
|
|
546
550
|
// src/api/judge/Judge.ts
|
|
547
|
-
import Mustache from "mustache";
|
|
548
551
|
var EVALUATION_SCHEMA = {
|
|
549
552
|
type: "object",
|
|
550
553
|
properties: {
|
|
@@ -562,15 +565,27 @@ var EVALUATION_SCHEMA = {
|
|
|
562
565
|
required: ["score", "reasoning"],
|
|
563
566
|
additionalProperties: false
|
|
564
567
|
};
|
|
568
|
+
function stripLegacyJudgeMessages(messages) {
|
|
569
|
+
return messages.filter(
|
|
570
|
+
(msg) => msg.role === "system" || !msg.content.includes("{{message_history}}") && !msg.content.includes("{{response_to_evaluate}}")
|
|
571
|
+
);
|
|
572
|
+
}
|
|
565
573
|
var Judge = class {
|
|
566
|
-
constructor(_aiConfig,
|
|
574
|
+
constructor(_aiConfig, _runner, _sampleRate = 1, logger) {
|
|
567
575
|
this._aiConfig = _aiConfig;
|
|
568
|
-
this.
|
|
576
|
+
this._runner = _runner;
|
|
577
|
+
this._sampleRate = _sampleRate;
|
|
569
578
|
this._logger = logger;
|
|
570
579
|
}
|
|
571
580
|
/**
|
|
572
|
-
*
|
|
573
|
-
*
|
|
581
|
+
* The default sampling rate baked in at construction. Used by `evaluate` /
|
|
582
|
+
* `evaluateMessages` when no per-call rate is supplied.
|
|
583
|
+
*/
|
|
584
|
+
get sampleRate() {
|
|
585
|
+
return this._sampleRate;
|
|
586
|
+
}
|
|
587
|
+
/**
|
|
588
|
+
* Gets the evaluation metric key from the judge AI config.
|
|
574
589
|
* Treats empty strings and whitespace-only strings as invalid.
|
|
575
590
|
* @returns The evaluation metric key, or undefined if not available
|
|
576
591
|
*/
|
|
@@ -578,12 +593,6 @@ var Judge = class {
|
|
|
578
593
|
if (this._aiConfig.evaluationMetricKey && this._aiConfig.evaluationMetricKey.trim().length > 0) {
|
|
579
594
|
return this._aiConfig.evaluationMetricKey.trim();
|
|
580
595
|
}
|
|
581
|
-
if (this._aiConfig.evaluationMetricKeys && this._aiConfig.evaluationMetricKeys.length > 0) {
|
|
582
|
-
const validKey = this._aiConfig.evaluationMetricKeys.find(
|
|
583
|
-
(key) => key && key.trim().length > 0
|
|
584
|
-
);
|
|
585
|
-
return validKey ? validKey.trim() : void 0;
|
|
586
|
-
}
|
|
587
596
|
return void 0;
|
|
588
597
|
}
|
|
589
598
|
/**
|
|
@@ -591,10 +600,13 @@ var Judge = class {
|
|
|
591
600
|
*
|
|
592
601
|
* @param input The input prompt or question that was provided to the AI
|
|
593
602
|
* @param output The AI-generated response to be evaluated
|
|
594
|
-
* @param samplingRate Sampling rate (0-1) to determine if evaluation should be processed
|
|
603
|
+
* @param samplingRate Sampling rate (0-1) to determine if evaluation should be processed.
|
|
604
|
+
* When omitted, the Judge's constructor-default rate is used. An explicit `0` overrides
|
|
605
|
+
* the default — only `undefined` falls through.
|
|
595
606
|
* @returns Promise that resolves to evaluation results
|
|
596
607
|
*/
|
|
597
|
-
async evaluate(input, output, samplingRate
|
|
608
|
+
async evaluate(input, output, samplingRate) {
|
|
609
|
+
const effectiveRate = samplingRate ?? this._sampleRate;
|
|
598
610
|
const result = {
|
|
599
611
|
success: false,
|
|
600
612
|
sampled: false,
|
|
@@ -612,26 +624,20 @@ var Judge = class {
|
|
|
612
624
|
result.errorMessage = "Judge configuration is missing required evaluation metric key";
|
|
613
625
|
return result;
|
|
614
626
|
}
|
|
615
|
-
if (
|
|
616
|
-
this._logger?.
|
|
617
|
-
result.sampled = true;
|
|
618
|
-
result.errorMessage = "Judge configuration must include messages";
|
|
619
|
-
return result;
|
|
620
|
-
}
|
|
621
|
-
if (Math.random() > samplingRate) {
|
|
622
|
-
this._logger?.debug(`Judge evaluation skipped due to sampling rate: ${samplingRate}`);
|
|
627
|
+
if (Math.random() > effectiveRate) {
|
|
628
|
+
this._logger?.debug(`Judge evaluation skipped due to sampling rate: ${effectiveRate}`);
|
|
623
629
|
return result;
|
|
624
630
|
}
|
|
625
631
|
result.sampled = true;
|
|
626
|
-
const
|
|
632
|
+
const evaluationInput = this._buildEvaluationInput(input, output);
|
|
627
633
|
const response = await tracker.trackMetricsOf(
|
|
628
634
|
(r) => r.metrics,
|
|
629
|
-
() => this.
|
|
635
|
+
() => this._runner.run(evaluationInput, EVALUATION_SCHEMA)
|
|
630
636
|
);
|
|
631
|
-
const evalResult = this._parseEvaluationResponse(response.
|
|
637
|
+
const evalResult = this._parseEvaluationResponse(response.parsed);
|
|
632
638
|
if (!evalResult) {
|
|
633
639
|
this._logger?.warn(
|
|
634
|
-
`Could not parse evaluation response: ${JSON.stringify(response.
|
|
640
|
+
`Could not parse evaluation response: ${JSON.stringify(response.parsed)}`,
|
|
635
641
|
tracker.getTrackData()
|
|
636
642
|
);
|
|
637
643
|
return result;
|
|
@@ -651,16 +657,21 @@ var Judge = class {
|
|
|
651
657
|
}
|
|
652
658
|
}
|
|
653
659
|
/**
|
|
654
|
-
* Evaluates an AI response from chat messages and
|
|
660
|
+
* Evaluates an AI response from chat messages and a runner result.
|
|
661
|
+
*
|
|
662
|
+
* Each message is rendered as `<role>: <content>` so the judge model can
|
|
663
|
+
* distinguish speakers in the message history. Messages are joined with a
|
|
664
|
+
* single newline.
|
|
655
665
|
*
|
|
656
666
|
* @param messages Array of messages representing the conversation history
|
|
657
|
-
* @param response The AI
|
|
658
|
-
* @param samplingRatio Sampling ratio (0-1)
|
|
667
|
+
* @param response The runner result containing the AI-generated content to evaluate
|
|
668
|
+
* @param samplingRatio Sampling ratio (0-1). When omitted, the Judge's
|
|
669
|
+
* constructor-default rate is used.
|
|
659
670
|
* @returns Promise that resolves to evaluation results
|
|
660
671
|
*/
|
|
661
|
-
async evaluateMessages(messages, response, samplingRatio
|
|
662
|
-
const input = messages.length === 0 ? "" : messages.map((msg) => msg.content).join("\
|
|
663
|
-
const output = response.
|
|
672
|
+
async evaluateMessages(messages, response, samplingRatio) {
|
|
673
|
+
const input = messages.length === 0 ? "" : messages.map((msg) => `${msg.role}: ${msg.content}`).join("\n");
|
|
674
|
+
const output = response.content;
|
|
664
675
|
return this.evaluate(input, output, samplingRatio);
|
|
665
676
|
}
|
|
666
677
|
/**
|
|
@@ -670,29 +681,23 @@ var Judge = class {
|
|
|
670
681
|
return this._aiConfig;
|
|
671
682
|
}
|
|
672
683
|
/**
|
|
673
|
-
* Returns the
|
|
684
|
+
* Returns the runner used by this judge.
|
|
674
685
|
*/
|
|
675
|
-
|
|
676
|
-
return this.
|
|
677
|
-
}
|
|
678
|
-
/**
|
|
679
|
-
* Constructs evaluation messages by combining judge's config messages with input/output.
|
|
680
|
-
*/
|
|
681
|
-
_constructEvaluationMessages(input, output) {
|
|
682
|
-
const messages = this._aiConfig.messages.map((msg) => ({
|
|
683
|
-
...msg,
|
|
684
|
-
content: this._interpolateMessage(msg.content, {
|
|
685
|
-
message_history: input,
|
|
686
|
-
response_to_evaluate: output
|
|
687
|
-
})
|
|
688
|
-
}));
|
|
689
|
-
return messages;
|
|
686
|
+
getRunner() {
|
|
687
|
+
return this._runner;
|
|
690
688
|
}
|
|
691
689
|
/**
|
|
692
|
-
*
|
|
690
|
+
* Builds the evaluation input string passed to the runner.
|
|
691
|
+
*
|
|
692
|
+
* Combines the original prompt and the response into a single, well-known
|
|
693
|
+
* format the judge model is expected to evaluate.
|
|
693
694
|
*/
|
|
694
|
-
|
|
695
|
-
return
|
|
695
|
+
_buildEvaluationInput(input, output) {
|
|
696
|
+
return `MESSAGE HISTORY:
|
|
697
|
+
${input}
|
|
698
|
+
|
|
699
|
+
RESPONSE TO EVALUATE:
|
|
700
|
+
${output}`;
|
|
696
701
|
}
|
|
697
702
|
/**
|
|
698
703
|
* Parses the structured evaluation response. Expects top-level {score, reasoning}.
|
|
@@ -718,115 +723,105 @@ var Judge = class {
|
|
|
718
723
|
// src/api/providers/AIProvider.ts
|
|
719
724
|
var AIProvider = class {
|
|
720
725
|
constructor(logger) {
|
|
721
|
-
this.
|
|
726
|
+
this._logger = logger;
|
|
722
727
|
}
|
|
723
728
|
/**
|
|
724
|
-
*
|
|
725
|
-
* This method should convert messages to provider format, invoke the model,
|
|
726
|
-
* and return a ChatResponse with the result and metrics.
|
|
729
|
+
* Create a Runner for a completion or judge AI Config.
|
|
727
730
|
*
|
|
728
|
-
*
|
|
729
|
-
*
|
|
731
|
+
* Override in provider subclasses to return a configured {@link Runner}.
|
|
732
|
+
* Default implementation returns `undefined`.
|
|
730
733
|
*
|
|
731
|
-
* @param
|
|
732
|
-
* @
|
|
734
|
+
* @param config The completion or judge AI configuration.
|
|
735
|
+
* @param multiTurn Whether the runner should accumulate conversation history
|
|
736
|
+
* across successive `run()` calls. Defaults to `true` (chat semantics).
|
|
737
|
+
* Pass `false` for stateless runners such as judges where each call must
|
|
738
|
+
* start from the initial config messages.
|
|
739
|
+
* @returns Promise resolving to a {@link Runner}, or `undefined` if this
|
|
740
|
+
* provider does not support model creation.
|
|
733
741
|
*/
|
|
734
|
-
async
|
|
735
|
-
|
|
736
|
-
return {
|
|
737
|
-
message: {
|
|
738
|
-
role: "assistant",
|
|
739
|
-
content: ""
|
|
740
|
-
},
|
|
741
|
-
metrics: {
|
|
742
|
-
success: false,
|
|
743
|
-
usage: {
|
|
744
|
-
total: 0,
|
|
745
|
-
input: 0,
|
|
746
|
-
output: 0
|
|
747
|
-
}
|
|
748
|
-
}
|
|
749
|
-
};
|
|
742
|
+
async createModel(_config, _multiTurn = true) {
|
|
743
|
+
return void 0;
|
|
750
744
|
}
|
|
751
745
|
/**
|
|
752
|
-
*
|
|
753
|
-
* This method should convert messages to provider format, invoke the model with
|
|
754
|
-
* structured output configuration, and return a structured response.
|
|
746
|
+
* Create a Runner for an agent AI Config.
|
|
755
747
|
*
|
|
756
|
-
*
|
|
757
|
-
*
|
|
748
|
+
* Override in provider subclasses to return a configured {@link Runner}.
|
|
749
|
+
* Default implementation returns `undefined`.
|
|
758
750
|
*
|
|
759
|
-
* @param
|
|
760
|
-
* @param
|
|
761
|
-
* @returns Promise
|
|
751
|
+
* @param config The agent AI configuration.
|
|
752
|
+
* @param tools Optional registry of callable tools.
|
|
753
|
+
* @returns Promise resolving to a {@link Runner}, or `undefined` if this
|
|
754
|
+
* provider does not support agent creation.
|
|
762
755
|
*/
|
|
763
|
-
async
|
|
764
|
-
|
|
765
|
-
return {
|
|
766
|
-
data: {},
|
|
767
|
-
rawResponse: "",
|
|
768
|
-
metrics: {
|
|
769
|
-
success: false,
|
|
770
|
-
usage: {
|
|
771
|
-
total: 0,
|
|
772
|
-
input: 0,
|
|
773
|
-
output: 0
|
|
774
|
-
}
|
|
775
|
-
}
|
|
776
|
-
};
|
|
756
|
+
async createAgent(_config, _tools) {
|
|
757
|
+
return void 0;
|
|
777
758
|
}
|
|
778
759
|
/**
|
|
779
|
-
*
|
|
780
|
-
*
|
|
781
|
-
*
|
|
760
|
+
* Create an AgentGraphRunner for an agent graph definition.
|
|
761
|
+
*
|
|
762
|
+
* Override in provider subclasses to return a configured {@link AgentGraphRunner}.
|
|
763
|
+
* Default implementation returns `undefined`.
|
|
782
764
|
*
|
|
783
|
-
* @param
|
|
784
|
-
* @param
|
|
785
|
-
* @returns Promise
|
|
765
|
+
* @param graphDef The agent graph definition.
|
|
766
|
+
* @param tools Optional registry of callable tools.
|
|
767
|
+
* @returns Promise resolving to an {@link AgentGraphRunner}, or `undefined` if
|
|
768
|
+
* this provider does not support graph execution.
|
|
786
769
|
*/
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
throw new Error("Provider implementations must override the static create method");
|
|
770
|
+
async createAgentGraph(_graphDef, _tools) {
|
|
771
|
+
return void 0;
|
|
790
772
|
}
|
|
791
773
|
};
|
|
792
774
|
|
|
793
|
-
// src/api/providers/
|
|
775
|
+
// src/api/providers/RunnerFactory.ts
|
|
794
776
|
var SUPPORTED_AI_PROVIDERS = [
|
|
795
777
|
"openai",
|
|
796
778
|
// Multi-provider packages should be last in the list
|
|
797
779
|
"langchain",
|
|
798
780
|
"vercel"
|
|
799
781
|
];
|
|
800
|
-
var
|
|
782
|
+
var RunnerFactory = class _RunnerFactory {
|
|
801
783
|
/**
|
|
802
|
-
*
|
|
803
|
-
* This method attempts to load provider-specific implementations dynamically.
|
|
804
|
-
* Returns undefined if the provider is not supported.
|
|
784
|
+
* Load and return the AIProvider factory for the given provider type.
|
|
805
785
|
*
|
|
806
|
-
*
|
|
807
|
-
*
|
|
808
|
-
* @
|
|
786
|
+
* This is the single place in the codebase that knows provider package names.
|
|
787
|
+
* Each supported provider package exports a `*RunnerFactory` class that
|
|
788
|
+
* extends {@link AIProvider}; this method instantiates it directly.
|
|
789
|
+
*
|
|
790
|
+
* @param providerType One of the {@link SUPPORTED_AI_PROVIDERS} values.
|
|
791
|
+
* @param logger Optional logger forwarded to the provider factory.
|
|
792
|
+
* @returns A configured {@link AIProvider} instance, or `undefined` if the
|
|
793
|
+
* package cannot be loaded.
|
|
809
794
|
*/
|
|
810
|
-
static async
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
795
|
+
static async _getProviderFactory(providerType, logger) {
|
|
796
|
+
try {
|
|
797
|
+
let module;
|
|
798
|
+
switch (providerType) {
|
|
799
|
+
case "openai": {
|
|
800
|
+
module = await import("@launchdarkly/server-sdk-ai-openai");
|
|
801
|
+
return new module.OpenAIRunnerFactory(logger);
|
|
802
|
+
}
|
|
803
|
+
case "langchain": {
|
|
804
|
+
module = await import("@launchdarkly/server-sdk-ai-langchain");
|
|
805
|
+
return new module.LangChainRunnerFactory(logger);
|
|
806
|
+
}
|
|
807
|
+
case "vercel": {
|
|
808
|
+
module = await import("@launchdarkly/server-sdk-ai-vercel");
|
|
809
|
+
return new module.VercelRunnerFactory(logger);
|
|
810
|
+
}
|
|
811
|
+
default:
|
|
812
|
+
return void 0;
|
|
821
813
|
}
|
|
814
|
+
} catch (error) {
|
|
815
|
+
logger?.warn(
|
|
816
|
+
`Unable to load provider package. Check that you have installed the correct package. ${error.message}`
|
|
817
|
+
);
|
|
818
|
+
return void 0;
|
|
822
819
|
}
|
|
823
|
-
logger?.warn(
|
|
824
|
-
`Provider is not supported or failed to initialize: ${aiConfig.provider?.name ?? "unknown"}`
|
|
825
|
-
);
|
|
826
|
-
return void 0;
|
|
827
820
|
}
|
|
828
821
|
/**
|
|
829
822
|
* Determine which providers to try based on defaultAiProvider and providerName.
|
|
823
|
+
*
|
|
824
|
+
* Mirrors Python's `_get_providers_to_try` helper.
|
|
830
825
|
*/
|
|
831
826
|
static _getProvidersToTry(defaultAiProvider, providerName) {
|
|
832
827
|
if (defaultAiProvider) {
|
|
@@ -843,57 +838,118 @@ var AIProviderFactory = class {
|
|
|
843
838
|
return Array.from(providerSet);
|
|
844
839
|
}
|
|
845
840
|
/**
|
|
846
|
-
* Try
|
|
841
|
+
* Try each provider in order and return the first non-undefined result.
|
|
842
|
+
*
|
|
843
|
+
* Mirrors Python's `_with_fallback` helper. Loads each provider factory via
|
|
844
|
+
* {@link _getProviderFactory} and calls `fn` with it. Returns the first
|
|
845
|
+
* truthy result, or `undefined` if no provider succeeds.
|
|
846
|
+
*
|
|
847
|
+
* @param providers Ordered list of provider types to try.
|
|
848
|
+
* @param fn Callback that calls the appropriate factory method on the provider.
|
|
849
|
+
* @param logger Optional logger forwarded to each provider factory.
|
|
847
850
|
*/
|
|
848
|
-
static async
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
case "langchain": {
|
|
858
|
-
module = await import("@launchdarkly/server-sdk-ai-langchain");
|
|
859
|
-
const provider = await module.LangChainProvider.create(aiConfig, logger);
|
|
860
|
-
return provider;
|
|
851
|
+
static async _withFallback(providers, fn, logger) {
|
|
852
|
+
for (const providerType of providers) {
|
|
853
|
+
logger?.debug(`Attempting to create runner with provider: ${providerType}`);
|
|
854
|
+
const factory = await _RunnerFactory._getProviderFactory(providerType, logger);
|
|
855
|
+
if (factory) {
|
|
856
|
+
const result = await fn(factory);
|
|
857
|
+
if (result) {
|
|
858
|
+
logger?.debug(`Successfully created runner with provider: ${providerType}`);
|
|
859
|
+
return result;
|
|
861
860
|
}
|
|
862
|
-
case "vercel": {
|
|
863
|
-
module = await import("@launchdarkly/server-sdk-ai-vercel");
|
|
864
|
-
const provider = await module.VercelProvider.create(aiConfig, logger);
|
|
865
|
-
return provider;
|
|
866
|
-
}
|
|
867
|
-
default:
|
|
868
|
-
return void 0;
|
|
869
861
|
}
|
|
870
|
-
}
|
|
862
|
+
}
|
|
863
|
+
return void 0;
|
|
864
|
+
}
|
|
865
|
+
/**
|
|
866
|
+
* Create a Runner for the given AI configuration.
|
|
867
|
+
*
|
|
868
|
+
* Suitable for completion, judge, and agent config modes. Dynamically
|
|
869
|
+
* loads the matching provider package via {@link _getProviderFactory} and
|
|
870
|
+
* delegates to its {@link AIProvider.createModel} method.
|
|
871
|
+
*
|
|
872
|
+
* @param config The AI configuration (completion, agent, or judge).
|
|
873
|
+
* @param logger Optional logger forwarded to the underlying provider.
|
|
874
|
+
* @param defaultAiProvider Optional provider override
|
|
875
|
+
* ('openai', 'langchain', 'vercel', …). When set, only that provider is
|
|
876
|
+
* tried. When omitted, providers are tried in priority order based on the
|
|
877
|
+
* provider name in the config.
|
|
878
|
+
* @param multiTurn Whether the runner should accumulate conversation history
|
|
879
|
+
* across successive `run()` calls. Defaults to `true` (chat semantics).
|
|
880
|
+
* Judges pass `false` so each evaluation starts from the initial config
|
|
881
|
+
* messages.
|
|
882
|
+
* @returns A configured {@link Runner} ready to invoke the model, or
|
|
883
|
+
* `undefined` if no suitable provider could be loaded.
|
|
884
|
+
*/
|
|
885
|
+
static async createModel(config, logger, defaultAiProvider, multiTurn = true) {
|
|
886
|
+
const providerName = config.provider?.name?.toLowerCase();
|
|
887
|
+
const providers = _RunnerFactory._getProvidersToTry(defaultAiProvider, providerName);
|
|
888
|
+
const runner = await _RunnerFactory._withFallback(
|
|
889
|
+
providers,
|
|
890
|
+
(factory) => factory.createModel(config, multiTurn),
|
|
891
|
+
logger
|
|
892
|
+
);
|
|
893
|
+
if (!runner) {
|
|
871
894
|
logger?.warn(
|
|
872
|
-
`
|
|
895
|
+
`Provider is not supported or failed to initialize: ${config.provider?.name ?? "unknown"}`
|
|
873
896
|
);
|
|
874
|
-
return void 0;
|
|
875
897
|
}
|
|
898
|
+
return runner;
|
|
899
|
+
}
|
|
900
|
+
/**
|
|
901
|
+
* Create a Runner for an agent AI Config.
|
|
902
|
+
*
|
|
903
|
+
* Delegates to the provider factory's {@link AIProvider.createAgent} method.
|
|
904
|
+
*
|
|
905
|
+
* @param config The agent AI configuration.
|
|
906
|
+
* @param tools Optional registry of callable tools.
|
|
907
|
+
* @param logger Optional logger forwarded to the underlying provider.
|
|
908
|
+
* @param defaultAiProvider Optional provider override.
|
|
909
|
+
* @returns A configured {@link Runner}, or `undefined` if no suitable
|
|
910
|
+
* provider could be loaded.
|
|
911
|
+
*/
|
|
912
|
+
static async createAgent(config, tools, logger, defaultAiProvider) {
|
|
913
|
+
const providerName = config.provider?.name?.toLowerCase();
|
|
914
|
+
const providers = _RunnerFactory._getProvidersToTry(defaultAiProvider, providerName);
|
|
915
|
+
const runner = await _RunnerFactory._withFallback(
|
|
916
|
+
providers,
|
|
917
|
+
(factory) => factory.createAgent(config, tools),
|
|
918
|
+
logger
|
|
919
|
+
);
|
|
920
|
+
if (!runner) {
|
|
921
|
+
logger?.warn(
|
|
922
|
+
`Provider is not supported or failed to initialize: ${config.provider?.name ?? "unknown"}`
|
|
923
|
+
);
|
|
924
|
+
}
|
|
925
|
+
return runner;
|
|
926
|
+
}
|
|
927
|
+
/**
|
|
928
|
+
* Create an AgentGraphRunner for the given agent graph definition.
|
|
929
|
+
*
|
|
930
|
+
* Delegates to the provider factory's {@link AIProvider.createAgentGraph} method.
|
|
931
|
+
*
|
|
932
|
+
* @param graphDef The agent graph definition.
|
|
933
|
+
* @param tools Optional registry of callable tools.
|
|
934
|
+
* @param logger Optional logger forwarded to the underlying provider.
|
|
935
|
+
* @param defaultAiProvider Optional provider override.
|
|
936
|
+
* @returns A configured {@link AgentGraphRunner}, or `undefined` if no
|
|
937
|
+
* suitable provider could be loaded.
|
|
938
|
+
*/
|
|
939
|
+
static async createAgentGraph(graphDef, tools, logger, defaultAiProvider) {
|
|
940
|
+
const providers = _RunnerFactory._getProvidersToTry(defaultAiProvider);
|
|
941
|
+
const runner = await _RunnerFactory._withFallback(
|
|
942
|
+
providers,
|
|
943
|
+
(factory) => factory.createAgentGraph(graphDef, tools),
|
|
944
|
+
logger
|
|
945
|
+
);
|
|
946
|
+
if (!runner) {
|
|
947
|
+
logger?.warn(`No provider could create an AgentGraphRunner for the given graph definition.`);
|
|
948
|
+
}
|
|
949
|
+
return runner;
|
|
876
950
|
}
|
|
877
951
|
};
|
|
878
952
|
|
|
879
|
-
// src/api/metrics/BedrockTokenUsage.ts
|
|
880
|
-
function createBedrockTokenUsage(data) {
|
|
881
|
-
return {
|
|
882
|
-
total: data.totalTokens || 0,
|
|
883
|
-
input: data.inputTokens || 0,
|
|
884
|
-
output: data.outputTokens || 0
|
|
885
|
-
};
|
|
886
|
-
}
|
|
887
|
-
|
|
888
|
-
// src/api/metrics/OpenAiUsage.ts
|
|
889
|
-
function createOpenAiUsage(data) {
|
|
890
|
-
return {
|
|
891
|
-
total: data.total_tokens ?? 0,
|
|
892
|
-
input: data.prompt_tokens ?? 0,
|
|
893
|
-
output: data.completion_tokens ?? 0
|
|
894
|
-
};
|
|
895
|
-
}
|
|
896
|
-
|
|
897
953
|
// src/api/metrics/LDFeedbackKind.ts
|
|
898
954
|
var LDFeedbackKind = /* @__PURE__ */ ((LDFeedbackKind2) => {
|
|
899
955
|
LDFeedbackKind2["Positive"] = "positive";
|
|
@@ -901,15 +957,6 @@ var LDFeedbackKind = /* @__PURE__ */ ((LDFeedbackKind2) => {
|
|
|
901
957
|
return LDFeedbackKind2;
|
|
902
958
|
})(LDFeedbackKind || {});
|
|
903
959
|
|
|
904
|
-
// src/api/metrics/VercelAISDKTokenUsage.ts
|
|
905
|
-
function createVercelAISDKTokenUsage(data) {
|
|
906
|
-
return {
|
|
907
|
-
total: data.totalTokens ?? 0,
|
|
908
|
-
input: data.inputTokens ?? data.promptTokens ?? 0,
|
|
909
|
-
output: data.outputTokens ?? data.completionTokens ?? 0
|
|
910
|
-
};
|
|
911
|
-
}
|
|
912
|
-
|
|
913
960
|
// src/LDAIConfigTrackerImpl.ts
|
|
914
961
|
var LDAIConfigTrackerImpl = class _LDAIConfigTrackerImpl {
|
|
915
962
|
constructor(_ldClient, _runId, _configKey, _variationKey, _version, _modelName, _providerName, _context, _graphKey) {
|
|
@@ -923,6 +970,7 @@ var LDAIConfigTrackerImpl = class _LDAIConfigTrackerImpl {
|
|
|
923
970
|
this._context = _context;
|
|
924
971
|
this._graphKey = _graphKey;
|
|
925
972
|
this._trackedMetrics = {};
|
|
973
|
+
this._trackedMetrics.resumptionToken = this.resumptionToken;
|
|
926
974
|
}
|
|
927
975
|
getTrackData() {
|
|
928
976
|
return {
|
|
@@ -963,7 +1011,7 @@ var LDAIConfigTrackerImpl = class _LDAIConfigTrackerImpl {
|
|
|
963
1011
|
trackDuration(duration) {
|
|
964
1012
|
if (this._trackedMetrics.durationMs !== void 0) {
|
|
965
1013
|
this._ldClient.logger?.warn(
|
|
966
|
-
"
|
|
1014
|
+
"Skipping trackDuration: duration already recorded on this tracker. Call createTracker on the AI Config for a new run."
|
|
967
1015
|
);
|
|
968
1016
|
return;
|
|
969
1017
|
}
|
|
@@ -984,7 +1032,7 @@ var LDAIConfigTrackerImpl = class _LDAIConfigTrackerImpl {
|
|
|
984
1032
|
trackTimeToFirstToken(timeToFirstTokenMs) {
|
|
985
1033
|
if (this._trackedMetrics.timeToFirstTokenMs !== void 0) {
|
|
986
1034
|
this._ldClient.logger?.warn(
|
|
987
|
-
"
|
|
1035
|
+
"Skipping trackTimeToFirstToken: time-to-first-token already recorded on this tracker. Call createTracker on the AI Config for a new run."
|
|
988
1036
|
);
|
|
989
1037
|
return;
|
|
990
1038
|
}
|
|
@@ -1006,6 +1054,10 @@ var LDAIConfigTrackerImpl = class _LDAIConfigTrackerImpl {
|
|
|
1006
1054
|
}
|
|
1007
1055
|
}
|
|
1008
1056
|
trackToolCall(toolKey) {
|
|
1057
|
+
if (!this._trackedMetrics.toolCalls) {
|
|
1058
|
+
this._trackedMetrics.toolCalls = [];
|
|
1059
|
+
}
|
|
1060
|
+
this._trackedMetrics.toolCalls.push(toolKey);
|
|
1009
1061
|
this._ldClient.track("$ld:ai:tool_call", this._context, { ...this.getTrackData(), toolKey }, 1);
|
|
1010
1062
|
}
|
|
1011
1063
|
trackToolCalls(toolKeys) {
|
|
@@ -1016,7 +1068,7 @@ var LDAIConfigTrackerImpl = class _LDAIConfigTrackerImpl {
|
|
|
1016
1068
|
trackFeedback(feedback) {
|
|
1017
1069
|
if (this._trackedMetrics.feedback !== void 0) {
|
|
1018
1070
|
this._ldClient.logger?.warn(
|
|
1019
|
-
"
|
|
1071
|
+
"Skipping trackFeedback: feedback already recorded on this tracker. Call createTracker on the AI Config for a new run."
|
|
1020
1072
|
);
|
|
1021
1073
|
return;
|
|
1022
1074
|
}
|
|
@@ -1030,7 +1082,7 @@ var LDAIConfigTrackerImpl = class _LDAIConfigTrackerImpl {
|
|
|
1030
1082
|
trackSuccess() {
|
|
1031
1083
|
if (this._trackedMetrics.success !== void 0) {
|
|
1032
1084
|
this._ldClient.logger?.warn(
|
|
1033
|
-
"
|
|
1085
|
+
"Skipping trackSuccess: success/error already recorded on this tracker. Call createTracker on the AI Config for a new run."
|
|
1034
1086
|
);
|
|
1035
1087
|
return;
|
|
1036
1088
|
}
|
|
@@ -1040,7 +1092,7 @@ var LDAIConfigTrackerImpl = class _LDAIConfigTrackerImpl {
|
|
|
1040
1092
|
trackError() {
|
|
1041
1093
|
if (this._trackedMetrics.success !== void 0) {
|
|
1042
1094
|
this._ldClient.logger?.warn(
|
|
1043
|
-
"
|
|
1095
|
+
"Skipping trackError: success/error already recorded on this tracker. Call createTracker on the AI Config for a new run."
|
|
1044
1096
|
);
|
|
1045
1097
|
return;
|
|
1046
1098
|
}
|
|
@@ -1061,8 +1113,11 @@ var LDAIConfigTrackerImpl = class _LDAIConfigTrackerImpl {
|
|
|
1061
1113
|
} else {
|
|
1062
1114
|
this.trackError();
|
|
1063
1115
|
}
|
|
1064
|
-
if (metrics.
|
|
1065
|
-
this.trackTokens(metrics.
|
|
1116
|
+
if (metrics.tokens) {
|
|
1117
|
+
this.trackTokens(metrics.tokens);
|
|
1118
|
+
}
|
|
1119
|
+
if (metrics.toolCalls?.length) {
|
|
1120
|
+
this.trackToolCalls(metrics.toolCalls);
|
|
1066
1121
|
}
|
|
1067
1122
|
return result;
|
|
1068
1123
|
}
|
|
@@ -1086,8 +1141,11 @@ var LDAIConfigTrackerImpl = class _LDAIConfigTrackerImpl {
|
|
|
1086
1141
|
} else {
|
|
1087
1142
|
this.trackError();
|
|
1088
1143
|
}
|
|
1089
|
-
if (metrics.
|
|
1090
|
-
this.trackTokens(metrics.
|
|
1144
|
+
if (metrics.tokens) {
|
|
1145
|
+
this.trackTokens(metrics.tokens);
|
|
1146
|
+
}
|
|
1147
|
+
if (metrics.toolCalls?.length) {
|
|
1148
|
+
this.trackToolCalls(metrics.toolCalls);
|
|
1091
1149
|
}
|
|
1092
1150
|
} catch (error) {
|
|
1093
1151
|
this.trackError();
|
|
@@ -1095,50 +1153,10 @@ var LDAIConfigTrackerImpl = class _LDAIConfigTrackerImpl {
|
|
|
1095
1153
|
this.trackDuration(Date.now() - startTime);
|
|
1096
1154
|
}
|
|
1097
1155
|
}
|
|
1098
|
-
async trackOpenAIMetrics(func) {
|
|
1099
|
-
try {
|
|
1100
|
-
const result = await this.trackDurationOf(func);
|
|
1101
|
-
this.trackSuccess();
|
|
1102
|
-
if (result.usage) {
|
|
1103
|
-
this.trackTokens(createOpenAiUsage(result.usage));
|
|
1104
|
-
}
|
|
1105
|
-
return result;
|
|
1106
|
-
} catch (err) {
|
|
1107
|
-
this.trackError();
|
|
1108
|
-
throw err;
|
|
1109
|
-
}
|
|
1110
|
-
}
|
|
1111
|
-
trackBedrockConverseMetrics(res) {
|
|
1112
|
-
if (res.$metadata?.httpStatusCode === 200) {
|
|
1113
|
-
this.trackSuccess();
|
|
1114
|
-
} else if (res.$metadata?.httpStatusCode && res.$metadata.httpStatusCode >= 400) {
|
|
1115
|
-
this.trackError();
|
|
1116
|
-
}
|
|
1117
|
-
if (res.metrics && res.metrics.latencyMs) {
|
|
1118
|
-
this.trackDuration(res.metrics.latencyMs);
|
|
1119
|
-
}
|
|
1120
|
-
if (res.usage) {
|
|
1121
|
-
this.trackTokens(createBedrockTokenUsage(res.usage));
|
|
1122
|
-
}
|
|
1123
|
-
return res;
|
|
1124
|
-
}
|
|
1125
|
-
async trackVercelAISDKGenerateTextMetrics(func) {
|
|
1126
|
-
try {
|
|
1127
|
-
const result = await this.trackDurationOf(func);
|
|
1128
|
-
this.trackSuccess();
|
|
1129
|
-
if (result.usage) {
|
|
1130
|
-
this.trackTokens(createVercelAISDKTokenUsage(result.usage));
|
|
1131
|
-
}
|
|
1132
|
-
return result;
|
|
1133
|
-
} catch (err) {
|
|
1134
|
-
this.trackError();
|
|
1135
|
-
throw err;
|
|
1136
|
-
}
|
|
1137
|
-
}
|
|
1138
1156
|
trackTokens(tokens) {
|
|
1139
1157
|
if (this._trackedMetrics.tokens !== void 0) {
|
|
1140
1158
|
this._ldClient.logger?.warn(
|
|
1141
|
-
"
|
|
1159
|
+
"Skipping trackTokens: token usage already recorded on this tracker. Call createTracker on the AI Config for a new run."
|
|
1142
1160
|
);
|
|
1143
1161
|
return;
|
|
1144
1162
|
}
|
|
@@ -1172,6 +1190,7 @@ var LDGraphTrackerImpl = class _LDGraphTrackerImpl {
|
|
|
1172
1190
|
this._version = _version;
|
|
1173
1191
|
this._context = _context;
|
|
1174
1192
|
this._summary = {};
|
|
1193
|
+
this._summary.resumptionToken = this.resumptionToken;
|
|
1175
1194
|
}
|
|
1176
1195
|
/**
|
|
1177
1196
|
* Reconstructs an {@link LDGraphTrackerImpl} from a resumption token, preserving
|
|
@@ -1197,15 +1216,12 @@ var LDGraphTrackerImpl = class _LDGraphTrackerImpl {
|
|
|
1197
1216
|
);
|
|
1198
1217
|
}
|
|
1199
1218
|
getTrackData() {
|
|
1200
|
-
|
|
1219
|
+
return {
|
|
1201
1220
|
runId: this._runId,
|
|
1202
1221
|
graphKey: this._graphKey,
|
|
1203
|
-
version: this._version
|
|
1222
|
+
version: this._version,
|
|
1223
|
+
...this._variationKey !== void 0 ? { variationKey: this._variationKey } : {}
|
|
1204
1224
|
};
|
|
1205
|
-
if (this._variationKey !== void 0) {
|
|
1206
|
-
data.variationKey = this._variationKey;
|
|
1207
|
-
}
|
|
1208
|
-
return data;
|
|
1209
1225
|
}
|
|
1210
1226
|
getSummary() {
|
|
1211
1227
|
return { ...this._summary };
|
|
@@ -1225,7 +1241,7 @@ var LDGraphTrackerImpl = class _LDGraphTrackerImpl {
|
|
|
1225
1241
|
trackInvocationSuccess() {
|
|
1226
1242
|
if (this._summary.success !== void 0) {
|
|
1227
1243
|
this._ldClient.logger?.warn(
|
|
1228
|
-
"
|
|
1244
|
+
"Skipping trackInvocationSuccess: invocation result already recorded on this graph tracker. Call createTracker on the agent graph for a new run."
|
|
1229
1245
|
);
|
|
1230
1246
|
return;
|
|
1231
1247
|
}
|
|
@@ -1235,7 +1251,7 @@ var LDGraphTrackerImpl = class _LDGraphTrackerImpl {
|
|
|
1235
1251
|
trackInvocationFailure() {
|
|
1236
1252
|
if (this._summary.success !== void 0) {
|
|
1237
1253
|
this._ldClient.logger?.warn(
|
|
1238
|
-
"
|
|
1254
|
+
"Skipping trackInvocationFailure: invocation result already recorded on this graph tracker. Call createTracker on the agent graph for a new run."
|
|
1239
1255
|
);
|
|
1240
1256
|
return;
|
|
1241
1257
|
}
|
|
@@ -1245,7 +1261,7 @@ var LDGraphTrackerImpl = class _LDGraphTrackerImpl {
|
|
|
1245
1261
|
trackDuration(durationMs) {
|
|
1246
1262
|
if (this._summary.durationMs !== void 0) {
|
|
1247
1263
|
this._ldClient.logger?.warn(
|
|
1248
|
-
"
|
|
1264
|
+
"Skipping trackDuration: duration already recorded on this graph tracker. Call createTracker on the agent graph for a new run."
|
|
1249
1265
|
);
|
|
1250
1266
|
return;
|
|
1251
1267
|
}
|
|
@@ -1260,7 +1276,7 @@ var LDGraphTrackerImpl = class _LDGraphTrackerImpl {
|
|
|
1260
1276
|
trackTotalTokens(tokens) {
|
|
1261
1277
|
if (this._summary.tokens !== void 0) {
|
|
1262
1278
|
this._ldClient.logger?.warn(
|
|
1263
|
-
"
|
|
1279
|
+
"Skipping trackTotalTokens: tokens already recorded on this graph tracker. Call createTracker on the agent graph for a new run."
|
|
1264
1280
|
);
|
|
1265
1281
|
return;
|
|
1266
1282
|
}
|
|
@@ -1275,7 +1291,7 @@ var LDGraphTrackerImpl = class _LDGraphTrackerImpl {
|
|
|
1275
1291
|
trackPath(path) {
|
|
1276
1292
|
if (this._summary.path !== void 0) {
|
|
1277
1293
|
this._ldClient.logger?.warn(
|
|
1278
|
-
"
|
|
1294
|
+
"Skipping trackPath: path already recorded on this graph tracker. Call createTracker on the agent graph for a new run."
|
|
1279
1295
|
);
|
|
1280
1296
|
return;
|
|
1281
1297
|
}
|
|
@@ -1310,13 +1326,14 @@ var LDGraphTrackerImpl = class _LDGraphTrackerImpl {
|
|
|
1310
1326
|
|
|
1311
1327
|
// src/sdkInfo.ts
|
|
1312
1328
|
var aiSdkName = "@launchdarkly/server-sdk-ai";
|
|
1313
|
-
var aiSdkVersion = "0.
|
|
1329
|
+
var aiSdkVersion = "1.0.0";
|
|
1314
1330
|
var aiSdkLanguage = "javascript";
|
|
1315
1331
|
|
|
1316
1332
|
// src/LDAIClientImpl.ts
|
|
1317
1333
|
var TRACK_SDK_INFO = "$ld:ai:sdk:info";
|
|
1318
1334
|
var TRACK_USAGE_COMPLETION_CONFIG = "$ld:ai:usage:completion-config";
|
|
1319
1335
|
var TRACK_USAGE_CREATE_CHAT = "$ld:ai:usage:create-chat";
|
|
1336
|
+
var TRACK_USAGE_CREATE_AGENT = "$ld:ai:usage:create-agent";
|
|
1320
1337
|
var TRACK_USAGE_JUDGE_CONFIG = "$ld:ai:usage:judge-config";
|
|
1321
1338
|
var TRACK_USAGE_CREATE_JUDGE = "$ld:ai:usage:create-judge";
|
|
1322
1339
|
var TRACK_USAGE_AGENT_CONFIG = "$ld:ai:usage:agent-config";
|
|
@@ -1344,18 +1361,11 @@ var LDAIClientImpl = class {
|
|
|
1344
1361
|
);
|
|
1345
1362
|
}
|
|
1346
1363
|
_interpolateTemplate(template, variables) {
|
|
1347
|
-
return
|
|
1364
|
+
return Mustache.render(template, variables, void 0, { escape: (item) => item });
|
|
1348
1365
|
}
|
|
1349
|
-
async _evaluate(key, context, defaultValue, mode, variables, graphKey) {
|
|
1366
|
+
async _evaluate(key, context, defaultValue, mode, variables, graphKey, defaultAiProvider) {
|
|
1350
1367
|
const ldFlagValue = LDAIConfigUtils.toFlagValue(defaultValue, mode);
|
|
1351
1368
|
const value = await this._ldClient.variation(key, context, ldFlagValue);
|
|
1352
|
-
const flagMode = value._ldMeta?.mode ?? "completion";
|
|
1353
|
-
if (flagMode !== mode) {
|
|
1354
|
-
this._logger?.warn(
|
|
1355
|
-
`AI Config mode mismatch for ${key}: expected ${mode}, got ${flagMode}. Returning disabled config.`
|
|
1356
|
-
);
|
|
1357
|
-
return LDAIConfigUtils.createDisabledConfig(key, mode);
|
|
1358
|
-
}
|
|
1359
1369
|
const trackerFactory = () => new LDAIConfigTrackerImpl(
|
|
1360
1370
|
this._ldClient,
|
|
1361
1371
|
randomUUID(),
|
|
@@ -1369,7 +1379,23 @@ var LDAIClientImpl = class {
|
|
|
1369
1379
|
context,
|
|
1370
1380
|
graphKey
|
|
1371
1381
|
);
|
|
1372
|
-
const
|
|
1382
|
+
const flagMode = value._ldMeta?.mode ?? "completion";
|
|
1383
|
+
let evaluator = Evaluator.noop();
|
|
1384
|
+
if (flagMode !== mode) {
|
|
1385
|
+
this._logger?.warn(
|
|
1386
|
+
`AI Config mode mismatch for ${key}: expected ${mode}, got ${flagMode}. Returning disabled config.`
|
|
1387
|
+
);
|
|
1388
|
+
return LDAIConfigUtils.createDisabledConfig(key, mode, trackerFactory, evaluator);
|
|
1389
|
+
}
|
|
1390
|
+
if (flagMode !== "judge") {
|
|
1391
|
+
evaluator = await this._buildEvaluator(
|
|
1392
|
+
value.judgeConfiguration?.judges ?? [],
|
|
1393
|
+
context,
|
|
1394
|
+
variables,
|
|
1395
|
+
defaultAiProvider
|
|
1396
|
+
);
|
|
1397
|
+
}
|
|
1398
|
+
const config = LDAIConfigUtils.fromFlagValue(key, value, trackerFactory, evaluator);
|
|
1373
1399
|
return this._applyInterpolation(config, context, variables);
|
|
1374
1400
|
}
|
|
1375
1401
|
_applyInterpolation(config, context, variables) {
|
|
@@ -1391,61 +1417,98 @@ var LDAIClientImpl = class {
|
|
|
1391
1417
|
}
|
|
1392
1418
|
return config;
|
|
1393
1419
|
}
|
|
1394
|
-
async
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1420
|
+
async _buildEvaluator(judgeConfigs, context, variables, defaultAiProvider) {
|
|
1421
|
+
if (judgeConfigs.length === 0) {
|
|
1422
|
+
return Evaluator.noop();
|
|
1423
|
+
}
|
|
1424
|
+
const judgeInstances = (await Promise.all(
|
|
1425
|
+
judgeConfigs.map(
|
|
1426
|
+
(jc) => this._createJudgeInstance(
|
|
1427
|
+
jc.key,
|
|
1428
|
+
context,
|
|
1429
|
+
void 0,
|
|
1430
|
+
variables,
|
|
1431
|
+
defaultAiProvider,
|
|
1432
|
+
jc.samplingRate
|
|
1433
|
+
)
|
|
1434
|
+
)
|
|
1435
|
+
)).filter((j) => j !== void 0);
|
|
1436
|
+
return new Evaluator(judgeInstances);
|
|
1437
|
+
}
|
|
1438
|
+
async _completionConfig(key, context, defaultValue, variables, defaultAiProvider) {
|
|
1439
|
+
return await this._evaluate(
|
|
1440
|
+
key,
|
|
1441
|
+
context,
|
|
1442
|
+
defaultValue,
|
|
1443
|
+
"completion",
|
|
1444
|
+
variables,
|
|
1445
|
+
void 0,
|
|
1446
|
+
defaultAiProvider
|
|
1447
|
+
);
|
|
1417
1448
|
}
|
|
1418
|
-
async completionConfig(key, context, defaultValue, variables) {
|
|
1449
|
+
async completionConfig(key, context, defaultValue, variables, defaultAiProvider) {
|
|
1419
1450
|
this._ldClient.track(TRACK_USAGE_COMPLETION_CONFIG, context, key, 1);
|
|
1420
|
-
return this._completionConfig(
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1451
|
+
return this._completionConfig(
|
|
1452
|
+
key,
|
|
1453
|
+
context,
|
|
1454
|
+
defaultValue ?? disabledAIConfig,
|
|
1455
|
+
variables,
|
|
1456
|
+
defaultAiProvider
|
|
1457
|
+
);
|
|
1427
1458
|
}
|
|
1428
1459
|
async _judgeConfig(key, context, defaultValue, variables) {
|
|
1429
|
-
|
|
1460
|
+
if (variables?.message_history !== void 0) {
|
|
1461
|
+
this._logger?.warn(
|
|
1462
|
+
"The variable 'message_history' is reserved by the judge and will be ignored."
|
|
1463
|
+
);
|
|
1464
|
+
}
|
|
1465
|
+
if (variables?.response_to_evaluate !== void 0) {
|
|
1466
|
+
this._logger?.warn(
|
|
1467
|
+
"The variable 'response_to_evaluate' is reserved by the judge and will be ignored."
|
|
1468
|
+
);
|
|
1469
|
+
}
|
|
1470
|
+
const extendedVariables = {
|
|
1471
|
+
...variables,
|
|
1472
|
+
message_history: "{{message_history}}",
|
|
1473
|
+
response_to_evaluate: "{{response_to_evaluate}}"
|
|
1474
|
+
};
|
|
1475
|
+
const config = await this._evaluate(
|
|
1476
|
+
key,
|
|
1477
|
+
context,
|
|
1478
|
+
defaultValue,
|
|
1479
|
+
"judge",
|
|
1480
|
+
extendedVariables
|
|
1481
|
+
);
|
|
1482
|
+
if (config.messages) {
|
|
1483
|
+
return { ...config, messages: stripLegacyJudgeMessages(config.messages) };
|
|
1484
|
+
}
|
|
1430
1485
|
return config;
|
|
1431
1486
|
}
|
|
1432
1487
|
async judgeConfig(key, context, defaultValue, variables) {
|
|
1433
1488
|
this._ldClient.track(TRACK_USAGE_JUDGE_CONFIG, context, key, 1);
|
|
1434
1489
|
return this._judgeConfig(key, context, defaultValue ?? disabledAIConfig, variables);
|
|
1435
1490
|
}
|
|
1436
|
-
async _agentConfig(key, context, defaultValue, variables, graphKey) {
|
|
1437
|
-
|
|
1438
|
-
|
|
1491
|
+
async _agentConfig(key, context, defaultValue, variables, graphKey, defaultAiProvider) {
|
|
1492
|
+
return await this._evaluate(
|
|
1493
|
+
key,
|
|
1494
|
+
context,
|
|
1495
|
+
defaultValue,
|
|
1496
|
+
"agent",
|
|
1497
|
+
variables,
|
|
1498
|
+
graphKey,
|
|
1499
|
+
defaultAiProvider
|
|
1500
|
+
);
|
|
1439
1501
|
}
|
|
1440
|
-
async agentConfig(key, context, defaultValue, variables) {
|
|
1502
|
+
async agentConfig(key, context, defaultValue, variables, defaultAiProvider) {
|
|
1441
1503
|
this._ldClient.track(TRACK_USAGE_AGENT_CONFIG, context, key, 1);
|
|
1442
|
-
return this._agentConfig(
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1504
|
+
return this._agentConfig(
|
|
1505
|
+
key,
|
|
1506
|
+
context,
|
|
1507
|
+
defaultValue ?? disabledAIConfig,
|
|
1508
|
+
variables,
|
|
1509
|
+
void 0,
|
|
1510
|
+
defaultAiProvider
|
|
1511
|
+
);
|
|
1449
1512
|
}
|
|
1450
1513
|
async agentConfigs(agentConfigs, context) {
|
|
1451
1514
|
this._ldClient.track(
|
|
@@ -1468,79 +1531,82 @@ var LDAIClientImpl = class {
|
|
|
1468
1531
|
);
|
|
1469
1532
|
return agents;
|
|
1470
1533
|
}
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
async agents(agentConfigs, context) {
|
|
1475
|
-
return this.agentConfigs(agentConfigs, context);
|
|
1476
|
-
}
|
|
1477
|
-
async createChat(key, context, defaultValue, variables, defaultAiProvider) {
|
|
1478
|
-
this._ldClient.track(TRACK_USAGE_CREATE_CHAT, context, key, 1);
|
|
1479
|
-
const config = await this._completionConfig(
|
|
1534
|
+
async createJudge(key, context, defaultValue, variables, defaultAiProvider, sampleRate = 1) {
|
|
1535
|
+
this._ldClient.track(TRACK_USAGE_CREATE_JUDGE, context, key, 1);
|
|
1536
|
+
return this._createJudgeInstance(
|
|
1480
1537
|
key,
|
|
1481
1538
|
context,
|
|
1482
|
-
defaultValue
|
|
1483
|
-
variables
|
|
1484
|
-
);
|
|
1485
|
-
if (!config.enabled) {
|
|
1486
|
-
this._logger?.info(`Chat configuration is disabled: ${key}`);
|
|
1487
|
-
return void 0;
|
|
1488
|
-
}
|
|
1489
|
-
const provider = await AIProviderFactory.create(config, this._logger, defaultAiProvider);
|
|
1490
|
-
if (!provider) {
|
|
1491
|
-
return void 0;
|
|
1492
|
-
}
|
|
1493
|
-
const judges = await this._initializeJudges(
|
|
1494
|
-
config.judgeConfiguration?.judges ?? [],
|
|
1495
|
-
context,
|
|
1539
|
+
defaultValue,
|
|
1496
1540
|
variables,
|
|
1497
|
-
defaultAiProvider
|
|
1541
|
+
defaultAiProvider,
|
|
1542
|
+
sampleRate
|
|
1498
1543
|
);
|
|
1499
|
-
return new TrackedChat(config, provider, judges, this._logger);
|
|
1500
1544
|
}
|
|
1501
|
-
async
|
|
1502
|
-
this._ldClient.track(TRACK_USAGE_CREATE_JUDGE, context, key, 1);
|
|
1545
|
+
async _createJudgeInstance(key, context, defaultValue, variables, defaultAiProvider, sampleRate = 1) {
|
|
1503
1546
|
try {
|
|
1504
|
-
if (variables?.message_history !== void 0) {
|
|
1505
|
-
this._logger?.warn(
|
|
1506
|
-
"The variable 'message_history' is reserved by the judge and will be ignored."
|
|
1507
|
-
);
|
|
1508
|
-
}
|
|
1509
|
-
if (variables?.response_to_evaluate !== void 0) {
|
|
1510
|
-
this._logger?.warn(
|
|
1511
|
-
"The variable 'response_to_evaluate' is reserved by the judge and will be ignored."
|
|
1512
|
-
);
|
|
1513
|
-
}
|
|
1514
|
-
const extendedVariables = {
|
|
1515
|
-
...variables,
|
|
1516
|
-
message_history: "{{message_history}}",
|
|
1517
|
-
response_to_evaluate: "{{response_to_evaluate}}"
|
|
1518
|
-
};
|
|
1519
1547
|
const judgeConfig = await this._judgeConfig(
|
|
1520
1548
|
key,
|
|
1521
1549
|
context,
|
|
1522
1550
|
defaultValue ?? disabledAIConfig,
|
|
1523
|
-
|
|
1551
|
+
variables
|
|
1524
1552
|
);
|
|
1525
1553
|
if (!judgeConfig.enabled) {
|
|
1526
1554
|
this._logger?.info(`Judge configuration is disabled: ${key}`);
|
|
1527
1555
|
return void 0;
|
|
1528
1556
|
}
|
|
1529
|
-
const
|
|
1530
|
-
|
|
1557
|
+
const runner = await RunnerFactory.createModel(
|
|
1558
|
+
judgeConfig,
|
|
1559
|
+
this._logger,
|
|
1560
|
+
defaultAiProvider,
|
|
1561
|
+
false
|
|
1562
|
+
);
|
|
1563
|
+
if (!runner) {
|
|
1531
1564
|
return void 0;
|
|
1532
1565
|
}
|
|
1533
|
-
return new Judge(judgeConfig,
|
|
1566
|
+
return new Judge(judgeConfig, runner, sampleRate, this._logger);
|
|
1534
1567
|
} catch (error) {
|
|
1535
1568
|
this._logger?.error(`Failed to initialize judge ${key}:`, error);
|
|
1536
1569
|
return void 0;
|
|
1537
1570
|
}
|
|
1538
1571
|
}
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1572
|
+
async createModel(key, context, defaultValue, variables, defaultAiProvider) {
|
|
1573
|
+
this._ldClient.track(TRACK_USAGE_CREATE_CHAT, context, key, 1);
|
|
1574
|
+
const config = await this._completionConfig(
|
|
1575
|
+
key,
|
|
1576
|
+
context,
|
|
1577
|
+
defaultValue ?? disabledAIConfig,
|
|
1578
|
+
variables,
|
|
1579
|
+
defaultAiProvider
|
|
1580
|
+
);
|
|
1581
|
+
if (!config.enabled) {
|
|
1582
|
+
this._logger?.info(`Completion configuration is disabled: ${key}`);
|
|
1583
|
+
return void 0;
|
|
1584
|
+
}
|
|
1585
|
+
const runner = await RunnerFactory.createModel(config, this._logger, defaultAiProvider);
|
|
1586
|
+
if (!runner) {
|
|
1587
|
+
return void 0;
|
|
1588
|
+
}
|
|
1589
|
+
return new ManagedModel(config, runner, this._logger);
|
|
1590
|
+
}
|
|
1591
|
+
async createAgent(key, context, defaultValue, variables, defaultAiProvider) {
|
|
1592
|
+
this._ldClient.track(TRACK_USAGE_CREATE_AGENT, context, key, 1);
|
|
1593
|
+
const config = await this._agentConfig(
|
|
1594
|
+
key,
|
|
1595
|
+
context,
|
|
1596
|
+
defaultValue ?? disabledAIConfig,
|
|
1597
|
+
variables,
|
|
1598
|
+
void 0,
|
|
1599
|
+
defaultAiProvider
|
|
1600
|
+
);
|
|
1601
|
+
if (!config.enabled) {
|
|
1602
|
+
this._logger?.info(`Agent configuration is disabled: ${key}`);
|
|
1603
|
+
return void 0;
|
|
1604
|
+
}
|
|
1605
|
+
const runner = await RunnerFactory.createAgent(config, void 0, this._logger, defaultAiProvider);
|
|
1606
|
+
if (!runner) {
|
|
1607
|
+
return void 0;
|
|
1608
|
+
}
|
|
1609
|
+
return new ManagedAgent(config, runner, this._logger);
|
|
1544
1610
|
}
|
|
1545
1611
|
createTracker(token, context) {
|
|
1546
1612
|
return LDAIConfigTrackerImpl.fromResumptionToken(token, this._ldClient, context);
|
|
@@ -1619,23 +1685,97 @@ var LDAIClientImpl = class {
|
|
|
1619
1685
|
}
|
|
1620
1686
|
};
|
|
1621
1687
|
|
|
1688
|
+
// src/api/ManagedAgentGraph.ts
|
|
1689
|
+
var ManagedAgentGraph = class {
|
|
1690
|
+
constructor(_graphDefinition, _logger) {
|
|
1691
|
+
this._graphDefinition = _graphDefinition;
|
|
1692
|
+
this._logger = _logger;
|
|
1693
|
+
}
|
|
1694
|
+
/**
|
|
1695
|
+
* Runs the agent graph using the provided runner function and returns a ManagedGraphResult.
|
|
1696
|
+
*
|
|
1697
|
+
* The runner function receives the graph tracker and AgentGraphDefinition,
|
|
1698
|
+
* executes the graph, and returns an AgentGraphRunnerResult.
|
|
1699
|
+
*
|
|
1700
|
+
* run() returns before ManagedGraphResult.evaluations resolves.
|
|
1701
|
+
*
|
|
1702
|
+
* @param runner Async function that executes the graph and returns AgentGraphRunnerResult.
|
|
1703
|
+
* @returns ManagedGraphResult with LDAIGraphMetricSummary and evaluations promise.
|
|
1704
|
+
*/
|
|
1705
|
+
async run(runner) {
|
|
1706
|
+
const graphTracker = this._graphDefinition.createTracker();
|
|
1707
|
+
const runnerResult = await runner(this._graphDefinition, graphTracker);
|
|
1708
|
+
const metrics = {
|
|
1709
|
+
success: runnerResult.metrics.success,
|
|
1710
|
+
path: runnerResult.metrics.path,
|
|
1711
|
+
durationMs: runnerResult.metrics.durationMs,
|
|
1712
|
+
tokens: runnerResult.metrics.tokens,
|
|
1713
|
+
nodeMetrics: this._trackNodeMetrics(runnerResult.metrics.nodeMetrics),
|
|
1714
|
+
resumptionToken: graphTracker.resumptionToken
|
|
1715
|
+
};
|
|
1716
|
+
const evaluations = Promise.resolve([]);
|
|
1717
|
+
return {
|
|
1718
|
+
content: runnerResult.content,
|
|
1719
|
+
metrics,
|
|
1720
|
+
raw: runnerResult.raw,
|
|
1721
|
+
evaluations
|
|
1722
|
+
};
|
|
1723
|
+
}
|
|
1724
|
+
/**
|
|
1725
|
+
* Converts per-node LDAIMetrics from the runner into LDAIMetricSummary by
|
|
1726
|
+
* creating a per-node tracker, firing tracking events, and calling getSummary().
|
|
1727
|
+
*/
|
|
1728
|
+
_trackNodeMetrics(nodeMetrics) {
|
|
1729
|
+
const summaries = {};
|
|
1730
|
+
for (const [nodeKey, metrics] of Object.entries(nodeMetrics)) {
|
|
1731
|
+
const node = this._graphDefinition.getNode(nodeKey);
|
|
1732
|
+
if (!node) {
|
|
1733
|
+
this._logger?.warn(`ManagedAgentGraph: no node found for key "${nodeKey}", skipping metrics`);
|
|
1734
|
+
continue;
|
|
1735
|
+
}
|
|
1736
|
+
const tracker = node.getConfig().createTracker();
|
|
1737
|
+
if (metrics.tokens) {
|
|
1738
|
+
tracker.trackTokens(metrics.tokens);
|
|
1739
|
+
}
|
|
1740
|
+
if (metrics.durationMs !== void 0) {
|
|
1741
|
+
tracker.trackDuration(metrics.durationMs);
|
|
1742
|
+
}
|
|
1743
|
+
if (metrics.toolCalls?.length) {
|
|
1744
|
+
tracker.trackToolCalls(metrics.toolCalls);
|
|
1745
|
+
}
|
|
1746
|
+
if (metrics.success) {
|
|
1747
|
+
tracker.trackSuccess();
|
|
1748
|
+
} else {
|
|
1749
|
+
tracker.trackError();
|
|
1750
|
+
}
|
|
1751
|
+
summaries[nodeKey] = tracker.getSummary();
|
|
1752
|
+
}
|
|
1753
|
+
return summaries;
|
|
1754
|
+
}
|
|
1755
|
+
/**
|
|
1756
|
+
* Returns the underlying AgentGraphDefinition.
|
|
1757
|
+
*/
|
|
1758
|
+
getGraphDefinition() {
|
|
1759
|
+
return this._graphDefinition;
|
|
1760
|
+
}
|
|
1761
|
+
};
|
|
1762
|
+
|
|
1622
1763
|
// src/index.ts
|
|
1623
1764
|
function initAi(ldClient) {
|
|
1624
1765
|
return new LDAIClientImpl(ldClient);
|
|
1625
1766
|
}
|
|
1626
1767
|
export {
|
|
1627
1768
|
AIProvider,
|
|
1628
|
-
AIProviderFactory,
|
|
1629
1769
|
AgentGraphDefinition,
|
|
1630
1770
|
AgentGraphNode,
|
|
1631
1771
|
Judge,
|
|
1632
1772
|
LDFeedbackKind,
|
|
1633
1773
|
LDGraphTrackerImpl,
|
|
1774
|
+
ManagedAgent,
|
|
1775
|
+
ManagedAgentGraph,
|
|
1776
|
+
ManagedModel,
|
|
1777
|
+
RunnerFactory,
|
|
1634
1778
|
SUPPORTED_AI_PROVIDERS,
|
|
1635
|
-
TrackedChat,
|
|
1636
|
-
createBedrockTokenUsage,
|
|
1637
|
-
createOpenAiUsage,
|
|
1638
|
-
createVercelAISDKTokenUsage,
|
|
1639
1779
|
initAi
|
|
1640
1780
|
};
|
|
1641
1781
|
//# sourceMappingURL=index.js.map
|