@launchdarkly/server-sdk-ai 0.19.0 → 0.20.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 +37 -0
- package/README.md +13 -16
- package/dist/index.cjs +586 -351
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +591 -265
- package/dist/index.d.ts +591 -265
- package/dist/index.js +582 -349
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
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
|
-
* Adds messages to the conversation history without invoking the model,
|
|
105
|
-
* which is useful for managing multi-turn conversations or injecting context.
|
|
66
|
+
* Invoke the model with a prompt string and return a ManagedResult.
|
|
106
67
|
*
|
|
107
|
-
*
|
|
68
|
+
* `run()` resolves before `ManagedResult.evaluations` resolves. Awaiting
|
|
69
|
+
* `evaluations` guarantees both judge evaluation and tracker.trackJudgeResult()
|
|
70
|
+
* are complete.
|
|
71
|
+
*
|
|
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
|
|
|
@@ -175,46 +156,52 @@ var LDAIConfigUtils = class {
|
|
|
175
156
|
* @param key The configuration key
|
|
176
157
|
* @param flagValue The flag value from LaunchDarkly
|
|
177
158
|
* @param trackerFactory A factory function that creates a new tracker for each execution
|
|
159
|
+
* @param evaluator The evaluator to attach to completion and agent configs
|
|
178
160
|
* @returns The appropriate AI configuration type
|
|
179
161
|
*/
|
|
180
|
-
static fromFlagValue(key, flagValue, trackerFactory) {
|
|
162
|
+
static fromFlagValue(key, flagValue, trackerFactory, evaluator) {
|
|
181
163
|
const flagValueMode = flagValue._ldMeta?.mode;
|
|
182
164
|
switch (flagValueMode) {
|
|
183
165
|
case "agent":
|
|
184
|
-
return this.toAgentConfig(key, flagValue, trackerFactory);
|
|
166
|
+
return this.toAgentConfig(key, flagValue, trackerFactory, evaluator);
|
|
185
167
|
case "judge":
|
|
186
168
|
return this.toJudgeConfig(key, flagValue, trackerFactory);
|
|
187
169
|
case "completion":
|
|
188
170
|
default:
|
|
189
|
-
return this.toCompletionConfig(key, flagValue, trackerFactory);
|
|
171
|
+
return this.toCompletionConfig(key, flagValue, trackerFactory, evaluator);
|
|
190
172
|
}
|
|
191
173
|
}
|
|
192
174
|
/**
|
|
193
175
|
* Creates a disabled configuration of the specified mode.
|
|
194
176
|
*
|
|
177
|
+
* @param key The configuration key
|
|
195
178
|
* @param mode The mode for the disabled config
|
|
179
|
+
* @param createTracker A factory function that creates a new tracker for each execution
|
|
180
|
+
* @param evaluator The evaluator to attach to completion and agent configs
|
|
196
181
|
* @returns A disabled config of the appropriate type
|
|
197
182
|
*/
|
|
198
|
-
static createDisabledConfig(key, mode) {
|
|
183
|
+
static createDisabledConfig(key, mode, createTracker, evaluator) {
|
|
199
184
|
switch (mode) {
|
|
200
185
|
case "agent":
|
|
201
186
|
return {
|
|
202
187
|
key,
|
|
203
188
|
enabled: false,
|
|
204
|
-
createTracker
|
|
189
|
+
createTracker,
|
|
190
|
+
evaluator
|
|
205
191
|
};
|
|
206
192
|
case "judge":
|
|
207
193
|
return {
|
|
208
194
|
key,
|
|
209
195
|
enabled: false,
|
|
210
|
-
createTracker
|
|
196
|
+
createTracker
|
|
211
197
|
};
|
|
212
198
|
case "completion":
|
|
213
199
|
default:
|
|
214
200
|
return {
|
|
215
201
|
key,
|
|
216
202
|
enabled: false,
|
|
217
|
-
createTracker
|
|
203
|
+
createTracker,
|
|
204
|
+
evaluator
|
|
218
205
|
};
|
|
219
206
|
}
|
|
220
207
|
}
|
|
@@ -256,12 +243,14 @@ var LDAIConfigUtils = class {
|
|
|
256
243
|
* @param key The configuration key
|
|
257
244
|
* @param flagValue The flag value from LaunchDarkly
|
|
258
245
|
* @param trackerFactory A factory function that creates a new tracker for each execution
|
|
246
|
+
* @param evaluator The evaluator for this completion config
|
|
259
247
|
* @returns A completion configuration
|
|
260
248
|
*/
|
|
261
|
-
static toCompletionConfig(key, flagValue, trackerFactory) {
|
|
249
|
+
static toCompletionConfig(key, flagValue, trackerFactory, evaluator) {
|
|
262
250
|
return {
|
|
263
251
|
...this._toBaseConfig(key, flagValue),
|
|
264
252
|
createTracker: trackerFactory,
|
|
253
|
+
evaluator,
|
|
265
254
|
messages: flagValue.messages,
|
|
266
255
|
judgeConfiguration: flagValue.judgeConfiguration,
|
|
267
256
|
tools: this._resolveTools(flagValue)
|
|
@@ -273,12 +262,14 @@ var LDAIConfigUtils = class {
|
|
|
273
262
|
* @param key The configuration key
|
|
274
263
|
* @param flagValue The flag value from LaunchDarkly
|
|
275
264
|
* @param trackerFactory A factory function that creates a new tracker for each execution
|
|
265
|
+
* @param evaluator The evaluator for this agent config
|
|
276
266
|
* @returns An agent configuration
|
|
277
267
|
*/
|
|
278
|
-
static toAgentConfig(key, flagValue, trackerFactory) {
|
|
268
|
+
static toAgentConfig(key, flagValue, trackerFactory, evaluator) {
|
|
279
269
|
return {
|
|
280
270
|
...this._toBaseConfig(key, flagValue),
|
|
281
271
|
createTracker: trackerFactory,
|
|
272
|
+
evaluator,
|
|
282
273
|
instructions: flagValue.instructions,
|
|
283
274
|
judgeConfiguration: flagValue.judgeConfiguration,
|
|
284
275
|
tools: this._resolveTools(flagValue)
|
|
@@ -543,8 +534,98 @@ var AgentGraphDefinition = class _AgentGraphDefinition {
|
|
|
543
534
|
}
|
|
544
535
|
};
|
|
545
536
|
|
|
537
|
+
// src/api/graph/ManagedAgentGraph.ts
|
|
538
|
+
var ManagedAgentGraph = class {
|
|
539
|
+
constructor(_graphDefinition, _logger) {
|
|
540
|
+
this._graphDefinition = _graphDefinition;
|
|
541
|
+
this._logger = _logger;
|
|
542
|
+
}
|
|
543
|
+
/**
|
|
544
|
+
* Runs the agent graph using the provided runner function and returns a ManagedGraphResult.
|
|
545
|
+
*
|
|
546
|
+
* The runner function receives the graph tracker and AgentGraphDefinition,
|
|
547
|
+
* executes the graph, and returns an AgentGraphRunnerResult.
|
|
548
|
+
*
|
|
549
|
+
* run() returns before ManagedGraphResult.evaluations resolves.
|
|
550
|
+
*
|
|
551
|
+
* @param runner Async function that executes the graph and returns AgentGraphRunnerResult.
|
|
552
|
+
* @returns ManagedGraphResult with LDAIGraphMetricSummary and evaluations promise.
|
|
553
|
+
*/
|
|
554
|
+
async run(runner) {
|
|
555
|
+
const graphTracker = this._graphDefinition.createTracker();
|
|
556
|
+
const runnerResult = await runner(this._graphDefinition, graphTracker);
|
|
557
|
+
const metrics = {
|
|
558
|
+
success: runnerResult.metrics.success,
|
|
559
|
+
path: runnerResult.metrics.path,
|
|
560
|
+
durationMs: runnerResult.metrics.durationMs,
|
|
561
|
+
tokens: runnerResult.metrics.tokens,
|
|
562
|
+
nodeMetrics: this._trackNodeMetrics(runnerResult.metrics.nodeMetrics),
|
|
563
|
+
resumptionToken: graphTracker.resumptionToken
|
|
564
|
+
};
|
|
565
|
+
const evaluations = Promise.resolve([]);
|
|
566
|
+
return {
|
|
567
|
+
content: runnerResult.content,
|
|
568
|
+
metrics,
|
|
569
|
+
raw: runnerResult.raw,
|
|
570
|
+
evaluations
|
|
571
|
+
};
|
|
572
|
+
}
|
|
573
|
+
/**
|
|
574
|
+
* Converts per-node LDAIMetrics from the runner into LDAIMetricSummary by
|
|
575
|
+
* creating a per-node tracker, firing tracking events, and calling getSummary().
|
|
576
|
+
*/
|
|
577
|
+
_trackNodeMetrics(nodeMetrics) {
|
|
578
|
+
const summaries = {};
|
|
579
|
+
for (const [nodeKey, metrics] of Object.entries(nodeMetrics)) {
|
|
580
|
+
const node = this._graphDefinition.getNode(nodeKey);
|
|
581
|
+
if (!node) {
|
|
582
|
+
this._logger?.warn(`ManagedAgentGraph: no node found for key "${nodeKey}", skipping metrics`);
|
|
583
|
+
continue;
|
|
584
|
+
}
|
|
585
|
+
const tracker = node.getConfig().createTracker();
|
|
586
|
+
if (metrics.tokens) {
|
|
587
|
+
tracker.trackTokens(metrics.tokens);
|
|
588
|
+
}
|
|
589
|
+
if (metrics.durationMs !== void 0) {
|
|
590
|
+
tracker.trackDuration(metrics.durationMs);
|
|
591
|
+
}
|
|
592
|
+
if (metrics.toolCalls?.length) {
|
|
593
|
+
tracker.trackToolCalls(metrics.toolCalls);
|
|
594
|
+
}
|
|
595
|
+
if (metrics.success) {
|
|
596
|
+
tracker.trackSuccess();
|
|
597
|
+
} else {
|
|
598
|
+
tracker.trackError();
|
|
599
|
+
}
|
|
600
|
+
summaries[nodeKey] = tracker.getSummary();
|
|
601
|
+
}
|
|
602
|
+
return summaries;
|
|
603
|
+
}
|
|
604
|
+
/**
|
|
605
|
+
* Returns the underlying AgentGraphDefinition.
|
|
606
|
+
*/
|
|
607
|
+
getGraphDefinition() {
|
|
608
|
+
return this._graphDefinition;
|
|
609
|
+
}
|
|
610
|
+
};
|
|
611
|
+
|
|
612
|
+
// src/api/judge/Evaluator.ts
|
|
613
|
+
var Evaluator = class _Evaluator {
|
|
614
|
+
constructor(_judges) {
|
|
615
|
+
this._judges = _judges;
|
|
616
|
+
}
|
|
617
|
+
static noop() {
|
|
618
|
+
return new _Evaluator([]);
|
|
619
|
+
}
|
|
620
|
+
async evaluate(input, output) {
|
|
621
|
+
if (this._judges.length === 0) {
|
|
622
|
+
return [];
|
|
623
|
+
}
|
|
624
|
+
return Promise.all(this._judges.map((judge) => judge.evaluate(input, output)));
|
|
625
|
+
}
|
|
626
|
+
};
|
|
627
|
+
|
|
546
628
|
// src/api/judge/Judge.ts
|
|
547
|
-
import Mustache from "mustache";
|
|
548
629
|
var EVALUATION_SCHEMA = {
|
|
549
630
|
type: "object",
|
|
550
631
|
properties: {
|
|
@@ -562,12 +643,25 @@ var EVALUATION_SCHEMA = {
|
|
|
562
643
|
required: ["score", "reasoning"],
|
|
563
644
|
additionalProperties: false
|
|
564
645
|
};
|
|
646
|
+
function stripLegacyJudgeMessages(messages) {
|
|
647
|
+
return messages.filter(
|
|
648
|
+
(msg) => msg.role === "system" || !msg.content.includes("{{message_history}}") && !msg.content.includes("{{response_to_evaluate}}")
|
|
649
|
+
);
|
|
650
|
+
}
|
|
565
651
|
var Judge = class {
|
|
566
|
-
constructor(_aiConfig,
|
|
652
|
+
constructor(_aiConfig, _runner, _sampleRate = 1, logger) {
|
|
567
653
|
this._aiConfig = _aiConfig;
|
|
568
|
-
this.
|
|
654
|
+
this._runner = _runner;
|
|
655
|
+
this._sampleRate = _sampleRate;
|
|
569
656
|
this._logger = logger;
|
|
570
657
|
}
|
|
658
|
+
/**
|
|
659
|
+
* The default sampling rate baked in at construction. Used by `evaluate` /
|
|
660
|
+
* `evaluateMessages` when no per-call rate is supplied.
|
|
661
|
+
*/
|
|
662
|
+
get sampleRate() {
|
|
663
|
+
return this._sampleRate;
|
|
664
|
+
}
|
|
571
665
|
/**
|
|
572
666
|
* Gets the evaluation metric key, prioritizing evaluationMetricKey over evaluationMetricKeys.
|
|
573
667
|
* Falls back to the first valid (non-empty, non-whitespace) value in evaluationMetricKeys if evaluationMetricKey is not provided.
|
|
@@ -591,10 +685,13 @@ var Judge = class {
|
|
|
591
685
|
*
|
|
592
686
|
* @param input The input prompt or question that was provided to the AI
|
|
593
687
|
* @param output The AI-generated response to be evaluated
|
|
594
|
-
* @param samplingRate Sampling rate (0-1) to determine if evaluation should be processed
|
|
688
|
+
* @param samplingRate Sampling rate (0-1) to determine if evaluation should be processed.
|
|
689
|
+
* When omitted, the Judge's constructor-default rate is used. An explicit `0` overrides
|
|
690
|
+
* the default — only `undefined` falls through.
|
|
595
691
|
* @returns Promise that resolves to evaluation results
|
|
596
692
|
*/
|
|
597
|
-
async evaluate(input, output, samplingRate
|
|
693
|
+
async evaluate(input, output, samplingRate) {
|
|
694
|
+
const effectiveRate = samplingRate ?? this._sampleRate;
|
|
598
695
|
const result = {
|
|
599
696
|
success: false,
|
|
600
697
|
sampled: false,
|
|
@@ -612,26 +709,20 @@ var Judge = class {
|
|
|
612
709
|
result.errorMessage = "Judge configuration is missing required evaluation metric key";
|
|
613
710
|
return result;
|
|
614
711
|
}
|
|
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}`);
|
|
712
|
+
if (Math.random() > effectiveRate) {
|
|
713
|
+
this._logger?.debug(`Judge evaluation skipped due to sampling rate: ${effectiveRate}`);
|
|
623
714
|
return result;
|
|
624
715
|
}
|
|
625
716
|
result.sampled = true;
|
|
626
|
-
const
|
|
717
|
+
const evaluationInput = this._buildEvaluationInput(input, output);
|
|
627
718
|
const response = await tracker.trackMetricsOf(
|
|
628
719
|
(r) => r.metrics,
|
|
629
|
-
() => this.
|
|
720
|
+
() => this._runner.run(evaluationInput, EVALUATION_SCHEMA)
|
|
630
721
|
);
|
|
631
|
-
const evalResult = this._parseEvaluationResponse(response.
|
|
722
|
+
const evalResult = this._parseEvaluationResponse(response.parsed);
|
|
632
723
|
if (!evalResult) {
|
|
633
724
|
this._logger?.warn(
|
|
634
|
-
`Could not parse evaluation response: ${JSON.stringify(response.
|
|
725
|
+
`Could not parse evaluation response: ${JSON.stringify(response.parsed)}`,
|
|
635
726
|
tracker.getTrackData()
|
|
636
727
|
);
|
|
637
728
|
return result;
|
|
@@ -655,10 +746,11 @@ var Judge = class {
|
|
|
655
746
|
*
|
|
656
747
|
* @param messages Array of messages representing the conversation history
|
|
657
748
|
* @param response The AI response to be evaluated
|
|
658
|
-
* @param samplingRatio Sampling ratio (0-1)
|
|
749
|
+
* @param samplingRatio Sampling ratio (0-1). When omitted, the Judge's
|
|
750
|
+
* constructor-default rate is used.
|
|
659
751
|
* @returns Promise that resolves to evaluation results
|
|
660
752
|
*/
|
|
661
|
-
async evaluateMessages(messages, response, samplingRatio
|
|
753
|
+
async evaluateMessages(messages, response, samplingRatio) {
|
|
662
754
|
const input = messages.length === 0 ? "" : messages.map((msg) => msg.content).join("\r\n");
|
|
663
755
|
const output = response.message.content;
|
|
664
756
|
return this.evaluate(input, output, samplingRatio);
|
|
@@ -670,29 +762,23 @@ var Judge = class {
|
|
|
670
762
|
return this._aiConfig;
|
|
671
763
|
}
|
|
672
764
|
/**
|
|
673
|
-
* Returns the
|
|
765
|
+
* Returns the runner used by this judge.
|
|
674
766
|
*/
|
|
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;
|
|
767
|
+
getRunner() {
|
|
768
|
+
return this._runner;
|
|
690
769
|
}
|
|
691
770
|
/**
|
|
692
|
-
*
|
|
771
|
+
* Builds the evaluation input string passed to the runner.
|
|
772
|
+
*
|
|
773
|
+
* Combines the original prompt and the response into a single, well-known
|
|
774
|
+
* format the judge model is expected to evaluate.
|
|
693
775
|
*/
|
|
694
|
-
|
|
695
|
-
return
|
|
776
|
+
_buildEvaluationInput(input, output) {
|
|
777
|
+
return `MESSAGE HISTORY:
|
|
778
|
+
${input}
|
|
779
|
+
|
|
780
|
+
RESPONSE TO EVALUATE:
|
|
781
|
+
${output}`;
|
|
696
782
|
}
|
|
697
783
|
/**
|
|
698
784
|
* Parses the structured evaluation response. Expects top-level {score, reasoning}.
|
|
@@ -718,115 +804,101 @@ var Judge = class {
|
|
|
718
804
|
// src/api/providers/AIProvider.ts
|
|
719
805
|
var AIProvider = class {
|
|
720
806
|
constructor(logger) {
|
|
721
|
-
this.
|
|
807
|
+
this._logger = logger;
|
|
722
808
|
}
|
|
723
809
|
/**
|
|
724
|
-
*
|
|
725
|
-
* This method should convert messages to provider format, invoke the model,
|
|
726
|
-
* and return a ChatResponse with the result and metrics.
|
|
810
|
+
* Create a Runner for a completion or judge AI Config.
|
|
727
811
|
*
|
|
728
|
-
*
|
|
729
|
-
*
|
|
812
|
+
* Override in provider subclasses to return a configured {@link Runner}.
|
|
813
|
+
* Default implementation returns `undefined`.
|
|
730
814
|
*
|
|
731
|
-
* @param
|
|
732
|
-
* @returns Promise
|
|
815
|
+
* @param config The completion or judge AI configuration.
|
|
816
|
+
* @returns Promise resolving to a {@link Runner}, or `undefined` if this
|
|
817
|
+
* provider does not support model creation.
|
|
733
818
|
*/
|
|
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
|
-
};
|
|
819
|
+
async createModel(_config) {
|
|
820
|
+
return void 0;
|
|
750
821
|
}
|
|
751
822
|
/**
|
|
752
|
-
*
|
|
753
|
-
* This method should convert messages to provider format, invoke the model with
|
|
754
|
-
* structured output configuration, and return a structured response.
|
|
823
|
+
* Create a Runner for an agent AI Config.
|
|
755
824
|
*
|
|
756
|
-
*
|
|
757
|
-
*
|
|
825
|
+
* Override in provider subclasses to return a configured {@link Runner}.
|
|
826
|
+
* Default implementation returns `undefined`.
|
|
758
827
|
*
|
|
759
|
-
* @param
|
|
760
|
-
* @param
|
|
761
|
-
* @returns Promise
|
|
828
|
+
* @param config The agent AI configuration.
|
|
829
|
+
* @param tools Optional registry of callable tools.
|
|
830
|
+
* @returns Promise resolving to a {@link Runner}, or `undefined` if this
|
|
831
|
+
* provider does not support agent creation.
|
|
762
832
|
*/
|
|
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
|
-
};
|
|
833
|
+
async createAgent(_config, _tools) {
|
|
834
|
+
return void 0;
|
|
777
835
|
}
|
|
778
836
|
/**
|
|
779
|
-
*
|
|
780
|
-
* Each provider implementation must provide their own static create method
|
|
781
|
-
* that accepts an AIConfig and returns a configured instance.
|
|
837
|
+
* Create an AgentGraphRunner for an agent graph definition.
|
|
782
838
|
*
|
|
783
|
-
*
|
|
784
|
-
*
|
|
785
|
-
*
|
|
839
|
+
* Override in provider subclasses to return a configured {@link AgentGraphRunner}.
|
|
840
|
+
* Default implementation returns `undefined`.
|
|
841
|
+
*
|
|
842
|
+
* @param graphDef The agent graph definition.
|
|
843
|
+
* @param tools Optional registry of callable tools.
|
|
844
|
+
* @returns Promise resolving to an {@link AgentGraphRunner}, or `undefined` if
|
|
845
|
+
* this provider does not support graph execution.
|
|
786
846
|
*/
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
throw new Error("Provider implementations must override the static create method");
|
|
847
|
+
async createAgentGraph(_graphDef, _tools) {
|
|
848
|
+
return void 0;
|
|
790
849
|
}
|
|
791
850
|
};
|
|
792
851
|
|
|
793
|
-
// src/api/providers/
|
|
852
|
+
// src/api/providers/RunnerFactory.ts
|
|
794
853
|
var SUPPORTED_AI_PROVIDERS = [
|
|
795
854
|
"openai",
|
|
796
855
|
// Multi-provider packages should be last in the list
|
|
797
856
|
"langchain",
|
|
798
857
|
"vercel"
|
|
799
858
|
];
|
|
800
|
-
var
|
|
859
|
+
var RunnerFactory = class _RunnerFactory {
|
|
801
860
|
/**
|
|
802
|
-
*
|
|
803
|
-
*
|
|
804
|
-
*
|
|
861
|
+
* Load and return the AIProvider factory for the given provider type.
|
|
862
|
+
*
|
|
863
|
+
* This is the single place in the codebase that knows provider package names.
|
|
864
|
+
* Each supported provider package exports a `*RunnerFactory` class that
|
|
865
|
+
* extends {@link AIProvider}; this method instantiates it directly.
|
|
805
866
|
*
|
|
806
|
-
* @param
|
|
807
|
-
* @param logger Optional logger
|
|
808
|
-
* @
|
|
867
|
+
* @param providerType One of the {@link SUPPORTED_AI_PROVIDERS} values.
|
|
868
|
+
* @param logger Optional logger forwarded to the provider factory.
|
|
869
|
+
* @returns A configured {@link AIProvider} instance, or `undefined` if the
|
|
870
|
+
* package cannot be loaded.
|
|
809
871
|
*/
|
|
810
|
-
static async
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
872
|
+
static async _getProviderFactory(providerType, logger) {
|
|
873
|
+
try {
|
|
874
|
+
let module;
|
|
875
|
+
switch (providerType) {
|
|
876
|
+
case "openai": {
|
|
877
|
+
module = await import("@launchdarkly/server-sdk-ai-openai");
|
|
878
|
+
return new module.OpenAIRunnerFactory(logger);
|
|
879
|
+
}
|
|
880
|
+
case "langchain": {
|
|
881
|
+
module = await import("@launchdarkly/server-sdk-ai-langchain");
|
|
882
|
+
return new module.LangChainRunnerFactory(logger);
|
|
883
|
+
}
|
|
884
|
+
case "vercel": {
|
|
885
|
+
module = await import("@launchdarkly/server-sdk-ai-vercel");
|
|
886
|
+
return new module.VercelRunnerFactory(logger);
|
|
887
|
+
}
|
|
888
|
+
default:
|
|
889
|
+
return void 0;
|
|
821
890
|
}
|
|
891
|
+
} catch (error) {
|
|
892
|
+
logger?.warn(
|
|
893
|
+
`Unable to load provider package. Check that you have installed the correct package. ${error.message}`
|
|
894
|
+
);
|
|
895
|
+
return void 0;
|
|
822
896
|
}
|
|
823
|
-
logger?.warn(
|
|
824
|
-
`Provider is not supported or failed to initialize: ${aiConfig.provider?.name ?? "unknown"}`
|
|
825
|
-
);
|
|
826
|
-
return void 0;
|
|
827
897
|
}
|
|
828
898
|
/**
|
|
829
899
|
* Determine which providers to try based on defaultAiProvider and providerName.
|
|
900
|
+
*
|
|
901
|
+
* Mirrors Python's `_get_providers_to_try` helper.
|
|
830
902
|
*/
|
|
831
903
|
static _getProvidersToTry(defaultAiProvider, providerName) {
|
|
832
904
|
if (defaultAiProvider) {
|
|
@@ -843,36 +915,111 @@ var AIProviderFactory = class {
|
|
|
843
915
|
return Array.from(providerSet);
|
|
844
916
|
}
|
|
845
917
|
/**
|
|
846
|
-
* Try
|
|
918
|
+
* Try each provider in order and return the first non-undefined result.
|
|
919
|
+
*
|
|
920
|
+
* Mirrors Python's `_with_fallback` helper. Loads each provider factory via
|
|
921
|
+
* {@link _getProviderFactory} and calls `fn` with it. Returns the first
|
|
922
|
+
* truthy result, or `undefined` if no provider succeeds.
|
|
923
|
+
*
|
|
924
|
+
* @param providers Ordered list of provider types to try.
|
|
925
|
+
* @param fn Callback that calls the appropriate factory method on the provider.
|
|
926
|
+
* @param logger Optional logger forwarded to each provider factory.
|
|
847
927
|
*/
|
|
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;
|
|
861
|
-
}
|
|
862
|
-
case "vercel": {
|
|
863
|
-
module = await import("@launchdarkly/server-sdk-ai-vercel");
|
|
864
|
-
const provider = await module.VercelProvider.create(aiConfig, logger);
|
|
865
|
-
return provider;
|
|
928
|
+
static async _withFallback(providers, fn, logger) {
|
|
929
|
+
for (const providerType of providers) {
|
|
930
|
+
logger?.debug(`Attempting to create runner with provider: ${providerType}`);
|
|
931
|
+
const factory = await _RunnerFactory._getProviderFactory(providerType, logger);
|
|
932
|
+
if (factory) {
|
|
933
|
+
const result = await fn(factory);
|
|
934
|
+
if (result) {
|
|
935
|
+
logger?.debug(`Successfully created runner with provider: ${providerType}`);
|
|
936
|
+
return result;
|
|
866
937
|
}
|
|
867
|
-
default:
|
|
868
|
-
return void 0;
|
|
869
938
|
}
|
|
870
|
-
}
|
|
939
|
+
}
|
|
940
|
+
return void 0;
|
|
941
|
+
}
|
|
942
|
+
/**
|
|
943
|
+
* Create a Runner for the given AI configuration.
|
|
944
|
+
*
|
|
945
|
+
* Suitable for completion, judge, and agent config modes. Dynamically
|
|
946
|
+
* loads the matching provider package via {@link _getProviderFactory} and
|
|
947
|
+
* delegates to its {@link AIProvider.createModel} method.
|
|
948
|
+
*
|
|
949
|
+
* @param config The AI configuration (completion, agent, or judge).
|
|
950
|
+
* @param logger Optional logger forwarded to the underlying provider.
|
|
951
|
+
* @param defaultAiProvider Optional provider override
|
|
952
|
+
* ('openai', 'langchain', 'vercel', …). When set, only that provider is
|
|
953
|
+
* tried. When omitted, providers are tried in priority order based on the
|
|
954
|
+
* provider name in the config.
|
|
955
|
+
* @returns A configured {@link Runner} ready to invoke the model, or
|
|
956
|
+
* `undefined` if no suitable provider could be loaded.
|
|
957
|
+
*/
|
|
958
|
+
static async createModel(config, logger, defaultAiProvider) {
|
|
959
|
+
const providerName = config.provider?.name?.toLowerCase();
|
|
960
|
+
const providers = _RunnerFactory._getProvidersToTry(defaultAiProvider, providerName);
|
|
961
|
+
const runner = await _RunnerFactory._withFallback(
|
|
962
|
+
providers,
|
|
963
|
+
(factory) => factory.createModel(config),
|
|
964
|
+
logger
|
|
965
|
+
);
|
|
966
|
+
if (!runner) {
|
|
871
967
|
logger?.warn(
|
|
872
|
-
`
|
|
968
|
+
`Provider is not supported or failed to initialize: ${config.provider?.name ?? "unknown"}`
|
|
873
969
|
);
|
|
874
|
-
return void 0;
|
|
875
970
|
}
|
|
971
|
+
return runner;
|
|
972
|
+
}
|
|
973
|
+
/**
|
|
974
|
+
* Create a Runner for an agent AI Config.
|
|
975
|
+
*
|
|
976
|
+
* Delegates to the provider factory's {@link AIProvider.createAgent} method.
|
|
977
|
+
*
|
|
978
|
+
* @param config The agent AI configuration.
|
|
979
|
+
* @param tools Optional registry of callable tools.
|
|
980
|
+
* @param logger Optional logger forwarded to the underlying provider.
|
|
981
|
+
* @param defaultAiProvider Optional provider override.
|
|
982
|
+
* @returns A configured {@link Runner}, or `undefined` if no suitable
|
|
983
|
+
* provider could be loaded.
|
|
984
|
+
*/
|
|
985
|
+
static async createAgent(config, tools, logger, defaultAiProvider) {
|
|
986
|
+
const providerName = config.provider?.name?.toLowerCase();
|
|
987
|
+
const providers = _RunnerFactory._getProvidersToTry(defaultAiProvider, providerName);
|
|
988
|
+
const runner = await _RunnerFactory._withFallback(
|
|
989
|
+
providers,
|
|
990
|
+
(factory) => factory.createAgent(config, tools),
|
|
991
|
+
logger
|
|
992
|
+
);
|
|
993
|
+
if (!runner) {
|
|
994
|
+
logger?.warn(
|
|
995
|
+
`Provider is not supported or failed to initialize: ${config.provider?.name ?? "unknown"}`
|
|
996
|
+
);
|
|
997
|
+
}
|
|
998
|
+
return runner;
|
|
999
|
+
}
|
|
1000
|
+
/**
|
|
1001
|
+
* Create an AgentGraphRunner for the given agent graph definition.
|
|
1002
|
+
*
|
|
1003
|
+
* Delegates to the provider factory's {@link AIProvider.createAgentGraph} method.
|
|
1004
|
+
*
|
|
1005
|
+
* @param graphDef The agent graph definition.
|
|
1006
|
+
* @param tools Optional registry of callable tools.
|
|
1007
|
+
* @param logger Optional logger forwarded to the underlying provider.
|
|
1008
|
+
* @param defaultAiProvider Optional provider override.
|
|
1009
|
+
* @returns A configured {@link AgentGraphRunner}, or `undefined` if no
|
|
1010
|
+
* suitable provider could be loaded.
|
|
1011
|
+
*/
|
|
1012
|
+
static async createAgentGraph(graphDef, tools, logger, defaultAiProvider) {
|
|
1013
|
+
const providers = _RunnerFactory._getProvidersToTry(defaultAiProvider);
|
|
1014
|
+
const runner = await _RunnerFactory._withFallback(
|
|
1015
|
+
providers,
|
|
1016
|
+
(factory) => factory.createAgentGraph(graphDef, tools),
|
|
1017
|
+
logger
|
|
1018
|
+
);
|
|
1019
|
+
if (!runner) {
|
|
1020
|
+
logger?.warn(`No provider could create an AgentGraphRunner for the given graph definition.`);
|
|
1021
|
+
}
|
|
1022
|
+
return runner;
|
|
876
1023
|
}
|
|
877
1024
|
};
|
|
878
1025
|
|
|
@@ -923,6 +1070,7 @@ var LDAIConfigTrackerImpl = class _LDAIConfigTrackerImpl {
|
|
|
923
1070
|
this._context = _context;
|
|
924
1071
|
this._graphKey = _graphKey;
|
|
925
1072
|
this._trackedMetrics = {};
|
|
1073
|
+
this._trackedMetrics.resumptionToken = this.resumptionToken;
|
|
926
1074
|
}
|
|
927
1075
|
getTrackData() {
|
|
928
1076
|
return {
|
|
@@ -1006,6 +1154,10 @@ var LDAIConfigTrackerImpl = class _LDAIConfigTrackerImpl {
|
|
|
1006
1154
|
}
|
|
1007
1155
|
}
|
|
1008
1156
|
trackToolCall(toolKey) {
|
|
1157
|
+
if (!this._trackedMetrics.toolCalls) {
|
|
1158
|
+
this._trackedMetrics.toolCalls = [];
|
|
1159
|
+
}
|
|
1160
|
+
this._trackedMetrics.toolCalls.push(toolKey);
|
|
1009
1161
|
this._ldClient.track("$ld:ai:tool_call", this._context, { ...this.getTrackData(), toolKey }, 1);
|
|
1010
1162
|
}
|
|
1011
1163
|
trackToolCalls(toolKeys) {
|
|
@@ -1061,8 +1213,11 @@ var LDAIConfigTrackerImpl = class _LDAIConfigTrackerImpl {
|
|
|
1061
1213
|
} else {
|
|
1062
1214
|
this.trackError();
|
|
1063
1215
|
}
|
|
1064
|
-
if (metrics.
|
|
1065
|
-
this.trackTokens(metrics.
|
|
1216
|
+
if (metrics.tokens) {
|
|
1217
|
+
this.trackTokens(metrics.tokens);
|
|
1218
|
+
}
|
|
1219
|
+
if (metrics.toolCalls?.length) {
|
|
1220
|
+
this.trackToolCalls(metrics.toolCalls);
|
|
1066
1221
|
}
|
|
1067
1222
|
return result;
|
|
1068
1223
|
}
|
|
@@ -1086,8 +1241,11 @@ var LDAIConfigTrackerImpl = class _LDAIConfigTrackerImpl {
|
|
|
1086
1241
|
} else {
|
|
1087
1242
|
this.trackError();
|
|
1088
1243
|
}
|
|
1089
|
-
if (metrics.
|
|
1090
|
-
this.trackTokens(metrics.
|
|
1244
|
+
if (metrics.tokens) {
|
|
1245
|
+
this.trackTokens(metrics.tokens);
|
|
1246
|
+
}
|
|
1247
|
+
if (metrics.toolCalls?.length) {
|
|
1248
|
+
this.trackToolCalls(metrics.toolCalls);
|
|
1091
1249
|
}
|
|
1092
1250
|
} catch (error) {
|
|
1093
1251
|
this.trackError();
|
|
@@ -1172,6 +1330,7 @@ var LDGraphTrackerImpl = class _LDGraphTrackerImpl {
|
|
|
1172
1330
|
this._version = _version;
|
|
1173
1331
|
this._context = _context;
|
|
1174
1332
|
this._summary = {};
|
|
1333
|
+
this._summary.resumptionToken = this.resumptionToken;
|
|
1175
1334
|
}
|
|
1176
1335
|
/**
|
|
1177
1336
|
* Reconstructs an {@link LDGraphTrackerImpl} from a resumption token, preserving
|
|
@@ -1197,15 +1356,12 @@ var LDGraphTrackerImpl = class _LDGraphTrackerImpl {
|
|
|
1197
1356
|
);
|
|
1198
1357
|
}
|
|
1199
1358
|
getTrackData() {
|
|
1200
|
-
|
|
1359
|
+
return {
|
|
1201
1360
|
runId: this._runId,
|
|
1202
1361
|
graphKey: this._graphKey,
|
|
1203
|
-
version: this._version
|
|
1362
|
+
version: this._version,
|
|
1363
|
+
...this._variationKey !== void 0 ? { variationKey: this._variationKey } : {}
|
|
1204
1364
|
};
|
|
1205
|
-
if (this._variationKey !== void 0) {
|
|
1206
|
-
data.variationKey = this._variationKey;
|
|
1207
|
-
}
|
|
1208
|
-
return data;
|
|
1209
1365
|
}
|
|
1210
1366
|
getSummary() {
|
|
1211
1367
|
return { ...this._summary };
|
|
@@ -1310,13 +1466,14 @@ var LDGraphTrackerImpl = class _LDGraphTrackerImpl {
|
|
|
1310
1466
|
|
|
1311
1467
|
// src/sdkInfo.ts
|
|
1312
1468
|
var aiSdkName = "@launchdarkly/server-sdk-ai";
|
|
1313
|
-
var aiSdkVersion = "0.
|
|
1469
|
+
var aiSdkVersion = "0.20.0";
|
|
1314
1470
|
var aiSdkLanguage = "javascript";
|
|
1315
1471
|
|
|
1316
1472
|
// src/LDAIClientImpl.ts
|
|
1317
1473
|
var TRACK_SDK_INFO = "$ld:ai:sdk:info";
|
|
1318
1474
|
var TRACK_USAGE_COMPLETION_CONFIG = "$ld:ai:usage:completion-config";
|
|
1319
1475
|
var TRACK_USAGE_CREATE_CHAT = "$ld:ai:usage:create-chat";
|
|
1476
|
+
var TRACK_USAGE_CREATE_AGENT = "$ld:ai:usage:create-agent";
|
|
1320
1477
|
var TRACK_USAGE_JUDGE_CONFIG = "$ld:ai:usage:judge-config";
|
|
1321
1478
|
var TRACK_USAGE_CREATE_JUDGE = "$ld:ai:usage:create-judge";
|
|
1322
1479
|
var TRACK_USAGE_AGENT_CONFIG = "$ld:ai:usage:agent-config";
|
|
@@ -1344,18 +1501,11 @@ var LDAIClientImpl = class {
|
|
|
1344
1501
|
);
|
|
1345
1502
|
}
|
|
1346
1503
|
_interpolateTemplate(template, variables) {
|
|
1347
|
-
return
|
|
1504
|
+
return Mustache.render(template, variables, void 0, { escape: (item) => item });
|
|
1348
1505
|
}
|
|
1349
|
-
async _evaluate(key, context, defaultValue, mode, variables, graphKey) {
|
|
1506
|
+
async _evaluate(key, context, defaultValue, mode, variables, graphKey, defaultAiProvider) {
|
|
1350
1507
|
const ldFlagValue = LDAIConfigUtils.toFlagValue(defaultValue, mode);
|
|
1351
1508
|
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
1509
|
const trackerFactory = () => new LDAIConfigTrackerImpl(
|
|
1360
1510
|
this._ldClient,
|
|
1361
1511
|
randomUUID(),
|
|
@@ -1369,7 +1519,23 @@ var LDAIClientImpl = class {
|
|
|
1369
1519
|
context,
|
|
1370
1520
|
graphKey
|
|
1371
1521
|
);
|
|
1372
|
-
const
|
|
1522
|
+
const flagMode = value._ldMeta?.mode ?? "completion";
|
|
1523
|
+
let evaluator = Evaluator.noop();
|
|
1524
|
+
if (flagMode !== mode) {
|
|
1525
|
+
this._logger?.warn(
|
|
1526
|
+
`AI Config mode mismatch for ${key}: expected ${mode}, got ${flagMode}. Returning disabled config.`
|
|
1527
|
+
);
|
|
1528
|
+
return LDAIConfigUtils.createDisabledConfig(key, mode, trackerFactory, evaluator);
|
|
1529
|
+
}
|
|
1530
|
+
if (flagMode !== "judge") {
|
|
1531
|
+
evaluator = await this._buildEvaluator(
|
|
1532
|
+
value.judgeConfiguration?.judges ?? [],
|
|
1533
|
+
context,
|
|
1534
|
+
variables,
|
|
1535
|
+
defaultAiProvider
|
|
1536
|
+
);
|
|
1537
|
+
}
|
|
1538
|
+
const config = LDAIConfigUtils.fromFlagValue(key, value, trackerFactory, evaluator);
|
|
1373
1539
|
return this._applyInterpolation(config, context, variables);
|
|
1374
1540
|
}
|
|
1375
1541
|
_applyInterpolation(config, context, variables) {
|
|
@@ -1391,33 +1557,44 @@ var LDAIClientImpl = class {
|
|
|
1391
1557
|
}
|
|
1392
1558
|
return config;
|
|
1393
1559
|
}
|
|
1394
|
-
async
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1560
|
+
async _buildEvaluator(judgeConfigs, context, variables, defaultAiProvider) {
|
|
1561
|
+
if (judgeConfigs.length === 0) {
|
|
1562
|
+
return Evaluator.noop();
|
|
1563
|
+
}
|
|
1564
|
+
const judgeInstances = (await Promise.all(
|
|
1565
|
+
judgeConfigs.map(
|
|
1566
|
+
(jc) => this._createJudgeInstance(
|
|
1567
|
+
jc.key,
|
|
1568
|
+
context,
|
|
1569
|
+
void 0,
|
|
1570
|
+
variables,
|
|
1571
|
+
defaultAiProvider,
|
|
1572
|
+
jc.samplingRate
|
|
1573
|
+
)
|
|
1574
|
+
)
|
|
1575
|
+
)).filter((j) => j !== void 0);
|
|
1576
|
+
return new Evaluator(judgeInstances);
|
|
1577
|
+
}
|
|
1578
|
+
async _completionConfig(key, context, defaultValue, variables, defaultAiProvider) {
|
|
1579
|
+
return await this._evaluate(
|
|
1580
|
+
key,
|
|
1581
|
+
context,
|
|
1582
|
+
defaultValue,
|
|
1583
|
+
"completion",
|
|
1584
|
+
variables,
|
|
1585
|
+
void 0,
|
|
1586
|
+
defaultAiProvider
|
|
1587
|
+
);
|
|
1417
1588
|
}
|
|
1418
|
-
async completionConfig(key, context, defaultValue, variables) {
|
|
1589
|
+
async completionConfig(key, context, defaultValue, variables, defaultAiProvider) {
|
|
1419
1590
|
this._ldClient.track(TRACK_USAGE_COMPLETION_CONFIG, context, key, 1);
|
|
1420
|
-
return this._completionConfig(
|
|
1591
|
+
return this._completionConfig(
|
|
1592
|
+
key,
|
|
1593
|
+
context,
|
|
1594
|
+
defaultValue ?? disabledAIConfig,
|
|
1595
|
+
variables,
|
|
1596
|
+
defaultAiProvider
|
|
1597
|
+
);
|
|
1421
1598
|
}
|
|
1422
1599
|
/**
|
|
1423
1600
|
* @deprecated Use `completionConfig` instead. This method will be removed in a future version.
|
|
@@ -1426,20 +1603,58 @@ var LDAIClientImpl = class {
|
|
|
1426
1603
|
return this.completionConfig(key, context, defaultValue, variables);
|
|
1427
1604
|
}
|
|
1428
1605
|
async _judgeConfig(key, context, defaultValue, variables) {
|
|
1429
|
-
|
|
1606
|
+
if (variables?.message_history !== void 0) {
|
|
1607
|
+
this._logger?.warn(
|
|
1608
|
+
"The variable 'message_history' is reserved by the judge and will be ignored."
|
|
1609
|
+
);
|
|
1610
|
+
}
|
|
1611
|
+
if (variables?.response_to_evaluate !== void 0) {
|
|
1612
|
+
this._logger?.warn(
|
|
1613
|
+
"The variable 'response_to_evaluate' is reserved by the judge and will be ignored."
|
|
1614
|
+
);
|
|
1615
|
+
}
|
|
1616
|
+
const extendedVariables = {
|
|
1617
|
+
...variables,
|
|
1618
|
+
message_history: "{{message_history}}",
|
|
1619
|
+
response_to_evaluate: "{{response_to_evaluate}}"
|
|
1620
|
+
};
|
|
1621
|
+
const config = await this._evaluate(
|
|
1622
|
+
key,
|
|
1623
|
+
context,
|
|
1624
|
+
defaultValue,
|
|
1625
|
+
"judge",
|
|
1626
|
+
extendedVariables
|
|
1627
|
+
);
|
|
1628
|
+
if (config.messages) {
|
|
1629
|
+
return { ...config, messages: stripLegacyJudgeMessages(config.messages) };
|
|
1630
|
+
}
|
|
1430
1631
|
return config;
|
|
1431
1632
|
}
|
|
1432
1633
|
async judgeConfig(key, context, defaultValue, variables) {
|
|
1433
1634
|
this._ldClient.track(TRACK_USAGE_JUDGE_CONFIG, context, key, 1);
|
|
1434
1635
|
return this._judgeConfig(key, context, defaultValue ?? disabledAIConfig, variables);
|
|
1435
1636
|
}
|
|
1436
|
-
async _agentConfig(key, context, defaultValue, variables, graphKey) {
|
|
1437
|
-
|
|
1438
|
-
|
|
1637
|
+
async _agentConfig(key, context, defaultValue, variables, graphKey, defaultAiProvider) {
|
|
1638
|
+
return await this._evaluate(
|
|
1639
|
+
key,
|
|
1640
|
+
context,
|
|
1641
|
+
defaultValue,
|
|
1642
|
+
"agent",
|
|
1643
|
+
variables,
|
|
1644
|
+
graphKey,
|
|
1645
|
+
defaultAiProvider
|
|
1646
|
+
);
|
|
1439
1647
|
}
|
|
1440
|
-
async agentConfig(key, context, defaultValue, variables) {
|
|
1648
|
+
async agentConfig(key, context, defaultValue, variables, defaultAiProvider) {
|
|
1441
1649
|
this._ldClient.track(TRACK_USAGE_AGENT_CONFIG, context, key, 1);
|
|
1442
|
-
return this._agentConfig(
|
|
1650
|
+
return this._agentConfig(
|
|
1651
|
+
key,
|
|
1652
|
+
context,
|
|
1653
|
+
defaultValue ?? disabledAIConfig,
|
|
1654
|
+
variables,
|
|
1655
|
+
void 0,
|
|
1656
|
+
defaultAiProvider
|
|
1657
|
+
);
|
|
1443
1658
|
}
|
|
1444
1659
|
/**
|
|
1445
1660
|
* @deprecated Use `agentConfig` instead. This method will be removed in a future version.
|
|
@@ -1474,73 +1689,89 @@ var LDAIClientImpl = class {
|
|
|
1474
1689
|
async agents(agentConfigs, context) {
|
|
1475
1690
|
return this.agentConfigs(agentConfigs, context);
|
|
1476
1691
|
}
|
|
1477
|
-
async
|
|
1478
|
-
this._ldClient.track(
|
|
1479
|
-
|
|
1692
|
+
async createJudge(key, context, defaultValue, variables, defaultAiProvider, sampleRate = 1) {
|
|
1693
|
+
this._ldClient.track(TRACK_USAGE_CREATE_JUDGE, context, key, 1);
|
|
1694
|
+
return this._createJudgeInstance(
|
|
1480
1695
|
key,
|
|
1481
1696
|
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,
|
|
1697
|
+
defaultValue,
|
|
1496
1698
|
variables,
|
|
1497
|
-
defaultAiProvider
|
|
1699
|
+
defaultAiProvider,
|
|
1700
|
+
sampleRate
|
|
1498
1701
|
);
|
|
1499
|
-
return new TrackedChat(config, provider, judges, this._logger);
|
|
1500
1702
|
}
|
|
1501
|
-
async
|
|
1502
|
-
this._ldClient.track(TRACK_USAGE_CREATE_JUDGE, context, key, 1);
|
|
1703
|
+
async _createJudgeInstance(key, context, defaultValue, variables, defaultAiProvider, sampleRate = 1) {
|
|
1503
1704
|
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
1705
|
const judgeConfig = await this._judgeConfig(
|
|
1520
1706
|
key,
|
|
1521
1707
|
context,
|
|
1522
1708
|
defaultValue ?? disabledAIConfig,
|
|
1523
|
-
|
|
1709
|
+
variables
|
|
1524
1710
|
);
|
|
1525
1711
|
if (!judgeConfig.enabled) {
|
|
1526
1712
|
this._logger?.info(`Judge configuration is disabled: ${key}`);
|
|
1527
1713
|
return void 0;
|
|
1528
1714
|
}
|
|
1529
|
-
const
|
|
1530
|
-
if (!
|
|
1715
|
+
const runner = await RunnerFactory.createModel(judgeConfig, this._logger, defaultAiProvider);
|
|
1716
|
+
if (!runner) {
|
|
1531
1717
|
return void 0;
|
|
1532
1718
|
}
|
|
1533
|
-
return new Judge(judgeConfig,
|
|
1719
|
+
return new Judge(judgeConfig, runner, sampleRate, this._logger);
|
|
1534
1720
|
} catch (error) {
|
|
1535
1721
|
this._logger?.error(`Failed to initialize judge ${key}:`, error);
|
|
1536
1722
|
return void 0;
|
|
1537
1723
|
}
|
|
1538
1724
|
}
|
|
1725
|
+
async createModel(key, context, defaultValue, variables, defaultAiProvider) {
|
|
1726
|
+
this._ldClient.track(TRACK_USAGE_CREATE_CHAT, context, key, 1);
|
|
1727
|
+
const config = await this._completionConfig(
|
|
1728
|
+
key,
|
|
1729
|
+
context,
|
|
1730
|
+
defaultValue ?? disabledAIConfig,
|
|
1731
|
+
variables,
|
|
1732
|
+
defaultAiProvider
|
|
1733
|
+
);
|
|
1734
|
+
if (!config.enabled) {
|
|
1735
|
+
this._logger?.info(`Completion configuration is disabled: ${key}`);
|
|
1736
|
+
return void 0;
|
|
1737
|
+
}
|
|
1738
|
+
const runner = await RunnerFactory.createModel(config, this._logger, defaultAiProvider);
|
|
1739
|
+
if (!runner) {
|
|
1740
|
+
return void 0;
|
|
1741
|
+
}
|
|
1742
|
+
return new ManagedModel(config, runner, this._logger);
|
|
1743
|
+
}
|
|
1744
|
+
async createAgent(key, context, defaultValue, variables, defaultAiProvider) {
|
|
1745
|
+
this._ldClient.track(TRACK_USAGE_CREATE_AGENT, context, key, 1);
|
|
1746
|
+
const config = await this._agentConfig(
|
|
1747
|
+
key,
|
|
1748
|
+
context,
|
|
1749
|
+
defaultValue ?? disabledAIConfig,
|
|
1750
|
+
variables,
|
|
1751
|
+
void 0,
|
|
1752
|
+
defaultAiProvider
|
|
1753
|
+
);
|
|
1754
|
+
if (!config.enabled) {
|
|
1755
|
+
this._logger?.info(`Agent configuration is disabled: ${key}`);
|
|
1756
|
+
return void 0;
|
|
1757
|
+
}
|
|
1758
|
+
const runner = await RunnerFactory.createAgent(config, void 0, this._logger, defaultAiProvider);
|
|
1759
|
+
if (!runner) {
|
|
1760
|
+
return void 0;
|
|
1761
|
+
}
|
|
1762
|
+
return new ManagedAgent(config, runner, this._logger);
|
|
1763
|
+
}
|
|
1764
|
+
/**
|
|
1765
|
+
* @deprecated Use `createModel` instead. This method will be removed in a future version.
|
|
1766
|
+
*/
|
|
1767
|
+
async createChat(key, context, defaultValue, variables, defaultAiProvider) {
|
|
1768
|
+
return this.createModel(key, context, defaultValue, variables, defaultAiProvider);
|
|
1769
|
+
}
|
|
1539
1770
|
/**
|
|
1540
|
-
* @deprecated Use `
|
|
1771
|
+
* @deprecated Use `createModel` instead. This method will be removed in a future version.
|
|
1541
1772
|
*/
|
|
1542
1773
|
async initChat(key, context, defaultValue, variables, defaultAiProvider) {
|
|
1543
|
-
return this.
|
|
1774
|
+
return this.createModel(key, context, defaultValue, variables, defaultAiProvider);
|
|
1544
1775
|
}
|
|
1545
1776
|
createTracker(token, context) {
|
|
1546
1777
|
return LDAIConfigTrackerImpl.fromResumptionToken(token, this._ldClient, context);
|
|
@@ -1625,14 +1856,16 @@ function initAi(ldClient) {
|
|
|
1625
1856
|
}
|
|
1626
1857
|
export {
|
|
1627
1858
|
AIProvider,
|
|
1628
|
-
AIProviderFactory,
|
|
1629
1859
|
AgentGraphDefinition,
|
|
1630
1860
|
AgentGraphNode,
|
|
1631
1861
|
Judge,
|
|
1632
1862
|
LDFeedbackKind,
|
|
1633
1863
|
LDGraphTrackerImpl,
|
|
1864
|
+
ManagedAgent,
|
|
1865
|
+
ManagedAgentGraph,
|
|
1866
|
+
ManagedModel,
|
|
1867
|
+
RunnerFactory,
|
|
1634
1868
|
SUPPORTED_AI_PROVIDERS,
|
|
1635
|
-
TrackedChat,
|
|
1636
1869
|
createBedrockTokenUsage,
|
|
1637
1870
|
createOpenAiUsage,
|
|
1638
1871
|
createVercelAISDKTokenUsage,
|