@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/dist/index.cjs CHANGED
@@ -31,14 +31,16 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
31
31
  var src_exports = {};
32
32
  __export(src_exports, {
33
33
  AIProvider: () => AIProvider,
34
- AIProviderFactory: () => AIProviderFactory,
35
34
  AgentGraphDefinition: () => AgentGraphDefinition,
36
35
  AgentGraphNode: () => AgentGraphNode,
37
36
  Judge: () => Judge,
38
37
  LDFeedbackKind: () => LDFeedbackKind,
39
38
  LDGraphTrackerImpl: () => LDGraphTrackerImpl,
39
+ ManagedAgent: () => ManagedAgent,
40
+ ManagedAgentGraph: () => ManagedAgentGraph,
41
+ ManagedModel: () => ManagedModel,
42
+ RunnerFactory: () => RunnerFactory,
40
43
  SUPPORTED_AI_PROVIDERS: () => SUPPORTED_AI_PROVIDERS,
41
- TrackedChat: () => TrackedChat,
42
44
  createBedrockTokenUsage: () => createBedrockTokenUsage,
43
45
  createOpenAiUsage: () => createOpenAiUsage,
44
46
  createVercelAISDKTokenUsage: () => createVercelAISDKTokenUsage,
@@ -47,131 +49,112 @@ __export(src_exports, {
47
49
  module.exports = __toCommonJS(src_exports);
48
50
 
49
51
  // src/LDAIClientImpl.ts
50
- var import_mustache2 = __toESM(require("mustache"), 1);
52
+ var import_mustache = __toESM(require("mustache"), 1);
51
53
  var import_node_crypto = require("crypto");
52
54
 
53
- // src/api/chat/TrackedChat.ts
54
- var TrackedChat = class {
55
- constructor(aiConfig, provider, judges = {}, _logger) {
56
- this.aiConfig = aiConfig;
57
- this.provider = provider;
58
- this.judges = judges;
55
+ // src/api/ManagedAgent.ts
56
+ var ManagedAgent = class {
57
+ constructor(aiAgentConfig, runner, _logger) {
58
+ this.aiAgentConfig = aiAgentConfig;
59
+ this.runner = runner;
59
60
  this._logger = _logger;
60
- this.messages = [];
61
61
  }
62
62
  /**
63
- * Invoke the chat model with a prompt string.
64
- * This method handles conversation management and tracking, delegating to the provider's invokeModel method.
63
+ * Invoke the agent with a prompt string and return a ManagedResult.
64
+ *
65
+ * `run()` resolves before `ManagedResult.evaluations` resolves. Awaiting
66
+ * `evaluations` guarantees both judge evaluation and tracker.trackJudgeResult()
67
+ * are complete.
68
+ *
69
+ * @param prompt The user input to send to the agent.
70
+ * @returns Promise resolving to ManagedResult (before evaluations settle).
65
71
  */
66
- async invoke(prompt) {
67
- const tracker = this.aiConfig.createTracker();
68
- const userMessage = {
69
- role: "user",
70
- content: prompt
71
- };
72
- this.messages.push(userMessage);
73
- const configMessages = this.aiConfig.messages || [];
74
- const allMessages = [...configMessages, ...this.messages];
75
- const response = await tracker.trackMetricsOf(
76
- (result) => result.metrics,
77
- () => this.provider.invokeModel(allMessages)
72
+ async run(prompt) {
73
+ const tracker = this.aiAgentConfig.createTracker();
74
+ const result = await tracker.trackMetricsOf(
75
+ (r) => r.metrics,
76
+ () => this.runner.run(prompt)
78
77
  );
79
- if (this.aiConfig.judgeConfiguration?.judges && this.aiConfig.judgeConfiguration.judges.length > 0) {
80
- response.evaluations = this._evaluateWithJudges(this.messages, response).then(
81
- (evaluations) => {
82
- evaluations.forEach((judgeResult) => {
83
- tracker.trackJudgeResult(judgeResult);
84
- });
85
- return evaluations;
78
+ const metrics = tracker.getSummary();
79
+ const output = result.content;
80
+ const evaluations = this.aiAgentConfig.evaluator.evaluate(prompt, output).then((results) => {
81
+ results.forEach((judgeResult) => {
82
+ if (!judgeResult.sampled) {
83
+ return;
86
84
  }
87
- );
88
- }
89
- this.messages.push(response.message);
90
- return response;
91
- }
92
- /**
93
- * Evaluates the response with all configured judges.
94
- * Returns a promise that resolves to an array of evaluation results.
95
- *
96
- * @param messages Array of messages representing the conversation history
97
- * @param response The AI response to be evaluated
98
- * @returns Promise resolving to array of judge evaluation results
99
- */
100
- async _evaluateWithJudges(messages, response) {
101
- const judgeConfigs = this.aiConfig.judgeConfiguration.judges;
102
- const evaluationPromises = judgeConfigs.map(async (judgeConfig) => {
103
- const judge = this.judges[judgeConfig.key];
104
- if (!judge) {
105
- this._logger?.warn(
106
- `Judge configuration is not enabled for ${judgeConfig.key} in ${this.aiConfig.key}`
107
- );
108
- const result = {
109
- success: false,
110
- sampled: true,
111
- errorMessage: `Judge configuration is not enabled for ${judgeConfig.key}`
112
- };
113
- return result;
114
- }
115
- return judge.evaluateMessages(messages, response, judgeConfig.samplingRate);
116
- });
117
- const results = await Promise.allSettled(evaluationPromises);
118
- return results.map((settled) => {
119
- if (settled.status === "fulfilled") {
120
- return settled.value;
121
- }
122
- const result = {
123
- success: false,
124
- sampled: true,
125
- errorMessage: "Judge evaluation failed"
126
- };
127
- return result;
85
+ tracker.trackJudgeResult(judgeResult);
86
+ });
87
+ return results;
88
+ }).catch((err) => {
89
+ this._logger?.warn("Judge evaluation failed unexpectedly:", err);
90
+ return [];
128
91
  });
92
+ return {
93
+ content: output,
94
+ metrics,
95
+ raw: result.raw,
96
+ parsed: result.parsed,
97
+ evaluations
98
+ };
129
99
  }
130
100
  /**
131
- * Get the underlying AI configuration used to initialize this TrackedChat.
101
+ * Get the underlying AI agent configuration used to initialize this ManagedAgent.
132
102
  */
133
103
  getConfig() {
134
- return this.aiConfig;
104
+ return this.aiAgentConfig;
135
105
  }
136
- /**
137
- * Get the underlying AI provider instance.
138
- * This provides direct access to the provider for advanced use cases.
139
- */
140
- getProvider() {
141
- return this.provider;
142
- }
143
- /**
144
- * Get the judges associated with this TrackedChat.
145
- * Returns a record of judge instances keyed by their configuration keys.
146
- */
147
- getJudges() {
148
- return this.judges;
106
+ };
107
+
108
+ // src/api/ManagedModel.ts
109
+ var ManagedModel = class {
110
+ constructor(aiConfig, runner, _logger) {
111
+ this.aiConfig = aiConfig;
112
+ this.runner = runner;
113
+ this._logger = _logger;
149
114
  }
150
115
  /**
151
- * Append messages to the conversation history.
152
- * Adds messages to the conversation history without invoking the model,
153
- * which is useful for managing multi-turn conversations or injecting context.
116
+ * Invoke the model with a prompt string and return a ManagedResult.
154
117
  *
155
- * @param messages Array of messages to append to the conversation history
118
+ * `run()` resolves before `ManagedResult.evaluations` resolves. Awaiting
119
+ * `evaluations` guarantees both judge evaluation and tracker.trackJudgeResult()
120
+ * are complete.
121
+ *
122
+ * @param prompt The user input to send to the model.
123
+ * @returns Promise resolving to ManagedResult (before evaluations settle).
156
124
  */
157
- appendMessages(messages) {
158
- this.messages.push(...messages);
125
+ async run(prompt) {
126
+ const tracker = this.aiConfig.createTracker();
127
+ const result = await tracker.trackMetricsOf(
128
+ (r) => r.metrics,
129
+ () => this.runner.run(prompt)
130
+ );
131
+ const metrics = tracker.getSummary();
132
+ const output = result.content;
133
+ const evaluations = this.aiConfig.evaluator.evaluate(prompt, output).then((results) => {
134
+ results.forEach((judgeResult) => {
135
+ if (!judgeResult.sampled) {
136
+ return;
137
+ }
138
+ tracker.trackJudgeResult(judgeResult);
139
+ });
140
+ return results;
141
+ }).catch((err) => {
142
+ this._logger?.warn("Judge evaluation failed unexpectedly:", err);
143
+ return [];
144
+ });
145
+ return {
146
+ content: output,
147
+ metrics,
148
+ raw: result.raw,
149
+ parsed: result.parsed,
150
+ evaluations
151
+ };
159
152
  }
160
153
  /**
161
- * Get all messages in the conversation history.
162
- *
163
- * @param includeConfigMessages Whether to include the config messages from the AIConfig.
164
- * Defaults to false.
165
- * @returns Array of messages. When includeConfigMessages is true, returns both config
166
- * messages and conversation history with config messages prepended. When false,
167
- * returns only the conversation history messages.
154
+ * Get the underlying AI configuration used to initialize this ManagedModel.
168
155
  */
169
- getMessages(includeConfigMessages = false) {
170
- if (includeConfigMessages) {
171
- const configMessages = this.aiConfig.messages || [];
172
- return [...configMessages, ...this.messages];
173
- }
174
- return [...this.messages];
156
+ getConfig() {
157
+ return this.aiConfig;
175
158
  }
176
159
  };
177
160
 
@@ -223,46 +206,52 @@ var LDAIConfigUtils = class {
223
206
  * @param key The configuration key
224
207
  * @param flagValue The flag value from LaunchDarkly
225
208
  * @param trackerFactory A factory function that creates a new tracker for each execution
209
+ * @param evaluator The evaluator to attach to completion and agent configs
226
210
  * @returns The appropriate AI configuration type
227
211
  */
228
- static fromFlagValue(key, flagValue, trackerFactory) {
212
+ static fromFlagValue(key, flagValue, trackerFactory, evaluator) {
229
213
  const flagValueMode = flagValue._ldMeta?.mode;
230
214
  switch (flagValueMode) {
231
215
  case "agent":
232
- return this.toAgentConfig(key, flagValue, trackerFactory);
216
+ return this.toAgentConfig(key, flagValue, trackerFactory, evaluator);
233
217
  case "judge":
234
218
  return this.toJudgeConfig(key, flagValue, trackerFactory);
235
219
  case "completion":
236
220
  default:
237
- return this.toCompletionConfig(key, flagValue, trackerFactory);
221
+ return this.toCompletionConfig(key, flagValue, trackerFactory, evaluator);
238
222
  }
239
223
  }
240
224
  /**
241
225
  * Creates a disabled configuration of the specified mode.
242
226
  *
227
+ * @param key The configuration key
243
228
  * @param mode The mode for the disabled config
229
+ * @param createTracker A factory function that creates a new tracker for each execution
230
+ * @param evaluator The evaluator to attach to completion and agent configs
244
231
  * @returns A disabled config of the appropriate type
245
232
  */
246
- static createDisabledConfig(key, mode) {
233
+ static createDisabledConfig(key, mode, createTracker, evaluator) {
247
234
  switch (mode) {
248
235
  case "agent":
249
236
  return {
250
237
  key,
251
238
  enabled: false,
252
- createTracker: void 0
239
+ createTracker,
240
+ evaluator
253
241
  };
254
242
  case "judge":
255
243
  return {
256
244
  key,
257
245
  enabled: false,
258
- createTracker: void 0
246
+ createTracker
259
247
  };
260
248
  case "completion":
261
249
  default:
262
250
  return {
263
251
  key,
264
252
  enabled: false,
265
- createTracker: void 0
253
+ createTracker,
254
+ evaluator
266
255
  };
267
256
  }
268
257
  }
@@ -304,12 +293,14 @@ var LDAIConfigUtils = class {
304
293
  * @param key The configuration key
305
294
  * @param flagValue The flag value from LaunchDarkly
306
295
  * @param trackerFactory A factory function that creates a new tracker for each execution
296
+ * @param evaluator The evaluator for this completion config
307
297
  * @returns A completion configuration
308
298
  */
309
- static toCompletionConfig(key, flagValue, trackerFactory) {
299
+ static toCompletionConfig(key, flagValue, trackerFactory, evaluator) {
310
300
  return {
311
301
  ...this._toBaseConfig(key, flagValue),
312
302
  createTracker: trackerFactory,
303
+ evaluator,
313
304
  messages: flagValue.messages,
314
305
  judgeConfiguration: flagValue.judgeConfiguration,
315
306
  tools: this._resolveTools(flagValue)
@@ -321,12 +312,14 @@ var LDAIConfigUtils = class {
321
312
  * @param key The configuration key
322
313
  * @param flagValue The flag value from LaunchDarkly
323
314
  * @param trackerFactory A factory function that creates a new tracker for each execution
315
+ * @param evaluator The evaluator for this agent config
324
316
  * @returns An agent configuration
325
317
  */
326
- static toAgentConfig(key, flagValue, trackerFactory) {
318
+ static toAgentConfig(key, flagValue, trackerFactory, evaluator) {
327
319
  return {
328
320
  ...this._toBaseConfig(key, flagValue),
329
321
  createTracker: trackerFactory,
322
+ evaluator,
330
323
  instructions: flagValue.instructions,
331
324
  judgeConfiguration: flagValue.judgeConfiguration,
332
325
  tools: this._resolveTools(flagValue)
@@ -591,8 +584,98 @@ var AgentGraphDefinition = class _AgentGraphDefinition {
591
584
  }
592
585
  };
593
586
 
587
+ // src/api/graph/ManagedAgentGraph.ts
588
+ var ManagedAgentGraph = class {
589
+ constructor(_graphDefinition, _logger) {
590
+ this._graphDefinition = _graphDefinition;
591
+ this._logger = _logger;
592
+ }
593
+ /**
594
+ * Runs the agent graph using the provided runner function and returns a ManagedGraphResult.
595
+ *
596
+ * The runner function receives the graph tracker and AgentGraphDefinition,
597
+ * executes the graph, and returns an AgentGraphRunnerResult.
598
+ *
599
+ * run() returns before ManagedGraphResult.evaluations resolves.
600
+ *
601
+ * @param runner Async function that executes the graph and returns AgentGraphRunnerResult.
602
+ * @returns ManagedGraphResult with LDAIGraphMetricSummary and evaluations promise.
603
+ */
604
+ async run(runner) {
605
+ const graphTracker = this._graphDefinition.createTracker();
606
+ const runnerResult = await runner(this._graphDefinition, graphTracker);
607
+ const metrics = {
608
+ success: runnerResult.metrics.success,
609
+ path: runnerResult.metrics.path,
610
+ durationMs: runnerResult.metrics.durationMs,
611
+ tokens: runnerResult.metrics.tokens,
612
+ nodeMetrics: this._trackNodeMetrics(runnerResult.metrics.nodeMetrics),
613
+ resumptionToken: graphTracker.resumptionToken
614
+ };
615
+ const evaluations = Promise.resolve([]);
616
+ return {
617
+ content: runnerResult.content,
618
+ metrics,
619
+ raw: runnerResult.raw,
620
+ evaluations
621
+ };
622
+ }
623
+ /**
624
+ * Converts per-node LDAIMetrics from the runner into LDAIMetricSummary by
625
+ * creating a per-node tracker, firing tracking events, and calling getSummary().
626
+ */
627
+ _trackNodeMetrics(nodeMetrics) {
628
+ const summaries = {};
629
+ for (const [nodeKey, metrics] of Object.entries(nodeMetrics)) {
630
+ const node = this._graphDefinition.getNode(nodeKey);
631
+ if (!node) {
632
+ this._logger?.warn(`ManagedAgentGraph: no node found for key "${nodeKey}", skipping metrics`);
633
+ continue;
634
+ }
635
+ const tracker = node.getConfig().createTracker();
636
+ if (metrics.tokens) {
637
+ tracker.trackTokens(metrics.tokens);
638
+ }
639
+ if (metrics.durationMs !== void 0) {
640
+ tracker.trackDuration(metrics.durationMs);
641
+ }
642
+ if (metrics.toolCalls?.length) {
643
+ tracker.trackToolCalls(metrics.toolCalls);
644
+ }
645
+ if (metrics.success) {
646
+ tracker.trackSuccess();
647
+ } else {
648
+ tracker.trackError();
649
+ }
650
+ summaries[nodeKey] = tracker.getSummary();
651
+ }
652
+ return summaries;
653
+ }
654
+ /**
655
+ * Returns the underlying AgentGraphDefinition.
656
+ */
657
+ getGraphDefinition() {
658
+ return this._graphDefinition;
659
+ }
660
+ };
661
+
662
+ // src/api/judge/Evaluator.ts
663
+ var Evaluator = class _Evaluator {
664
+ constructor(_judges) {
665
+ this._judges = _judges;
666
+ }
667
+ static noop() {
668
+ return new _Evaluator([]);
669
+ }
670
+ async evaluate(input, output) {
671
+ if (this._judges.length === 0) {
672
+ return [];
673
+ }
674
+ return Promise.all(this._judges.map((judge) => judge.evaluate(input, output)));
675
+ }
676
+ };
677
+
594
678
  // src/api/judge/Judge.ts
595
- var import_mustache = __toESM(require("mustache"), 1);
596
679
  var EVALUATION_SCHEMA = {
597
680
  type: "object",
598
681
  properties: {
@@ -610,12 +693,25 @@ var EVALUATION_SCHEMA = {
610
693
  required: ["score", "reasoning"],
611
694
  additionalProperties: false
612
695
  };
696
+ function stripLegacyJudgeMessages(messages) {
697
+ return messages.filter(
698
+ (msg) => msg.role === "system" || !msg.content.includes("{{message_history}}") && !msg.content.includes("{{response_to_evaluate}}")
699
+ );
700
+ }
613
701
  var Judge = class {
614
- constructor(_aiConfig, _aiProvider, logger) {
702
+ constructor(_aiConfig, _runner, _sampleRate = 1, logger) {
615
703
  this._aiConfig = _aiConfig;
616
- this._aiProvider = _aiProvider;
704
+ this._runner = _runner;
705
+ this._sampleRate = _sampleRate;
617
706
  this._logger = logger;
618
707
  }
708
+ /**
709
+ * The default sampling rate baked in at construction. Used by `evaluate` /
710
+ * `evaluateMessages` when no per-call rate is supplied.
711
+ */
712
+ get sampleRate() {
713
+ return this._sampleRate;
714
+ }
619
715
  /**
620
716
  * Gets the evaluation metric key, prioritizing evaluationMetricKey over evaluationMetricKeys.
621
717
  * Falls back to the first valid (non-empty, non-whitespace) value in evaluationMetricKeys if evaluationMetricKey is not provided.
@@ -639,10 +735,13 @@ var Judge = class {
639
735
  *
640
736
  * @param input The input prompt or question that was provided to the AI
641
737
  * @param output The AI-generated response to be evaluated
642
- * @param samplingRate Sampling rate (0-1) to determine if evaluation should be processed (defaults to 1)
738
+ * @param samplingRate Sampling rate (0-1) to determine if evaluation should be processed.
739
+ * When omitted, the Judge's constructor-default rate is used. An explicit `0` overrides
740
+ * the default — only `undefined` falls through.
643
741
  * @returns Promise that resolves to evaluation results
644
742
  */
645
- async evaluate(input, output, samplingRate = 1) {
743
+ async evaluate(input, output, samplingRate) {
744
+ const effectiveRate = samplingRate ?? this._sampleRate;
646
745
  const result = {
647
746
  success: false,
648
747
  sampled: false,
@@ -660,26 +759,20 @@ var Judge = class {
660
759
  result.errorMessage = "Judge configuration is missing required evaluation metric key";
661
760
  return result;
662
761
  }
663
- if (!this._aiConfig.messages) {
664
- this._logger?.warn("Judge configuration must include messages", tracker.getTrackData());
665
- result.sampled = true;
666
- result.errorMessage = "Judge configuration must include messages";
667
- return result;
668
- }
669
- if (Math.random() > samplingRate) {
670
- this._logger?.debug(`Judge evaluation skipped due to sampling rate: ${samplingRate}`);
762
+ if (Math.random() > effectiveRate) {
763
+ this._logger?.debug(`Judge evaluation skipped due to sampling rate: ${effectiveRate}`);
671
764
  return result;
672
765
  }
673
766
  result.sampled = true;
674
- const messages = this._constructEvaluationMessages(input, output);
767
+ const evaluationInput = this._buildEvaluationInput(input, output);
675
768
  const response = await tracker.trackMetricsOf(
676
769
  (r) => r.metrics,
677
- () => this._aiProvider.invokeStructuredModel(messages, EVALUATION_SCHEMA)
770
+ () => this._runner.run(evaluationInput, EVALUATION_SCHEMA)
678
771
  );
679
- const evalResult = this._parseEvaluationResponse(response.data);
772
+ const evalResult = this._parseEvaluationResponse(response.parsed);
680
773
  if (!evalResult) {
681
774
  this._logger?.warn(
682
- `Could not parse evaluation response: ${JSON.stringify(response.data)}`,
775
+ `Could not parse evaluation response: ${JSON.stringify(response.parsed)}`,
683
776
  tracker.getTrackData()
684
777
  );
685
778
  return result;
@@ -703,10 +796,11 @@ var Judge = class {
703
796
  *
704
797
  * @param messages Array of messages representing the conversation history
705
798
  * @param response The AI response to be evaluated
706
- * @param samplingRatio Sampling ratio (0-1) to determine if evaluation should be processed (defaults to 1)
799
+ * @param samplingRatio Sampling ratio (0-1). When omitted, the Judge's
800
+ * constructor-default rate is used.
707
801
  * @returns Promise that resolves to evaluation results
708
802
  */
709
- async evaluateMessages(messages, response, samplingRatio = 1) {
803
+ async evaluateMessages(messages, response, samplingRatio) {
710
804
  const input = messages.length === 0 ? "" : messages.map((msg) => msg.content).join("\r\n");
711
805
  const output = response.message.content;
712
806
  return this.evaluate(input, output, samplingRatio);
@@ -718,29 +812,23 @@ var Judge = class {
718
812
  return this._aiConfig;
719
813
  }
720
814
  /**
721
- * Returns the AI provider used by this judge.
815
+ * Returns the runner used by this judge.
722
816
  */
723
- getProvider() {
724
- return this._aiProvider;
725
- }
726
- /**
727
- * Constructs evaluation messages by combining judge's config messages with input/output.
728
- */
729
- _constructEvaluationMessages(input, output) {
730
- const messages = this._aiConfig.messages.map((msg) => ({
731
- ...msg,
732
- content: this._interpolateMessage(msg.content, {
733
- message_history: input,
734
- response_to_evaluate: output
735
- })
736
- }));
737
- return messages;
817
+ getRunner() {
818
+ return this._runner;
738
819
  }
739
820
  /**
740
- * Interpolates message content with variables using Mustache templating.
821
+ * Builds the evaluation input string passed to the runner.
822
+ *
823
+ * Combines the original prompt and the response into a single, well-known
824
+ * format the judge model is expected to evaluate.
741
825
  */
742
- _interpolateMessage(content, variables) {
743
- return import_mustache.default.render(content, variables, void 0, { escape: (item) => item });
826
+ _buildEvaluationInput(input, output) {
827
+ return `MESSAGE HISTORY:
828
+ ${input}
829
+
830
+ RESPONSE TO EVALUATE:
831
+ ${output}`;
744
832
  }
745
833
  /**
746
834
  * Parses the structured evaluation response. Expects top-level {score, reasoning}.
@@ -766,115 +854,101 @@ var Judge = class {
766
854
  // src/api/providers/AIProvider.ts
767
855
  var AIProvider = class {
768
856
  constructor(logger) {
769
- this.logger = logger;
857
+ this._logger = logger;
770
858
  }
771
859
  /**
772
- * Invoke the chat model with an array of messages.
773
- * This method should convert messages to provider format, invoke the model,
774
- * and return a ChatResponse with the result and metrics.
860
+ * Create a Runner for a completion or judge AI Config.
775
861
  *
776
- * Default implementation takes no action and returns a placeholder response.
777
- * Provider implementations should override this method.
862
+ * Override in provider subclasses to return a configured {@link Runner}.
863
+ * Default implementation returns `undefined`.
778
864
  *
779
- * @param messages Array of LDMessage objects representing the conversation
780
- * @returns Promise that resolves to a ChatResponse containing the model's response
865
+ * @param config The completion or judge AI configuration.
866
+ * @returns Promise resolving to a {@link Runner}, or `undefined` if this
867
+ * provider does not support model creation.
781
868
  */
782
- async invokeModel(_messages) {
783
- this.logger?.warn("invokeModel not implemented by this provider");
784
- return {
785
- message: {
786
- role: "assistant",
787
- content: ""
788
- },
789
- metrics: {
790
- success: false,
791
- usage: {
792
- total: 0,
793
- input: 0,
794
- output: 0
795
- }
796
- }
797
- };
869
+ async createModel(_config) {
870
+ return void 0;
798
871
  }
799
872
  /**
800
- * Invoke the chat model with structured output support.
801
- * This method should convert messages to provider format, invoke the model with
802
- * structured output configuration, and return a structured response.
873
+ * Create a Runner for an agent AI Config.
803
874
  *
804
- * Default implementation takes no action and returns a placeholder response.
805
- * Provider implementations should override this method.
875
+ * Override in provider subclasses to return a configured {@link Runner}.
876
+ * Default implementation returns `undefined`.
806
877
  *
807
- * @param messages Array of LDMessage objects representing the conversation
808
- * @param responseStructure Dictionary of output configurations keyed by output name
809
- * @returns Promise that resolves to a structured response
878
+ * @param config The agent AI configuration.
879
+ * @param tools Optional registry of callable tools.
880
+ * @returns Promise resolving to a {@link Runner}, or `undefined` if this
881
+ * provider does not support agent creation.
810
882
  */
811
- async invokeStructuredModel(_messages, _responseStructure) {
812
- this.logger?.warn("invokeStructuredModel not implemented by this provider");
813
- return {
814
- data: {},
815
- rawResponse: "",
816
- metrics: {
817
- success: false,
818
- usage: {
819
- total: 0,
820
- input: 0,
821
- output: 0
822
- }
823
- }
824
- };
883
+ async createAgent(_config, _tools) {
884
+ return void 0;
825
885
  }
826
886
  /**
827
- * Static method that constructs an instance of the provider.
828
- * Each provider implementation must provide their own static create method
829
- * that accepts an AIConfig and returns a configured instance.
887
+ * Create an AgentGraphRunner for an agent graph definition.
830
888
  *
831
- * @param aiConfig The LaunchDarkly AI configuration
832
- * @param logger Optional logger for the provider
833
- * @returns Promise that resolves to a configured provider instance
889
+ * Override in provider subclasses to return a configured {@link AgentGraphRunner}.
890
+ * Default implementation returns `undefined`.
891
+ *
892
+ * @param graphDef The agent graph definition.
893
+ * @param tools Optional registry of callable tools.
894
+ * @returns Promise resolving to an {@link AgentGraphRunner}, or `undefined` if
895
+ * this provider does not support graph execution.
834
896
  */
835
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
836
- static async create(aiConfig, logger) {
837
- throw new Error("Provider implementations must override the static create method");
897
+ async createAgentGraph(_graphDef, _tools) {
898
+ return void 0;
838
899
  }
839
900
  };
840
901
 
841
- // src/api/providers/AIProviderFactory.ts
902
+ // src/api/providers/RunnerFactory.ts
842
903
  var SUPPORTED_AI_PROVIDERS = [
843
904
  "openai",
844
905
  // Multi-provider packages should be last in the list
845
906
  "langchain",
846
907
  "vercel"
847
908
  ];
848
- var AIProviderFactory = class {
909
+ var RunnerFactory = class _RunnerFactory {
849
910
  /**
850
- * Create an AIProvider instance based on the AI configuration.
851
- * This method attempts to load provider-specific implementations dynamically.
852
- * Returns undefined if the provider is not supported.
911
+ * Load and return the AIProvider factory for the given provider type.
912
+ *
913
+ * This is the single place in the codebase that knows provider package names.
914
+ * Each supported provider package exports a `*RunnerFactory` class that
915
+ * extends {@link AIProvider}; this method instantiates it directly.
853
916
  *
854
- * @param aiConfig The AI configuration
855
- * @param logger Optional logger for logging provider initialization
856
- * @param defaultAiProvider Optional default AI provider to use
917
+ * @param providerType One of the {@link SUPPORTED_AI_PROVIDERS} values.
918
+ * @param logger Optional logger forwarded to the provider factory.
919
+ * @returns A configured {@link AIProvider} instance, or `undefined` if the
920
+ * package cannot be loaded.
857
921
  */
858
- static async create(aiConfig, logger, defaultAiProvider) {
859
- const providerName = aiConfig.provider?.name?.toLowerCase();
860
- const providersToTry = this._getProvidersToTry(defaultAiProvider, providerName);
861
- for (const providerType of providersToTry) {
862
- logger?.debug(
863
- `Attempting to create AIProvider for: ${aiConfig.provider?.name} with provider type: ${providerType}`
864
- );
865
- const provider = await this._tryCreateProvider(providerType, aiConfig, logger);
866
- if (provider) {
867
- logger?.debug(`Successfully created AIProvider for: ${aiConfig.provider?.name}`);
868
- return provider;
922
+ static async _getProviderFactory(providerType, logger) {
923
+ try {
924
+ let module2;
925
+ switch (providerType) {
926
+ case "openai": {
927
+ module2 = await import("@launchdarkly/server-sdk-ai-openai");
928
+ return new module2.OpenAIRunnerFactory(logger);
929
+ }
930
+ case "langchain": {
931
+ module2 = await import("@launchdarkly/server-sdk-ai-langchain");
932
+ return new module2.LangChainRunnerFactory(logger);
933
+ }
934
+ case "vercel": {
935
+ module2 = await import("@launchdarkly/server-sdk-ai-vercel");
936
+ return new module2.VercelRunnerFactory(logger);
937
+ }
938
+ default:
939
+ return void 0;
869
940
  }
941
+ } catch (error) {
942
+ logger?.warn(
943
+ `Unable to load provider package. Check that you have installed the correct package. ${error.message}`
944
+ );
945
+ return void 0;
870
946
  }
871
- logger?.warn(
872
- `Provider is not supported or failed to initialize: ${aiConfig.provider?.name ?? "unknown"}`
873
- );
874
- return void 0;
875
947
  }
876
948
  /**
877
949
  * Determine which providers to try based on defaultAiProvider and providerName.
950
+ *
951
+ * Mirrors Python's `_get_providers_to_try` helper.
878
952
  */
879
953
  static _getProvidersToTry(defaultAiProvider, providerName) {
880
954
  if (defaultAiProvider) {
@@ -891,36 +965,111 @@ var AIProviderFactory = class {
891
965
  return Array.from(providerSet);
892
966
  }
893
967
  /**
894
- * Try to create a provider of the specified type.
968
+ * Try each provider in order and return the first non-undefined result.
969
+ *
970
+ * Mirrors Python's `_with_fallback` helper. Loads each provider factory via
971
+ * {@link _getProviderFactory} and calls `fn` with it. Returns the first
972
+ * truthy result, or `undefined` if no provider succeeds.
973
+ *
974
+ * @param providers Ordered list of provider types to try.
975
+ * @param fn Callback that calls the appropriate factory method on the provider.
976
+ * @param logger Optional logger forwarded to each provider factory.
895
977
  */
896
- static async _tryCreateProvider(providerType, aiConfig, logger) {
897
- try {
898
- let module2;
899
- switch (providerType) {
900
- case "openai": {
901
- module2 = await import("@launchdarkly/server-sdk-ai-openai");
902
- const provider = await module2.OpenAIProvider.create(aiConfig, logger);
903
- return provider;
904
- }
905
- case "langchain": {
906
- module2 = await import("@launchdarkly/server-sdk-ai-langchain");
907
- const provider = await module2.LangChainProvider.create(aiConfig, logger);
908
- return provider;
909
- }
910
- case "vercel": {
911
- module2 = await import("@launchdarkly/server-sdk-ai-vercel");
912
- const provider = await module2.VercelProvider.create(aiConfig, logger);
913
- return provider;
978
+ static async _withFallback(providers, fn, logger) {
979
+ for (const providerType of providers) {
980
+ logger?.debug(`Attempting to create runner with provider: ${providerType}`);
981
+ const factory = await _RunnerFactory._getProviderFactory(providerType, logger);
982
+ if (factory) {
983
+ const result = await fn(factory);
984
+ if (result) {
985
+ logger?.debug(`Successfully created runner with provider: ${providerType}`);
986
+ return result;
914
987
  }
915
- default:
916
- return void 0;
917
988
  }
918
- } catch (error) {
989
+ }
990
+ return void 0;
991
+ }
992
+ /**
993
+ * Create a Runner for the given AI configuration.
994
+ *
995
+ * Suitable for completion, judge, and agent config modes. Dynamically
996
+ * loads the matching provider package via {@link _getProviderFactory} and
997
+ * delegates to its {@link AIProvider.createModel} method.
998
+ *
999
+ * @param config The AI configuration (completion, agent, or judge).
1000
+ * @param logger Optional logger forwarded to the underlying provider.
1001
+ * @param defaultAiProvider Optional provider override
1002
+ * ('openai', 'langchain', 'vercel', …). When set, only that provider is
1003
+ * tried. When omitted, providers are tried in priority order based on the
1004
+ * provider name in the config.
1005
+ * @returns A configured {@link Runner} ready to invoke the model, or
1006
+ * `undefined` if no suitable provider could be loaded.
1007
+ */
1008
+ static async createModel(config, logger, defaultAiProvider) {
1009
+ const providerName = config.provider?.name?.toLowerCase();
1010
+ const providers = _RunnerFactory._getProvidersToTry(defaultAiProvider, providerName);
1011
+ const runner = await _RunnerFactory._withFallback(
1012
+ providers,
1013
+ (factory) => factory.createModel(config),
1014
+ logger
1015
+ );
1016
+ if (!runner) {
919
1017
  logger?.warn(
920
- `Unable to create AIProvider. Check that you have installed the correct package. ${error.message}`
1018
+ `Provider is not supported or failed to initialize: ${config.provider?.name ?? "unknown"}`
921
1019
  );
922
- return void 0;
923
1020
  }
1021
+ return runner;
1022
+ }
1023
+ /**
1024
+ * Create a Runner for an agent AI Config.
1025
+ *
1026
+ * Delegates to the provider factory's {@link AIProvider.createAgent} method.
1027
+ *
1028
+ * @param config The agent AI configuration.
1029
+ * @param tools Optional registry of callable tools.
1030
+ * @param logger Optional logger forwarded to the underlying provider.
1031
+ * @param defaultAiProvider Optional provider override.
1032
+ * @returns A configured {@link Runner}, or `undefined` if no suitable
1033
+ * provider could be loaded.
1034
+ */
1035
+ static async createAgent(config, tools, logger, defaultAiProvider) {
1036
+ const providerName = config.provider?.name?.toLowerCase();
1037
+ const providers = _RunnerFactory._getProvidersToTry(defaultAiProvider, providerName);
1038
+ const runner = await _RunnerFactory._withFallback(
1039
+ providers,
1040
+ (factory) => factory.createAgent(config, tools),
1041
+ logger
1042
+ );
1043
+ if (!runner) {
1044
+ logger?.warn(
1045
+ `Provider is not supported or failed to initialize: ${config.provider?.name ?? "unknown"}`
1046
+ );
1047
+ }
1048
+ return runner;
1049
+ }
1050
+ /**
1051
+ * Create an AgentGraphRunner for the given agent graph definition.
1052
+ *
1053
+ * Delegates to the provider factory's {@link AIProvider.createAgentGraph} method.
1054
+ *
1055
+ * @param graphDef The agent graph definition.
1056
+ * @param tools Optional registry of callable tools.
1057
+ * @param logger Optional logger forwarded to the underlying provider.
1058
+ * @param defaultAiProvider Optional provider override.
1059
+ * @returns A configured {@link AgentGraphRunner}, or `undefined` if no
1060
+ * suitable provider could be loaded.
1061
+ */
1062
+ static async createAgentGraph(graphDef, tools, logger, defaultAiProvider) {
1063
+ const providers = _RunnerFactory._getProvidersToTry(defaultAiProvider);
1064
+ const runner = await _RunnerFactory._withFallback(
1065
+ providers,
1066
+ (factory) => factory.createAgentGraph(graphDef, tools),
1067
+ logger
1068
+ );
1069
+ if (!runner) {
1070
+ logger?.warn(`No provider could create an AgentGraphRunner for the given graph definition.`);
1071
+ }
1072
+ return runner;
924
1073
  }
925
1074
  };
926
1075
 
@@ -971,6 +1120,7 @@ var LDAIConfigTrackerImpl = class _LDAIConfigTrackerImpl {
971
1120
  this._context = _context;
972
1121
  this._graphKey = _graphKey;
973
1122
  this._trackedMetrics = {};
1123
+ this._trackedMetrics.resumptionToken = this.resumptionToken;
974
1124
  }
975
1125
  getTrackData() {
976
1126
  return {
@@ -1054,6 +1204,10 @@ var LDAIConfigTrackerImpl = class _LDAIConfigTrackerImpl {
1054
1204
  }
1055
1205
  }
1056
1206
  trackToolCall(toolKey) {
1207
+ if (!this._trackedMetrics.toolCalls) {
1208
+ this._trackedMetrics.toolCalls = [];
1209
+ }
1210
+ this._trackedMetrics.toolCalls.push(toolKey);
1057
1211
  this._ldClient.track("$ld:ai:tool_call", this._context, { ...this.getTrackData(), toolKey }, 1);
1058
1212
  }
1059
1213
  trackToolCalls(toolKeys) {
@@ -1109,8 +1263,11 @@ var LDAIConfigTrackerImpl = class _LDAIConfigTrackerImpl {
1109
1263
  } else {
1110
1264
  this.trackError();
1111
1265
  }
1112
- if (metrics.usage) {
1113
- this.trackTokens(metrics.usage);
1266
+ if (metrics.tokens) {
1267
+ this.trackTokens(metrics.tokens);
1268
+ }
1269
+ if (metrics.toolCalls?.length) {
1270
+ this.trackToolCalls(metrics.toolCalls);
1114
1271
  }
1115
1272
  return result;
1116
1273
  }
@@ -1134,8 +1291,11 @@ var LDAIConfigTrackerImpl = class _LDAIConfigTrackerImpl {
1134
1291
  } else {
1135
1292
  this.trackError();
1136
1293
  }
1137
- if (metrics.usage) {
1138
- this.trackTokens(metrics.usage);
1294
+ if (metrics.tokens) {
1295
+ this.trackTokens(metrics.tokens);
1296
+ }
1297
+ if (metrics.toolCalls?.length) {
1298
+ this.trackToolCalls(metrics.toolCalls);
1139
1299
  }
1140
1300
  } catch (error) {
1141
1301
  this.trackError();
@@ -1220,6 +1380,7 @@ var LDGraphTrackerImpl = class _LDGraphTrackerImpl {
1220
1380
  this._version = _version;
1221
1381
  this._context = _context;
1222
1382
  this._summary = {};
1383
+ this._summary.resumptionToken = this.resumptionToken;
1223
1384
  }
1224
1385
  /**
1225
1386
  * Reconstructs an {@link LDGraphTrackerImpl} from a resumption token, preserving
@@ -1245,15 +1406,12 @@ var LDGraphTrackerImpl = class _LDGraphTrackerImpl {
1245
1406
  );
1246
1407
  }
1247
1408
  getTrackData() {
1248
- const data = {
1409
+ return {
1249
1410
  runId: this._runId,
1250
1411
  graphKey: this._graphKey,
1251
- version: this._version
1412
+ version: this._version,
1413
+ ...this._variationKey !== void 0 ? { variationKey: this._variationKey } : {}
1252
1414
  };
1253
- if (this._variationKey !== void 0) {
1254
- data.variationKey = this._variationKey;
1255
- }
1256
- return data;
1257
1415
  }
1258
1416
  getSummary() {
1259
1417
  return { ...this._summary };
@@ -1358,13 +1516,14 @@ var LDGraphTrackerImpl = class _LDGraphTrackerImpl {
1358
1516
 
1359
1517
  // src/sdkInfo.ts
1360
1518
  var aiSdkName = "@launchdarkly/server-sdk-ai";
1361
- var aiSdkVersion = "0.19.0";
1519
+ var aiSdkVersion = "0.20.0";
1362
1520
  var aiSdkLanguage = "javascript";
1363
1521
 
1364
1522
  // src/LDAIClientImpl.ts
1365
1523
  var TRACK_SDK_INFO = "$ld:ai:sdk:info";
1366
1524
  var TRACK_USAGE_COMPLETION_CONFIG = "$ld:ai:usage:completion-config";
1367
1525
  var TRACK_USAGE_CREATE_CHAT = "$ld:ai:usage:create-chat";
1526
+ var TRACK_USAGE_CREATE_AGENT = "$ld:ai:usage:create-agent";
1368
1527
  var TRACK_USAGE_JUDGE_CONFIG = "$ld:ai:usage:judge-config";
1369
1528
  var TRACK_USAGE_CREATE_JUDGE = "$ld:ai:usage:create-judge";
1370
1529
  var TRACK_USAGE_AGENT_CONFIG = "$ld:ai:usage:agent-config";
@@ -1392,18 +1551,11 @@ var LDAIClientImpl = class {
1392
1551
  );
1393
1552
  }
1394
1553
  _interpolateTemplate(template, variables) {
1395
- return import_mustache2.default.render(template, variables, void 0, { escape: (item) => item });
1554
+ return import_mustache.default.render(template, variables, void 0, { escape: (item) => item });
1396
1555
  }
1397
- async _evaluate(key, context, defaultValue, mode, variables, graphKey) {
1556
+ async _evaluate(key, context, defaultValue, mode, variables, graphKey, defaultAiProvider) {
1398
1557
  const ldFlagValue = LDAIConfigUtils.toFlagValue(defaultValue, mode);
1399
1558
  const value = await this._ldClient.variation(key, context, ldFlagValue);
1400
- const flagMode = value._ldMeta?.mode ?? "completion";
1401
- if (flagMode !== mode) {
1402
- this._logger?.warn(
1403
- `AI Config mode mismatch for ${key}: expected ${mode}, got ${flagMode}. Returning disabled config.`
1404
- );
1405
- return LDAIConfigUtils.createDisabledConfig(key, mode);
1406
- }
1407
1559
  const trackerFactory = () => new LDAIConfigTrackerImpl(
1408
1560
  this._ldClient,
1409
1561
  (0, import_node_crypto.randomUUID)(),
@@ -1417,7 +1569,23 @@ var LDAIClientImpl = class {
1417
1569
  context,
1418
1570
  graphKey
1419
1571
  );
1420
- const config = LDAIConfigUtils.fromFlagValue(key, value, trackerFactory);
1572
+ const flagMode = value._ldMeta?.mode ?? "completion";
1573
+ let evaluator = Evaluator.noop();
1574
+ if (flagMode !== mode) {
1575
+ this._logger?.warn(
1576
+ `AI Config mode mismatch for ${key}: expected ${mode}, got ${flagMode}. Returning disabled config.`
1577
+ );
1578
+ return LDAIConfigUtils.createDisabledConfig(key, mode, trackerFactory, evaluator);
1579
+ }
1580
+ if (flagMode !== "judge") {
1581
+ evaluator = await this._buildEvaluator(
1582
+ value.judgeConfiguration?.judges ?? [],
1583
+ context,
1584
+ variables,
1585
+ defaultAiProvider
1586
+ );
1587
+ }
1588
+ const config = LDAIConfigUtils.fromFlagValue(key, value, trackerFactory, evaluator);
1421
1589
  return this._applyInterpolation(config, context, variables);
1422
1590
  }
1423
1591
  _applyInterpolation(config, context, variables) {
@@ -1439,33 +1607,44 @@ var LDAIClientImpl = class {
1439
1607
  }
1440
1608
  return config;
1441
1609
  }
1442
- async _initializeJudges(judgeConfigs, context, variables, defaultAiProvider) {
1443
- const judges = {};
1444
- const judgePromises = judgeConfigs.map(async (judgeConfig) => {
1445
- const judge = await this.createJudge(
1446
- judgeConfig.key,
1447
- context,
1448
- void 0,
1449
- variables,
1450
- defaultAiProvider
1451
- );
1452
- return judge ? { key: judgeConfig.key, judge } : null;
1453
- });
1454
- const results = await Promise.all(judgePromises);
1455
- results.forEach((result) => {
1456
- if (result) {
1457
- judges[result.key] = result.judge;
1458
- }
1459
- });
1460
- return judges;
1461
- }
1462
- async _completionConfig(key, context, defaultValue, variables) {
1463
- const config = await this._evaluate(key, context, defaultValue, "completion", variables);
1464
- return config;
1610
+ async _buildEvaluator(judgeConfigs, context, variables, defaultAiProvider) {
1611
+ if (judgeConfigs.length === 0) {
1612
+ return Evaluator.noop();
1613
+ }
1614
+ const judgeInstances = (await Promise.all(
1615
+ judgeConfigs.map(
1616
+ (jc) => this._createJudgeInstance(
1617
+ jc.key,
1618
+ context,
1619
+ void 0,
1620
+ variables,
1621
+ defaultAiProvider,
1622
+ jc.samplingRate
1623
+ )
1624
+ )
1625
+ )).filter((j) => j !== void 0);
1626
+ return new Evaluator(judgeInstances);
1627
+ }
1628
+ async _completionConfig(key, context, defaultValue, variables, defaultAiProvider) {
1629
+ return await this._evaluate(
1630
+ key,
1631
+ context,
1632
+ defaultValue,
1633
+ "completion",
1634
+ variables,
1635
+ void 0,
1636
+ defaultAiProvider
1637
+ );
1465
1638
  }
1466
- async completionConfig(key, context, defaultValue, variables) {
1639
+ async completionConfig(key, context, defaultValue, variables, defaultAiProvider) {
1467
1640
  this._ldClient.track(TRACK_USAGE_COMPLETION_CONFIG, context, key, 1);
1468
- return this._completionConfig(key, context, defaultValue ?? disabledAIConfig, variables);
1641
+ return this._completionConfig(
1642
+ key,
1643
+ context,
1644
+ defaultValue ?? disabledAIConfig,
1645
+ variables,
1646
+ defaultAiProvider
1647
+ );
1469
1648
  }
1470
1649
  /**
1471
1650
  * @deprecated Use `completionConfig` instead. This method will be removed in a future version.
@@ -1474,20 +1653,58 @@ var LDAIClientImpl = class {
1474
1653
  return this.completionConfig(key, context, defaultValue, variables);
1475
1654
  }
1476
1655
  async _judgeConfig(key, context, defaultValue, variables) {
1477
- const config = await this._evaluate(key, context, defaultValue, "judge", variables);
1656
+ if (variables?.message_history !== void 0) {
1657
+ this._logger?.warn(
1658
+ "The variable 'message_history' is reserved by the judge and will be ignored."
1659
+ );
1660
+ }
1661
+ if (variables?.response_to_evaluate !== void 0) {
1662
+ this._logger?.warn(
1663
+ "The variable 'response_to_evaluate' is reserved by the judge and will be ignored."
1664
+ );
1665
+ }
1666
+ const extendedVariables = {
1667
+ ...variables,
1668
+ message_history: "{{message_history}}",
1669
+ response_to_evaluate: "{{response_to_evaluate}}"
1670
+ };
1671
+ const config = await this._evaluate(
1672
+ key,
1673
+ context,
1674
+ defaultValue,
1675
+ "judge",
1676
+ extendedVariables
1677
+ );
1678
+ if (config.messages) {
1679
+ return { ...config, messages: stripLegacyJudgeMessages(config.messages) };
1680
+ }
1478
1681
  return config;
1479
1682
  }
1480
1683
  async judgeConfig(key, context, defaultValue, variables) {
1481
1684
  this._ldClient.track(TRACK_USAGE_JUDGE_CONFIG, context, key, 1);
1482
1685
  return this._judgeConfig(key, context, defaultValue ?? disabledAIConfig, variables);
1483
1686
  }
1484
- async _agentConfig(key, context, defaultValue, variables, graphKey) {
1485
- const config = await this._evaluate(key, context, defaultValue, "agent", variables, graphKey);
1486
- return config;
1687
+ async _agentConfig(key, context, defaultValue, variables, graphKey, defaultAiProvider) {
1688
+ return await this._evaluate(
1689
+ key,
1690
+ context,
1691
+ defaultValue,
1692
+ "agent",
1693
+ variables,
1694
+ graphKey,
1695
+ defaultAiProvider
1696
+ );
1487
1697
  }
1488
- async agentConfig(key, context, defaultValue, variables) {
1698
+ async agentConfig(key, context, defaultValue, variables, defaultAiProvider) {
1489
1699
  this._ldClient.track(TRACK_USAGE_AGENT_CONFIG, context, key, 1);
1490
- return this._agentConfig(key, context, defaultValue ?? disabledAIConfig, variables);
1700
+ return this._agentConfig(
1701
+ key,
1702
+ context,
1703
+ defaultValue ?? disabledAIConfig,
1704
+ variables,
1705
+ void 0,
1706
+ defaultAiProvider
1707
+ );
1491
1708
  }
1492
1709
  /**
1493
1710
  * @deprecated Use `agentConfig` instead. This method will be removed in a future version.
@@ -1522,73 +1739,89 @@ var LDAIClientImpl = class {
1522
1739
  async agents(agentConfigs, context) {
1523
1740
  return this.agentConfigs(agentConfigs, context);
1524
1741
  }
1525
- async createChat(key, context, defaultValue, variables, defaultAiProvider) {
1526
- this._ldClient.track(TRACK_USAGE_CREATE_CHAT, context, key, 1);
1527
- const config = await this._completionConfig(
1742
+ async createJudge(key, context, defaultValue, variables, defaultAiProvider, sampleRate = 1) {
1743
+ this._ldClient.track(TRACK_USAGE_CREATE_JUDGE, context, key, 1);
1744
+ return this._createJudgeInstance(
1528
1745
  key,
1529
1746
  context,
1530
- defaultValue ?? disabledAIConfig,
1531
- variables
1532
- );
1533
- if (!config.enabled) {
1534
- this._logger?.info(`Chat configuration is disabled: ${key}`);
1535
- return void 0;
1536
- }
1537
- const provider = await AIProviderFactory.create(config, this._logger, defaultAiProvider);
1538
- if (!provider) {
1539
- return void 0;
1540
- }
1541
- const judges = await this._initializeJudges(
1542
- config.judgeConfiguration?.judges ?? [],
1543
- context,
1747
+ defaultValue,
1544
1748
  variables,
1545
- defaultAiProvider
1749
+ defaultAiProvider,
1750
+ sampleRate
1546
1751
  );
1547
- return new TrackedChat(config, provider, judges, this._logger);
1548
1752
  }
1549
- async createJudge(key, context, defaultValue, variables, defaultAiProvider) {
1550
- this._ldClient.track(TRACK_USAGE_CREATE_JUDGE, context, key, 1);
1753
+ async _createJudgeInstance(key, context, defaultValue, variables, defaultAiProvider, sampleRate = 1) {
1551
1754
  try {
1552
- if (variables?.message_history !== void 0) {
1553
- this._logger?.warn(
1554
- "The variable 'message_history' is reserved by the judge and will be ignored."
1555
- );
1556
- }
1557
- if (variables?.response_to_evaluate !== void 0) {
1558
- this._logger?.warn(
1559
- "The variable 'response_to_evaluate' is reserved by the judge and will be ignored."
1560
- );
1561
- }
1562
- const extendedVariables = {
1563
- ...variables,
1564
- message_history: "{{message_history}}",
1565
- response_to_evaluate: "{{response_to_evaluate}}"
1566
- };
1567
1755
  const judgeConfig = await this._judgeConfig(
1568
1756
  key,
1569
1757
  context,
1570
1758
  defaultValue ?? disabledAIConfig,
1571
- extendedVariables
1759
+ variables
1572
1760
  );
1573
1761
  if (!judgeConfig.enabled) {
1574
1762
  this._logger?.info(`Judge configuration is disabled: ${key}`);
1575
1763
  return void 0;
1576
1764
  }
1577
- const provider = await AIProviderFactory.create(judgeConfig, this._logger, defaultAiProvider);
1578
- if (!provider) {
1765
+ const runner = await RunnerFactory.createModel(judgeConfig, this._logger, defaultAiProvider);
1766
+ if (!runner) {
1579
1767
  return void 0;
1580
1768
  }
1581
- return new Judge(judgeConfig, provider, this._logger);
1769
+ return new Judge(judgeConfig, runner, sampleRate, this._logger);
1582
1770
  } catch (error) {
1583
1771
  this._logger?.error(`Failed to initialize judge ${key}:`, error);
1584
1772
  return void 0;
1585
1773
  }
1586
1774
  }
1775
+ async createModel(key, context, defaultValue, variables, defaultAiProvider) {
1776
+ this._ldClient.track(TRACK_USAGE_CREATE_CHAT, context, key, 1);
1777
+ const config = await this._completionConfig(
1778
+ key,
1779
+ context,
1780
+ defaultValue ?? disabledAIConfig,
1781
+ variables,
1782
+ defaultAiProvider
1783
+ );
1784
+ if (!config.enabled) {
1785
+ this._logger?.info(`Completion configuration is disabled: ${key}`);
1786
+ return void 0;
1787
+ }
1788
+ const runner = await RunnerFactory.createModel(config, this._logger, defaultAiProvider);
1789
+ if (!runner) {
1790
+ return void 0;
1791
+ }
1792
+ return new ManagedModel(config, runner, this._logger);
1793
+ }
1794
+ async createAgent(key, context, defaultValue, variables, defaultAiProvider) {
1795
+ this._ldClient.track(TRACK_USAGE_CREATE_AGENT, context, key, 1);
1796
+ const config = await this._agentConfig(
1797
+ key,
1798
+ context,
1799
+ defaultValue ?? disabledAIConfig,
1800
+ variables,
1801
+ void 0,
1802
+ defaultAiProvider
1803
+ );
1804
+ if (!config.enabled) {
1805
+ this._logger?.info(`Agent configuration is disabled: ${key}`);
1806
+ return void 0;
1807
+ }
1808
+ const runner = await RunnerFactory.createAgent(config, void 0, this._logger, defaultAiProvider);
1809
+ if (!runner) {
1810
+ return void 0;
1811
+ }
1812
+ return new ManagedAgent(config, runner, this._logger);
1813
+ }
1814
+ /**
1815
+ * @deprecated Use `createModel` instead. This method will be removed in a future version.
1816
+ */
1817
+ async createChat(key, context, defaultValue, variables, defaultAiProvider) {
1818
+ return this.createModel(key, context, defaultValue, variables, defaultAiProvider);
1819
+ }
1587
1820
  /**
1588
- * @deprecated Use `createChat` instead. This method will be removed in a future version.
1821
+ * @deprecated Use `createModel` instead. This method will be removed in a future version.
1589
1822
  */
1590
1823
  async initChat(key, context, defaultValue, variables, defaultAiProvider) {
1591
- return this.createChat(key, context, defaultValue, variables, defaultAiProvider);
1824
+ return this.createModel(key, context, defaultValue, variables, defaultAiProvider);
1592
1825
  }
1593
1826
  createTracker(token, context) {
1594
1827
  return LDAIConfigTrackerImpl.fromResumptionToken(token, this._ldClient, context);
@@ -1674,14 +1907,16 @@ function initAi(ldClient) {
1674
1907
  // Annotate the CommonJS export names for ESM import in node:
1675
1908
  0 && (module.exports = {
1676
1909
  AIProvider,
1677
- AIProviderFactory,
1678
1910
  AgentGraphDefinition,
1679
1911
  AgentGraphNode,
1680
1912
  Judge,
1681
1913
  LDFeedbackKind,
1682
1914
  LDGraphTrackerImpl,
1915
+ ManagedAgent,
1916
+ ManagedAgentGraph,
1917
+ ManagedModel,
1918
+ RunnerFactory,
1683
1919
  SUPPORTED_AI_PROVIDERS,
1684
- TrackedChat,
1685
1920
  createBedrockTokenUsage,
1686
1921
  createOpenAiUsage,
1687
1922
  createVercelAISDKTokenUsage,