braintrust 3.4.0 → 3.6.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.
Files changed (58) hide show
  1. package/dev/dist/index.d.mts +49 -7
  2. package/dev/dist/index.d.ts +49 -7
  3. package/dev/dist/index.js +2383 -494
  4. package/dev/dist/index.mjs +2213 -324
  5. package/dist/auto-instrumentations/bundler/esbuild.cjs +289 -10
  6. package/dist/auto-instrumentations/bundler/esbuild.d.mts +2 -2
  7. package/dist/auto-instrumentations/bundler/esbuild.d.ts +2 -2
  8. package/dist/auto-instrumentations/bundler/esbuild.mjs +2 -2
  9. package/dist/auto-instrumentations/bundler/rollup.cjs +289 -10
  10. package/dist/auto-instrumentations/bundler/rollup.mjs +2 -2
  11. package/dist/auto-instrumentations/bundler/vite.cjs +289 -10
  12. package/dist/auto-instrumentations/bundler/vite.d.mts +2 -2
  13. package/dist/auto-instrumentations/bundler/vite.d.ts +2 -2
  14. package/dist/auto-instrumentations/bundler/vite.mjs +2 -2
  15. package/dist/auto-instrumentations/bundler/webpack.cjs +289 -10
  16. package/dist/auto-instrumentations/bundler/webpack.d.mts +2 -2
  17. package/dist/auto-instrumentations/bundler/webpack.d.ts +2 -2
  18. package/dist/auto-instrumentations/bundler/webpack.mjs +2 -2
  19. package/dist/auto-instrumentations/chunk-EVUKFMHG.mjs +41 -0
  20. package/dist/auto-instrumentations/{chunk-LVWWLUMN.mjs → chunk-F7WAXFNM.mjs} +290 -11
  21. package/dist/auto-instrumentations/chunk-VLEJ5AEK.mjs +41 -0
  22. package/dist/auto-instrumentations/{chunk-D5ZPIUEL.mjs → chunk-WOUC73KB.mjs} +3 -1
  23. package/dist/auto-instrumentations/hook.mjs +358 -48
  24. package/dist/auto-instrumentations/index.cjs +290 -10
  25. package/dist/auto-instrumentations/index.d.mts +3 -1
  26. package/dist/auto-instrumentations/index.d.ts +3 -1
  27. package/dist/auto-instrumentations/index.mjs +3 -1
  28. package/dist/auto-instrumentations/loader/cjs-patch.cjs +32 -10
  29. package/dist/auto-instrumentations/loader/cjs-patch.mjs +10 -5
  30. package/dist/auto-instrumentations/loader/esm-hook.mjs +4 -4
  31. package/dist/auto-instrumentations/loader/get-package-version.cjs +28 -8
  32. package/dist/auto-instrumentations/loader/get-package-version.d.mts +2 -1
  33. package/dist/auto-instrumentations/loader/get-package-version.d.ts +2 -1
  34. package/dist/auto-instrumentations/loader/get-package-version.mjs +3 -1
  35. package/dist/browser.d.mts +357 -271
  36. package/dist/browser.d.ts +357 -271
  37. package/dist/browser.js +2345 -343
  38. package/dist/browser.mjs +2345 -343
  39. package/dist/cli.js +2296 -414
  40. package/dist/edge-light.d.mts +1 -1
  41. package/dist/edge-light.d.ts +1 -1
  42. package/dist/edge-light.js +2292 -315
  43. package/dist/edge-light.mjs +2292 -315
  44. package/dist/index.d.mts +370 -284
  45. package/dist/index.d.ts +370 -284
  46. package/dist/index.js +2642 -638
  47. package/dist/index.mjs +2385 -381
  48. package/dist/instrumentation/index.d.mts +3 -0
  49. package/dist/instrumentation/index.d.ts +3 -0
  50. package/dist/instrumentation/index.js +1955 -198
  51. package/dist/instrumentation/index.mjs +1955 -198
  52. package/dist/workerd.d.mts +1 -1
  53. package/dist/workerd.d.ts +1 -1
  54. package/dist/workerd.js +2292 -315
  55. package/dist/workerd.mjs +2292 -315
  56. package/package.json +22 -6
  57. package/dist/auto-instrumentations/chunk-XDBPUTVE.mjs +0 -22
  58. package/dist/auto-instrumentations/chunk-ZEC7BCL4.mjs +0 -22
package/dist/browser.js CHANGED
@@ -161,6 +161,7 @@ __export(browser_exports, {
161
161
  wrapMastraAgent: () => wrapMastraAgent,
162
162
  wrapOpenAI: () => wrapOpenAI,
163
163
  wrapOpenAIv4: () => wrapOpenAIv4,
164
+ wrapOpenRouter: () => wrapOpenRouter,
164
165
  wrapTraced: () => wrapTraced,
165
166
  wrapVitest: () => wrapVitest
166
167
  });
@@ -182,8 +183,54 @@ var DefaultAsyncLocalStorage = class {
182
183
  return void 0;
183
184
  }
184
185
  };
185
- var DefaultTracingChannel = class {
186
+ var DefaultChannel = class {
187
+ constructor(name) {
188
+ this.name = name;
189
+ }
186
190
  hasSubscribers = false;
191
+ subscribe(_subscription) {
192
+ }
193
+ unsubscribe(_subscription) {
194
+ return false;
195
+ }
196
+ bindStore(_store, _transform) {
197
+ }
198
+ unbindStore(_store) {
199
+ return false;
200
+ }
201
+ publish(_message) {
202
+ }
203
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
204
+ runStores(_message, fn, thisArg, ...args) {
205
+ return fn.apply(thisArg, args);
206
+ }
207
+ };
208
+ var DefaultTracingChannel = class {
209
+ start;
210
+ end;
211
+ asyncStart;
212
+ asyncEnd;
213
+ error;
214
+ constructor(nameOrChannels) {
215
+ if (typeof nameOrChannels === "string") {
216
+ this.start = new DefaultChannel(`tracing:${nameOrChannels}:start`);
217
+ this.end = new DefaultChannel(`tracing:${nameOrChannels}:end`);
218
+ this.asyncStart = new DefaultChannel(
219
+ `tracing:${nameOrChannels}:asyncStart`
220
+ );
221
+ this.asyncEnd = new DefaultChannel(`tracing:${nameOrChannels}:asyncEnd`);
222
+ this.error = new DefaultChannel(`tracing:${nameOrChannels}:error`);
223
+ return;
224
+ }
225
+ this.start = nameOrChannels.start ?? new DefaultChannel("tracing:start");
226
+ this.end = nameOrChannels.end ?? new DefaultChannel("tracing:end");
227
+ this.asyncStart = nameOrChannels.asyncStart ?? new DefaultChannel("tracing:asyncStart");
228
+ this.asyncEnd = nameOrChannels.asyncEnd ?? new DefaultChannel("tracing:asyncEnd");
229
+ this.error = nameOrChannels.error ?? new DefaultChannel("tracing:error");
230
+ }
231
+ get hasSubscribers() {
232
+ return this.start.hasSubscribers || this.end.hasSubscribers || this.asyncStart.hasSubscribers || this.asyncEnd.hasSubscribers || this.error.hasSubscribers;
233
+ }
187
234
  subscribe(_handlers) {
188
235
  }
189
236
  unsubscribe(_handlers) {
@@ -211,7 +258,7 @@ var iso = {
211
258
  getCallerLocation: () => void 0,
212
259
  newAsyncLocalStorage: () => new DefaultAsyncLocalStorage(),
213
260
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
214
- newTracingChannel: (_nameOrChannels) => new DefaultTracingChannel(),
261
+ newTracingChannel: (nameOrChannels) => new DefaultTracingChannel(nameOrChannels),
215
262
  processOn: (_0, _1) => {
216
263
  },
217
264
  basename: (filepath) => filepath.split(/[\\/]/).pop() || filepath,
@@ -2278,6 +2325,8 @@ var Experiment = import_v36.z.object({
2278
2325
  deleted_at: import_v36.z.union([import_v36.z.string(), import_v36.z.null()]).optional(),
2279
2326
  dataset_id: import_v36.z.union([import_v36.z.string(), import_v36.z.null()]).optional(),
2280
2327
  dataset_version: import_v36.z.union([import_v36.z.string(), import_v36.z.null()]).optional(),
2328
+ parameters_id: import_v36.z.union([import_v36.z.string(), import_v36.z.null()]).optional(),
2329
+ parameters_version: import_v36.z.union([import_v36.z.string(), import_v36.z.null()]).optional(),
2281
2330
  public: import_v36.z.boolean(),
2282
2331
  user_id: import_v36.z.union([import_v36.z.string(), import_v36.z.null()]).optional(),
2283
2332
  metadata: import_v36.z.union([import_v36.z.object({}).partial().passthrough(), import_v36.z.null()]).optional(),
@@ -2300,7 +2349,11 @@ var SpanType = import_v36.z.union([
2300
2349
  import_v36.z.null()
2301
2350
  ]);
2302
2351
  var SpanAttributes = import_v36.z.union([
2303
- import_v36.z.object({ name: import_v36.z.union([import_v36.z.string(), import_v36.z.null()]), type: SpanType }).partial().passthrough(),
2352
+ import_v36.z.object({
2353
+ name: import_v36.z.union([import_v36.z.string(), import_v36.z.null()]),
2354
+ type: SpanType,
2355
+ purpose: import_v36.z.union([import_v36.z.literal("scorer"), import_v36.z.null()])
2356
+ }).partial().passthrough(),
2304
2357
  import_v36.z.null()
2305
2358
  ]);
2306
2359
  var ExperimentEvent = import_v36.z.object({
@@ -2740,6 +2793,7 @@ var FunctionId = import_v36.z.union([
2740
2793
  version: import_v36.z.string()
2741
2794
  }),
2742
2795
  code: import_v36.z.string(),
2796
+ function_type: FunctionTypeEnum.and(import_v36.z.unknown()).optional(),
2743
2797
  name: import_v36.z.union([import_v36.z.string(), import_v36.z.null()]).optional()
2744
2798
  }),
2745
2799
  import_v36.z.object({
@@ -2969,7 +3023,12 @@ var TopicAutomationConfig = import_v36.z.object({
2969
3023
  topic_map_functions: import_v36.z.array(TopicMapFunctionAutomation),
2970
3024
  scope: import_v36.z.union([SpanScope, TraceScope, GroupScope, import_v36.z.null()]).optional(),
2971
3025
  data_scope: TopicAutomationDataScope.optional(),
2972
- btql_filter: import_v36.z.union([import_v36.z.string(), import_v36.z.null()]).optional()
3026
+ btql_filter: import_v36.z.union([import_v36.z.string(), import_v36.z.null()]).optional(),
3027
+ backfill_time_range: import_v36.z.union([
3028
+ import_v36.z.string(),
3029
+ import_v36.z.object({ from: import_v36.z.string(), to: import_v36.z.string() }),
3030
+ import_v36.z.null()
3031
+ ]).optional()
2973
3032
  });
2974
3033
  var ProjectAutomation = import_v36.z.object({
2975
3034
  id: import_v36.z.string().uuid(),
@@ -4390,6 +4449,9 @@ var BRAINTRUST_ATTACHMENT = BraintrustAttachmentReference.shape.type.value;
4390
4449
  var EXTERNAL_ATTACHMENT = ExternalAttachmentReference.shape.type.value;
4391
4450
  var LOGS3_OVERFLOW_REFERENCE_TYPE = "logs3_overflow";
4392
4451
  var BRAINTRUST_PARAMS = Object.keys(BraintrustModelParams.shape);
4452
+ var RESET_CONTEXT_MANAGER_STATE = Symbol.for(
4453
+ "braintrust.resetContextManagerState"
4454
+ );
4393
4455
  var DEFAULT_MAX_REQUEST_SIZE = 6 * 1024 * 1024;
4394
4456
  var parametersRowSchema = import_v38.z.object({
4395
4457
  id: import_v38.z.string().uuid(),
@@ -4406,6 +4468,12 @@ var parametersRowSchema = import_v38.z.object({
4406
4468
  }),
4407
4469
  metadata: import_v38.z.union([import_v38.z.object({}).partial().passthrough(), import_v38.z.null()]).optional()
4408
4470
  });
4471
+ var InlineAttachmentReferenceSchema = import_v38.z.object({
4472
+ type: import_v38.z.literal("inline_attachment"),
4473
+ src: import_v38.z.string().min(1),
4474
+ content_type: import_v38.z.string().optional(),
4475
+ filename: import_v38.z.string().optional()
4476
+ });
4409
4477
  var LoginInvalidOrgError = class extends Error {
4410
4478
  constructor(message) {
4411
4479
  super(message);
@@ -4446,13 +4514,18 @@ function applyMaskingToField(maskingFunction, data, fieldName) {
4446
4514
  return `ERROR: Failed to mask field '${fieldName}' - ${errorType}`;
4447
4515
  }
4448
4516
  }
4517
+ var BRAINTRUST_CURRENT_SPAN_STORE = Symbol.for(
4518
+ "braintrust.currentSpanStore"
4519
+ );
4449
4520
  var ContextManager = class {
4450
4521
  };
4451
4522
  var BraintrustContextManager = class extends ContextManager {
4452
4523
  _currentSpan;
4524
+ [BRAINTRUST_CURRENT_SPAN_STORE];
4453
4525
  constructor() {
4454
4526
  super();
4455
4527
  this._currentSpan = isomorph_default.newAsyncLocalStorage();
4528
+ this[BRAINTRUST_CURRENT_SPAN_STORE] = this._currentSpan;
4456
4529
  }
4457
4530
  getParentSpanIds() {
4458
4531
  const currentSpan2 = this._currentSpan.getStore();
@@ -4659,6 +4732,9 @@ var BraintrustState = class _BraintrustState {
4659
4732
  resetIdGenState() {
4660
4733
  this._idGenerator = null;
4661
4734
  }
4735
+ [RESET_CONTEXT_MANAGER_STATE]() {
4736
+ this._contextManager = null;
4737
+ }
4662
4738
  get idGenerator() {
4663
4739
  if (this._idGenerator === null) {
4664
4740
  this._idGenerator = getIdGenerator();
@@ -6607,6 +6683,7 @@ function init(projectOrOptions, optionalOptions) {
6607
6683
  experiment,
6608
6684
  description,
6609
6685
  dataset,
6686
+ parameters,
6610
6687
  baseExperiment,
6611
6688
  isPublic,
6612
6689
  open,
@@ -6724,6 +6801,17 @@ function init(projectOrOptions, optionalOptions) {
6724
6801
  args["dataset_version"] = await dataset.version();
6725
6802
  }
6726
6803
  }
6804
+ if (parameters !== void 0) {
6805
+ if (RemoteEvalParameters.isParameters(parameters)) {
6806
+ args["parameters_id"] = parameters.id;
6807
+ args["parameters_version"] = parameters.version;
6808
+ } else {
6809
+ args["parameters_id"] = parameters.id;
6810
+ if (parameters.version !== void 0) {
6811
+ args["parameters_version"] = parameters.version;
6812
+ }
6813
+ }
6814
+ }
6727
6815
  if (isPublic !== void 0) {
6728
6816
  args["public"] = isPublic;
6729
6817
  }
@@ -6982,11 +7070,7 @@ async function loadPrompt({
6982
7070
  forceLogin,
6983
7071
  state: stateArg
6984
7072
  }) {
6985
- if (version && environment) {
6986
- throw new Error(
6987
- "Cannot specify both 'version' and 'environment' parameters. Please use only one (remove the other)."
6988
- );
6989
- }
7073
+ const versionOrEnvironment = version ? { version } : environment ? { environment } : {};
6990
7074
  if (id) {
6991
7075
  } else if (isEmpty2(projectName) && isEmpty2(projectId)) {
6992
7076
  throw new Error("Must specify either projectName or projectId");
@@ -7004,10 +7088,7 @@ async function loadPrompt({
7004
7088
  forceLogin
7005
7089
  });
7006
7090
  if (id) {
7007
- response = await state.apiConn().get_json(`v1/prompt/${id}`, {
7008
- ...version && { version },
7009
- ...environment && { environment }
7010
- });
7091
+ response = await state.apiConn().get_json(`v1/prompt/${id}`, versionOrEnvironment);
7011
7092
  if (response) {
7012
7093
  response = { objects: [response] };
7013
7094
  }
@@ -7016,12 +7097,11 @@ async function loadPrompt({
7016
7097
  project_name: projectName,
7017
7098
  project_id: projectId,
7018
7099
  slug,
7019
- version,
7020
- ...environment && { environment }
7100
+ ...versionOrEnvironment
7021
7101
  });
7022
7102
  }
7023
7103
  } catch (e) {
7024
- if (environment || version) {
7104
+ if (version || environment) {
7025
7105
  throw new Error(`Prompt not found with specified parameters: ${e}`);
7026
7106
  }
7027
7107
  debugLogger.forState(state).warn("Failed to load prompt, attempting to fall back to cache:", e);
@@ -7099,11 +7179,7 @@ async function loadParameters({
7099
7179
  forceLogin,
7100
7180
  state: stateArg
7101
7181
  }) {
7102
- if (version && environment) {
7103
- throw new Error(
7104
- "Cannot specify both 'version' and 'environment' parameters. Please use only one (remove the other)."
7105
- );
7106
- }
7182
+ const versionOrEnvironment = version ? { version } : environment ? { environment } : {};
7107
7183
  if (id) {
7108
7184
  } else if (isEmpty2(projectName) && isEmpty2(projectId)) {
7109
7185
  throw new Error("Must specify either projectName or projectId");
@@ -7122,8 +7198,7 @@ async function loadParameters({
7122
7198
  });
7123
7199
  if (id) {
7124
7200
  response = await state.apiConn().get_json(`v1/function/${id}`, {
7125
- ...version && { version },
7126
- ...environment && { environment }
7201
+ ...versionOrEnvironment
7127
7202
  });
7128
7203
  if (response) {
7129
7204
  response = { objects: [response] };
@@ -7133,13 +7208,12 @@ async function loadParameters({
7133
7208
  project_name: projectName,
7134
7209
  project_id: projectId,
7135
7210
  slug,
7136
- version,
7137
7211
  function_type: "parameters",
7138
- ...environment && { environment }
7212
+ ...versionOrEnvironment
7139
7213
  });
7140
7214
  }
7141
7215
  } catch (e) {
7142
- if (environment || version) {
7216
+ if (version || environment) {
7143
7217
  throw new Error(`Parameters not found with specified parameters: ${e}`);
7144
7218
  }
7145
7219
  debugLogger.forState(state).warn("Failed to load parameters, attempting to fall back to cache:", e);
@@ -8922,40 +8996,85 @@ var Dataset2 = class extends ObjectFetcher {
8922
8996
  return typeof data === "object" && data !== null && "__braintrust_dataset_marker" in data;
8923
8997
  }
8924
8998
  };
8999
+ function isAttachmentObject(value) {
9000
+ return BraintrustAttachmentReference.safeParse(value).success || InlineAttachmentReferenceSchema.safeParse(value).success || ExternalAttachmentReference.safeParse(value).success;
9001
+ }
9002
+ function isURL(url) {
9003
+ try {
9004
+ const parsedUrl = new URL(url.trim());
9005
+ return parsedUrl.protocol === "http:" || parsedUrl.protocol === "https:";
9006
+ } catch {
9007
+ return false;
9008
+ }
9009
+ }
9010
+ function expandAttachmentArrayPreTemplate(content, variables) {
9011
+ if (typeof content !== "string") return null;
9012
+ const match = content.match(/^\{\{\s*([\w.]+)\s*\}\}$/);
9013
+ if (!match) return null;
9014
+ const varPath = match[1];
9015
+ const value = varPath.includes(".") ? getObjValueByPath(variables, varPath.split(".")) : variables[varPath];
9016
+ if (!Array.isArray(value)) return null;
9017
+ const allValid = value.every(
9018
+ (v) => isAttachmentObject(v) || typeof v === "string" && isURL(v)
9019
+ );
9020
+ if (!allValid) return null;
9021
+ return value.map((item) => ({
9022
+ type: "image_url",
9023
+ image_url: { url: item }
9024
+ }));
9025
+ }
8925
9026
  function renderMessage(render, message) {
9027
+ return renderMessageImpl(render, message, {});
9028
+ }
9029
+ function renderMessageImpl(render, message, variables) {
8926
9030
  return {
8927
9031
  ...message,
8928
9032
  ..."content" in message ? {
8929
- content: isEmpty2(message.content) ? void 0 : typeof message.content === "string" ? render(message.content) : message.content.map((c) => {
9033
+ content: isEmpty2(message.content) ? void 0 : typeof message.content === "string" ? render(message.content) : message.content.flatMap((c) => {
8930
9034
  switch (c.type) {
8931
9035
  case "text":
8932
- return { ...c, text: render(c.text) };
9036
+ return [{ ...c, text: render(c.text) }];
8933
9037
  case "image_url":
8934
9038
  if (isObject(c.image_url.url)) {
8935
9039
  throw new Error(
8936
9040
  "Attachments must be replaced with URLs before calling `build()`"
8937
9041
  );
8938
9042
  }
8939
- return {
8940
- ...c,
8941
- image_url: {
8942
- ...c.image_url,
8943
- url: render(c.image_url.url)
9043
+ if (variables) {
9044
+ const expanded = expandAttachmentArrayPreTemplate(
9045
+ c.image_url.url,
9046
+ variables
9047
+ );
9048
+ if (expanded) {
9049
+ return expanded;
8944
9050
  }
8945
- };
9051
+ }
9052
+ return [
9053
+ {
9054
+ ...c,
9055
+ image_url: {
9056
+ ...c.image_url,
9057
+ url: render(c.image_url.url)
9058
+ }
9059
+ }
9060
+ ];
8946
9061
  case "file":
8947
- return {
8948
- ...c,
8949
- file: {
8950
- file_data: render(c.file.file_data || ""),
8951
- ...c.file.file_id && {
8952
- file_id: render(c.file.file_id)
8953
- },
8954
- ...c.file.filename && {
8955
- filename: render(c.file.filename)
9062
+ return [
9063
+ {
9064
+ ...c,
9065
+ file: {
9066
+ ...c.file.file_data && {
9067
+ file_data: render(c.file.file_data)
9068
+ },
9069
+ ...c.file.file_id && {
9070
+ file_id: render(c.file.file_id)
9071
+ },
9072
+ ...c.file.filename && {
9073
+ filename: render(c.file.filename)
9074
+ }
8956
9075
  }
8957
9076
  }
8958
- };
9077
+ ];
8959
9078
  default:
8960
9079
  const _exhaustiveCheck = c;
8961
9080
  return _exhaustiveCheck;
@@ -9112,17 +9231,19 @@ var Prompt2 = class _Prompt {
9112
9231
  }
9113
9232
  runBuild(buildArgs, options) {
9114
9233
  const { flavor } = options;
9115
- const params = {
9116
- ...this.defaults,
9117
- ...Object.fromEntries(
9118
- Object.entries(this.options.params || {}).filter(
9119
- ([k, _v]) => !BRAINTRUST_PARAMS.includes(k)
9120
- )
9121
- ),
9122
- ...!isEmpty2(this.options.model) ? {
9123
- model: this.options.model
9124
- } : {}
9125
- };
9234
+ const params = Object.fromEntries(
9235
+ Object.entries({
9236
+ ...this.defaults,
9237
+ ...Object.fromEntries(
9238
+ Object.entries(this.options.params || {}).filter(
9239
+ ([k, _v]) => !BRAINTRUST_PARAMS.includes(k)
9240
+ )
9241
+ ),
9242
+ ...!isEmpty2(this.options.model) ? {
9243
+ model: this.options.model
9244
+ } : {}
9245
+ }).filter(([key, value]) => key !== "response_format" || value !== null)
9246
+ );
9126
9247
  if (!("model" in params) || isEmpty2(params.model)) {
9127
9248
  throw new Error(
9128
9249
  "No model specified. Either specify it in the prompt or as a default"
@@ -9222,7 +9343,7 @@ var Prompt2 = class _Prompt {
9222
9343
  templateFormat
9223
9344
  });
9224
9345
  const baseMessages = (prompt.messages || []).map(
9225
- (m) => renderMessage(render, m)
9346
+ (m) => renderMessageImpl(render, m, variables)
9226
9347
  );
9227
9348
  const hasSystemPrompt = baseMessages.some((m) => m.role === "system");
9228
9349
  const messages = [
@@ -9342,6 +9463,8 @@ async function simulateLoginForTests() {
9342
9463
  function simulateLogoutForTests() {
9343
9464
  const state = _internalGetGlobalState();
9344
9465
  state.resetLoginInfo();
9466
+ state.resetIdGenState();
9467
+ state[RESET_CONTEXT_MANAGER_STATE]();
9345
9468
  state.appUrl = "https://www.braintrust.dev";
9346
9469
  return state;
9347
9470
  }
@@ -9941,7 +10064,11 @@ function startSpanForEvent(config, event, channelName) {
9941
10064
  });
9942
10065
  const startTime = getCurrentUnixTimestamp();
9943
10066
  try {
9944
- const { input, metadata } = config.extractInput(event.arguments);
10067
+ const { input, metadata } = config.extractInput(
10068
+ event.arguments,
10069
+ event,
10070
+ span
10071
+ );
9945
10072
  span.log({
9946
10073
  input,
9947
10074
  metadata: mergeInputMetadata(metadata, spanInfoMetadata)
@@ -9951,6 +10078,36 @@ function startSpanForEvent(config, event, channelName) {
9951
10078
  }
9952
10079
  return { span, startTime };
9953
10080
  }
10081
+ function ensureSpanStateForEvent(states, config, event, channelName) {
10082
+ const key = event;
10083
+ const existing = states.get(key);
10084
+ if (existing) {
10085
+ return existing;
10086
+ }
10087
+ const created = startSpanForEvent(config, event, channelName);
10088
+ states.set(key, created);
10089
+ return created;
10090
+ }
10091
+ function bindCurrentSpanStoreToStart(tracingChannel2, states, config, channelName) {
10092
+ const state = _internalGetGlobalState();
10093
+ const startChannel = tracingChannel2.start;
10094
+ const currentSpanStore = state?.contextManager ? state.contextManager[BRAINTRUST_CURRENT_SPAN_STORE] : void 0;
10095
+ if (!currentSpanStore || !startChannel) {
10096
+ return void 0;
10097
+ }
10098
+ startChannel.bindStore(
10099
+ currentSpanStore,
10100
+ (event) => ensureSpanStateForEvent(
10101
+ states,
10102
+ config,
10103
+ event,
10104
+ channelName
10105
+ ).span
10106
+ );
10107
+ return () => {
10108
+ startChannel.unbindStore(currentSpanStore);
10109
+ };
10110
+ }
9954
10111
  function logErrorAndEnd(states, event) {
9955
10112
  const spanData = states.get(event);
9956
10113
  if (!spanData) {
@@ -9966,15 +10123,19 @@ function traceAsyncChannel(channel2, config) {
9966
10123
  const tracingChannel2 = channel2.tracingChannel();
9967
10124
  const states = /* @__PURE__ */ new WeakMap();
9968
10125
  const channelName = channel2.channelName;
10126
+ const unbindCurrentSpanStore = bindCurrentSpanStoreToStart(
10127
+ tracingChannel2,
10128
+ states,
10129
+ config,
10130
+ channelName
10131
+ );
9969
10132
  const handlers = {
9970
10133
  start: (event) => {
9971
- states.set(
10134
+ ensureSpanStateForEvent(
10135
+ states,
10136
+ config,
9972
10137
  event,
9973
- startSpanForEvent(
9974
- config,
9975
- event,
9976
- channelName
9977
- )
10138
+ channelName
9978
10139
  );
9979
10140
  },
9980
10141
  asyncEnd: (event) => {
@@ -10016,6 +10177,7 @@ function traceAsyncChannel(channel2, config) {
10016
10177
  };
10017
10178
  tracingChannel2.subscribe(handlers);
10018
10179
  return () => {
10180
+ unbindCurrentSpanStore?.();
10019
10181
  tracingChannel2.unsubscribe(handlers);
10020
10182
  };
10021
10183
  }
@@ -10023,15 +10185,19 @@ function traceStreamingChannel(channel2, config) {
10023
10185
  const tracingChannel2 = channel2.tracingChannel();
10024
10186
  const states = /* @__PURE__ */ new WeakMap();
10025
10187
  const channelName = channel2.channelName;
10188
+ const unbindCurrentSpanStore = bindCurrentSpanStoreToStart(
10189
+ tracingChannel2,
10190
+ states,
10191
+ config,
10192
+ channelName
10193
+ );
10026
10194
  const handlers = {
10027
10195
  start: (event) => {
10028
- states.set(
10196
+ ensureSpanStateForEvent(
10197
+ states,
10198
+ config,
10029
10199
  event,
10030
- startSpanForEvent(
10031
- config,
10032
- event,
10033
- channelName
10034
- )
10200
+ channelName
10035
10201
  );
10036
10202
  },
10037
10203
  asyncEnd: (event) => {
@@ -10105,6 +10271,16 @@ function traceStreamingChannel(channel2, config) {
10105
10271
  });
10106
10272
  return;
10107
10273
  }
10274
+ if (config.patchResult?.({
10275
+ channelName,
10276
+ endEvent: asyncEndEvent,
10277
+ result: asyncEndEvent.result,
10278
+ span,
10279
+ startTime
10280
+ })) {
10281
+ states.delete(event);
10282
+ return;
10283
+ }
10108
10284
  try {
10109
10285
  const output = config.extractOutput(
10110
10286
  asyncEndEvent.result,
@@ -10137,6 +10313,7 @@ function traceStreamingChannel(channel2, config) {
10137
10313
  };
10138
10314
  tracingChannel2.subscribe(handlers);
10139
10315
  return () => {
10316
+ unbindCurrentSpanStore?.();
10140
10317
  tracingChannel2.unsubscribe(handlers);
10141
10318
  };
10142
10319
  }
@@ -10144,15 +10321,19 @@ function traceSyncStreamChannel(channel2, config) {
10144
10321
  const tracingChannel2 = channel2.tracingChannel();
10145
10322
  const states = /* @__PURE__ */ new WeakMap();
10146
10323
  const channelName = channel2.channelName;
10324
+ const unbindCurrentSpanStore = bindCurrentSpanStoreToStart(
10325
+ tracingChannel2,
10326
+ states,
10327
+ config,
10328
+ channelName
10329
+ );
10147
10330
  const handlers = {
10148
10331
  start: (event) => {
10149
- states.set(
10332
+ ensureSpanStateForEvent(
10333
+ states,
10334
+ config,
10150
10335
  event,
10151
- startSpanForEvent(
10152
- config,
10153
- event,
10154
- channelName
10155
- )
10336
+ channelName
10156
10337
  );
10157
10338
  },
10158
10339
  end: (event) => {
@@ -10161,8 +10342,17 @@ function traceSyncStreamChannel(channel2, config) {
10161
10342
  return;
10162
10343
  }
10163
10344
  const { span, startTime } = spanData;
10164
- const resultEvent = event;
10165
- const stream = resultEvent.result;
10345
+ const endEvent = event;
10346
+ if (config.patchResult?.({
10347
+ channelName,
10348
+ endEvent,
10349
+ result: endEvent.result,
10350
+ span,
10351
+ startTime
10352
+ })) {
10353
+ return;
10354
+ }
10355
+ const stream = endEvent.result;
10166
10356
  if (!isSyncStreamLike(stream)) {
10167
10357
  span.end();
10168
10358
  states.delete(event);
@@ -10232,6 +10422,7 @@ function traceSyncStreamChannel(channel2, config) {
10232
10422
  };
10233
10423
  tracingChannel2.subscribe(handlers);
10234
10424
  return () => {
10425
+ unbindCurrentSpanStore?.();
10235
10426
  tracingChannel2.unsubscribe(handlers);
10236
10427
  };
10237
10428
  }
@@ -11133,6 +11324,108 @@ function filterFrom2(obj, fieldsToRemove) {
11133
11324
  return result;
11134
11325
  }
11135
11326
 
11327
+ // src/wrappers/ai-sdk/normalize-logged-output.ts
11328
+ var REMOVE_NORMALIZED_VALUE = Symbol("braintrust.ai-sdk.remove-normalized");
11329
+ function normalizeAISDKLoggedOutput(value) {
11330
+ const normalized = normalizeAISDKLoggedValue(value);
11331
+ return normalized === REMOVE_NORMALIZED_VALUE ? {} : normalized;
11332
+ }
11333
+ function normalizeAISDKLoggedValue(value, context = {}) {
11334
+ if (Array.isArray(value)) {
11335
+ return value.map((entry) => normalizeAISDKLoggedValue(entry, context)).filter((entry) => entry !== REMOVE_NORMALIZED_VALUE);
11336
+ }
11337
+ if (!value || typeof value !== "object") {
11338
+ return value;
11339
+ }
11340
+ const nextInProviderMetadata = context.inProviderMetadata || context.parentKey === "providerMetadata" || context.parentKey === "experimental_providerMetadata";
11341
+ const normalizedEntries = [];
11342
+ for (const [key, entry] of Object.entries(value)) {
11343
+ if (key === "cachedPromptTokens" && entry === 0) {
11344
+ continue;
11345
+ }
11346
+ if (context.parentKey === "request" && key === "body" && entry === "<omitted>") {
11347
+ continue;
11348
+ }
11349
+ const normalizedEntry = normalizeAISDKLoggedValue(entry, {
11350
+ inProviderMetadata: nextInProviderMetadata,
11351
+ parentKey: key
11352
+ });
11353
+ if (normalizedEntry === REMOVE_NORMALIZED_VALUE) {
11354
+ continue;
11355
+ }
11356
+ normalizedEntries.push([key, normalizedEntry]);
11357
+ }
11358
+ if (normalizedEntries.length === 0) {
11359
+ if (context.parentKey === "request" || nextInProviderMetadata) {
11360
+ return REMOVE_NORMALIZED_VALUE;
11361
+ }
11362
+ return {};
11363
+ }
11364
+ return Object.fromEntries(normalizedEntries);
11365
+ }
11366
+
11367
+ // src/zod/utils.ts
11368
+ var import_zod_to_json_schema = require("zod-to-json-schema");
11369
+ var z42 = __toESM(require("zod/v4"));
11370
+ function isZodV4(zodObject) {
11371
+ return typeof zodObject === "object" && zodObject !== null && "_zod" in zodObject && zodObject._zod !== void 0;
11372
+ }
11373
+ function zodToJsonSchema(schema) {
11374
+ if (isZodV4(schema)) {
11375
+ return z42.toJSONSchema(schema, {
11376
+ target: "draft-7"
11377
+ });
11378
+ }
11379
+ return (0, import_zod_to_json_schema.zodToJsonSchema)(schema);
11380
+ }
11381
+
11382
+ // src/wrappers/ai-sdk/tool-serialization.ts
11383
+ function isZodSchema(value) {
11384
+ return value != null && typeof value === "object" && "_def" in value && typeof value._def === "object";
11385
+ }
11386
+ function serializeZodSchema(schema) {
11387
+ try {
11388
+ return zodToJsonSchema(schema);
11389
+ } catch {
11390
+ return {
11391
+ type: "object",
11392
+ description: "Zod schema (conversion failed)"
11393
+ };
11394
+ }
11395
+ }
11396
+ function serializeTool(tool) {
11397
+ if (!tool || typeof tool !== "object") {
11398
+ return tool;
11399
+ }
11400
+ const serialized = { ...tool };
11401
+ if (isZodSchema(serialized.inputSchema)) {
11402
+ serialized.inputSchema = serializeZodSchema(serialized.inputSchema);
11403
+ }
11404
+ if (isZodSchema(serialized.parameters)) {
11405
+ serialized.parameters = serializeZodSchema(serialized.parameters);
11406
+ }
11407
+ if ("execute" in serialized) {
11408
+ delete serialized.execute;
11409
+ }
11410
+ if ("render" in serialized) {
11411
+ delete serialized.render;
11412
+ }
11413
+ return serialized;
11414
+ }
11415
+ function serializeAISDKToolsForLogging(tools) {
11416
+ if (!tools || typeof tools !== "object") {
11417
+ return tools;
11418
+ }
11419
+ if (Array.isArray(tools)) {
11420
+ return tools.map(serializeTool);
11421
+ }
11422
+ const serialized = {};
11423
+ for (const [key, tool] of Object.entries(tools)) {
11424
+ serialized[key] = serializeTool(tool);
11425
+ }
11426
+ return serialized;
11427
+ }
11428
+
11136
11429
  // src/instrumentation/plugins/ai-sdk-channels.ts
11137
11430
  var aiSDKChannels = defineChannels("ai", {
11138
11431
  generateText: channel({
@@ -11143,6 +11436,10 @@ var aiSDKChannels = defineChannels("ai", {
11143
11436
  channelName: "streamText",
11144
11437
  kind: "async"
11145
11438
  }),
11439
+ streamTextSync: channel({
11440
+ channelName: "streamText.sync",
11441
+ kind: "sync-stream"
11442
+ }),
11146
11443
  generateObject: channel({
11147
11444
  channelName: "generateObject",
11148
11445
  kind: "async"
@@ -11151,6 +11448,10 @@ var aiSDKChannels = defineChannels("ai", {
11151
11448
  channelName: "streamObject",
11152
11449
  kind: "async"
11153
11450
  }),
11451
+ streamObjectSync: channel({
11452
+ channelName: "streamObject.sync",
11453
+ kind: "sync-stream"
11454
+ }),
11154
11455
  agentGenerate: channel({
11155
11456
  channelName: "Agent.generate",
11156
11457
  kind: "async"
@@ -11158,6 +11459,14 @@ var aiSDKChannels = defineChannels("ai", {
11158
11459
  agentStream: channel({
11159
11460
  channelName: "Agent.stream",
11160
11461
  kind: "async"
11462
+ }),
11463
+ toolLoopAgentGenerate: channel({
11464
+ channelName: "ToolLoopAgent.generate",
11465
+ kind: "async"
11466
+ }),
11467
+ toolLoopAgentStream: channel({
11468
+ channelName: "ToolLoopAgent.stream",
11469
+ kind: "async"
11161
11470
  })
11162
11471
  });
11163
11472
 
@@ -11176,6 +11485,8 @@ var DEFAULT_DENY_OUTPUT_PATHS = [
11176
11485
  "steps[].response.body",
11177
11486
  "steps[].response.headers"
11178
11487
  ];
11488
+ var AUTO_PATCHED_MODEL = Symbol.for("braintrust.ai-sdk.auto-patched-model");
11489
+ var AUTO_PATCHED_TOOL = Symbol.for("braintrust.ai-sdk.auto-patched-tool");
11179
11490
  var AISDKPlugin = class extends BasePlugin {
11180
11491
  config;
11181
11492
  constructor(config = {}) {
@@ -11194,22 +11505,12 @@ var AISDKPlugin = class extends BasePlugin {
11194
11505
  traceStreamingChannel(aiSDKChannels.generateText, {
11195
11506
  name: "generateText",
11196
11507
  type: "llm" /* LLM */,
11197
- extractInput: ([params]) => {
11198
- return {
11199
- input: processAISDKInput(params),
11200
- metadata: extractMetadataFromParams(params)
11201
- };
11202
- },
11203
- extractOutput: (result) => {
11508
+ extractInput: ([params], event, span) => prepareAISDKInput(params, event, span, denyOutputPaths),
11509
+ extractOutput: (result, endEvent) => {
11510
+ finalizeAISDKChildTracing(endEvent);
11204
11511
  return processAISDKOutput(result, denyOutputPaths);
11205
11512
  },
11206
- extractMetrics: (result, startTime) => {
11207
- const metrics = extractTokenMetrics(result);
11208
- if (startTime) {
11209
- metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
11210
- }
11211
- return metrics;
11212
- },
11513
+ extractMetrics: (result, _startTime, endEvent) => extractTopLevelAISDKMetrics(result, endEvent),
11213
11514
  aggregateChunks: aggregateAISDKChunks
11214
11515
  })
11215
11516
  );
@@ -11217,45 +11518,43 @@ var AISDKPlugin = class extends BasePlugin {
11217
11518
  traceStreamingChannel(aiSDKChannels.streamText, {
11218
11519
  name: "streamText",
11219
11520
  type: "llm" /* LLM */,
11220
- extractInput: ([params]) => {
11221
- return {
11222
- input: processAISDKInput(params),
11223
- metadata: extractMetadataFromParams(params)
11224
- };
11225
- },
11226
- extractOutput: (result) => {
11227
- return processAISDKOutput(result, denyOutputPaths);
11228
- },
11229
- extractMetrics: (result, startTime) => {
11230
- const metrics = extractTokenMetrics(result);
11231
- if (startTime) {
11232
- metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
11233
- }
11234
- return metrics;
11235
- },
11236
- aggregateChunks: aggregateAISDKChunks
11521
+ extractInput: ([params], event, span) => prepareAISDKInput(params, event, span, denyOutputPaths),
11522
+ extractOutput: (result) => processAISDKOutput(result, denyOutputPaths),
11523
+ extractMetrics: (result, startTime, endEvent) => extractTopLevelAISDKMetrics(result, endEvent, startTime),
11524
+ aggregateChunks: aggregateAISDKChunks,
11525
+ patchResult: ({ endEvent, result, span, startTime }) => patchAISDKStreamingResult({
11526
+ denyOutputPaths,
11527
+ endEvent,
11528
+ result,
11529
+ span,
11530
+ startTime
11531
+ })
11532
+ })
11533
+ );
11534
+ this.unsubscribers.push(
11535
+ traceSyncStreamChannel(aiSDKChannels.streamTextSync, {
11536
+ name: "streamText",
11537
+ type: "llm" /* LLM */,
11538
+ extractInput: ([params], event, span) => prepareAISDKInput(params, event, span, denyOutputPaths),
11539
+ patchResult: ({ endEvent, result, span, startTime }) => patchAISDKStreamingResult({
11540
+ denyOutputPaths,
11541
+ endEvent,
11542
+ result,
11543
+ span,
11544
+ startTime
11545
+ })
11237
11546
  })
11238
11547
  );
11239
11548
  this.unsubscribers.push(
11240
11549
  traceStreamingChannel(aiSDKChannels.generateObject, {
11241
11550
  name: "generateObject",
11242
11551
  type: "llm" /* LLM */,
11243
- extractInput: ([params]) => {
11244
- return {
11245
- input: processAISDKInput(params),
11246
- metadata: extractMetadataFromParams(params)
11247
- };
11248
- },
11249
- extractOutput: (result) => {
11552
+ extractInput: ([params], event, span) => prepareAISDKInput(params, event, span, denyOutputPaths),
11553
+ extractOutput: (result, endEvent) => {
11554
+ finalizeAISDKChildTracing(endEvent);
11250
11555
  return processAISDKOutput(result, denyOutputPaths);
11251
11556
  },
11252
- extractMetrics: (result, startTime) => {
11253
- const metrics = extractTokenMetrics(result);
11254
- if (startTime) {
11255
- metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
11256
- }
11257
- return metrics;
11258
- },
11557
+ extractMetrics: (result, _startTime, endEvent) => extractTopLevelAISDKMetrics(result, endEvent),
11259
11558
  aggregateChunks: aggregateAISDKChunks
11260
11559
  })
11261
11560
  );
@@ -11263,45 +11562,43 @@ var AISDKPlugin = class extends BasePlugin {
11263
11562
  traceStreamingChannel(aiSDKChannels.streamObject, {
11264
11563
  name: "streamObject",
11265
11564
  type: "llm" /* LLM */,
11266
- extractInput: ([params]) => {
11267
- return {
11268
- input: processAISDKInput(params),
11269
- metadata: extractMetadataFromParams(params)
11270
- };
11271
- },
11272
- extractOutput: (result) => {
11273
- return processAISDKOutput(result, denyOutputPaths);
11274
- },
11275
- extractMetrics: (result, startTime) => {
11276
- const metrics = extractTokenMetrics(result);
11277
- if (startTime) {
11278
- metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
11279
- }
11280
- return metrics;
11281
- },
11282
- aggregateChunks: aggregateAISDKChunks
11565
+ extractInput: ([params], event, span) => prepareAISDKInput(params, event, span, denyOutputPaths),
11566
+ extractOutput: (result) => processAISDKOutput(result, denyOutputPaths),
11567
+ extractMetrics: (result, startTime, endEvent) => extractTopLevelAISDKMetrics(result, endEvent, startTime),
11568
+ aggregateChunks: aggregateAISDKChunks,
11569
+ patchResult: ({ endEvent, result, span, startTime }) => patchAISDKStreamingResult({
11570
+ denyOutputPaths,
11571
+ endEvent,
11572
+ result,
11573
+ span,
11574
+ startTime
11575
+ })
11576
+ })
11577
+ );
11578
+ this.unsubscribers.push(
11579
+ traceSyncStreamChannel(aiSDKChannels.streamObjectSync, {
11580
+ name: "streamObject",
11581
+ type: "llm" /* LLM */,
11582
+ extractInput: ([params], event, span) => prepareAISDKInput(params, event, span, denyOutputPaths),
11583
+ patchResult: ({ endEvent, result, span, startTime }) => patchAISDKStreamingResult({
11584
+ denyOutputPaths,
11585
+ endEvent,
11586
+ result,
11587
+ span,
11588
+ startTime
11589
+ })
11283
11590
  })
11284
11591
  );
11285
11592
  this.unsubscribers.push(
11286
11593
  traceStreamingChannel(aiSDKChannels.agentGenerate, {
11287
11594
  name: "Agent.generate",
11288
11595
  type: "llm" /* LLM */,
11289
- extractInput: ([params]) => {
11290
- return {
11291
- input: processAISDKInput(params),
11292
- metadata: extractMetadataFromParams(params)
11293
- };
11294
- },
11295
- extractOutput: (result) => {
11596
+ extractInput: ([params], event, span) => prepareAISDKInput(params, event, span, denyOutputPaths),
11597
+ extractOutput: (result, endEvent) => {
11598
+ finalizeAISDKChildTracing(endEvent);
11296
11599
  return processAISDKOutput(result, denyOutputPaths);
11297
11600
  },
11298
- extractMetrics: (result, startTime) => {
11299
- const metrics = extractTokenMetrics(result);
11300
- if (startTime) {
11301
- metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
11302
- }
11303
- return metrics;
11304
- },
11601
+ extractMetrics: (result, _startTime, endEvent) => extractTopLevelAISDKMetrics(result, endEvent),
11305
11602
  aggregateChunks: aggregateAISDKChunks
11306
11603
  })
11307
11604
  );
@@ -11309,52 +11606,470 @@ var AISDKPlugin = class extends BasePlugin {
11309
11606
  traceStreamingChannel(aiSDKChannels.agentStream, {
11310
11607
  name: "Agent.stream",
11311
11608
  type: "llm" /* LLM */,
11312
- extractInput: ([params]) => {
11313
- return {
11314
- input: processAISDKInput(params),
11315
- metadata: extractMetadataFromParams(params)
11316
- };
11317
- },
11318
- extractOutput: (result) => {
11319
- return processAISDKOutput(result, denyOutputPaths);
11320
- },
11321
- extractMetrics: (result, startTime) => {
11322
- const metrics = extractTokenMetrics(result);
11323
- if (startTime) {
11324
- metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
11325
- }
11326
- return metrics;
11609
+ extractInput: ([params], event, span) => prepareAISDKInput(params, event, span, denyOutputPaths),
11610
+ extractOutput: (result) => processAISDKOutput(result, denyOutputPaths),
11611
+ extractMetrics: (result, startTime, endEvent) => extractTopLevelAISDKMetrics(result, endEvent, startTime),
11612
+ aggregateChunks: aggregateAISDKChunks,
11613
+ patchResult: ({ endEvent, result, span, startTime }) => patchAISDKStreamingResult({
11614
+ denyOutputPaths,
11615
+ endEvent,
11616
+ result,
11617
+ span,
11618
+ startTime
11619
+ })
11620
+ })
11621
+ );
11622
+ this.unsubscribers.push(
11623
+ traceStreamingChannel(aiSDKChannels.toolLoopAgentGenerate, {
11624
+ name: "ToolLoopAgent.generate",
11625
+ type: "llm" /* LLM */,
11626
+ extractInput: ([params], event, span) => prepareAISDKInput(params, event, span, denyOutputPaths),
11627
+ extractOutput: (result, endEvent) => {
11628
+ finalizeAISDKChildTracing(endEvent);
11629
+ return processAISDKOutput(result, denyOutputPaths);
11327
11630
  },
11631
+ extractMetrics: (result, _startTime, endEvent) => extractTopLevelAISDKMetrics(result, endEvent),
11328
11632
  aggregateChunks: aggregateAISDKChunks
11329
11633
  })
11330
11634
  );
11635
+ this.unsubscribers.push(
11636
+ traceStreamingChannel(aiSDKChannels.toolLoopAgentStream, {
11637
+ name: "ToolLoopAgent.stream",
11638
+ type: "llm" /* LLM */,
11639
+ extractInput: ([params], event, span) => prepareAISDKInput(params, event, span, denyOutputPaths),
11640
+ extractOutput: (result) => processAISDKOutput(result, denyOutputPaths),
11641
+ extractMetrics: (result, startTime, endEvent) => extractTopLevelAISDKMetrics(result, endEvent, startTime),
11642
+ aggregateChunks: aggregateAISDKChunks,
11643
+ patchResult: ({ endEvent, result, span, startTime }) => patchAISDKStreamingResult({
11644
+ denyOutputPaths,
11645
+ endEvent,
11646
+ result,
11647
+ span,
11648
+ startTime
11649
+ })
11650
+ })
11651
+ );
11331
11652
  }
11332
11653
  };
11333
11654
  function processAISDKInput(params) {
11334
11655
  if (!params) return params;
11335
- return processInputAttachments(params);
11656
+ const input = processInputAttachments(params);
11657
+ if (!input || typeof input !== "object" || Array.isArray(input)) {
11658
+ return input;
11659
+ }
11660
+ const { tools: _tools, ...rest } = input;
11661
+ return rest;
11662
+ }
11663
+ function prepareAISDKInput(params, event, span, denyOutputPaths) {
11664
+ const input = processAISDKInput(params);
11665
+ const metadata = extractMetadataFromParams(params, event.self);
11666
+ const childTracing = prepareAISDKChildTracing(
11667
+ params,
11668
+ event.self,
11669
+ span,
11670
+ denyOutputPaths
11671
+ );
11672
+ event.__braintrust_ai_sdk_model_wrapped = childTracing.modelWrapped;
11673
+ if (childTracing.cleanup) {
11674
+ event.__braintrust_ai_sdk_cleanup = childTracing.cleanup;
11675
+ }
11676
+ return {
11677
+ input,
11678
+ metadata
11679
+ };
11680
+ }
11681
+ function extractTopLevelAISDKMetrics(result, event, startTime) {
11682
+ const metrics = hasModelChildTracing(event) ? {} : extractTokenMetrics(result);
11683
+ if (startTime) {
11684
+ metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
11685
+ }
11686
+ return metrics;
11336
11687
  }
11337
- function extractMetadataFromParams(params) {
11688
+ function hasModelChildTracing(event) {
11689
+ return event?.__braintrust_ai_sdk_model_wrapped === true;
11690
+ }
11691
+ function extractMetadataFromParams(params, self) {
11338
11692
  const metadata = {
11339
11693
  braintrust: {
11340
11694
  integration_name: "ai-sdk",
11341
11695
  sdk_language: "typescript"
11342
11696
  }
11343
11697
  };
11344
- const { model, provider } = serializeModelWithProvider(params.model);
11698
+ const agentModel = self && typeof self === "object" && "model" in self && self.model ? self.model : self && typeof self === "object" && "settings" in self && self.settings?.model ? self.settings?.model : void 0;
11699
+ const { model, provider } = serializeModelWithProvider(
11700
+ params.model ?? agentModel
11701
+ );
11345
11702
  if (model) {
11346
11703
  metadata.model = model;
11347
11704
  }
11348
11705
  if (provider) {
11349
11706
  metadata.provider = provider;
11350
11707
  }
11708
+ const tools = serializeAISDKToolsForLogging(params.tools);
11709
+ if (tools) {
11710
+ metadata.tools = tools;
11711
+ }
11351
11712
  return metadata;
11352
11713
  }
11714
+ function prepareAISDKChildTracing(params, self, parentSpan, denyOutputPaths) {
11715
+ const cleanup = [];
11716
+ const patchedModels = /* @__PURE__ */ new WeakSet();
11717
+ const patchedTools = /* @__PURE__ */ new WeakSet();
11718
+ let modelWrapped = false;
11719
+ const patchModel = (model) => {
11720
+ const resolvedModel = resolveAISDKModel(model);
11721
+ if (!resolvedModel || typeof resolvedModel !== "object" || typeof resolvedModel.doGenerate !== "function" || patchedModels.has(resolvedModel) || resolvedModel[AUTO_PATCHED_MODEL]) {
11722
+ return;
11723
+ }
11724
+ patchedModels.add(resolvedModel);
11725
+ resolvedModel[AUTO_PATCHED_MODEL] = true;
11726
+ modelWrapped = true;
11727
+ const originalDoGenerate = resolvedModel.doGenerate;
11728
+ const originalDoStream = resolvedModel.doStream;
11729
+ const baseMetadata = buildAISDKChildMetadata(resolvedModel);
11730
+ resolvedModel.doGenerate = async function doGeneratePatched(options) {
11731
+ return parentSpan.traced(
11732
+ async (span) => {
11733
+ const result = await Reflect.apply(
11734
+ originalDoGenerate,
11735
+ resolvedModel,
11736
+ [options]
11737
+ );
11738
+ span.log({
11739
+ output: processAISDKOutput(result, denyOutputPaths),
11740
+ metrics: extractTokenMetrics(result),
11741
+ ...buildResolvedMetadataPayload(result)
11742
+ });
11743
+ return result;
11744
+ },
11745
+ {
11746
+ name: "doGenerate",
11747
+ spanAttributes: {
11748
+ type: "llm" /* LLM */
11749
+ },
11750
+ event: {
11751
+ input: processAISDKInput(options),
11752
+ metadata: baseMetadata
11753
+ }
11754
+ }
11755
+ );
11756
+ };
11757
+ if (originalDoStream) {
11758
+ resolvedModel.doStream = async function doStreamPatched(options) {
11759
+ const span = parentSpan.startSpan({
11760
+ name: "doStream",
11761
+ spanAttributes: {
11762
+ type: "llm" /* LLM */
11763
+ },
11764
+ event: {
11765
+ input: processAISDKInput(options),
11766
+ metadata: baseMetadata
11767
+ }
11768
+ });
11769
+ const result = await withCurrent(
11770
+ span,
11771
+ () => Reflect.apply(originalDoStream, resolvedModel, [options])
11772
+ );
11773
+ const output = {};
11774
+ let text = "";
11775
+ let reasoning = "";
11776
+ const toolCalls = [];
11777
+ let object = void 0;
11778
+ const transformStream = new TransformStream({
11779
+ transform(chunk, controller) {
11780
+ switch (chunk.type) {
11781
+ case "text-delta":
11782
+ text += extractTextDelta(chunk);
11783
+ break;
11784
+ case "reasoning-delta":
11785
+ if (chunk.delta) {
11786
+ reasoning += chunk.delta;
11787
+ } else if (chunk.text) {
11788
+ reasoning += chunk.text;
11789
+ }
11790
+ break;
11791
+ case "tool-call":
11792
+ toolCalls.push(chunk);
11793
+ break;
11794
+ case "object":
11795
+ object = chunk.object;
11796
+ break;
11797
+ case "raw":
11798
+ if (chunk.rawValue) {
11799
+ const rawVal = chunk.rawValue;
11800
+ if (rawVal.delta?.content) {
11801
+ text += rawVal.delta.content;
11802
+ } else if (rawVal.choices?.[0]?.delta?.content) {
11803
+ text += rawVal.choices[0].delta.content;
11804
+ } else if (typeof rawVal.text === "string") {
11805
+ text += rawVal.text;
11806
+ } else if (typeof rawVal.content === "string") {
11807
+ text += rawVal.content;
11808
+ }
11809
+ }
11810
+ break;
11811
+ case "finish":
11812
+ output.text = text;
11813
+ output.reasoning = reasoning;
11814
+ output.toolCalls = toolCalls;
11815
+ output.finishReason = chunk.finishReason;
11816
+ output.usage = chunk.usage;
11817
+ if (object !== void 0) {
11818
+ output.object = object;
11819
+ }
11820
+ span.log({
11821
+ output: processAISDKOutput(
11822
+ output,
11823
+ denyOutputPaths
11824
+ ),
11825
+ metrics: extractTokenMetrics(output),
11826
+ ...buildResolvedMetadataPayload(output)
11827
+ });
11828
+ span.end();
11829
+ break;
11830
+ }
11831
+ controller.enqueue(chunk);
11832
+ }
11833
+ });
11834
+ return {
11835
+ ...result,
11836
+ stream: result.stream.pipeThrough(transformStream)
11837
+ };
11838
+ };
11839
+ }
11840
+ cleanup.push(() => {
11841
+ resolvedModel.doGenerate = originalDoGenerate;
11842
+ if (originalDoStream) {
11843
+ resolvedModel.doStream = originalDoStream;
11844
+ }
11845
+ delete resolvedModel[AUTO_PATCHED_MODEL];
11846
+ });
11847
+ };
11848
+ const patchTool = (tool, name) => {
11849
+ if (tool == null || typeof tool !== "object" || !("execute" in tool) || typeof tool.execute !== "function" || patchedTools.has(tool) || tool[AUTO_PATCHED_TOOL]) {
11850
+ return;
11851
+ }
11852
+ patchedTools.add(tool);
11853
+ tool[AUTO_PATCHED_TOOL] = true;
11854
+ const originalExecute = tool.execute;
11855
+ tool.execute = function executePatched(...args) {
11856
+ const result = Reflect.apply(originalExecute, this, args);
11857
+ if (isAsyncGenerator(result)) {
11858
+ return (async function* () {
11859
+ const span = parentSpan.startSpan({
11860
+ name,
11861
+ spanAttributes: {
11862
+ type: "tool" /* TOOL */
11863
+ }
11864
+ });
11865
+ span.log({ input: args.length === 1 ? args[0] : args });
11866
+ try {
11867
+ let lastValue;
11868
+ for await (const value of result) {
11869
+ lastValue = value;
11870
+ yield value;
11871
+ }
11872
+ span.log({ output: lastValue });
11873
+ } catch (error) {
11874
+ span.log({
11875
+ error: error instanceof Error ? error.message : String(error)
11876
+ });
11877
+ throw error;
11878
+ } finally {
11879
+ span.end();
11880
+ }
11881
+ })();
11882
+ }
11883
+ return parentSpan.traced(
11884
+ async (span) => {
11885
+ span.log({ input: args.length === 1 ? args[0] : args });
11886
+ const awaitedResult = await result;
11887
+ span.log({ output: awaitedResult });
11888
+ return awaitedResult;
11889
+ },
11890
+ {
11891
+ name,
11892
+ spanAttributes: {
11893
+ type: "tool" /* TOOL */
11894
+ }
11895
+ }
11896
+ );
11897
+ };
11898
+ cleanup.push(() => {
11899
+ tool.execute = originalExecute;
11900
+ delete tool[AUTO_PATCHED_TOOL];
11901
+ });
11902
+ };
11903
+ const patchTools = (tools) => {
11904
+ if (!tools) {
11905
+ return;
11906
+ }
11907
+ const inferName = (tool, fallback2) => tool && (tool.name || tool.toolName || tool.id) || fallback2;
11908
+ if (Array.isArray(tools)) {
11909
+ tools.forEach(
11910
+ (tool, index) => patchTool(tool, inferName(tool, `tool[${index}]`))
11911
+ );
11912
+ return;
11913
+ }
11914
+ for (const [key, tool] of Object.entries(tools)) {
11915
+ patchTool(tool, key);
11916
+ }
11917
+ };
11918
+ if (params && typeof params === "object") {
11919
+ patchModel(params.model);
11920
+ patchTools(params.tools);
11921
+ }
11922
+ if (self && typeof self === "object") {
11923
+ const selfRecord = self;
11924
+ if (selfRecord.model !== void 0) {
11925
+ patchModel(selfRecord.model);
11926
+ }
11927
+ if (selfRecord.settings && typeof selfRecord.settings === "object") {
11928
+ if (selfRecord.settings.model !== void 0) {
11929
+ patchModel(selfRecord.settings.model);
11930
+ }
11931
+ if (selfRecord.settings.tools !== void 0) {
11932
+ patchTools(selfRecord.settings.tools);
11933
+ }
11934
+ }
11935
+ }
11936
+ return {
11937
+ cleanup: cleanup.length > 0 ? () => {
11938
+ while (cleanup.length > 0) {
11939
+ cleanup.pop()?.();
11940
+ }
11941
+ } : void 0,
11942
+ modelWrapped
11943
+ };
11944
+ }
11945
+ function finalizeAISDKChildTracing(event) {
11946
+ const cleanup = event?.__braintrust_ai_sdk_cleanup;
11947
+ if (event && typeof cleanup === "function") {
11948
+ cleanup();
11949
+ delete event.__braintrust_ai_sdk_cleanup;
11950
+ }
11951
+ }
11952
+ function patchAISDKStreamingResult(args) {
11953
+ const { denyOutputPaths, endEvent, result, span, startTime } = args;
11954
+ if (!result || typeof result !== "object") {
11955
+ return false;
11956
+ }
11957
+ const resultRecord = result;
11958
+ if (!isReadableStreamLike(resultRecord.baseStream)) {
11959
+ return false;
11960
+ }
11961
+ let firstChunkTime;
11962
+ const wrappedBaseStream = resultRecord.baseStream.pipeThrough(
11963
+ new TransformStream({
11964
+ transform(chunk, controller) {
11965
+ if (firstChunkTime === void 0) {
11966
+ firstChunkTime = getCurrentUnixTimestamp();
11967
+ }
11968
+ controller.enqueue(chunk);
11969
+ },
11970
+ async flush() {
11971
+ const metrics = extractTopLevelAISDKMetrics(result, endEvent);
11972
+ if (metrics.time_to_first_token === void 0 && firstChunkTime !== void 0) {
11973
+ metrics.time_to_first_token = firstChunkTime - startTime;
11974
+ }
11975
+ const output = await processAISDKStreamingOutput(
11976
+ result,
11977
+ denyOutputPaths
11978
+ );
11979
+ const metadata = buildResolvedMetadataPayload(result).metadata;
11980
+ span.log({
11981
+ output,
11982
+ ...metadata ? { metadata } : {},
11983
+ metrics
11984
+ });
11985
+ finalizeAISDKChildTracing(endEvent);
11986
+ span.end();
11987
+ }
11988
+ })
11989
+ );
11990
+ Object.defineProperty(resultRecord, "baseStream", {
11991
+ configurable: true,
11992
+ enumerable: true,
11993
+ value: wrappedBaseStream,
11994
+ writable: true
11995
+ });
11996
+ return true;
11997
+ }
11998
+ function isReadableStreamLike(value) {
11999
+ return value != null && typeof value === "object" && typeof value.pipeThrough === "function";
12000
+ }
12001
+ async function processAISDKStreamingOutput(result, denyOutputPaths) {
12002
+ const output = processAISDKOutput(result, denyOutputPaths);
12003
+ if (!output || typeof output !== "object") {
12004
+ return output;
12005
+ }
12006
+ const outputRecord = output;
12007
+ try {
12008
+ if ("text" in result && typeof result.text === "string") {
12009
+ outputRecord.text = result.text;
12010
+ }
12011
+ } catch {
12012
+ }
12013
+ try {
12014
+ if ("object" in result) {
12015
+ const resolvedObject = await Promise.resolve(result.object);
12016
+ if (resolvedObject !== void 0) {
12017
+ outputRecord.object = resolvedObject;
12018
+ }
12019
+ }
12020
+ } catch {
12021
+ }
12022
+ return outputRecord;
12023
+ }
12024
+ function buildAISDKChildMetadata(model) {
12025
+ const { model: modelId, provider } = serializeModelWithProvider(model);
12026
+ return {
12027
+ ...modelId ? { model: modelId } : {},
12028
+ ...provider ? { provider } : {},
12029
+ braintrust: {
12030
+ integration_name: "ai-sdk",
12031
+ sdk_language: "typescript"
12032
+ }
12033
+ };
12034
+ }
12035
+ function buildResolvedMetadataPayload(result) {
12036
+ const gatewayInfo = extractGatewayRoutingInfo(result);
12037
+ const metadata = {};
12038
+ if (gatewayInfo?.provider) {
12039
+ metadata.provider = gatewayInfo.provider;
12040
+ }
12041
+ if (gatewayInfo?.model) {
12042
+ metadata.model = gatewayInfo.model;
12043
+ }
12044
+ if (result.finishReason !== void 0) {
12045
+ metadata.finish_reason = result.finishReason;
12046
+ }
12047
+ return Object.keys(metadata).length > 0 ? { metadata } : {};
12048
+ }
12049
+ function resolveAISDKModel(model) {
12050
+ if (typeof model !== "string") {
12051
+ return model;
12052
+ }
12053
+ const provider = globalThis.AI_SDK_DEFAULT_PROVIDER ?? null;
12054
+ if (provider && typeof provider.languageModel === "function") {
12055
+ return provider.languageModel(model);
12056
+ }
12057
+ return model;
12058
+ }
12059
+ function extractTextDelta(chunk) {
12060
+ if (typeof chunk.textDelta === "string") return chunk.textDelta;
12061
+ if (typeof chunk.delta === "string") return chunk.delta;
12062
+ if (typeof chunk.text === "string") return chunk.text;
12063
+ if (typeof chunk.content === "string") return chunk.content;
12064
+ return "";
12065
+ }
12066
+ function isAsyncGenerator(value) {
12067
+ return value != null && typeof value === "object" && typeof value[Symbol.asyncIterator] === "function" && typeof value.next === "function" && typeof value.return === "function" && typeof value.throw === "function";
12068
+ }
11353
12069
  function processAISDKOutput(output, denyOutputPaths) {
11354
12070
  if (!output) return output;
11355
- const getterValues = extractGetterValues(output);
11356
- const merged = { ...output, ...getterValues };
11357
- return omit(merged, denyOutputPaths);
12071
+ const merged = extractSerializableOutputFields(output);
12072
+ return normalizeAISDKLoggedOutput(omit(merged, denyOutputPaths));
11358
12073
  }
11359
12074
  function extractTokenMetrics(result) {
11360
12075
  const metrics = {};
@@ -11404,12 +12119,14 @@ function extractTokenMetrics(result) {
11404
12119
  }
11405
12120
  return metrics;
11406
12121
  }
11407
- function aggregateAISDKChunks(chunks) {
12122
+ function aggregateAISDKChunks(chunks, _result, endEvent) {
11408
12123
  const lastChunk = chunks[chunks.length - 1];
11409
12124
  const output = {};
11410
12125
  let metrics = {};
12126
+ let metadata;
11411
12127
  if (lastChunk) {
11412
- metrics = extractTokenMetrics(lastChunk);
12128
+ metrics = hasModelChildTracing(endEvent) ? {} : extractTokenMetrics(lastChunk);
12129
+ metadata = buildResolvedMetadataPayload(lastChunk).metadata;
11413
12130
  if (lastChunk.text !== void 0) {
11414
12131
  output.text = lastChunk.text;
11415
12132
  }
@@ -11423,7 +12140,8 @@ function aggregateAISDKChunks(chunks) {
11423
12140
  output.toolCalls = lastChunk.toolCalls;
11424
12141
  }
11425
12142
  }
11426
- return { output, metrics };
12143
+ finalizeAISDKChildTracing(endEvent);
12144
+ return { output, metrics, metadata };
11427
12145
  }
11428
12146
  function extractGetterValues(obj) {
11429
12147
  const getterValues = {};
@@ -11443,7 +12161,7 @@ function extractGetterValues(obj) {
11443
12161
  ];
11444
12162
  for (const name of getterNames) {
11445
12163
  try {
11446
- if (obj && name in obj && typeof obj[name] !== "function") {
12164
+ if (obj && name in obj && isSerializableOutputValue(obj[name])) {
11447
12165
  getterValues[name] = obj[name];
11448
12166
  }
11449
12167
  } catch {
@@ -11451,6 +12169,47 @@ function extractGetterValues(obj) {
11451
12169
  }
11452
12170
  return getterValues;
11453
12171
  }
12172
+ function extractSerializableOutputFields(output) {
12173
+ const serialized = {};
12174
+ const directFieldNames = [
12175
+ "steps",
12176
+ "request",
12177
+ "responseMessages",
12178
+ "warnings",
12179
+ "rawResponse",
12180
+ "response",
12181
+ "providerMetadata",
12182
+ "experimental_providerMetadata"
12183
+ ];
12184
+ for (const name of directFieldNames) {
12185
+ try {
12186
+ const value = output?.[name];
12187
+ if (isSerializableOutputValue(value)) {
12188
+ serialized[name] = value;
12189
+ }
12190
+ } catch {
12191
+ }
12192
+ }
12193
+ return {
12194
+ ...serialized,
12195
+ ...extractGetterValues(output)
12196
+ };
12197
+ }
12198
+ function isSerializableOutputValue(value) {
12199
+ if (typeof value === "function") {
12200
+ return false;
12201
+ }
12202
+ if (value && typeof value === "object" && typeof value.then === "function") {
12203
+ return false;
12204
+ }
12205
+ if (value && typeof value === "object" && typeof value.getReader === "function") {
12206
+ return false;
12207
+ }
12208
+ if (value && typeof value === "object" && typeof value[Symbol.asyncIterator] === "function") {
12209
+ return false;
12210
+ }
12211
+ return true;
12212
+ }
11454
12213
  function serializeModelWithProvider(model) {
11455
12214
  const modelId = typeof model === "string" ? model : model?.modelId;
11456
12215
  const explicitProvider = typeof model === "object" ? model?.provider : void 0;
@@ -11476,6 +12235,25 @@ function parseGatewayModelString(modelString) {
11476
12235
  }
11477
12236
  return { model: modelString };
11478
12237
  }
12238
+ function extractGatewayRoutingInfo(result) {
12239
+ if (result?.steps && Array.isArray(result.steps) && result.steps.length > 0) {
12240
+ const routing2 = result.steps[0]?.providerMetadata?.gateway?.routing;
12241
+ if (routing2) {
12242
+ return {
12243
+ provider: routing2.resolvedProvider || routing2.finalProvider,
12244
+ model: routing2.resolvedProviderApiModelId
12245
+ };
12246
+ }
12247
+ }
12248
+ const routing = result?.providerMetadata?.gateway?.routing;
12249
+ if (routing) {
12250
+ return {
12251
+ provider: routing.resolvedProvider || routing.finalProvider,
12252
+ model: routing.resolvedProviderApiModelId
12253
+ };
12254
+ }
12255
+ return null;
12256
+ }
11479
12257
  function extractCostFromResult(result) {
11480
12258
  if (result?.steps && Array.isArray(result.steps) && result.steps.length > 0) {
11481
12259
  let totalCost = 0;
@@ -12153,57 +12931,1086 @@ function aggregateGenerateContentChunks(chunks, startTime) {
12153
12931
  }
12154
12932
  }
12155
12933
  }
12156
- }
12934
+ }
12935
+ }
12936
+ const output = {};
12937
+ const parts = [];
12938
+ if (thoughtText) {
12939
+ parts.push({ text: thoughtText, thought: true });
12940
+ }
12941
+ if (text) {
12942
+ parts.push({ text });
12943
+ }
12944
+ parts.push(...otherParts);
12945
+ if (parts.length > 0 && lastResponse?.candidates) {
12946
+ const candidates = [];
12947
+ for (const candidate of lastResponse.candidates) {
12948
+ const candidateDict = {
12949
+ content: {
12950
+ parts,
12951
+ role: "model"
12952
+ }
12953
+ };
12954
+ if (candidate.finishReason !== void 0) {
12955
+ candidateDict.finishReason = candidate.finishReason;
12956
+ }
12957
+ if (candidate.safetyRatings) {
12958
+ candidateDict.safetyRatings = candidate.safetyRatings;
12959
+ }
12960
+ candidates.push(candidateDict);
12961
+ }
12962
+ output.candidates = candidates;
12963
+ }
12964
+ if (usageMetadata) {
12965
+ output.usageMetadata = usageMetadata;
12966
+ populateUsageMetrics(metrics, usageMetadata);
12967
+ }
12968
+ if (text) {
12969
+ output.text = text;
12970
+ }
12971
+ return { output, metrics };
12972
+ }
12973
+ function tryToDict(obj) {
12974
+ if (obj === null || obj === void 0) {
12975
+ return null;
12976
+ }
12977
+ if (typeof obj === "object") {
12978
+ if ("toJSON" in obj && // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
12979
+ typeof obj.toJSON === "function") {
12980
+ return obj.toJSON();
12981
+ }
12982
+ return obj;
12983
+ }
12984
+ return null;
12985
+ }
12986
+
12987
+ // src/instrumentation/plugins/openrouter-channels.ts
12988
+ var openRouterChannels = defineChannels("@openrouter/sdk", {
12989
+ chatSend: channel({
12990
+ channelName: "chat.send",
12991
+ kind: "async"
12992
+ }),
12993
+ embeddingsGenerate: channel({
12994
+ channelName: "embeddings.generate",
12995
+ kind: "async"
12996
+ }),
12997
+ betaResponsesSend: channel({
12998
+ channelName: "beta.responses.send",
12999
+ kind: "async"
13000
+ }),
13001
+ callModel: channel({
13002
+ channelName: "callModel",
13003
+ kind: "sync-stream"
13004
+ }),
13005
+ toolExecute: channel({
13006
+ channelName: "tool.execute",
13007
+ kind: "async"
13008
+ })
13009
+ });
13010
+
13011
+ // src/openrouter-utils.ts
13012
+ var TOKEN_NAME_MAP2 = {
13013
+ promptTokens: "prompt_tokens",
13014
+ inputTokens: "prompt_tokens",
13015
+ completionTokens: "completion_tokens",
13016
+ outputTokens: "completion_tokens",
13017
+ totalTokens: "tokens",
13018
+ prompt_tokens: "prompt_tokens",
13019
+ input_tokens: "prompt_tokens",
13020
+ completion_tokens: "completion_tokens",
13021
+ output_tokens: "completion_tokens",
13022
+ total_tokens: "tokens"
13023
+ };
13024
+ var TOKEN_DETAIL_PREFIX_MAP = {
13025
+ promptTokensDetails: "prompt",
13026
+ inputTokensDetails: "prompt",
13027
+ completionTokensDetails: "completion",
13028
+ outputTokensDetails: "completion",
13029
+ costDetails: "cost",
13030
+ prompt_tokens_details: "prompt",
13031
+ input_tokens_details: "prompt",
13032
+ completion_tokens_details: "completion",
13033
+ output_tokens_details: "completion",
13034
+ cost_details: "cost"
13035
+ };
13036
+ function camelToSnake(value) {
13037
+ return value.replace(/[A-Z]/g, (match) => `_${match.toLowerCase()}`);
13038
+ }
13039
+ function parseOpenRouterMetricsFromUsage(usage) {
13040
+ if (!isObject(usage)) {
13041
+ return {};
13042
+ }
13043
+ const metrics = {};
13044
+ for (const [name, value] of Object.entries(usage)) {
13045
+ if (typeof value === "number") {
13046
+ metrics[TOKEN_NAME_MAP2[name] || camelToSnake(name)] = value;
13047
+ continue;
13048
+ }
13049
+ if (!isObject(value)) {
13050
+ continue;
13051
+ }
13052
+ const prefix = TOKEN_DETAIL_PREFIX_MAP[name];
13053
+ if (!prefix) {
13054
+ continue;
13055
+ }
13056
+ for (const [nestedName, nestedValue] of Object.entries(value)) {
13057
+ if (typeof nestedValue !== "number") {
13058
+ continue;
13059
+ }
13060
+ metrics[`${prefix}_${camelToSnake(nestedName)}`] = nestedValue;
13061
+ }
13062
+ }
13063
+ return metrics;
13064
+ }
13065
+ function extractOpenRouterUsageMetadata(usage) {
13066
+ if (!isObject(usage)) {
13067
+ return void 0;
13068
+ }
13069
+ const metadata = {};
13070
+ if (typeof usage.isByok === "boolean") {
13071
+ metadata.is_byok = usage.isByok;
13072
+ } else if (typeof usage.is_byok === "boolean") {
13073
+ metadata.is_byok = usage.is_byok;
13074
+ }
13075
+ return Object.keys(metadata).length > 0 ? metadata : void 0;
13076
+ }
13077
+
13078
+ // src/openrouter-logging.ts
13079
+ var OMITTED_OPENROUTER_KEYS = /* @__PURE__ */ new Set([
13080
+ "execute",
13081
+ "render",
13082
+ "nextTurnParams",
13083
+ "requireApproval"
13084
+ ]);
13085
+ function parseOpenRouterModelString(model) {
13086
+ if (typeof model !== "string") {
13087
+ return { model };
13088
+ }
13089
+ const slashIndex = model.indexOf("/");
13090
+ if (slashIndex > 0 && slashIndex < model.length - 1) {
13091
+ return {
13092
+ provider: model.substring(0, slashIndex),
13093
+ model: model.substring(slashIndex + 1)
13094
+ };
13095
+ }
13096
+ return { model };
13097
+ }
13098
+ function isZodSchema2(value) {
13099
+ return value != null && typeof value === "object" && "_def" in value && typeof value._def === "object";
13100
+ }
13101
+ function serializeZodSchema2(schema) {
13102
+ try {
13103
+ return zodToJsonSchema(schema);
13104
+ } catch {
13105
+ return {
13106
+ type: "object",
13107
+ description: "Zod schema (conversion failed)"
13108
+ };
13109
+ }
13110
+ }
13111
+ function serializeOpenRouterTool(tool) {
13112
+ if (!isObject(tool)) {
13113
+ return tool;
13114
+ }
13115
+ const serialized = {};
13116
+ for (const [key, value] of Object.entries(tool)) {
13117
+ if (OMITTED_OPENROUTER_KEYS.has(key)) {
13118
+ continue;
13119
+ }
13120
+ if (key === "function" && isObject(value)) {
13121
+ serialized.function = sanitizeOpenRouterLoggedValue(value);
13122
+ continue;
13123
+ }
13124
+ serialized[key] = sanitizeOpenRouterLoggedValue(value);
13125
+ }
13126
+ return serialized;
13127
+ }
13128
+ function serializeOpenRouterToolsForLogging(tools) {
13129
+ if (!Array.isArray(tools)) {
13130
+ return void 0;
13131
+ }
13132
+ return tools.map((tool) => serializeOpenRouterTool(tool));
13133
+ }
13134
+ function sanitizeOpenRouterLoggedValue(value) {
13135
+ if (isZodSchema2(value)) {
13136
+ return serializeZodSchema2(value);
13137
+ }
13138
+ if (typeof value === "function") {
13139
+ return "[Function]";
13140
+ }
13141
+ if (Array.isArray(value)) {
13142
+ return value.map((entry) => sanitizeOpenRouterLoggedValue(entry));
13143
+ }
13144
+ if (!isObject(value)) {
13145
+ return value;
13146
+ }
13147
+ const sanitized = {};
13148
+ for (const [key, entry] of Object.entries(value)) {
13149
+ if (OMITTED_OPENROUTER_KEYS.has(key)) {
13150
+ continue;
13151
+ }
13152
+ if (key === "tools" && Array.isArray(entry)) {
13153
+ sanitized.tools = serializeOpenRouterToolsForLogging(entry);
13154
+ continue;
13155
+ }
13156
+ sanitized[key] = sanitizeOpenRouterLoggedValue(entry);
13157
+ }
13158
+ return sanitized;
13159
+ }
13160
+ function buildOpenRouterMetadata(metadata, httpReferer, xTitle) {
13161
+ const sanitized = sanitizeOpenRouterLoggedValue(metadata);
13162
+ const metadataRecord = isObject(sanitized) ? sanitized : {};
13163
+ const { model, provider: providerRouting, ...rest } = metadataRecord;
13164
+ const normalizedModel = parseOpenRouterModelString(model);
13165
+ return {
13166
+ ...rest,
13167
+ ...normalizedModel.model !== void 0 ? { model: normalizedModel.model } : {},
13168
+ ...providerRouting !== void 0 ? { providerRouting } : {},
13169
+ ...httpReferer !== void 0 ? { httpReferer } : {},
13170
+ ...xTitle !== void 0 ? { xTitle } : {},
13171
+ provider: normalizedModel.provider || "openrouter"
13172
+ };
13173
+ }
13174
+ function buildOpenRouterEmbeddingMetadata(metadata, httpReferer, xTitle) {
13175
+ const normalized = buildOpenRouterMetadata(metadata, httpReferer, xTitle);
13176
+ return typeof normalized.model === "string" ? {
13177
+ ...normalized,
13178
+ embedding_model: normalized.model
13179
+ } : normalized;
13180
+ }
13181
+ function extractOpenRouterCallModelInput(request) {
13182
+ return isObject(request) && "input" in request ? sanitizeOpenRouterLoggedValue(request.input) : void 0;
13183
+ }
13184
+ function extractOpenRouterCallModelMetadata(request) {
13185
+ if (!isObject(request)) {
13186
+ return { provider: "openrouter" };
13187
+ }
13188
+ const { input: _input, ...metadata } = request;
13189
+ return buildOpenRouterMetadata(metadata, void 0, void 0);
13190
+ }
13191
+ function extractOpenRouterResponseMetadata(result) {
13192
+ if (!isObject(result)) {
13193
+ return void 0;
13194
+ }
13195
+ const { output: _output, data: _data, usage, ...metadata } = result;
13196
+ const sanitized = sanitizeOpenRouterLoggedValue(metadata);
13197
+ const metadataRecord = isObject(sanitized) ? sanitized : {};
13198
+ const { model, provider, ...rest } = metadataRecord;
13199
+ const normalizedModel = parseOpenRouterModelString(model);
13200
+ const normalizedProvider = (typeof provider === "string" ? provider : void 0) || normalizedModel.provider;
13201
+ const usageMetadata = extractOpenRouterUsageMetadata(usage);
13202
+ const combined = {
13203
+ ...rest,
13204
+ ...normalizedModel.model !== void 0 ? { model: normalizedModel.model } : {},
13205
+ ...usageMetadata || {},
13206
+ ...normalizedProvider !== void 0 ? { provider: normalizedProvider } : {}
13207
+ };
13208
+ return Object.keys(combined).length > 0 ? combined : void 0;
13209
+ }
13210
+ function extractOpenRouterResponseOutput(response, fallbackOutput) {
13211
+ if (isObject(response) && "output" in response && response.output !== void 0) {
13212
+ return sanitizeOpenRouterLoggedValue(response.output);
13213
+ }
13214
+ if (fallbackOutput !== void 0) {
13215
+ return sanitizeOpenRouterLoggedValue(fallbackOutput);
13216
+ }
13217
+ return void 0;
13218
+ }
13219
+
13220
+ // src/openrouter-tool-wrapping.ts
13221
+ var OPENROUTER_WRAPPED_TOOL = Symbol("braintrust.openrouter.wrappedTool");
13222
+ var OPENROUTER_WRAPPED_CALL_MODEL_RESULT = Symbol(
13223
+ "braintrust.openrouter.wrappedCallModelResult"
13224
+ );
13225
+ var OPENROUTER_CALL_MODEL_STREAM_METHODS = [
13226
+ "getFullResponsesStream",
13227
+ "getItemsStream",
13228
+ "getNewMessagesStream",
13229
+ "getReasoningStream",
13230
+ "getTextStream",
13231
+ "getToolCallsStream",
13232
+ "getToolStream"
13233
+ ];
13234
+ var OPENROUTER_CALL_MODEL_CONTEXT_METHODS = [
13235
+ "cancel",
13236
+ "getPendingToolCalls",
13237
+ "getState",
13238
+ "getToolCalls",
13239
+ "requiresApproval"
13240
+ ];
13241
+ function startOpenRouterCallModelSpan(request) {
13242
+ return startSpan({
13243
+ name: "openrouter.callModel",
13244
+ spanAttributes: {
13245
+ type: "llm" /* LLM */
13246
+ },
13247
+ event: {
13248
+ input: extractOpenRouterCallModelInput(request),
13249
+ metadata: extractOpenRouterCallModelMetadata(request)
13250
+ }
13251
+ });
13252
+ }
13253
+ function patchOpenRouterCallModelRequestTools(request) {
13254
+ if (!Array.isArray(request.tools) || request.tools.length === 0) {
13255
+ return void 0;
13256
+ }
13257
+ const originalTools = request.tools;
13258
+ const wrappedTools = originalTools.map((tool) => wrapOpenRouterTool(tool));
13259
+ const didPatch = wrappedTools.some(
13260
+ (tool, index) => tool !== originalTools[index]
13261
+ );
13262
+ if (!didPatch) {
13263
+ return void 0;
13264
+ }
13265
+ request.tools = wrappedTools;
13266
+ return () => {
13267
+ request.tools = originalTools;
13268
+ };
13269
+ }
13270
+ function patchOpenRouterCallModelResult(span, result, request) {
13271
+ if (!isObject(result) || isWrappedCallModelResult(result)) {
13272
+ return false;
13273
+ }
13274
+ const resultLike = result;
13275
+ const hasInstrumentableMethod = typeof resultLike.getResponse === "function" || typeof resultLike.getText === "function" || OPENROUTER_CALL_MODEL_STREAM_METHODS.some(
13276
+ (methodName) => typeof resultLike[methodName] === "function"
13277
+ );
13278
+ if (!hasInstrumentableMethod) {
13279
+ return false;
13280
+ }
13281
+ Object.defineProperty(resultLike, OPENROUTER_WRAPPED_CALL_MODEL_RESULT, {
13282
+ value: true,
13283
+ enumerable: false,
13284
+ configurable: false
13285
+ });
13286
+ const originalGetResponse = typeof resultLike.getResponse === "function" ? resultLike.getResponse.bind(resultLike) : void 0;
13287
+ const originalGetInitialResponse = typeof resultLike.getInitialResponse === "function" ? resultLike.getInitialResponse.bind(resultLike) : void 0;
13288
+ const originalMakeFollowupRequest = typeof resultLike.makeFollowupRequest === "function" ? resultLike.makeFollowupRequest.bind(resultLike) : void 0;
13289
+ let ended = false;
13290
+ let tracedTurnCount = 0;
13291
+ const endSpanWithResult = async (response, fallbackOutput) => {
13292
+ if (ended) {
13293
+ return;
13294
+ }
13295
+ ended = true;
13296
+ const finalResponse = getFinalOpenRouterCallModelResponse(
13297
+ resultLike,
13298
+ response
13299
+ );
13300
+ if (finalResponse) {
13301
+ const rounds = getOpenRouterCallModelRounds(resultLike);
13302
+ const metadata = extractOpenRouterCallModelResultMetadata(
13303
+ finalResponse,
13304
+ rounds.length + 1
13305
+ );
13306
+ span.log({
13307
+ output: extractOpenRouterResponseOutput(finalResponse, fallbackOutput),
13308
+ ...metadata ? { metadata } : {},
13309
+ metrics: aggregateOpenRouterCallModelMetrics(rounds, finalResponse)
13310
+ });
13311
+ span.end();
13312
+ return;
13313
+ }
13314
+ if (fallbackOutput !== void 0) {
13315
+ span.log({
13316
+ output: fallbackOutput
13317
+ });
13318
+ }
13319
+ span.end();
13320
+ };
13321
+ const endSpanWithError = (error) => {
13322
+ if (ended) {
13323
+ return;
13324
+ }
13325
+ ended = true;
13326
+ span.log({
13327
+ error: normalizeError(error).message
13328
+ });
13329
+ span.end();
13330
+ };
13331
+ const finalizeFromResponse = async (fallbackOutput) => {
13332
+ if (!originalGetResponse) {
13333
+ await endSpanWithResult(void 0, fallbackOutput);
13334
+ return;
13335
+ }
13336
+ try {
13337
+ await endSpanWithResult(await originalGetResponse(), fallbackOutput);
13338
+ } catch {
13339
+ await endSpanWithResult(void 0, fallbackOutput);
13340
+ }
13341
+ };
13342
+ if (originalGetResponse) {
13343
+ resultLike.getResponse = async (...args) => {
13344
+ return await withCurrent(span, async () => {
13345
+ try {
13346
+ const response = await originalGetResponse(...args);
13347
+ await endSpanWithResult(response);
13348
+ return response;
13349
+ } catch (error) {
13350
+ endSpanWithError(error);
13351
+ throw error;
13352
+ }
13353
+ });
13354
+ };
13355
+ }
13356
+ if (typeof resultLike.getText === "function") {
13357
+ const originalGetText = resultLike.getText.bind(resultLike);
13358
+ resultLike.getText = async (...args) => {
13359
+ return await withCurrent(span, async () => {
13360
+ try {
13361
+ const text = await originalGetText(...args);
13362
+ await finalizeFromResponse(text);
13363
+ return text;
13364
+ } catch (error) {
13365
+ endSpanWithError(error);
13366
+ throw error;
13367
+ }
13368
+ });
13369
+ };
13370
+ }
13371
+ for (const methodName of OPENROUTER_CALL_MODEL_CONTEXT_METHODS) {
13372
+ if (typeof resultLike[methodName] !== "function") {
13373
+ continue;
13374
+ }
13375
+ const originalMethod = resultLike[methodName];
13376
+ resultLike[methodName] = async (...args) => {
13377
+ return await withCurrent(span, async () => {
13378
+ return await originalMethod.apply(resultLike, args);
13379
+ });
13380
+ };
13381
+ }
13382
+ for (const methodName of OPENROUTER_CALL_MODEL_STREAM_METHODS) {
13383
+ if (typeof resultLike[methodName] !== "function") {
13384
+ continue;
13385
+ }
13386
+ const originalMethod = resultLike[methodName];
13387
+ resultLike[methodName] = (...args) => {
13388
+ const stream = withCurrent(
13389
+ span,
13390
+ () => originalMethod.apply(resultLike, args)
13391
+ );
13392
+ if (!isAsyncIterable2(stream)) {
13393
+ return stream;
13394
+ }
13395
+ return wrapAsyncIterableWithSpan({
13396
+ finalize: finalizeFromResponse,
13397
+ iteratorFactory: () => stream[Symbol.asyncIterator](),
13398
+ onError: endSpanWithError,
13399
+ span
13400
+ });
13401
+ };
13402
+ }
13403
+ if (originalGetInitialResponse) {
13404
+ let initialTurnTraced = false;
13405
+ resultLike.getInitialResponse = async (...args) => {
13406
+ if (initialTurnTraced) {
13407
+ return await withCurrent(span, async () => {
13408
+ return await originalGetInitialResponse(...args);
13409
+ });
13410
+ }
13411
+ initialTurnTraced = true;
13412
+ const resolvedRequest = getOpenRouterResolvedRequest(resultLike, request);
13413
+ const childSpan = startOpenRouterCallModelTurnSpan({
13414
+ request: resolvedRequest,
13415
+ step: tracedTurnCount + 1,
13416
+ stepType: tracedTurnCount === 0 ? "initial" : "continue"
13417
+ });
13418
+ return await withCurrent(childSpan, async () => {
13419
+ try {
13420
+ const response = await originalGetInitialResponse(...args);
13421
+ tracedTurnCount++;
13422
+ finishOpenRouterCallModelTurnSpan({
13423
+ response,
13424
+ step: tracedTurnCount,
13425
+ stepType: tracedTurnCount === 1 ? "initial" : "continue",
13426
+ span: childSpan
13427
+ });
13428
+ return response;
13429
+ } catch (error) {
13430
+ childSpan.log({
13431
+ error: normalizeError(error).message
13432
+ });
13433
+ childSpan.end();
13434
+ throw error;
13435
+ }
13436
+ });
13437
+ };
13438
+ }
13439
+ if (originalMakeFollowupRequest) {
13440
+ resultLike.makeFollowupRequest = async (...args) => {
13441
+ const currentResponse = args[0];
13442
+ const toolResults = Array.isArray(args[1]) ? args[1] : [];
13443
+ const resolvedRequest = getOpenRouterResolvedRequest(resultLike, request);
13444
+ const followupRequest = buildOpenRouterFollowupRequest(
13445
+ resolvedRequest,
13446
+ currentResponse,
13447
+ toolResults
13448
+ );
13449
+ const childSpan = startOpenRouterCallModelTurnSpan({
13450
+ request: followupRequest,
13451
+ step: tracedTurnCount + 1,
13452
+ stepType: "continue"
13453
+ });
13454
+ return await withCurrent(childSpan, async () => {
13455
+ try {
13456
+ const response = await originalMakeFollowupRequest(...args);
13457
+ tracedTurnCount++;
13458
+ finishOpenRouterCallModelTurnSpan({
13459
+ response,
13460
+ step: tracedTurnCount,
13461
+ stepType: "continue",
13462
+ span: childSpan
13463
+ });
13464
+ return response;
13465
+ } catch (error) {
13466
+ childSpan.log({
13467
+ error: normalizeError(error).message
13468
+ });
13469
+ childSpan.end();
13470
+ throw error;
13471
+ }
13472
+ });
13473
+ };
13474
+ }
13475
+ return true;
13476
+ }
13477
+ function wrapOpenRouterTool(tool) {
13478
+ if (isWrappedTool(tool) || !tool.function || typeof tool.function !== "object" || typeof tool.function.execute !== "function") {
13479
+ return tool;
13480
+ }
13481
+ const toolName = tool.function.name || "tool";
13482
+ const originalExecute = tool.function.execute;
13483
+ const wrappedTool = {
13484
+ ...tool,
13485
+ function: {
13486
+ ...tool.function,
13487
+ execute(...args) {
13488
+ return traceToolExecution({
13489
+ args,
13490
+ execute: () => Reflect.apply(originalExecute, this, args),
13491
+ toolCallId: getToolCallId(args[1]),
13492
+ toolName
13493
+ });
13494
+ }
13495
+ }
13496
+ };
13497
+ Object.defineProperty(wrappedTool, OPENROUTER_WRAPPED_TOOL, {
13498
+ value: true,
13499
+ enumerable: false,
13500
+ configurable: false
13501
+ });
13502
+ return wrappedTool;
13503
+ }
13504
+ function isWrappedTool(tool) {
13505
+ return Boolean(tool[OPENROUTER_WRAPPED_TOOL]);
13506
+ }
13507
+ function isWrappedCallModelResult(value) {
13508
+ return Boolean(
13509
+ isObject(value) && value[OPENROUTER_WRAPPED_CALL_MODEL_RESULT]
13510
+ );
13511
+ }
13512
+ function traceToolExecution(args) {
13513
+ const tracingChannel2 = openRouterChannels.toolExecute.tracingChannel();
13514
+ const input = args.args.length > 0 ? args.args[0] : void 0;
13515
+ const event = {
13516
+ arguments: [input],
13517
+ span_info: {
13518
+ name: args.toolName
13519
+ },
13520
+ toolCallId: args.toolCallId,
13521
+ toolName: args.toolName
13522
+ };
13523
+ tracingChannel2.start.publish(event);
13524
+ try {
13525
+ const result = args.execute();
13526
+ return publishToolResult(tracingChannel2, event, result);
13527
+ } catch (error) {
13528
+ event.error = normalizeError(error);
13529
+ tracingChannel2.error.publish(event);
13530
+ throw error;
13531
+ }
13532
+ }
13533
+ function publishToolResult(tracingChannel2, event, result) {
13534
+ if (isPromiseLike(result)) {
13535
+ return result.then(
13536
+ (resolved) => {
13537
+ event.result = resolved;
13538
+ tracingChannel2.asyncEnd.publish(event);
13539
+ return resolved;
13540
+ },
13541
+ (error) => {
13542
+ event.error = normalizeError(error);
13543
+ tracingChannel2.error.publish(event);
13544
+ throw error;
13545
+ }
13546
+ );
13547
+ }
13548
+ event.result = result;
13549
+ tracingChannel2.asyncEnd.publish(event);
13550
+ return result;
13551
+ }
13552
+ function getToolCallId(context) {
13553
+ const toolContext = context;
13554
+ return typeof toolContext?.toolCall?.id === "string" ? toolContext.toolCall.id : void 0;
13555
+ }
13556
+ function extractOpenRouterCallModelResultMetadata(response, turnCount) {
13557
+ const combined = {
13558
+ ...extractOpenRouterResponseMetadata(response) || {},
13559
+ ...turnCount !== void 0 ? { turn_count: turnCount } : {}
13560
+ };
13561
+ return Object.keys(combined).length > 0 ? combined : void 0;
13562
+ }
13563
+ function getFinalOpenRouterCallModelResponse(result, response) {
13564
+ if (isObject(response)) {
13565
+ return response;
13566
+ }
13567
+ return isObject(result.finalResponse) ? result.finalResponse : void 0;
13568
+ }
13569
+ function getOpenRouterCallModelRounds(result) {
13570
+ if (!Array.isArray(result.allToolExecutionRounds)) {
13571
+ return [];
13572
+ }
13573
+ return result.allToolExecutionRounds.filter((round) => isObject(round)).map((round) => ({
13574
+ response: isObject(round.response) ? round.response : void 0,
13575
+ round: typeof round.round === "number" ? round.round : void 0,
13576
+ toolResults: Array.isArray(round.toolResults) ? round.toolResults : []
13577
+ })).filter((round) => round.response !== void 0);
13578
+ }
13579
+ function aggregateOpenRouterCallModelMetrics(rounds, finalResponse) {
13580
+ const metrics = {};
13581
+ const responses = [
13582
+ ...rounds.map((round) => round.response).filter(isObject),
13583
+ finalResponse
13584
+ ];
13585
+ for (const response of responses) {
13586
+ const responseMetrics = parseOpenRouterMetricsFromUsage(response.usage);
13587
+ for (const [name, value] of Object.entries(responseMetrics)) {
13588
+ metrics[name] = (metrics[name] || 0) + value;
13589
+ }
13590
+ }
13591
+ return metrics;
13592
+ }
13593
+ function buildNextOpenRouterCallModelInput(currentInput, response, toolResults) {
13594
+ const normalizedInput = Array.isArray(currentInput) ? [...currentInput] : currentInput === void 0 ? [] : [currentInput];
13595
+ const responseOutput = Array.isArray(response.output) ? response.output : response.output === void 0 ? [] : [response.output];
13596
+ return [...normalizedInput, ...responseOutput, ...toolResults].map(
13597
+ (entry) => sanitizeOpenRouterLoggedValue(entry)
13598
+ );
13599
+ }
13600
+ function startOpenRouterCallModelTurnSpan(args) {
13601
+ const requestRecord = isObject(args.request) ? args.request : void 0;
13602
+ const metadata = requestRecord ? extractOpenRouterCallModelMetadata(requestRecord) : { provider: "openrouter" };
13603
+ if (isObject(metadata) && "tools" in metadata) {
13604
+ delete metadata.tools;
13605
+ }
13606
+ return startSpan({
13607
+ name: "openrouter.beta.responses.send",
13608
+ spanAttributes: {
13609
+ type: "llm" /* LLM */
13610
+ },
13611
+ event: {
13612
+ input: requestRecord ? extractOpenRouterCallModelInput(requestRecord) : void 0,
13613
+ metadata: {
13614
+ ...metadata,
13615
+ step: args.step,
13616
+ step_type: args.stepType
13617
+ }
13618
+ }
13619
+ });
13620
+ }
13621
+ function finishOpenRouterCallModelTurnSpan(args) {
13622
+ if (!isObject(args.response)) {
13623
+ args.span.end();
13624
+ return;
13625
+ }
13626
+ args.span.log({
13627
+ output: extractOpenRouterResponseOutput(args.response),
13628
+ ...extractOpenRouterResponseMetadata(args.response) ? {
13629
+ metadata: {
13630
+ ...extractOpenRouterResponseMetadata(args.response),
13631
+ ...args.step !== void 0 ? { step: args.step } : {},
13632
+ ...args.stepType ? { step_type: args.stepType } : {}
13633
+ }
13634
+ } : {},
13635
+ metrics: parseOpenRouterMetricsFromUsage(args.response.usage)
13636
+ });
13637
+ args.span.end();
13638
+ }
13639
+ function getOpenRouterResolvedRequest(result, request) {
13640
+ if (isObject(result.resolvedRequest)) {
13641
+ return result.resolvedRequest;
13642
+ }
13643
+ return request;
13644
+ }
13645
+ function buildOpenRouterFollowupRequest(request, currentResponse, toolResults) {
13646
+ if (!request) {
13647
+ return void 0;
13648
+ }
13649
+ return {
13650
+ ...request,
13651
+ input: buildNextOpenRouterCallModelInput(
13652
+ extractOpenRouterCallModelInput(request),
13653
+ isObject(currentResponse) ? currentResponse : {},
13654
+ toolResults
13655
+ ),
13656
+ stream: false
13657
+ };
13658
+ }
13659
+ function wrapAsyncIterableWithSpan(args) {
13660
+ return {
13661
+ [Symbol.asyncIterator]() {
13662
+ const iterator = args.iteratorFactory();
13663
+ return {
13664
+ next(value) {
13665
+ return withCurrent(
13666
+ args.span,
13667
+ () => value === void 0 ? iterator.next() : iterator.next(value)
13668
+ ).then(
13669
+ async (result) => {
13670
+ if (result.done) {
13671
+ await args.finalize();
13672
+ }
13673
+ return result;
13674
+ },
13675
+ (error) => {
13676
+ args.onError(error);
13677
+ throw error;
13678
+ }
13679
+ );
13680
+ },
13681
+ return(value) {
13682
+ if (typeof iterator.return !== "function") {
13683
+ return args.finalize().then(() => ({
13684
+ done: true,
13685
+ value
13686
+ }));
13687
+ }
13688
+ return withCurrent(args.span, () => iterator.return(value)).then(
13689
+ async (result) => {
13690
+ await args.finalize();
13691
+ return result;
13692
+ },
13693
+ (error) => {
13694
+ args.onError(error);
13695
+ throw error;
13696
+ }
13697
+ );
13698
+ },
13699
+ throw(error) {
13700
+ args.onError(error);
13701
+ if (typeof iterator.throw !== "function") {
13702
+ return Promise.reject(error);
13703
+ }
13704
+ return withCurrent(args.span, () => iterator.throw(error));
13705
+ },
13706
+ [Symbol.asyncIterator]() {
13707
+ return this;
13708
+ }
13709
+ };
13710
+ }
13711
+ };
13712
+ }
13713
+ function isAsyncIterable2(value) {
13714
+ return !!value && (typeof value === "object" || typeof value === "function") && Symbol.asyncIterator in value && typeof value[Symbol.asyncIterator] === "function";
13715
+ }
13716
+ function isPromiseLike(value) {
13717
+ return !!value && (typeof value === "object" || typeof value === "function") && "then" in value && typeof value.then === "function";
13718
+ }
13719
+ function normalizeError(error) {
13720
+ return error instanceof Error ? error : new Error(String(error));
13721
+ }
13722
+
13723
+ // src/instrumentation/plugins/openrouter-plugin.ts
13724
+ var OpenRouterPlugin = class extends BasePlugin {
13725
+ onEnable() {
13726
+ this.subscribeToOpenRouterChannels();
13727
+ }
13728
+ onDisable() {
13729
+ this.unsubscribers = unsubscribeAll(this.unsubscribers);
13730
+ }
13731
+ subscribeToOpenRouterChannels() {
13732
+ this.unsubscribers.push(
13733
+ traceStreamingChannel(openRouterChannels.chatSend, {
13734
+ name: "openrouter.chat.send",
13735
+ type: "llm" /* LLM */,
13736
+ extractInput: (args) => {
13737
+ const request = getOpenRouterRequestArg(args);
13738
+ const chatGenerationParams = isObject(request?.chatGenerationParams) ? request.chatGenerationParams : {};
13739
+ const httpReferer = request?.httpReferer;
13740
+ const xTitle = request?.xTitle;
13741
+ const { messages, ...metadata } = chatGenerationParams;
13742
+ return {
13743
+ input: messages,
13744
+ metadata: buildOpenRouterMetadata(metadata, httpReferer, xTitle)
13745
+ };
13746
+ },
13747
+ extractOutput: (result) => {
13748
+ return isObject(result) ? result.choices : void 0;
13749
+ },
13750
+ extractMetrics: (result, startTime) => {
13751
+ const metrics = parseOpenRouterMetricsFromUsage(result?.usage);
13752
+ if (startTime) {
13753
+ metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
13754
+ }
13755
+ return metrics;
13756
+ },
13757
+ aggregateChunks: aggregateOpenRouterChatChunks
13758
+ })
13759
+ );
13760
+ this.unsubscribers.push(
13761
+ traceAsyncChannel(openRouterChannels.embeddingsGenerate, {
13762
+ name: "openrouter.embeddings.generate",
13763
+ type: "llm" /* LLM */,
13764
+ extractInput: (args) => {
13765
+ const request = getOpenRouterRequestArg(args);
13766
+ const requestBody = isObject(request?.requestBody) ? request.requestBody : {};
13767
+ const httpReferer = request?.httpReferer;
13768
+ const xTitle = request?.xTitle;
13769
+ const { input, ...metadata } = requestBody;
13770
+ return {
13771
+ input,
13772
+ metadata: buildOpenRouterEmbeddingMetadata(
13773
+ metadata,
13774
+ httpReferer,
13775
+ xTitle
13776
+ )
13777
+ };
13778
+ },
13779
+ extractOutput: (result) => {
13780
+ if (!isObject(result)) {
13781
+ return void 0;
13782
+ }
13783
+ const embedding = result.data?.[0]?.embedding;
13784
+ return Array.isArray(embedding) ? { embedding_length: embedding.length } : void 0;
13785
+ },
13786
+ extractMetadata: (result) => {
13787
+ if (!isObject(result)) {
13788
+ return void 0;
13789
+ }
13790
+ return extractOpenRouterResponseMetadata(result);
13791
+ },
13792
+ extractMetrics: (result) => {
13793
+ return isObject(result) ? parseOpenRouterMetricsFromUsage(result.usage) : {};
13794
+ }
13795
+ })
13796
+ );
13797
+ this.unsubscribers.push(
13798
+ traceStreamingChannel(openRouterChannels.betaResponsesSend, {
13799
+ name: "openrouter.beta.responses.send",
13800
+ type: "llm" /* LLM */,
13801
+ extractInput: (args) => {
13802
+ const request = getOpenRouterRequestArg(args);
13803
+ const openResponsesRequest = isObject(request?.openResponsesRequest) ? request.openResponsesRequest : {};
13804
+ const httpReferer = request?.httpReferer;
13805
+ const xTitle = request?.xTitle;
13806
+ const { input, ...metadata } = openResponsesRequest;
13807
+ return {
13808
+ input,
13809
+ metadata: buildOpenRouterMetadata(metadata, httpReferer, xTitle)
13810
+ };
13811
+ },
13812
+ extractOutput: (result) => extractOpenRouterResponseOutput(result),
13813
+ extractMetadata: (result) => extractOpenRouterResponseMetadata(result),
13814
+ extractMetrics: (result, startTime) => {
13815
+ const metrics = parseOpenRouterMetricsFromUsage(result?.usage);
13816
+ if (startTime) {
13817
+ metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
13818
+ }
13819
+ return metrics;
13820
+ },
13821
+ aggregateChunks: aggregateOpenRouterResponseStreamEvents
13822
+ })
13823
+ );
13824
+ this.unsubscribers.push(
13825
+ traceSyncStreamChannel(openRouterChannels.callModel, {
13826
+ name: "openrouter.callModel",
13827
+ type: "llm" /* LLM */,
13828
+ extractInput: (args) => {
13829
+ const request = getOpenRouterCallModelRequestArg(args);
13830
+ return {
13831
+ input: request ? extractOpenRouterCallModelInput(request) : void 0,
13832
+ metadata: request ? extractOpenRouterCallModelMetadata(request) : { provider: "openrouter" }
13833
+ };
13834
+ },
13835
+ patchResult: ({ endEvent, result, span }) => {
13836
+ return patchOpenRouterCallModelResult(
13837
+ span,
13838
+ result,
13839
+ getOpenRouterCallModelRequestArg(endEvent.arguments)
13840
+ );
13841
+ }
13842
+ })
13843
+ );
13844
+ this.unsubscribers.push(
13845
+ traceStreamingChannel(openRouterChannels.toolExecute, {
13846
+ name: "openrouter.tool",
13847
+ type: "tool" /* TOOL */,
13848
+ extractInput: (args, event) => ({
13849
+ input: args[0],
13850
+ metadata: {
13851
+ provider: "openrouter",
13852
+ tool_name: event.toolName,
13853
+ ...event.toolCallId ? { tool_call_id: event.toolCallId } : {}
13854
+ }
13855
+ }),
13856
+ extractOutput: (result) => result,
13857
+ extractMetrics: () => ({}),
13858
+ aggregateChunks: (chunks) => ({
13859
+ output: chunks.length > 0 ? chunks[chunks.length - 1] : void 0,
13860
+ metrics: {}
13861
+ })
13862
+ })
13863
+ );
13864
+ const callModelChannel = openRouterChannels.callModel.tracingChannel();
13865
+ const callModelHandlers = {
13866
+ start: (event) => {
13867
+ const request = getOpenRouterCallModelRequestArg(event.arguments);
13868
+ if (!request) {
13869
+ return;
13870
+ }
13871
+ patchOpenRouterCallModelRequestTools(request);
13872
+ }
13873
+ };
13874
+ callModelChannel.subscribe(callModelHandlers);
13875
+ this.unsubscribers.push(() => {
13876
+ callModelChannel.unsubscribe(callModelHandlers);
13877
+ });
12157
13878
  }
12158
- const output = {};
12159
- const parts = [];
12160
- if (thoughtText) {
12161
- parts.push({ text: thoughtText, thought: true });
13879
+ };
13880
+ function normalizeArgs(args) {
13881
+ if (Array.isArray(args)) {
13882
+ return args;
12162
13883
  }
12163
- if (text) {
12164
- parts.push({ text });
13884
+ if (isArrayLike(args)) {
13885
+ return Array.from(args);
12165
13886
  }
12166
- parts.push(...otherParts);
12167
- if (parts.length > 0 && lastResponse?.candidates) {
12168
- const candidates = [];
12169
- for (const candidate of lastResponse.candidates) {
12170
- const candidateDict = {
12171
- content: {
12172
- parts,
12173
- role: "model"
12174
- }
12175
- };
12176
- if (candidate.finishReason !== void 0) {
12177
- candidateDict.finishReason = candidate.finishReason;
13887
+ return [args];
13888
+ }
13889
+ function isArrayLike(value) {
13890
+ return isObject(value) && "length" in value && typeof value.length === "number" && Number.isInteger(value.length) && value.length >= 0;
13891
+ }
13892
+ function getOpenRouterRequestArg(args) {
13893
+ const normalizedArgs = normalizeArgs(args);
13894
+ const keyedCandidate = normalizedArgs.find(
13895
+ (arg) => isObject(arg) && ("chatGenerationParams" in arg || "requestBody" in arg || "openResponsesRequest" in arg)
13896
+ );
13897
+ if (isObject(keyedCandidate)) {
13898
+ return keyedCandidate;
13899
+ }
13900
+ const firstObjectArg = normalizedArgs.find((arg) => isObject(arg));
13901
+ return isObject(firstObjectArg) ? firstObjectArg : void 0;
13902
+ }
13903
+ function getOpenRouterCallModelRequestArg(args) {
13904
+ const firstObjectArg = normalizeArgs(args).find((arg) => isObject(arg));
13905
+ return isObject(firstObjectArg) ? firstObjectArg : void 0;
13906
+ }
13907
+ function aggregateOpenRouterChatChunks(chunks) {
13908
+ let role;
13909
+ let content = "";
13910
+ let toolCalls;
13911
+ let finishReason;
13912
+ let metrics = {};
13913
+ for (const chunk of chunks) {
13914
+ metrics = {
13915
+ ...metrics,
13916
+ ...parseOpenRouterMetricsFromUsage(chunk?.usage)
13917
+ };
13918
+ const choice = chunk?.choices?.[0];
13919
+ const delta = choice?.delta;
13920
+ if (!delta) {
13921
+ if (choice?.finish_reason !== void 0) {
13922
+ finishReason = choice.finish_reason;
12178
13923
  }
12179
- if (candidate.safetyRatings) {
12180
- candidateDict.safetyRatings = candidate.safetyRatings;
13924
+ continue;
13925
+ }
13926
+ if (!role && delta.role) {
13927
+ role = delta.role;
13928
+ }
13929
+ if (typeof delta.content === "string") {
13930
+ content += delta.content;
13931
+ }
13932
+ const choiceFinishReason = choice?.finishReason ?? choice?.finish_reason ?? void 0;
13933
+ const deltaFinishReason = delta.finishReason ?? delta.finish_reason ?? void 0;
13934
+ if (choiceFinishReason !== void 0) {
13935
+ finishReason = choiceFinishReason;
13936
+ } else if (deltaFinishReason !== void 0) {
13937
+ finishReason = deltaFinishReason;
13938
+ }
13939
+ const toolCallDeltas = Array.isArray(delta.toolCalls) ? delta.toolCalls : Array.isArray(delta.tool_calls) ? delta.tool_calls : void 0;
13940
+ if (!toolCallDeltas) {
13941
+ continue;
13942
+ }
13943
+ for (const toolDelta of toolCallDeltas) {
13944
+ if (!toolDelta?.function) {
13945
+ continue;
12181
13946
  }
12182
- candidates.push(candidateDict);
13947
+ const toolIndex = toolDelta.index ?? 0;
13948
+ const existingToolCall = toolCalls?.[toolIndex];
13949
+ if (!existingToolCall || toolDelta.id && existingToolCall.id !== void 0 && existingToolCall.id !== toolDelta.id) {
13950
+ const nextToolCalls = [...toolCalls || []];
13951
+ nextToolCalls[toolIndex] = {
13952
+ index: toolIndex,
13953
+ id: toolDelta.id,
13954
+ type: toolDelta.type,
13955
+ function: {
13956
+ name: toolDelta.function.name,
13957
+ arguments: toolDelta.function.arguments || ""
13958
+ }
13959
+ };
13960
+ toolCalls = nextToolCalls;
13961
+ continue;
13962
+ }
13963
+ const current = existingToolCall;
13964
+ if (toolDelta.id && !current.id) {
13965
+ current.id = toolDelta.id;
13966
+ }
13967
+ if (toolDelta.type && !current.type) {
13968
+ current.type = toolDelta.type;
13969
+ }
13970
+ if (toolDelta.function.name && !current.function.name) {
13971
+ current.function.name = toolDelta.function.name;
13972
+ }
13973
+ current.function.arguments += toolDelta.function.arguments || "";
12183
13974
  }
12184
- output.candidates = candidates;
12185
- }
12186
- if (usageMetadata) {
12187
- output.usageMetadata = usageMetadata;
12188
- populateUsageMetrics(metrics, usageMetadata);
12189
- }
12190
- if (text) {
12191
- output.text = text;
12192
13975
  }
12193
- return { output, metrics };
13976
+ return {
13977
+ output: [
13978
+ {
13979
+ index: 0,
13980
+ message: {
13981
+ role,
13982
+ content: content || void 0,
13983
+ ...toolCalls ? { tool_calls: toolCalls } : {}
13984
+ },
13985
+ logprobs: null,
13986
+ finish_reason: finishReason
13987
+ }
13988
+ ],
13989
+ metrics
13990
+ };
12194
13991
  }
12195
- function tryToDict(obj) {
12196
- if (obj === null || obj === void 0) {
12197
- return null;
12198
- }
12199
- if (typeof obj === "object") {
12200
- if ("toJSON" in obj && // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
12201
- typeof obj.toJSON === "function") {
12202
- return obj.toJSON();
13992
+ function aggregateOpenRouterResponseStreamEvents(chunks) {
13993
+ let finalResponse;
13994
+ for (const chunk of chunks) {
13995
+ const response = chunk?.response;
13996
+ if (!response) {
13997
+ continue;
13998
+ }
13999
+ if (chunk.type === "response.completed" || chunk.type === "response.incomplete" || chunk.type === "response.failed") {
14000
+ finalResponse = response;
12203
14001
  }
12204
- return obj;
12205
14002
  }
12206
- return null;
14003
+ if (!finalResponse) {
14004
+ return {
14005
+ output: void 0,
14006
+ metrics: {}
14007
+ };
14008
+ }
14009
+ return {
14010
+ output: extractOpenRouterResponseOutput(finalResponse),
14011
+ metrics: parseOpenRouterMetricsFromUsage(finalResponse.usage),
14012
+ ...extractOpenRouterResponseMetadata(finalResponse) ? { metadata: extractOpenRouterResponseMetadata(finalResponse) } : {}
14013
+ };
12207
14014
  }
12208
14015
 
12209
14016
  // src/instrumentation/braintrust-plugin.ts
@@ -12214,6 +14021,7 @@ var BraintrustPlugin = class extends BasePlugin {
12214
14021
  aiSDKPlugin = null;
12215
14022
  claudeAgentSDKPlugin = null;
12216
14023
  googleGenAIPlugin = null;
14024
+ openRouterPlugin = null;
12217
14025
  constructor(config = {}) {
12218
14026
  super();
12219
14027
  this.config = config;
@@ -12240,6 +14048,10 @@ var BraintrustPlugin = class extends BasePlugin {
12240
14048
  this.googleGenAIPlugin = new GoogleGenAIPlugin();
12241
14049
  this.googleGenAIPlugin.enable();
12242
14050
  }
14051
+ if (integrations.openrouter !== false) {
14052
+ this.openRouterPlugin = new OpenRouterPlugin();
14053
+ this.openRouterPlugin.enable();
14054
+ }
12243
14055
  }
12244
14056
  onDisable() {
12245
14057
  if (this.openaiPlugin) {
@@ -12262,6 +14074,10 @@ var BraintrustPlugin = class extends BasePlugin {
12262
14074
  this.googleGenAIPlugin.disable();
12263
14075
  this.googleGenAIPlugin = null;
12264
14076
  }
14077
+ if (this.openRouterPlugin) {
14078
+ this.openRouterPlugin.disable();
14079
+ this.openRouterPlugin = null;
14080
+ }
12265
14081
  }
12266
14082
  };
12267
14083
 
@@ -12333,7 +14149,8 @@ var PluginRegistry = class {
12333
14149
  vercel: true,
12334
14150
  aisdk: true,
12335
14151
  google: true,
12336
- claudeAgentSDK: true
14152
+ claudeAgentSDK: true,
14153
+ openrouter: true
12337
14154
  };
12338
14155
  }
12339
14156
  /**
@@ -12357,6 +14174,62 @@ function configureInstrumentation(config) {
12357
14174
  registry.configure(config);
12358
14175
  }
12359
14176
 
14177
+ // src/auto-instrumentations/patch-tracing-channel.ts
14178
+ function patchTracingChannel(tracingChannelFn) {
14179
+ const dummyChannel = tracingChannelFn("__braintrust_probe__");
14180
+ const TracingChannel = dummyChannel?.constructor;
14181
+ if (!TracingChannel?.prototype) {
14182
+ return;
14183
+ }
14184
+ if (!Object.getOwnPropertyDescriptor(TracingChannel.prototype, "hasSubscribers")) {
14185
+ Object.defineProperty(TracingChannel.prototype, "hasSubscribers", {
14186
+ configurable: true,
14187
+ enumerable: false,
14188
+ get() {
14189
+ return Boolean(
14190
+ this.start?.hasSubscribers || this.end?.hasSubscribers || this.asyncStart?.hasSubscribers || this.asyncEnd?.hasSubscribers || this.error?.hasSubscribers
14191
+ );
14192
+ }
14193
+ });
14194
+ }
14195
+ if (TracingChannel.prototype.tracePromise) {
14196
+ TracingChannel.prototype.tracePromise = function(fn, context = {}, thisArg, ...args) {
14197
+ const { start, end, asyncStart, asyncEnd, error } = this;
14198
+ function reject2(err) {
14199
+ context.error = err;
14200
+ error?.publish(context);
14201
+ asyncStart?.publish(context);
14202
+ asyncEnd?.publish(context);
14203
+ return Promise.reject(err);
14204
+ }
14205
+ function resolve(result) {
14206
+ context.result = result;
14207
+ asyncStart?.publish(context);
14208
+ asyncEnd?.publish(context);
14209
+ return result;
14210
+ }
14211
+ return start.runStores(context, () => {
14212
+ try {
14213
+ const result = Reflect.apply(fn, thisArg, args);
14214
+ end?.publish(context);
14215
+ if (result && (typeof result === "object" || typeof result === "function") && typeof result.then === "function") {
14216
+ return result.then(resolve, reject2);
14217
+ }
14218
+ context.result = result;
14219
+ asyncStart?.publish(context);
14220
+ asyncEnd?.publish(context);
14221
+ return result;
14222
+ } catch (err) {
14223
+ context.error = err;
14224
+ error?.publish(context);
14225
+ end?.publish(context);
14226
+ throw err;
14227
+ }
14228
+ });
14229
+ };
14230
+ }
14231
+ }
14232
+
12360
14233
  // src/browser/config.ts
12361
14234
  var browserConfigured = false;
12362
14235
  function configureBrowser() {
@@ -12371,6 +14244,7 @@ function configureBrowser() {
12371
14244
  } catch {
12372
14245
  }
12373
14246
  isomorph_default.newTracingChannel = (nameOrChannels) => (0, import_dc_browser.tracingChannel)(nameOrChannels);
14247
+ patchTracingChannel(import_dc_browser.tracingChannel);
12374
14248
  isomorph_default.getEnv = (name) => {
12375
14249
  if (typeof process === "undefined" || typeof process.env === "undefined") {
12376
14250
  return void 0;
@@ -12525,6 +14399,7 @@ __export(exports_exports, {
12525
14399
  wrapMastraAgent: () => wrapMastraAgent,
12526
14400
  wrapOpenAI: () => wrapOpenAI,
12527
14401
  wrapOpenAIv4: () => wrapOpenAIv4,
14402
+ wrapOpenRouter: () => wrapOpenRouter,
12528
14403
  wrapTraced: () => wrapTraced,
12529
14404
  wrapVitest: () => wrapVitest
12530
14405
  });
@@ -12855,7 +14730,7 @@ function wrapOpenAIv4(openai) {
12855
14730
  return baseVal;
12856
14731
  }
12857
14732
  });
12858
- const chatProxy = new Proxy(typedOpenai.chat, {
14733
+ const chatProxy2 = new Proxy(typedOpenai.chat, {
12859
14734
  get(target, name, receiver) {
12860
14735
  if (name === "completions") {
12861
14736
  return completionProxy;
@@ -12865,7 +14740,7 @@ function wrapOpenAIv4(openai) {
12865
14740
  });
12866
14741
  const embeddingProxy = createEndpointProxy(typedOpenai.embeddings, wrapEmbeddings);
12867
14742
  const moderationProxy = createEndpointProxy(typedOpenai.moderations, wrapModerations);
12868
- let betaProxy2;
14743
+ let betaProxy3;
12869
14744
  if (typedOpenai.beta?.chat?.completions?.stream) {
12870
14745
  const betaChatCompletionProxy = new Proxy(
12871
14746
  typedOpenai?.beta?.chat.completions,
@@ -12889,7 +14764,7 @@ function wrapOpenAIv4(openai) {
12889
14764
  return Reflect.get(target, name, receiver);
12890
14765
  }
12891
14766
  });
12892
- betaProxy2 = new Proxy(typedOpenai.beta, {
14767
+ betaProxy3 = new Proxy(typedOpenai.beta, {
12893
14768
  get(target, name, receiver) {
12894
14769
  if (name === "chat") {
12895
14770
  return betaChatProxy;
@@ -12902,7 +14777,7 @@ function wrapOpenAIv4(openai) {
12902
14777
  get(target, name, receiver) {
12903
14778
  switch (name) {
12904
14779
  case "chat":
12905
- return chatProxy;
14780
+ return chatProxy2;
12906
14781
  case "embeddings":
12907
14782
  return embeddingProxy;
12908
14783
  case "moderations":
@@ -12910,8 +14785,8 @@ function wrapOpenAIv4(openai) {
12910
14785
  case "responses":
12911
14786
  return responsesProxy(typedOpenai);
12912
14787
  }
12913
- if (name === "beta" && betaProxy2) {
12914
- return betaProxy2;
14788
+ if (name === "beta" && betaProxy3) {
14789
+ return betaProxy3;
12915
14790
  }
12916
14791
  return Reflect.get(target, name, receiver);
12917
14792
  }
@@ -12994,35 +14869,28 @@ function createEndpointProxy(target, wrapperFn) {
12994
14869
  });
12995
14870
  }
12996
14871
  function wrapApiCreateWithChannel(create, channel2) {
12997
- return async (allParams, options) => {
14872
+ return (allParams, options) => {
12998
14873
  const { span_info, params } = splitSpanInfo(allParams);
12999
- const traceContext = createChannelContext(channel2, params, span_info);
13000
- const { data } = await tracePromiseWithResponse(
13001
- channel2,
13002
- traceContext,
13003
- create(params, options)
13004
- );
13005
- return data;
14874
+ let executionPromise = null;
14875
+ const ensureExecuted = () => {
14876
+ if (!executionPromise) {
14877
+ executionPromise = (async () => {
14878
+ const traceContext = createChannelContext(channel2, params, span_info);
14879
+ return tracePromiseWithResponse(
14880
+ channel2,
14881
+ traceContext,
14882
+ create(params, options)
14883
+ );
14884
+ })();
14885
+ }
14886
+ return executionPromise;
14887
+ };
14888
+ return createLazyAPIPromise(ensureExecuted);
13006
14889
  };
13007
14890
  }
13008
14891
  var wrapEmbeddings = (create) => wrapApiCreateWithChannel(create, openAIChannels.embeddingsCreate);
13009
14892
  var wrapModerations = (create) => wrapApiCreateWithChannel(create, openAIChannels.moderationsCreate);
13010
14893
 
13011
- // src/zod/utils.ts
13012
- var import_zod_to_json_schema = require("zod-to-json-schema");
13013
- var z42 = __toESM(require("zod/v4"));
13014
- function isZodV4(zodObject) {
13015
- return typeof zodObject === "object" && zodObject !== null && "_zod" in zodObject && zodObject._zod !== void 0;
13016
- }
13017
- function zodToJsonSchema(schema) {
13018
- if (isZodV4(schema)) {
13019
- return z42.toJSONSchema(schema, {
13020
- target: "draft-7"
13021
- });
13022
- }
13023
- return (0, import_zod_to_json_schema.zodToJsonSchema)(schema);
13024
- }
13025
-
13026
14894
  // src/wrappers/ai-sdk/ai-sdk.ts
13027
14895
  var DENY_OUTPUT_PATHS = [
13028
14896
  // v3
@@ -13117,9 +14985,11 @@ var wrapAgentGenerate = (generate, instance, options = {}) => {
13117
14985
  return async (params) => makeGenerateTextWrapper(
13118
14986
  `${instance.constructor.name}.generate`,
13119
14987
  options,
13120
- generate.bind(instance)
14988
+ generate.bind(instance),
13121
14989
  // as of v5 this is just streamText under the hood
13122
14990
  // Follows what the AI SDK does under the hood when calling generateText
14991
+ void 0,
14992
+ "function" /* FUNCTION */
13123
14993
  )({ ...instance.settings, ...params });
13124
14994
  };
13125
14995
  var wrapAgentStream = (stream, instance, options = {}) => {
@@ -13128,11 +14998,12 @@ var wrapAgentStream = (stream, instance, options = {}) => {
13128
14998
  options,
13129
14999
  stream.bind(instance),
13130
15000
  // as of v5 this is just streamText under the hood
13131
- void 0
15001
+ void 0,
13132
15002
  // aiSDK not needed since model is already on instance
15003
+ "function" /* FUNCTION */
13133
15004
  )({ ...instance.settings, ...params });
13134
15005
  };
13135
- var makeGenerateTextWrapper = (name, options, generateText, aiSDK) => {
15006
+ var makeGenerateTextWrapper = (name, options, generateText, aiSDK, spanType = "llm" /* LLM */) => {
13136
15007
  const wrapper = async function(allParams) {
13137
15008
  const { span_info, ...params } = allParams;
13138
15009
  const {
@@ -13141,6 +15012,7 @@ var makeGenerateTextWrapper = (name, options, generateText, aiSDK) => {
13141
15012
  spanAttributes: spanInfoAttrs
13142
15013
  } = span_info ?? {};
13143
15014
  const { model, provider } = serializeModelWithProvider2(params.model);
15015
+ const serializedTools = serializeAISDKToolsForLogging(params.tools);
13144
15016
  const processedInput = await processInputAttachments2(params);
13145
15017
  return traced(
13146
15018
  async (span) => {
@@ -13153,7 +15025,7 @@ var makeGenerateTextWrapper = (name, options, generateText, aiSDK) => {
13153
15025
  model: wrappedModel,
13154
15026
  tools: wrapTools(params.tools)
13155
15027
  });
13156
- const gatewayInfo = extractGatewayRoutingInfo(result);
15028
+ const gatewayInfo = extractGatewayRoutingInfo2(result);
13157
15029
  const resolvedMetadata = {};
13158
15030
  if (gatewayInfo?.provider) {
13159
15031
  resolvedMetadata.provider = gatewayInfo.provider;
@@ -13171,7 +15043,7 @@ var makeGenerateTextWrapper = (name, options, generateText, aiSDK) => {
13171
15043
  {
13172
15044
  name: spanName || name,
13173
15045
  spanAttributes: {
13174
- type: "llm" /* LLM */,
15046
+ type: spanType,
13175
15047
  ...spanInfoAttrs
13176
15048
  },
13177
15049
  event: {
@@ -13180,6 +15052,7 @@ var makeGenerateTextWrapper = (name, options, generateText, aiSDK) => {
13180
15052
  ...spanInfoMetadata,
13181
15053
  model,
13182
15054
  ...provider ? { provider } : {},
15055
+ ...serializedTools ? { tools: serializedTools } : {},
13183
15056
  braintrust: {
13184
15057
  integration_name: "ai-sdk",
13185
15058
  sdk_language: "typescript"
@@ -13214,11 +15087,12 @@ var wrapModel = (model, ai) => {
13214
15087
  const originalDoStream = resolvedModel.doStream?.bind(resolvedModel);
13215
15088
  const { model: modelId, provider } = serializeModelWithProvider2(resolvedModel);
13216
15089
  const wrappedDoGenerate = async (options) => {
15090
+ const serializedTools = serializeAISDKToolsForLogging(options.tools);
13217
15091
  const processedInput = await processInputAttachments2(options);
13218
15092
  return traced(
13219
15093
  async (span) => {
13220
15094
  const result = await originalDoGenerate(options);
13221
- const gatewayInfo = extractGatewayRoutingInfo(result);
15095
+ const gatewayInfo = extractGatewayRoutingInfo2(result);
13222
15096
  const resolvedMetadata = {};
13223
15097
  if (gatewayInfo?.provider) {
13224
15098
  resolvedMetadata.provider = gatewayInfo.provider;
@@ -13246,6 +15120,7 @@ var wrapModel = (model, ai) => {
13246
15120
  metadata: {
13247
15121
  model: modelId,
13248
15122
  ...provider ? { provider } : {},
15123
+ ...serializedTools ? { tools: serializedTools } : {},
13249
15124
  braintrust: {
13250
15125
  integration_name: "ai-sdk",
13251
15126
  sdk_language: "typescript"
@@ -13258,6 +15133,7 @@ var wrapModel = (model, ai) => {
13258
15133
  const wrappedDoStream = async (options) => {
13259
15134
  const startTime = Date.now();
13260
15135
  let receivedFirst = false;
15136
+ const serializedTools = serializeAISDKToolsForLogging(options.tools);
13261
15137
  const processedInput = await processInputAttachments2(options);
13262
15138
  const span = startSpan({
13263
15139
  name: "doStream",
@@ -13269,6 +15145,7 @@ var wrapModel = (model, ai) => {
13269
15145
  metadata: {
13270
15146
  model: modelId,
13271
15147
  ...provider ? { provider } : {},
15148
+ ...serializedTools ? { tools: serializedTools } : {},
13272
15149
  braintrust: {
13273
15150
  integration_name: "ai-sdk",
13274
15151
  sdk_language: "typescript"
@@ -13282,7 +15159,7 @@ var wrapModel = (model, ai) => {
13282
15159
  let reasoning = "";
13283
15160
  const toolCalls = [];
13284
15161
  let object = void 0;
13285
- const extractTextDelta = (chunk) => {
15162
+ const extractTextDelta2 = (chunk) => {
13286
15163
  if (typeof chunk.textDelta === "string") return chunk.textDelta;
13287
15164
  if (typeof chunk.delta === "string") return chunk.delta;
13288
15165
  if (typeof chunk.text === "string") return chunk.text;
@@ -13301,7 +15178,7 @@ var wrapModel = (model, ai) => {
13301
15178
  }
13302
15179
  switch (chunk.type) {
13303
15180
  case "text-delta":
13304
- text += extractTextDelta(chunk);
15181
+ text += extractTextDelta2(chunk);
13305
15182
  break;
13306
15183
  case "reasoning-delta":
13307
15184
  if (chunk.delta) {
@@ -13339,7 +15216,7 @@ var wrapModel = (model, ai) => {
13339
15216
  if (object !== void 0) {
13340
15217
  output.object = object;
13341
15218
  }
13342
- const gatewayInfo = extractGatewayRoutingInfo(output);
15219
+ const gatewayInfo = extractGatewayRoutingInfo2(output);
13343
15220
  const resolvedMetadata = {};
13344
15221
  if (gatewayInfo?.provider) {
13345
15222
  resolvedMetadata.provider = gatewayInfo.provider;
@@ -13401,6 +15278,7 @@ var wrapGenerateObject = (generateObject, options = {}, aiSDK) => {
13401
15278
  spanAttributes: spanInfoAttrs
13402
15279
  } = span_info ?? {};
13403
15280
  const { model, provider } = serializeModelWithProvider2(params.model);
15281
+ const serializedTools = serializeAISDKToolsForLogging(params.tools);
13404
15282
  const processedInput = await processInputAttachments2(params);
13405
15283
  return traced(
13406
15284
  async (span) => {
@@ -13414,7 +15292,7 @@ var wrapGenerateObject = (generateObject, options = {}, aiSDK) => {
13414
15292
  tools: wrapTools(params.tools)
13415
15293
  });
13416
15294
  const output = await processOutput(result, options.denyOutputPaths);
13417
- const gatewayInfo = extractGatewayRoutingInfo(result);
15295
+ const gatewayInfo = extractGatewayRoutingInfo2(result);
13418
15296
  const resolvedMetadata = {};
13419
15297
  if (gatewayInfo?.provider) {
13420
15298
  resolvedMetadata.provider = gatewayInfo.provider;
@@ -13441,6 +15319,7 @@ var wrapGenerateObject = (generateObject, options = {}, aiSDK) => {
13441
15319
  ...spanInfoMetadata,
13442
15320
  model,
13443
15321
  ...provider ? { provider } : {},
15322
+ ...serializedTools ? { tools: serializedTools } : {},
13444
15323
  braintrust: {
13445
15324
  integration_name: "ai-sdk",
13446
15325
  sdk_language: "typescript"
@@ -13451,7 +15330,7 @@ var wrapGenerateObject = (generateObject, options = {}, aiSDK) => {
13451
15330
  );
13452
15331
  };
13453
15332
  };
13454
- var makeStreamTextWrapper = (name, options, streamText, aiSDK) => {
15333
+ var makeStreamTextWrapper = (name, options, streamText, aiSDK, spanType = "llm" /* LLM */) => {
13455
15334
  const wrapper = function(allParams) {
13456
15335
  const { span_info, ...params } = allParams;
13457
15336
  const {
@@ -13460,11 +15339,12 @@ var makeStreamTextWrapper = (name, options, streamText, aiSDK) => {
13460
15339
  spanAttributes: spanInfoAttrs
13461
15340
  } = span_info ?? {};
13462
15341
  const { model, provider } = serializeModelWithProvider2(params.model);
15342
+ const serializedTools = serializeAISDKToolsForLogging(params.tools);
13463
15343
  const { input: processedInput, outputPromise } = processInputAttachmentsSync(params);
13464
15344
  const span = startSpan({
13465
15345
  name: spanName || name,
13466
15346
  spanAttributes: {
13467
- type: "llm" /* LLM */,
15347
+ type: spanType,
13468
15348
  ...spanInfoAttrs
13469
15349
  },
13470
15350
  event: {
@@ -13473,6 +15353,7 @@ var makeStreamTextWrapper = (name, options, streamText, aiSDK) => {
13473
15353
  ...spanInfoMetadata,
13474
15354
  model,
13475
15355
  ...provider ? { provider } : {},
15356
+ ...serializedTools ? { tools: serializedTools } : {},
13476
15357
  braintrust: {
13477
15358
  integration_name: "ai-sdk",
13478
15359
  sdk_language: "typescript"
@@ -13512,7 +15393,7 @@ var makeStreamTextWrapper = (name, options, streamText, aiSDK) => {
13512
15393
  },
13513
15394
  onFinish: async (event) => {
13514
15395
  params.onFinish?.(event);
13515
- const gatewayInfo = extractGatewayRoutingInfo(event);
15396
+ const gatewayInfo = extractGatewayRoutingInfo2(event);
13516
15397
  const resolvedMetadata = {};
13517
15398
  if (gatewayInfo?.provider) {
13518
15399
  resolvedMetadata.provider = gatewayInfo.provider;
@@ -13588,6 +15469,7 @@ var wrapStreamObject = (streamObject, options = {}, aiSDK) => {
13588
15469
  spanAttributes: spanInfoAttrs
13589
15470
  } = span_info ?? {};
13590
15471
  const { model, provider } = serializeModelWithProvider2(params.model);
15472
+ const serializedTools = serializeAISDKToolsForLogging(params.tools);
13591
15473
  const { input: processedInput, outputPromise } = processInputAttachmentsSync(params);
13592
15474
  const span = startSpan({
13593
15475
  name: spanName || "streamObject",
@@ -13601,6 +15483,7 @@ var wrapStreamObject = (streamObject, options = {}, aiSDK) => {
13601
15483
  ...spanInfoMetadata,
13602
15484
  model,
13603
15485
  ...provider ? { provider } : {},
15486
+ ...serializedTools ? { tools: serializedTools } : {},
13604
15487
  braintrust: {
13605
15488
  integration_name: "ai-sdk",
13606
15489
  sdk_language: "typescript"
@@ -13640,7 +15523,7 @@ var wrapStreamObject = (streamObject, options = {}, aiSDK) => {
13640
15523
  },
13641
15524
  onFinish: async (event) => {
13642
15525
  params.onFinish?.(event);
13643
- const gatewayInfo = extractGatewayRoutingInfo(event);
15526
+ const gatewayInfo = extractGatewayRoutingInfo2(event);
13644
15527
  const resolvedMetadata = {};
13645
15528
  if (gatewayInfo?.provider) {
13646
15529
  resolvedMetadata.provider = gatewayInfo.provider;
@@ -13717,7 +15600,7 @@ var wrapTools = (tools) => {
13717
15600
  }
13718
15601
  return wrappedTools;
13719
15602
  };
13720
- var isAsyncGenerator = (value) => {
15603
+ var isAsyncGenerator2 = (value) => {
13721
15604
  return value != null && typeof value === "object" && typeof value[Symbol.asyncIterator] === "function" && typeof value.next === "function" && typeof value.return === "function" && typeof value.throw === "function";
13722
15605
  };
13723
15606
  var wrapToolExecute = (tool, name) => {
@@ -13728,7 +15611,7 @@ var wrapToolExecute = (tool, name) => {
13728
15611
  if (prop === "execute") {
13729
15612
  const wrappedExecute = (...args) => {
13730
15613
  const result = originalExecute.apply(target, args);
13731
- if (isAsyncGenerator(result)) {
15614
+ if (isAsyncGenerator2(result)) {
13732
15615
  return (async function* () {
13733
15616
  const span = startSpan({
13734
15617
  name,
@@ -13848,7 +15731,7 @@ function serializeModelWithProvider2(model) {
13848
15731
  provider: explicitProvider || parsed.provider
13849
15732
  };
13850
15733
  }
13851
- function extractGatewayRoutingInfo(result) {
15734
+ function extractGatewayRoutingInfo2(result) {
13852
15735
  if (result?.steps && Array.isArray(result.steps) && result.steps.length > 0) {
13853
15736
  const routing2 = result.steps[0]?.providerMetadata?.gateway?.routing;
13854
15737
  if (routing2) {
@@ -13867,10 +15750,10 @@ function extractGatewayRoutingInfo(result) {
13867
15750
  }
13868
15751
  return null;
13869
15752
  }
13870
- var isZodSchema = (value) => {
15753
+ var isZodSchema3 = (value) => {
13871
15754
  return value != null && typeof value === "object" && "_def" in value && typeof value._def === "object";
13872
15755
  };
13873
- var serializeZodSchema = (schema) => {
15756
+ var serializeZodSchema3 = (schema) => {
13874
15757
  try {
13875
15758
  return zodToJsonSchema(schema);
13876
15759
  } catch {
@@ -13880,34 +15763,6 @@ var serializeZodSchema = (schema) => {
13880
15763
  };
13881
15764
  }
13882
15765
  };
13883
- var processTools = (tools) => {
13884
- if (!tools || typeof tools !== "object") return tools;
13885
- if (Array.isArray(tools)) {
13886
- return tools.map(processTool);
13887
- }
13888
- const processed = {};
13889
- for (const [key, tool] of Object.entries(tools)) {
13890
- processed[key] = processTool(tool);
13891
- }
13892
- return processed;
13893
- };
13894
- var processTool = (tool) => {
13895
- if (!tool || typeof tool !== "object") return tool;
13896
- const processed = { ...tool };
13897
- if (isZodSchema(processed.inputSchema)) {
13898
- processed.inputSchema = serializeZodSchema(processed.inputSchema);
13899
- }
13900
- if (isZodSchema(processed.parameters)) {
13901
- processed.parameters = serializeZodSchema(processed.parameters);
13902
- }
13903
- if ("execute" in processed) {
13904
- processed.execute = "[Function]";
13905
- }
13906
- if ("render" in processed) {
13907
- processed.render = "[Function]";
13908
- }
13909
- return processed;
13910
- };
13911
15766
  var isOutputObject = (value) => {
13912
15767
  if (value == null || typeof value !== "object") {
13913
15768
  return false;
@@ -13946,10 +15801,10 @@ var serializeOutputObject = (output, model) => {
13946
15801
  if (typeof responseFormat.then === "function") {
13947
15802
  result.response_format = Promise.resolve(responseFormat).then(
13948
15803
  (resolved) => {
13949
- if (resolved.schema && isZodSchema(resolved.schema)) {
15804
+ if (resolved.schema && isZodSchema3(resolved.schema)) {
13950
15805
  return {
13951
15806
  ...resolved,
13952
- schema: serializeZodSchema(resolved.schema)
15807
+ schema: serializeZodSchema3(resolved.schema)
13953
15808
  };
13954
15809
  }
13955
15810
  return resolved;
@@ -13957,10 +15812,10 @@ var serializeOutputObject = (output, model) => {
13957
15812
  );
13958
15813
  } else {
13959
15814
  const syncResponseFormat = responseFormat;
13960
- if (syncResponseFormat.schema && isZodSchema(syncResponseFormat.schema)) {
15815
+ if (syncResponseFormat.schema && isZodSchema3(syncResponseFormat.schema)) {
13961
15816
  responseFormat = {
13962
15817
  ...syncResponseFormat,
13963
- schema: serializeZodSchema(syncResponseFormat.schema)
15818
+ schema: serializeZodSchema3(syncResponseFormat.schema)
13964
15819
  };
13965
15820
  }
13966
15821
  result.response_format = responseFormat;
@@ -13986,14 +15841,14 @@ var processInputAttachmentsSync = (input) => {
13986
15841
  processed.prompt = processPromptContent(input.prompt);
13987
15842
  }
13988
15843
  }
13989
- if (input.tools) {
13990
- processed.tools = processTools(input.tools);
15844
+ if (input.schema && isZodSchema3(input.schema)) {
15845
+ processed.schema = serializeZodSchema3(input.schema);
13991
15846
  }
13992
- if (input.schema && isZodSchema(input.schema)) {
13993
- processed.schema = serializeZodSchema(input.schema);
15847
+ if (input.callOptionsSchema && isZodSchema3(input.callOptionsSchema)) {
15848
+ processed.callOptionsSchema = serializeZodSchema3(input.callOptionsSchema);
13994
15849
  }
13995
- if (input.callOptionsSchema && isZodSchema(input.callOptionsSchema)) {
13996
- processed.callOptionsSchema = serializeZodSchema(input.callOptionsSchema);
15850
+ if (input.tools) {
15851
+ processed.tools = serializeAISDKToolsForLogging(input.tools);
13997
15852
  }
13998
15853
  let outputPromise;
13999
15854
  if (input.output && isOutputObject(input.output)) {
@@ -14027,14 +15882,14 @@ var processInputAttachments2 = async (input) => {
14027
15882
  processed.prompt = processPromptContent(input.prompt);
14028
15883
  }
14029
15884
  }
14030
- if (input.tools) {
14031
- processed.tools = processTools(input.tools);
15885
+ if (input.schema && isZodSchema3(input.schema)) {
15886
+ processed.schema = serializeZodSchema3(input.schema);
14032
15887
  }
14033
- if (input.schema && isZodSchema(input.schema)) {
14034
- processed.schema = serializeZodSchema(input.schema);
15888
+ if (input.callOptionsSchema && isZodSchema3(input.callOptionsSchema)) {
15889
+ processed.callOptionsSchema = serializeZodSchema3(input.callOptionsSchema);
14035
15890
  }
14036
- if (input.callOptionsSchema && isZodSchema(input.callOptionsSchema)) {
14037
- processed.callOptionsSchema = serializeZodSchema(input.callOptionsSchema);
15891
+ if (input.tools) {
15892
+ processed.tools = serializeAISDKToolsForLogging(input.tools);
14038
15893
  }
14039
15894
  if (input.output && isOutputObject(input.output)) {
14040
15895
  const serialized = serializeOutputObject(input.output, input.model);
@@ -14235,7 +16090,9 @@ var processOutput = async (output, denyOutputPaths) => {
14235
16090
  const getterValues = extractGetterValues2(output);
14236
16091
  const processed = await processOutputAttachments(output);
14237
16092
  const merged = { ...processed, ...getterValues };
14238
- return omit2(merged, denyOutputPaths ?? DENY_OUTPUT_PATHS);
16093
+ return normalizeAISDKLoggedOutput(
16094
+ omit2(merged, denyOutputPaths ?? DENY_OUTPUT_PATHS)
16095
+ );
14239
16096
  };
14240
16097
  var processOutputAttachments = async (output) => {
14241
16098
  try {
@@ -14798,14 +16655,14 @@ function extractModelFromResult(result) {
14798
16655
  function extractModelFromWrapGenerateCallback(model) {
14799
16656
  return model?.modelId;
14800
16657
  }
14801
- function camelToSnake(str) {
16658
+ function camelToSnake2(str) {
14802
16659
  return str.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`);
14803
16660
  }
14804
16661
  function extractModelParameters(params, excludeKeys) {
14805
16662
  const modelParams = {};
14806
16663
  for (const [key, value] of Object.entries(params)) {
14807
16664
  if (value !== void 0 && !excludeKeys.has(key)) {
14808
- const snakeKey = camelToSnake(key);
16665
+ const snakeKey = camelToSnake2(key);
14809
16666
  modelParams[snakeKey] = value;
14810
16667
  }
14811
16668
  }
@@ -15665,7 +17522,7 @@ function filterSerializableOptions2(options) {
15665
17522
  }
15666
17523
  return filtered;
15667
17524
  }
15668
- function isAsyncIterable2(value) {
17525
+ function isAsyncIterable3(value) {
15669
17526
  return value !== null && typeof value === "object" && Symbol.asyncIterator in value && typeof value[Symbol.asyncIterator] === "function";
15670
17527
  }
15671
17528
  function wrapClaudeAgentQuery(queryFn, defaultThis) {
@@ -15673,7 +17530,7 @@ function wrapClaudeAgentQuery(queryFn, defaultThis) {
15673
17530
  apply(target, thisArg, argArray) {
15674
17531
  const params = argArray[0] ?? {};
15675
17532
  const { prompt, options = {} } = params;
15676
- const promptIsAsyncIterable = isAsyncIterable2(prompt);
17533
+ const promptIsAsyncIterable = isAsyncIterable3(prompt);
15677
17534
  let capturedPromptMessages;
15678
17535
  let promptForQuery = prompt;
15679
17536
  let promptStarted = false;
@@ -16293,11 +18150,13 @@ function serializeInput2(params) {
16293
18150
  if (params.config) {
16294
18151
  const config = tryToDict2(params.config);
16295
18152
  if (config) {
16296
- const tools = serializeTools2(params);
16297
- if (tools) {
16298
- config.tools = tools;
16299
- }
16300
- input.config = config;
18153
+ const filteredConfig = {};
18154
+ Object.keys(config).forEach((key) => {
18155
+ if (key !== "tools") {
18156
+ filteredConfig[key] = config[key];
18157
+ }
18158
+ });
18159
+ input.config = filteredConfig;
16301
18160
  }
16302
18161
  }
16303
18162
  return input;
@@ -16378,6 +18237,10 @@ function extractMetadata2(params) {
16378
18237
  });
16379
18238
  }
16380
18239
  }
18240
+ const tools = serializeTools2(params);
18241
+ if (tools) {
18242
+ metadata.tools = tools;
18243
+ }
16381
18244
  return metadata;
16382
18245
  }
16383
18246
  function extractGenerateContentMetrics2(response, start) {
@@ -16516,6 +18379,111 @@ function tryToDict2(obj) {
16516
18379
  return null;
16517
18380
  }
16518
18381
 
18382
+ // src/wrappers/openrouter.ts
18383
+ function wrapOpenRouter(openrouter) {
18384
+ const or = openrouter;
18385
+ if (or && typeof or === "object" && ("chat" in or && typeof or.chat === "object" && or.chat && "send" in or.chat && "embeddings" in or && typeof or.embeddings === "object" && or.embeddings && "generate" in or.embeddings || "callModel" in or && typeof or.callModel === "function")) {
18386
+ return openRouterProxy(or);
18387
+ }
18388
+ console.warn("Unsupported OpenRouter library. Not wrapping.");
18389
+ return openrouter;
18390
+ }
18391
+ function openRouterProxy(openrouter) {
18392
+ return new Proxy(openrouter, {
18393
+ get(target, prop, receiver) {
18394
+ switch (prop) {
18395
+ case "chat":
18396
+ return target.chat ? chatProxy(target.chat) : target.chat;
18397
+ case "embeddings":
18398
+ return target.embeddings ? embeddingsProxy(target.embeddings) : target.embeddings;
18399
+ case "beta":
18400
+ return target.beta ? betaProxy2(target.beta) : target.beta;
18401
+ case "callModel":
18402
+ return typeof target.callModel === "function" ? wrapCallModel(target.callModel.bind(target)) : target.callModel;
18403
+ default:
18404
+ return Reflect.get(target, prop, receiver);
18405
+ }
18406
+ }
18407
+ });
18408
+ }
18409
+ function betaProxy2(beta) {
18410
+ return new Proxy(beta, {
18411
+ get(target, prop, receiver) {
18412
+ if (prop === "responses") {
18413
+ return target.responses ? responsesProxy2(target.responses) : void 0;
18414
+ }
18415
+ return Reflect.get(target, prop, receiver);
18416
+ }
18417
+ });
18418
+ }
18419
+ function chatProxy(chat) {
18420
+ return new Proxy(chat, {
18421
+ get(target, prop, receiver) {
18422
+ if (prop === "send") {
18423
+ return wrapChatSend(target.send.bind(target));
18424
+ }
18425
+ return Reflect.get(target, prop, receiver);
18426
+ }
18427
+ });
18428
+ }
18429
+ function embeddingsProxy(embeddings) {
18430
+ return new Proxy(embeddings, {
18431
+ get(target, prop, receiver) {
18432
+ if (prop === "generate") {
18433
+ return wrapEmbeddingsGenerate(target.generate.bind(target));
18434
+ }
18435
+ return Reflect.get(target, prop, receiver);
18436
+ }
18437
+ });
18438
+ }
18439
+ function responsesProxy2(responses) {
18440
+ return new Proxy(responses, {
18441
+ get(target, prop, receiver) {
18442
+ if (prop === "send") {
18443
+ return wrapResponsesSend(target.send.bind(target));
18444
+ }
18445
+ return Reflect.get(target, prop, receiver);
18446
+ }
18447
+ });
18448
+ }
18449
+ function wrapChatSend(send) {
18450
+ return (request, options) => openRouterChannels.chatSend.tracePromise(() => send(request, options), {
18451
+ arguments: [request]
18452
+ });
18453
+ }
18454
+ function wrapEmbeddingsGenerate(generate) {
18455
+ return (request, options) => openRouterChannels.embeddingsGenerate.tracePromise(
18456
+ () => generate(request, options),
18457
+ { arguments: [request] }
18458
+ );
18459
+ }
18460
+ function wrapResponsesSend(send) {
18461
+ return (request, options) => openRouterChannels.betaResponsesSend.tracePromise(
18462
+ () => send(request, options),
18463
+ { arguments: [request] }
18464
+ );
18465
+ }
18466
+ function wrapCallModel(callModel) {
18467
+ return (request, options) => {
18468
+ const patchedRequest = { ...request };
18469
+ patchOpenRouterCallModelRequestTools(patchedRequest);
18470
+ const span = startOpenRouterCallModelSpan(patchedRequest);
18471
+ try {
18472
+ const result = callModel(patchedRequest, options);
18473
+ if (!patchOpenRouterCallModelResult(span, result, patchedRequest)) {
18474
+ span.end();
18475
+ }
18476
+ return result;
18477
+ } catch (error) {
18478
+ span.log({
18479
+ error: error instanceof Error ? error.message : String(error)
18480
+ });
18481
+ span.end();
18482
+ throw error;
18483
+ }
18484
+ };
18485
+ }
18486
+
16519
18487
  // src/wrappers/vitest/context-manager.ts
16520
18488
  var VitestContextManager = class {
16521
18489
  /**
@@ -17415,7 +19383,7 @@ function unescapePath(path) {
17415
19383
  }
17416
19384
  var graph_framework_default = { createGraph };
17417
19385
 
17418
- // ../node_modules/async/dist/async.mjs
19386
+ // ../node_modules/.pnpm/async@3.2.5/node_modules/async/dist/async.mjs
17419
19387
  function initialParams(fn) {
17420
19388
  return function(...args) {
17421
19389
  var callback = args.pop();
@@ -17483,10 +19451,10 @@ function invokeCallback(callback, error, value) {
17483
19451
  function isAsync(fn) {
17484
19452
  return fn[Symbol.toStringTag] === "AsyncFunction";
17485
19453
  }
17486
- function isAsyncGenerator2(fn) {
19454
+ function isAsyncGenerator3(fn) {
17487
19455
  return fn[Symbol.toStringTag] === "AsyncGenerator";
17488
19456
  }
17489
- function isAsyncIterable3(obj) {
19457
+ function isAsyncIterable4(obj) {
17490
19458
  return typeof obj[Symbol.asyncIterator] === "function";
17491
19459
  }
17492
19460
  function wrapAsync(asyncFn) {
@@ -17536,10 +19504,11 @@ function _asyncMap(eachfn, arr, iteratee, callback) {
17536
19504
  callback(err, results);
17537
19505
  });
17538
19506
  }
17539
- function isArrayLike(value) {
19507
+ function isArrayLike2(value) {
17540
19508
  return value && typeof value.length === "number" && value.length >= 0 && value.length % 1 === 0;
17541
19509
  }
17542
19510
  var breakLoop = {};
19511
+ var breakLoop$1 = breakLoop;
17543
19512
  function once(fn) {
17544
19513
  function wrapper(...args) {
17545
19514
  if (fn === null) return;
@@ -17583,7 +19552,7 @@ function createObjectIterator(obj) {
17583
19552
  };
17584
19553
  }
17585
19554
  function createIterator(coll) {
17586
- if (isArrayLike(coll)) {
19555
+ if (isArrayLike2(coll)) {
17587
19556
  return createArrayIterator(coll);
17588
19557
  }
17589
19558
  var iterator = getIterator(coll);
@@ -17631,7 +19600,7 @@ function asyncEachOfLimit(generator, limit, iteratee, callback) {
17631
19600
  canceled = true;
17632
19601
  return;
17633
19602
  }
17634
- if (result === breakLoop || done && running <= 0) {
19603
+ if (result === breakLoop$1 || done && running <= 0) {
17635
19604
  done = true;
17636
19605
  return callback(null);
17637
19606
  }
@@ -17654,10 +19623,10 @@ var eachOfLimit$2 = (limit) => {
17654
19623
  if (!obj) {
17655
19624
  return callback(null);
17656
19625
  }
17657
- if (isAsyncGenerator2(obj)) {
19626
+ if (isAsyncGenerator3(obj)) {
17658
19627
  return asyncEachOfLimit(obj, limit, iteratee, callback);
17659
19628
  }
17660
- if (isAsyncIterable3(obj)) {
19629
+ if (isAsyncIterable4(obj)) {
17661
19630
  return asyncEachOfLimit(obj[Symbol.asyncIterator](), limit, iteratee, callback);
17662
19631
  }
17663
19632
  var nextElem = createIterator(obj);
@@ -17674,7 +19643,7 @@ var eachOfLimit$2 = (limit) => {
17674
19643
  } else if (err === false) {
17675
19644
  done = true;
17676
19645
  canceled = true;
17677
- } else if (value === breakLoop || done && running <= 0) {
19646
+ } else if (value === breakLoop$1 || done && running <= 0) {
17678
19647
  done = true;
17679
19648
  return callback(null);
17680
19649
  } else if (!looping) {
@@ -17717,7 +19686,7 @@ function eachOfArrayLike(coll, iteratee, callback) {
17717
19686
  if (canceled === true) return;
17718
19687
  if (err) {
17719
19688
  callback(err);
17720
- } else if (++completed === length || value === breakLoop) {
19689
+ } else if (++completed === length || value === breakLoop$1) {
17721
19690
  callback(null);
17722
19691
  }
17723
19692
  }
@@ -17729,7 +19698,7 @@ function eachOfGeneric(coll, iteratee, callback) {
17729
19698
  return eachOfLimit$1(coll, Infinity, iteratee, callback);
17730
19699
  }
17731
19700
  function eachOf(coll, iteratee, callback) {
17732
- var eachOfImplementation = isArrayLike(coll) ? eachOfArrayLike : eachOfGeneric;
19701
+ var eachOfImplementation = isArrayLike2(coll) ? eachOfArrayLike : eachOfGeneric;
17733
19702
  return eachOfImplementation(coll, wrapAsync(iteratee), callback);
17734
19703
  }
17735
19704
  var eachOf$1 = awaitify(eachOf, 3);
@@ -18113,7 +20082,7 @@ function _createTester(check, getResult) {
18113
20082
  if (check(result) && !testResult) {
18114
20083
  testPassed = true;
18115
20084
  testResult = getResult(true, value);
18116
- return callback(null, breakLoop);
20085
+ return callback(null, breakLoop$1);
18117
20086
  }
18118
20087
  callback();
18119
20088
  });
@@ -18244,7 +20213,7 @@ function filterGeneric(eachfn, coll, iteratee, callback) {
18244
20213
  });
18245
20214
  }
18246
20215
  function _filter(eachfn, coll, iteratee, callback) {
18247
- var filter2 = isArrayLike(coll) ? filterArray : filterGeneric;
20216
+ var filter2 = isArrayLike2(coll) ? filterArray : filterGeneric;
18248
20217
  return filter2(eachfn, coll, wrapAsync(iteratee), callback);
18249
20218
  }
18250
20219
  function filter(coll, iteratee, callback) {
@@ -18319,7 +20288,7 @@ if (hasNextTick) {
18319
20288
  }
18320
20289
  var nextTick = wrap(_defer);
18321
20290
  var _parallel = awaitify((eachfn, tasks, callback) => {
18322
- var results = isArrayLike(tasks) ? [] : {};
20291
+ var results = isArrayLike2(tasks) ? [] : {};
18323
20292
  eachfn(tasks, (task, key, taskCb) => {
18324
20293
  wrapAsync(task)((err, ...result) => {
18325
20294
  if (result.length < 2) {
@@ -18737,7 +20706,8 @@ var promptDefinitionSchema = promptContentsSchema.and(
18737
20706
  import_v310.z.object({
18738
20707
  model: import_v310.z.string(),
18739
20708
  params: ModelParams.optional(),
18740
- templateFormat: import_v310.z.enum(["mustache", "nunjucks", "none"]).optional()
20709
+ templateFormat: import_v310.z.enum(["mustache", "nunjucks", "none"]).optional(),
20710
+ environments: import_v310.z.array(import_v310.z.string()).optional()
18741
20711
  })
18742
20712
  );
18743
20713
  var promptDefinitionWithToolsSchema = promptDefinitionSchema.and(
@@ -18896,6 +20866,22 @@ function initExperiment2(state, options = {}) {
18896
20866
  setCurrent: false
18897
20867
  });
18898
20868
  }
20869
+ async function getExperimentParametersRef(parameters) {
20870
+ if (!parameters) {
20871
+ return void 0;
20872
+ }
20873
+ const resolvedParameters = parameters instanceof Promise ? await parameters : parameters;
20874
+ if (!RemoteEvalParameters.isParameters(resolvedParameters)) {
20875
+ return void 0;
20876
+ }
20877
+ if (resolvedParameters.id === void 0) {
20878
+ return void 0;
20879
+ }
20880
+ return {
20881
+ id: resolvedParameters.id,
20882
+ version: resolvedParameters.version
20883
+ };
20884
+ }
18899
20885
  function callEvaluatorData(data) {
18900
20886
  const dataResult = typeof data === "function" ? data() : data;
18901
20887
  let baseExperiment = void 0;
@@ -18907,7 +20893,7 @@ function callEvaluatorData(data) {
18907
20893
  baseExperiment
18908
20894
  };
18909
20895
  }
18910
- function isAsyncIterable4(value) {
20896
+ function isAsyncIterable5(value) {
18911
20897
  return typeof value === "object" && value !== null && Symbol.asyncIterator in value && typeof value[Symbol.asyncIterator] === "function";
18912
20898
  }
18913
20899
  function isIterable(value) {
@@ -18962,6 +20948,7 @@ async function Eval(name, evaluator, reporterOrOpts) {
18962
20948
  const { data, baseExperiment: defaultBaseExperiment } = callEvaluatorData(
18963
20949
  evaluator.data
18964
20950
  );
20951
+ const parameters = await getExperimentParametersRef(evaluator.parameters);
18965
20952
  const experiment = options.parent || options.noSendLogs ? null : initExperiment2(evaluator.state, {
18966
20953
  ...evaluator.projectId ? { projectId: evaluator.projectId } : { project: name },
18967
20954
  experiment: evaluator.experimentName,
@@ -18974,7 +20961,8 @@ async function Eval(name, evaluator, reporterOrOpts) {
18974
20961
  baseExperimentId: evaluator.baseExperimentId,
18975
20962
  gitMetadataSettings: evaluator.gitMetadataSettings,
18976
20963
  repoInfo: evaluator.repoInfo,
18977
- dataset: Dataset2.isDataset(data) ? data : void 0
20964
+ dataset: Dataset2.isDataset(data) ? data : void 0,
20965
+ parameters
18978
20966
  });
18979
20967
  if (experiment && typeof process !== "undefined" && globalThis.BRAINTRUST_CONTEXT_MANAGER !== void 0) {
18980
20968
  await experiment._waitForId();
@@ -19029,7 +21017,7 @@ async function Eval(name, evaluator, reporterOrOpts) {
19029
21017
  if (experiment) {
19030
21018
  await experiment.flush().catch(console.error);
19031
21019
  } else if (options.parent) {
19032
- await flush().catch(console.error);
21020
+ await flush({ state: evaluator.state }).catch(console.error);
19033
21021
  }
19034
21022
  }
19035
21023
  } finally {
@@ -19129,7 +21117,7 @@ async function runEvaluatorInternal(experiment, evaluator, progressReporter, fil
19129
21117
  }
19130
21118
  const resolvedDataResult = dataResult instanceof Promise ? await dataResult : dataResult;
19131
21119
  const dataIterable = (() => {
19132
- if (isAsyncIterable4(resolvedDataResult)) {
21120
+ if (isAsyncIterable5(resolvedDataResult)) {
19133
21121
  return resolvedDataResult;
19134
21122
  }
19135
21123
  if (Array.isArray(resolvedDataResult) || isIterable(resolvedDataResult)) {
@@ -19417,6 +21405,7 @@ async function runEvaluatorInternal(experiment, evaluator, progressReporter, fil
19417
21405
  },
19418
21406
  Math.max(evaluator.maxConcurrency ?? Number.MAX_SAFE_INTEGER, 1)
19419
21407
  );
21408
+ const queueErrors = [];
19420
21409
  const enqueuePromise = (async () => {
19421
21410
  for await (const datum of dataIterable) {
19422
21411
  if (cancelled) {
@@ -19432,7 +21421,11 @@ async function runEvaluatorInternal(experiment, evaluator, progressReporter, fil
19432
21421
  }
19433
21422
  scheduledTrials++;
19434
21423
  progressReporter.setTotal?.(evaluator.evalName, scheduledTrials);
19435
- q.push({ datum, trialIndex });
21424
+ q.pushAsync({ datum, trialIndex }).catch((e) => {
21425
+ if (queueErrors.length < 5) {
21426
+ queueErrors.push(e);
21427
+ }
21428
+ });
19436
21429
  }
19437
21430
  }
19438
21431
  })();
@@ -19480,6 +21473,12 @@ async function runEvaluatorInternal(experiment, evaluator, progressReporter, fil
19480
21473
  })();
19481
21474
  try {
19482
21475
  await Promise.race([waitForQueue, cancel()]);
21476
+ if (queueErrors.length > 0) {
21477
+ throw new AggregateError(
21478
+ queueErrors,
21479
+ `Encountered ${queueErrors.length} unhandled task errors`
21480
+ );
21481
+ }
19483
21482
  } catch (e) {
19484
21483
  q.kill();
19485
21484
  if (e instanceof InternalAbortError) {
@@ -19883,6 +21882,7 @@ var CodePrompt = class {
19883
21882
  toolFunctions;
19884
21883
  tags;
19885
21884
  metadata;
21885
+ environmentSlugs;
19886
21886
  constructor(project, prompt, toolFunctions, opts, functionType) {
19887
21887
  this.project = project;
19888
21888
  this.name = opts.name;
@@ -19895,6 +21895,7 @@ var CodePrompt = class {
19895
21895
  this.functionType = functionType;
19896
21896
  this.tags = opts.tags;
19897
21897
  this.metadata = opts.metadata;
21898
+ this.environmentSlugs = opts.environments;
19898
21899
  }
19899
21900
  async toFunctionDefinition(projectNameToId) {
19900
21901
  const prompt_data = {
@@ -19929,7 +21930,8 @@ var CodePrompt = class {
19929
21930
  prompt_data,
19930
21931
  if_exists: this.ifExists,
19931
21932
  tags: this.tags,
19932
- metadata: this.metadata
21933
+ metadata: this.metadata,
21934
+ environments: this.environmentSlugs && this.environmentSlugs.length > 0 ? this.environmentSlugs.map((slug) => ({ slug })) : void 0
19933
21935
  };
19934
21936
  }
19935
21937
  };