braintrust 3.5.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 (41) hide show
  1. package/dev/dist/index.d.mts +4 -2
  2. package/dev/dist/index.d.ts +4 -2
  3. package/dev/dist/index.js +1353 -211
  4. package/dev/dist/index.mjs +1170 -28
  5. package/dist/auto-instrumentations/bundler/esbuild.cjs +81 -0
  6. package/dist/auto-instrumentations/bundler/esbuild.mjs +2 -2
  7. package/dist/auto-instrumentations/bundler/rollup.cjs +81 -0
  8. package/dist/auto-instrumentations/bundler/rollup.mjs +2 -2
  9. package/dist/auto-instrumentations/bundler/vite.cjs +81 -0
  10. package/dist/auto-instrumentations/bundler/vite.mjs +2 -2
  11. package/dist/auto-instrumentations/bundler/webpack.cjs +81 -0
  12. package/dist/auto-instrumentations/bundler/webpack.mjs +2 -2
  13. package/dist/auto-instrumentations/{chunk-DQTPSXJB.mjs → chunk-F7WAXFNM.mjs} +82 -1
  14. package/dist/auto-instrumentations/{chunk-F3TJZ3Z2.mjs → chunk-WOUC73KB.mjs} +3 -1
  15. package/dist/auto-instrumentations/hook.mjs +139 -49
  16. package/dist/auto-instrumentations/index.cjs +82 -0
  17. package/dist/auto-instrumentations/index.d.mts +3 -1
  18. package/dist/auto-instrumentations/index.d.ts +3 -1
  19. package/dist/auto-instrumentations/index.mjs +3 -1
  20. package/dist/browser.d.mts +17 -4
  21. package/dist/browser.d.ts +17 -4
  22. package/dist/browser.js +1479 -232
  23. package/dist/browser.mjs +1479 -232
  24. package/dist/cli.js +1162 -20
  25. package/dist/edge-light.d.mts +1 -1
  26. package/dist/edge-light.d.ts +1 -1
  27. package/dist/edge-light.js +1412 -222
  28. package/dist/edge-light.mjs +1412 -222
  29. package/dist/index.d.mts +30 -17
  30. package/dist/index.d.ts +30 -17
  31. package/dist/index.js +1763 -514
  32. package/dist/index.mjs +1458 -209
  33. package/dist/instrumentation/index.d.mts +3 -0
  34. package/dist/instrumentation/index.d.ts +3 -0
  35. package/dist/instrumentation/index.js +1102 -19
  36. package/dist/instrumentation/index.mjs +1102 -19
  37. package/dist/workerd.d.mts +1 -1
  38. package/dist/workerd.d.ts +1 -1
  39. package/dist/workerd.js +1412 -222
  40. package/dist/workerd.mjs +1412 -222
  41. package/package.json +1 -1
package/dist/index.mjs CHANGED
@@ -8,6 +8,64 @@ var __export = (target, all) => {
8
8
  import { AsyncLocalStorage } from "node:async_hooks";
9
9
  import * as diagnostics_channel from "node:diagnostics_channel";
10
10
  import * as path from "node:path";
11
+
12
+ // src/auto-instrumentations/patch-tracing-channel.ts
13
+ function patchTracingChannel(tracingChannelFn) {
14
+ const dummyChannel = tracingChannelFn("__braintrust_probe__");
15
+ const TracingChannel = dummyChannel?.constructor;
16
+ if (!TracingChannel?.prototype) {
17
+ return;
18
+ }
19
+ if (!Object.getOwnPropertyDescriptor(TracingChannel.prototype, "hasSubscribers")) {
20
+ Object.defineProperty(TracingChannel.prototype, "hasSubscribers", {
21
+ configurable: true,
22
+ enumerable: false,
23
+ get() {
24
+ return Boolean(
25
+ this.start?.hasSubscribers || this.end?.hasSubscribers || this.asyncStart?.hasSubscribers || this.asyncEnd?.hasSubscribers || this.error?.hasSubscribers
26
+ );
27
+ }
28
+ });
29
+ }
30
+ if (TracingChannel.prototype.tracePromise) {
31
+ TracingChannel.prototype.tracePromise = function(fn, context = {}, thisArg, ...args) {
32
+ const { start, end, asyncStart, asyncEnd, error } = this;
33
+ function reject2(err) {
34
+ context.error = err;
35
+ error?.publish(context);
36
+ asyncStart?.publish(context);
37
+ asyncEnd?.publish(context);
38
+ return Promise.reject(err);
39
+ }
40
+ function resolve(result) {
41
+ context.result = result;
42
+ asyncStart?.publish(context);
43
+ asyncEnd?.publish(context);
44
+ return result;
45
+ }
46
+ return start.runStores(context, () => {
47
+ try {
48
+ const result = Reflect.apply(fn, thisArg, args);
49
+ end?.publish(context);
50
+ if (result && (typeof result === "object" || typeof result === "function") && typeof result.then === "function") {
51
+ return result.then(resolve, reject2);
52
+ }
53
+ context.result = result;
54
+ asyncStart?.publish(context);
55
+ asyncEnd?.publish(context);
56
+ return result;
57
+ } catch (err) {
58
+ context.error = err;
59
+ error?.publish(context);
60
+ end?.publish(context);
61
+ throw err;
62
+ }
63
+ });
64
+ };
65
+ }
66
+ }
67
+
68
+ // src/node/config.ts
11
69
  import * as fs from "node:fs/promises";
12
70
  import * as os from "node:os";
13
71
  import * as fsSync from "node:fs";
@@ -4510,6 +4568,9 @@ var BRAINTRUST_ATTACHMENT = BraintrustAttachmentReference.shape.type.value;
4510
4568
  var EXTERNAL_ATTACHMENT = ExternalAttachmentReference.shape.type.value;
4511
4569
  var LOGS3_OVERFLOW_REFERENCE_TYPE = "logs3_overflow";
4512
4570
  var BRAINTRUST_PARAMS = Object.keys(BraintrustModelParams.shape);
4571
+ var RESET_CONTEXT_MANAGER_STATE = Symbol.for(
4572
+ "braintrust.resetContextManagerState"
4573
+ );
4513
4574
  var DEFAULT_MAX_REQUEST_SIZE = 6 * 1024 * 1024;
4514
4575
  var parametersRowSchema = z8.object({
4515
4576
  id: z8.string().uuid(),
@@ -4572,13 +4633,18 @@ function applyMaskingToField(maskingFunction, data, fieldName) {
4572
4633
  return `ERROR: Failed to mask field '${fieldName}' - ${errorType}`;
4573
4634
  }
4574
4635
  }
4636
+ var BRAINTRUST_CURRENT_SPAN_STORE = Symbol.for(
4637
+ "braintrust.currentSpanStore"
4638
+ );
4575
4639
  var ContextManager = class {
4576
4640
  };
4577
4641
  var BraintrustContextManager = class extends ContextManager {
4578
4642
  _currentSpan;
4643
+ [BRAINTRUST_CURRENT_SPAN_STORE];
4579
4644
  constructor() {
4580
4645
  super();
4581
4646
  this._currentSpan = isomorph_default.newAsyncLocalStorage();
4647
+ this[BRAINTRUST_CURRENT_SPAN_STORE] = this._currentSpan;
4582
4648
  }
4583
4649
  getParentSpanIds() {
4584
4650
  const currentSpan2 = this._currentSpan.getStore();
@@ -4785,6 +4851,9 @@ var BraintrustState = class _BraintrustState {
4785
4851
  resetIdGenState() {
4786
4852
  this._idGenerator = null;
4787
4853
  }
4854
+ [RESET_CONTEXT_MANAGER_STATE]() {
4855
+ this._contextManager = null;
4856
+ }
4788
4857
  get idGenerator() {
4789
4858
  if (this._idGenerator === null) {
4790
4859
  this._idGenerator = getIdGenerator();
@@ -7120,11 +7189,7 @@ async function loadPrompt({
7120
7189
  forceLogin,
7121
7190
  state: stateArg
7122
7191
  }) {
7123
- if (version && environment) {
7124
- throw new Error(
7125
- "Cannot specify both 'version' and 'environment' parameters. Please use only one (remove the other)."
7126
- );
7127
- }
7192
+ const versionOrEnvironment = version ? { version } : environment ? { environment } : {};
7128
7193
  if (id) {
7129
7194
  } else if (isEmpty2(projectName) && isEmpty2(projectId)) {
7130
7195
  throw new Error("Must specify either projectName or projectId");
@@ -7142,10 +7207,7 @@ async function loadPrompt({
7142
7207
  forceLogin
7143
7208
  });
7144
7209
  if (id) {
7145
- response = await state.apiConn().get_json(`v1/prompt/${id}`, {
7146
- ...version && { version },
7147
- ...environment && { environment }
7148
- });
7210
+ response = await state.apiConn().get_json(`v1/prompt/${id}`, versionOrEnvironment);
7149
7211
  if (response) {
7150
7212
  response = { objects: [response] };
7151
7213
  }
@@ -7154,12 +7216,11 @@ async function loadPrompt({
7154
7216
  project_name: projectName,
7155
7217
  project_id: projectId,
7156
7218
  slug,
7157
- version,
7158
- ...environment && { environment }
7219
+ ...versionOrEnvironment
7159
7220
  });
7160
7221
  }
7161
7222
  } catch (e) {
7162
- if (environment || version) {
7223
+ if (version || environment) {
7163
7224
  throw new Error(`Prompt not found with specified parameters: ${e}`);
7164
7225
  }
7165
7226
  debugLogger.forState(state).warn("Failed to load prompt, attempting to fall back to cache:", e);
@@ -7237,11 +7298,7 @@ async function loadParameters({
7237
7298
  forceLogin,
7238
7299
  state: stateArg
7239
7300
  }) {
7240
- if (version && environment) {
7241
- throw new Error(
7242
- "Cannot specify both 'version' and 'environment' parameters. Please use only one (remove the other)."
7243
- );
7244
- }
7301
+ const versionOrEnvironment = version ? { version } : environment ? { environment } : {};
7245
7302
  if (id) {
7246
7303
  } else if (isEmpty2(projectName) && isEmpty2(projectId)) {
7247
7304
  throw new Error("Must specify either projectName or projectId");
@@ -7260,8 +7317,7 @@ async function loadParameters({
7260
7317
  });
7261
7318
  if (id) {
7262
7319
  response = await state.apiConn().get_json(`v1/function/${id}`, {
7263
- ...version && { version },
7264
- ...environment && { environment }
7320
+ ...versionOrEnvironment
7265
7321
  });
7266
7322
  if (response) {
7267
7323
  response = { objects: [response] };
@@ -7271,13 +7327,12 @@ async function loadParameters({
7271
7327
  project_name: projectName,
7272
7328
  project_id: projectId,
7273
7329
  slug,
7274
- version,
7275
7330
  function_type: "parameters",
7276
- ...environment && { environment }
7331
+ ...versionOrEnvironment
7277
7332
  });
7278
7333
  }
7279
7334
  } catch (e) {
7280
- if (environment || version) {
7335
+ if (version || environment) {
7281
7336
  throw new Error(`Parameters not found with specified parameters: ${e}`);
7282
7337
  }
7283
7338
  debugLogger.forState(state).warn("Failed to load parameters, attempting to fall back to cache:", e);
@@ -9527,6 +9582,8 @@ async function simulateLoginForTests() {
9527
9582
  function simulateLogoutForTests() {
9528
9583
  const state = _internalGetGlobalState();
9529
9584
  state.resetLoginInfo();
9585
+ state.resetIdGenState();
9586
+ state[RESET_CONTEXT_MANAGER_STATE]();
9530
9587
  state.appUrl = "https://www.braintrust.dev";
9531
9588
  return state;
9532
9589
  }
@@ -10140,6 +10197,36 @@ function startSpanForEvent(config, event, channelName) {
10140
10197
  }
10141
10198
  return { span, startTime };
10142
10199
  }
10200
+ function ensureSpanStateForEvent(states, config, event, channelName) {
10201
+ const key = event;
10202
+ const existing = states.get(key);
10203
+ if (existing) {
10204
+ return existing;
10205
+ }
10206
+ const created = startSpanForEvent(config, event, channelName);
10207
+ states.set(key, created);
10208
+ return created;
10209
+ }
10210
+ function bindCurrentSpanStoreToStart(tracingChannel2, states, config, channelName) {
10211
+ const state = _internalGetGlobalState();
10212
+ const startChannel = tracingChannel2.start;
10213
+ const currentSpanStore = state?.contextManager ? state.contextManager[BRAINTRUST_CURRENT_SPAN_STORE] : void 0;
10214
+ if (!currentSpanStore || !startChannel) {
10215
+ return void 0;
10216
+ }
10217
+ startChannel.bindStore(
10218
+ currentSpanStore,
10219
+ (event) => ensureSpanStateForEvent(
10220
+ states,
10221
+ config,
10222
+ event,
10223
+ channelName
10224
+ ).span
10225
+ );
10226
+ return () => {
10227
+ startChannel.unbindStore(currentSpanStore);
10228
+ };
10229
+ }
10143
10230
  function logErrorAndEnd(states, event) {
10144
10231
  const spanData = states.get(event);
10145
10232
  if (!spanData) {
@@ -10155,15 +10242,19 @@ function traceAsyncChannel(channel2, config) {
10155
10242
  const tracingChannel2 = channel2.tracingChannel();
10156
10243
  const states = /* @__PURE__ */ new WeakMap();
10157
10244
  const channelName = channel2.channelName;
10245
+ const unbindCurrentSpanStore = bindCurrentSpanStoreToStart(
10246
+ tracingChannel2,
10247
+ states,
10248
+ config,
10249
+ channelName
10250
+ );
10158
10251
  const handlers = {
10159
10252
  start: (event) => {
10160
- states.set(
10253
+ ensureSpanStateForEvent(
10254
+ states,
10255
+ config,
10161
10256
  event,
10162
- startSpanForEvent(
10163
- config,
10164
- event,
10165
- channelName
10166
- )
10257
+ channelName
10167
10258
  );
10168
10259
  },
10169
10260
  asyncEnd: (event) => {
@@ -10205,6 +10296,7 @@ function traceAsyncChannel(channel2, config) {
10205
10296
  };
10206
10297
  tracingChannel2.subscribe(handlers);
10207
10298
  return () => {
10299
+ unbindCurrentSpanStore?.();
10208
10300
  tracingChannel2.unsubscribe(handlers);
10209
10301
  };
10210
10302
  }
@@ -10212,15 +10304,19 @@ function traceStreamingChannel(channel2, config) {
10212
10304
  const tracingChannel2 = channel2.tracingChannel();
10213
10305
  const states = /* @__PURE__ */ new WeakMap();
10214
10306
  const channelName = channel2.channelName;
10307
+ const unbindCurrentSpanStore = bindCurrentSpanStoreToStart(
10308
+ tracingChannel2,
10309
+ states,
10310
+ config,
10311
+ channelName
10312
+ );
10215
10313
  const handlers = {
10216
10314
  start: (event) => {
10217
- states.set(
10315
+ ensureSpanStateForEvent(
10316
+ states,
10317
+ config,
10218
10318
  event,
10219
- startSpanForEvent(
10220
- config,
10221
- event,
10222
- channelName
10223
- )
10319
+ channelName
10224
10320
  );
10225
10321
  },
10226
10322
  asyncEnd: (event) => {
@@ -10336,6 +10432,7 @@ function traceStreamingChannel(channel2, config) {
10336
10432
  };
10337
10433
  tracingChannel2.subscribe(handlers);
10338
10434
  return () => {
10435
+ unbindCurrentSpanStore?.();
10339
10436
  tracingChannel2.unsubscribe(handlers);
10340
10437
  };
10341
10438
  }
@@ -10343,15 +10440,19 @@ function traceSyncStreamChannel(channel2, config) {
10343
10440
  const tracingChannel2 = channel2.tracingChannel();
10344
10441
  const states = /* @__PURE__ */ new WeakMap();
10345
10442
  const channelName = channel2.channelName;
10443
+ const unbindCurrentSpanStore = bindCurrentSpanStoreToStart(
10444
+ tracingChannel2,
10445
+ states,
10446
+ config,
10447
+ channelName
10448
+ );
10346
10449
  const handlers = {
10347
10450
  start: (event) => {
10348
- states.set(
10451
+ ensureSpanStateForEvent(
10452
+ states,
10453
+ config,
10349
10454
  event,
10350
- startSpanForEvent(
10351
- config,
10352
- event,
10353
- channelName
10354
- )
10455
+ channelName
10355
10456
  );
10356
10457
  },
10357
10458
  end: (event) => {
@@ -10440,6 +10541,7 @@ function traceSyncStreamChannel(channel2, config) {
10440
10541
  };
10441
10542
  tracingChannel2.subscribe(handlers);
10442
10543
  return () => {
10544
+ unbindCurrentSpanStore?.();
10443
10545
  tracingChannel2.unsubscribe(handlers);
10444
10546
  };
10445
10547
  }
@@ -13001,166 +13103,1206 @@ function tryToDict(obj) {
13001
13103
  return null;
13002
13104
  }
13003
13105
 
13004
- // src/instrumentation/braintrust-plugin.ts
13005
- var BraintrustPlugin = class extends BasePlugin {
13006
- config;
13007
- openaiPlugin = null;
13008
- anthropicPlugin = null;
13009
- aiSDKPlugin = null;
13010
- claudeAgentSDKPlugin = null;
13011
- googleGenAIPlugin = null;
13012
- constructor(config = {}) {
13013
- super();
13014
- this.config = config;
13106
+ // src/instrumentation/plugins/openrouter-channels.ts
13107
+ var openRouterChannels = defineChannels("@openrouter/sdk", {
13108
+ chatSend: channel({
13109
+ channelName: "chat.send",
13110
+ kind: "async"
13111
+ }),
13112
+ embeddingsGenerate: channel({
13113
+ channelName: "embeddings.generate",
13114
+ kind: "async"
13115
+ }),
13116
+ betaResponsesSend: channel({
13117
+ channelName: "beta.responses.send",
13118
+ kind: "async"
13119
+ }),
13120
+ callModel: channel({
13121
+ channelName: "callModel",
13122
+ kind: "sync-stream"
13123
+ }),
13124
+ toolExecute: channel({
13125
+ channelName: "tool.execute",
13126
+ kind: "async"
13127
+ })
13128
+ });
13129
+
13130
+ // src/openrouter-utils.ts
13131
+ var TOKEN_NAME_MAP2 = {
13132
+ promptTokens: "prompt_tokens",
13133
+ inputTokens: "prompt_tokens",
13134
+ completionTokens: "completion_tokens",
13135
+ outputTokens: "completion_tokens",
13136
+ totalTokens: "tokens",
13137
+ prompt_tokens: "prompt_tokens",
13138
+ input_tokens: "prompt_tokens",
13139
+ completion_tokens: "completion_tokens",
13140
+ output_tokens: "completion_tokens",
13141
+ total_tokens: "tokens"
13142
+ };
13143
+ var TOKEN_DETAIL_PREFIX_MAP = {
13144
+ promptTokensDetails: "prompt",
13145
+ inputTokensDetails: "prompt",
13146
+ completionTokensDetails: "completion",
13147
+ outputTokensDetails: "completion",
13148
+ costDetails: "cost",
13149
+ prompt_tokens_details: "prompt",
13150
+ input_tokens_details: "prompt",
13151
+ completion_tokens_details: "completion",
13152
+ output_tokens_details: "completion",
13153
+ cost_details: "cost"
13154
+ };
13155
+ function camelToSnake(value) {
13156
+ return value.replace(/[A-Z]/g, (match) => `_${match.toLowerCase()}`);
13157
+ }
13158
+ function parseOpenRouterMetricsFromUsage(usage) {
13159
+ if (!isObject(usage)) {
13160
+ return {};
13015
13161
  }
13016
- onEnable() {
13017
- const integrations = this.config.integrations || {};
13018
- if (integrations.openai !== false) {
13019
- this.openaiPlugin = new OpenAIPlugin();
13020
- this.openaiPlugin.enable();
13021
- }
13022
- if (integrations.anthropic !== false) {
13023
- this.anthropicPlugin = new AnthropicPlugin();
13024
- this.anthropicPlugin.enable();
13162
+ const metrics = {};
13163
+ for (const [name, value] of Object.entries(usage)) {
13164
+ if (typeof value === "number") {
13165
+ metrics[TOKEN_NAME_MAP2[name] || camelToSnake(name)] = value;
13166
+ continue;
13025
13167
  }
13026
- if (integrations.aisdk !== false && integrations.vercel !== false) {
13027
- this.aiSDKPlugin = new AISDKPlugin();
13028
- this.aiSDKPlugin.enable();
13168
+ if (!isObject(value)) {
13169
+ continue;
13029
13170
  }
13030
- if (integrations.claudeAgentSDK !== false) {
13031
- this.claudeAgentSDKPlugin = new ClaudeAgentSDKPlugin();
13032
- this.claudeAgentSDKPlugin.enable();
13171
+ const prefix = TOKEN_DETAIL_PREFIX_MAP[name];
13172
+ if (!prefix) {
13173
+ continue;
13033
13174
  }
13034
- if (integrations.googleGenAI !== false && integrations.google !== false) {
13035
- this.googleGenAIPlugin = new GoogleGenAIPlugin();
13036
- this.googleGenAIPlugin.enable();
13175
+ for (const [nestedName, nestedValue] of Object.entries(value)) {
13176
+ if (typeof nestedValue !== "number") {
13177
+ continue;
13178
+ }
13179
+ metrics[`${prefix}_${camelToSnake(nestedName)}`] = nestedValue;
13037
13180
  }
13038
13181
  }
13039
- onDisable() {
13040
- if (this.openaiPlugin) {
13041
- this.openaiPlugin.disable();
13042
- this.openaiPlugin = null;
13043
- }
13044
- if (this.anthropicPlugin) {
13045
- this.anthropicPlugin.disable();
13046
- this.anthropicPlugin = null;
13047
- }
13048
- if (this.aiSDKPlugin) {
13049
- this.aiSDKPlugin.disable();
13050
- this.aiSDKPlugin = null;
13051
- }
13052
- if (this.claudeAgentSDKPlugin) {
13053
- this.claudeAgentSDKPlugin.disable();
13054
- this.claudeAgentSDKPlugin = null;
13055
- }
13056
- if (this.googleGenAIPlugin) {
13057
- this.googleGenAIPlugin.disable();
13058
- this.googleGenAIPlugin = null;
13059
- }
13182
+ return metrics;
13183
+ }
13184
+ function extractOpenRouterUsageMetadata(usage) {
13185
+ if (!isObject(usage)) {
13186
+ return void 0;
13060
13187
  }
13061
- };
13188
+ const metadata = {};
13189
+ if (typeof usage.isByok === "boolean") {
13190
+ metadata.is_byok = usage.isByok;
13191
+ } else if (typeof usage.is_byok === "boolean") {
13192
+ metadata.is_byok = usage.is_byok;
13193
+ }
13194
+ return Object.keys(metadata).length > 0 ? metadata : void 0;
13195
+ }
13062
13196
 
13063
- // src/instrumentation/registry.ts
13064
- var PluginRegistry = class {
13065
- braintrustPlugin = null;
13066
- config = {};
13067
- enabled = false;
13068
- /**
13069
- * Configure which integrations should be enabled.
13070
- * This must be called before any SDK imports to take effect.
13071
- */
13072
- configure(config) {
13073
- if (this.enabled) {
13074
- console.warn(
13075
- "Braintrust: Cannot configure instrumentation after it has been enabled. Call configureInstrumentation() before importing any AI SDKs."
13076
- );
13077
- return;
13078
- }
13079
- this.config = { ...this.config, ...config };
13197
+ // src/openrouter-logging.ts
13198
+ var OMITTED_OPENROUTER_KEYS = /* @__PURE__ */ new Set([
13199
+ "execute",
13200
+ "render",
13201
+ "nextTurnParams",
13202
+ "requireApproval"
13203
+ ]);
13204
+ function parseOpenRouterModelString(model) {
13205
+ if (typeof model !== "string") {
13206
+ return { model };
13080
13207
  }
13081
- /**
13082
- * Enable all configured plugins.
13083
- * Called automatically when the library is loaded.
13084
- */
13085
- enable() {
13086
- if (this.enabled) {
13087
- return;
13088
- }
13089
- this.enabled = true;
13090
- const envConfig = this.readEnvConfig();
13091
- const finalConfig = {
13092
- integrations: {
13093
- ...this.getDefaultConfig(),
13094
- ...this.config.integrations,
13095
- ...envConfig.integrations
13096
- }
13208
+ const slashIndex = model.indexOf("/");
13209
+ if (slashIndex > 0 && slashIndex < model.length - 1) {
13210
+ return {
13211
+ provider: model.substring(0, slashIndex),
13212
+ model: model.substring(slashIndex + 1)
13097
13213
  };
13098
- this.braintrustPlugin = new BraintrustPlugin(finalConfig);
13099
- this.braintrustPlugin.enable();
13100
13214
  }
13101
- /**
13102
- * Disable all plugins.
13103
- * Primarily used for testing.
13104
- */
13105
- disable() {
13106
- if (!this.enabled) {
13107
- return;
13215
+ return { model };
13216
+ }
13217
+ function isZodSchema2(value) {
13218
+ return value != null && typeof value === "object" && "_def" in value && typeof value._def === "object";
13219
+ }
13220
+ function serializeZodSchema2(schema) {
13221
+ try {
13222
+ return zodToJsonSchema(schema);
13223
+ } catch {
13224
+ return {
13225
+ type: "object",
13226
+ description: "Zod schema (conversion failed)"
13227
+ };
13228
+ }
13229
+ }
13230
+ function serializeOpenRouterTool(tool) {
13231
+ if (!isObject(tool)) {
13232
+ return tool;
13233
+ }
13234
+ const serialized = {};
13235
+ for (const [key, value] of Object.entries(tool)) {
13236
+ if (OMITTED_OPENROUTER_KEYS.has(key)) {
13237
+ continue;
13108
13238
  }
13109
- this.enabled = false;
13110
- if (this.braintrustPlugin) {
13111
- this.braintrustPlugin.disable();
13112
- this.braintrustPlugin = null;
13239
+ if (key === "function" && isObject(value)) {
13240
+ serialized.function = sanitizeOpenRouterLoggedValue(value);
13241
+ continue;
13113
13242
  }
13243
+ serialized[key] = sanitizeOpenRouterLoggedValue(value);
13114
13244
  }
13115
- /**
13116
- * Check if instrumentation is enabled.
13117
- */
13118
- isEnabled() {
13119
- return this.enabled;
13245
+ return serialized;
13246
+ }
13247
+ function serializeOpenRouterToolsForLogging(tools) {
13248
+ if (!Array.isArray(tools)) {
13249
+ return void 0;
13120
13250
  }
13121
- /**
13122
- * Get default configuration (all integrations enabled).
13123
- */
13124
- getDefaultConfig() {
13125
- return {
13126
- openai: true,
13127
- anthropic: true,
13128
- vercel: true,
13129
- aisdk: true,
13130
- google: true,
13131
- claudeAgentSDK: true
13132
- };
13251
+ return tools.map((tool) => serializeOpenRouterTool(tool));
13252
+ }
13253
+ function sanitizeOpenRouterLoggedValue(value) {
13254
+ if (isZodSchema2(value)) {
13255
+ return serializeZodSchema2(value);
13133
13256
  }
13134
- /**
13135
- * Read configuration from environment variables.
13136
- * Supports: BRAINTRUST_DISABLE_INSTRUMENTATION=openai,anthropic,...
13137
- */
13138
- readEnvConfig() {
13139
- const integrations = {};
13140
- const disabledList = isomorph_default.getEnv("BRAINTRUST_DISABLE_INSTRUMENTATION");
13141
- if (disabledList) {
13142
- const disabled = disabledList.split(",").map((s) => s.trim().toLowerCase()).filter((s) => s.length > 0);
13143
- for (const sdk of disabled) {
13144
- integrations[sdk] = false;
13145
- }
13257
+ if (typeof value === "function") {
13258
+ return "[Function]";
13259
+ }
13260
+ if (Array.isArray(value)) {
13261
+ return value.map((entry) => sanitizeOpenRouterLoggedValue(entry));
13262
+ }
13263
+ if (!isObject(value)) {
13264
+ return value;
13265
+ }
13266
+ const sanitized = {};
13267
+ for (const [key, entry] of Object.entries(value)) {
13268
+ if (OMITTED_OPENROUTER_KEYS.has(key)) {
13269
+ continue;
13146
13270
  }
13147
- return { integrations };
13271
+ if (key === "tools" && Array.isArray(entry)) {
13272
+ sanitized.tools = serializeOpenRouterToolsForLogging(entry);
13273
+ continue;
13274
+ }
13275
+ sanitized[key] = sanitizeOpenRouterLoggedValue(entry);
13148
13276
  }
13149
- };
13150
- var registry = new PluginRegistry();
13151
- function configureInstrumentation(config) {
13152
- registry.configure(config);
13277
+ return sanitized;
13153
13278
  }
13154
-
13155
- // src/node/config.ts
13156
- function configureNode() {
13157
- isomorph_default.buildType = "node";
13158
- isomorph_default.getRepoInfo = getRepoInfo;
13279
+ function buildOpenRouterMetadata(metadata, httpReferer, xTitle) {
13280
+ const sanitized = sanitizeOpenRouterLoggedValue(metadata);
13281
+ const metadataRecord = isObject(sanitized) ? sanitized : {};
13282
+ const { model, provider: providerRouting, ...rest } = metadataRecord;
13283
+ const normalizedModel = parseOpenRouterModelString(model);
13284
+ return {
13285
+ ...rest,
13286
+ ...normalizedModel.model !== void 0 ? { model: normalizedModel.model } : {},
13287
+ ...providerRouting !== void 0 ? { providerRouting } : {},
13288
+ ...httpReferer !== void 0 ? { httpReferer } : {},
13289
+ ...xTitle !== void 0 ? { xTitle } : {},
13290
+ provider: normalizedModel.provider || "openrouter"
13291
+ };
13292
+ }
13293
+ function buildOpenRouterEmbeddingMetadata(metadata, httpReferer, xTitle) {
13294
+ const normalized = buildOpenRouterMetadata(metadata, httpReferer, xTitle);
13295
+ return typeof normalized.model === "string" ? {
13296
+ ...normalized,
13297
+ embedding_model: normalized.model
13298
+ } : normalized;
13299
+ }
13300
+ function extractOpenRouterCallModelInput(request) {
13301
+ return isObject(request) && "input" in request ? sanitizeOpenRouterLoggedValue(request.input) : void 0;
13302
+ }
13303
+ function extractOpenRouterCallModelMetadata(request) {
13304
+ if (!isObject(request)) {
13305
+ return { provider: "openrouter" };
13306
+ }
13307
+ const { input: _input, ...metadata } = request;
13308
+ return buildOpenRouterMetadata(metadata, void 0, void 0);
13309
+ }
13310
+ function extractOpenRouterResponseMetadata(result) {
13311
+ if (!isObject(result)) {
13312
+ return void 0;
13313
+ }
13314
+ const { output: _output, data: _data, usage, ...metadata } = result;
13315
+ const sanitized = sanitizeOpenRouterLoggedValue(metadata);
13316
+ const metadataRecord = isObject(sanitized) ? sanitized : {};
13317
+ const { model, provider, ...rest } = metadataRecord;
13318
+ const normalizedModel = parseOpenRouterModelString(model);
13319
+ const normalizedProvider = (typeof provider === "string" ? provider : void 0) || normalizedModel.provider;
13320
+ const usageMetadata = extractOpenRouterUsageMetadata(usage);
13321
+ const combined = {
13322
+ ...rest,
13323
+ ...normalizedModel.model !== void 0 ? { model: normalizedModel.model } : {},
13324
+ ...usageMetadata || {},
13325
+ ...normalizedProvider !== void 0 ? { provider: normalizedProvider } : {}
13326
+ };
13327
+ return Object.keys(combined).length > 0 ? combined : void 0;
13328
+ }
13329
+ function extractOpenRouterResponseOutput(response, fallbackOutput) {
13330
+ if (isObject(response) && "output" in response && response.output !== void 0) {
13331
+ return sanitizeOpenRouterLoggedValue(response.output);
13332
+ }
13333
+ if (fallbackOutput !== void 0) {
13334
+ return sanitizeOpenRouterLoggedValue(fallbackOutput);
13335
+ }
13336
+ return void 0;
13337
+ }
13338
+
13339
+ // src/openrouter-tool-wrapping.ts
13340
+ var OPENROUTER_WRAPPED_TOOL = Symbol("braintrust.openrouter.wrappedTool");
13341
+ var OPENROUTER_WRAPPED_CALL_MODEL_RESULT = Symbol(
13342
+ "braintrust.openrouter.wrappedCallModelResult"
13343
+ );
13344
+ var OPENROUTER_CALL_MODEL_STREAM_METHODS = [
13345
+ "getFullResponsesStream",
13346
+ "getItemsStream",
13347
+ "getNewMessagesStream",
13348
+ "getReasoningStream",
13349
+ "getTextStream",
13350
+ "getToolCallsStream",
13351
+ "getToolStream"
13352
+ ];
13353
+ var OPENROUTER_CALL_MODEL_CONTEXT_METHODS = [
13354
+ "cancel",
13355
+ "getPendingToolCalls",
13356
+ "getState",
13357
+ "getToolCalls",
13358
+ "requiresApproval"
13359
+ ];
13360
+ function startOpenRouterCallModelSpan(request) {
13361
+ return startSpan({
13362
+ name: "openrouter.callModel",
13363
+ spanAttributes: {
13364
+ type: "llm" /* LLM */
13365
+ },
13366
+ event: {
13367
+ input: extractOpenRouterCallModelInput(request),
13368
+ metadata: extractOpenRouterCallModelMetadata(request)
13369
+ }
13370
+ });
13371
+ }
13372
+ function patchOpenRouterCallModelRequestTools(request) {
13373
+ if (!Array.isArray(request.tools) || request.tools.length === 0) {
13374
+ return void 0;
13375
+ }
13376
+ const originalTools = request.tools;
13377
+ const wrappedTools = originalTools.map((tool) => wrapOpenRouterTool(tool));
13378
+ const didPatch = wrappedTools.some(
13379
+ (tool, index) => tool !== originalTools[index]
13380
+ );
13381
+ if (!didPatch) {
13382
+ return void 0;
13383
+ }
13384
+ request.tools = wrappedTools;
13385
+ return () => {
13386
+ request.tools = originalTools;
13387
+ };
13388
+ }
13389
+ function patchOpenRouterCallModelResult(span, result, request) {
13390
+ if (!isObject(result) || isWrappedCallModelResult(result)) {
13391
+ return false;
13392
+ }
13393
+ const resultLike = result;
13394
+ const hasInstrumentableMethod = typeof resultLike.getResponse === "function" || typeof resultLike.getText === "function" || OPENROUTER_CALL_MODEL_STREAM_METHODS.some(
13395
+ (methodName) => typeof resultLike[methodName] === "function"
13396
+ );
13397
+ if (!hasInstrumentableMethod) {
13398
+ return false;
13399
+ }
13400
+ Object.defineProperty(resultLike, OPENROUTER_WRAPPED_CALL_MODEL_RESULT, {
13401
+ value: true,
13402
+ enumerable: false,
13403
+ configurable: false
13404
+ });
13405
+ const originalGetResponse = typeof resultLike.getResponse === "function" ? resultLike.getResponse.bind(resultLike) : void 0;
13406
+ const originalGetInitialResponse = typeof resultLike.getInitialResponse === "function" ? resultLike.getInitialResponse.bind(resultLike) : void 0;
13407
+ const originalMakeFollowupRequest = typeof resultLike.makeFollowupRequest === "function" ? resultLike.makeFollowupRequest.bind(resultLike) : void 0;
13408
+ let ended = false;
13409
+ let tracedTurnCount = 0;
13410
+ const endSpanWithResult = async (response, fallbackOutput) => {
13411
+ if (ended) {
13412
+ return;
13413
+ }
13414
+ ended = true;
13415
+ const finalResponse = getFinalOpenRouterCallModelResponse(
13416
+ resultLike,
13417
+ response
13418
+ );
13419
+ if (finalResponse) {
13420
+ const rounds = getOpenRouterCallModelRounds(resultLike);
13421
+ const metadata = extractOpenRouterCallModelResultMetadata(
13422
+ finalResponse,
13423
+ rounds.length + 1
13424
+ );
13425
+ span.log({
13426
+ output: extractOpenRouterResponseOutput(finalResponse, fallbackOutput),
13427
+ ...metadata ? { metadata } : {},
13428
+ metrics: aggregateOpenRouterCallModelMetrics(rounds, finalResponse)
13429
+ });
13430
+ span.end();
13431
+ return;
13432
+ }
13433
+ if (fallbackOutput !== void 0) {
13434
+ span.log({
13435
+ output: fallbackOutput
13436
+ });
13437
+ }
13438
+ span.end();
13439
+ };
13440
+ const endSpanWithError = (error) => {
13441
+ if (ended) {
13442
+ return;
13443
+ }
13444
+ ended = true;
13445
+ span.log({
13446
+ error: normalizeError(error).message
13447
+ });
13448
+ span.end();
13449
+ };
13450
+ const finalizeFromResponse = async (fallbackOutput) => {
13451
+ if (!originalGetResponse) {
13452
+ await endSpanWithResult(void 0, fallbackOutput);
13453
+ return;
13454
+ }
13455
+ try {
13456
+ await endSpanWithResult(await originalGetResponse(), fallbackOutput);
13457
+ } catch {
13458
+ await endSpanWithResult(void 0, fallbackOutput);
13459
+ }
13460
+ };
13461
+ if (originalGetResponse) {
13462
+ resultLike.getResponse = async (...args) => {
13463
+ return await withCurrent(span, async () => {
13464
+ try {
13465
+ const response = await originalGetResponse(...args);
13466
+ await endSpanWithResult(response);
13467
+ return response;
13468
+ } catch (error) {
13469
+ endSpanWithError(error);
13470
+ throw error;
13471
+ }
13472
+ });
13473
+ };
13474
+ }
13475
+ if (typeof resultLike.getText === "function") {
13476
+ const originalGetText = resultLike.getText.bind(resultLike);
13477
+ resultLike.getText = async (...args) => {
13478
+ return await withCurrent(span, async () => {
13479
+ try {
13480
+ const text = await originalGetText(...args);
13481
+ await finalizeFromResponse(text);
13482
+ return text;
13483
+ } catch (error) {
13484
+ endSpanWithError(error);
13485
+ throw error;
13486
+ }
13487
+ });
13488
+ };
13489
+ }
13490
+ for (const methodName of OPENROUTER_CALL_MODEL_CONTEXT_METHODS) {
13491
+ if (typeof resultLike[methodName] !== "function") {
13492
+ continue;
13493
+ }
13494
+ const originalMethod = resultLike[methodName];
13495
+ resultLike[methodName] = async (...args) => {
13496
+ return await withCurrent(span, async () => {
13497
+ return await originalMethod.apply(resultLike, args);
13498
+ });
13499
+ };
13500
+ }
13501
+ for (const methodName of OPENROUTER_CALL_MODEL_STREAM_METHODS) {
13502
+ if (typeof resultLike[methodName] !== "function") {
13503
+ continue;
13504
+ }
13505
+ const originalMethod = resultLike[methodName];
13506
+ resultLike[methodName] = (...args) => {
13507
+ const stream = withCurrent(
13508
+ span,
13509
+ () => originalMethod.apply(resultLike, args)
13510
+ );
13511
+ if (!isAsyncIterable2(stream)) {
13512
+ return stream;
13513
+ }
13514
+ return wrapAsyncIterableWithSpan({
13515
+ finalize: finalizeFromResponse,
13516
+ iteratorFactory: () => stream[Symbol.asyncIterator](),
13517
+ onError: endSpanWithError,
13518
+ span
13519
+ });
13520
+ };
13521
+ }
13522
+ if (originalGetInitialResponse) {
13523
+ let initialTurnTraced = false;
13524
+ resultLike.getInitialResponse = async (...args) => {
13525
+ if (initialTurnTraced) {
13526
+ return await withCurrent(span, async () => {
13527
+ return await originalGetInitialResponse(...args);
13528
+ });
13529
+ }
13530
+ initialTurnTraced = true;
13531
+ const resolvedRequest = getOpenRouterResolvedRequest(resultLike, request);
13532
+ const childSpan = startOpenRouterCallModelTurnSpan({
13533
+ request: resolvedRequest,
13534
+ step: tracedTurnCount + 1,
13535
+ stepType: tracedTurnCount === 0 ? "initial" : "continue"
13536
+ });
13537
+ return await withCurrent(childSpan, async () => {
13538
+ try {
13539
+ const response = await originalGetInitialResponse(...args);
13540
+ tracedTurnCount++;
13541
+ finishOpenRouterCallModelTurnSpan({
13542
+ response,
13543
+ step: tracedTurnCount,
13544
+ stepType: tracedTurnCount === 1 ? "initial" : "continue",
13545
+ span: childSpan
13546
+ });
13547
+ return response;
13548
+ } catch (error) {
13549
+ childSpan.log({
13550
+ error: normalizeError(error).message
13551
+ });
13552
+ childSpan.end();
13553
+ throw error;
13554
+ }
13555
+ });
13556
+ };
13557
+ }
13558
+ if (originalMakeFollowupRequest) {
13559
+ resultLike.makeFollowupRequest = async (...args) => {
13560
+ const currentResponse = args[0];
13561
+ const toolResults = Array.isArray(args[1]) ? args[1] : [];
13562
+ const resolvedRequest = getOpenRouterResolvedRequest(resultLike, request);
13563
+ const followupRequest = buildOpenRouterFollowupRequest(
13564
+ resolvedRequest,
13565
+ currentResponse,
13566
+ toolResults
13567
+ );
13568
+ const childSpan = startOpenRouterCallModelTurnSpan({
13569
+ request: followupRequest,
13570
+ step: tracedTurnCount + 1,
13571
+ stepType: "continue"
13572
+ });
13573
+ return await withCurrent(childSpan, async () => {
13574
+ try {
13575
+ const response = await originalMakeFollowupRequest(...args);
13576
+ tracedTurnCount++;
13577
+ finishOpenRouterCallModelTurnSpan({
13578
+ response,
13579
+ step: tracedTurnCount,
13580
+ stepType: "continue",
13581
+ span: childSpan
13582
+ });
13583
+ return response;
13584
+ } catch (error) {
13585
+ childSpan.log({
13586
+ error: normalizeError(error).message
13587
+ });
13588
+ childSpan.end();
13589
+ throw error;
13590
+ }
13591
+ });
13592
+ };
13593
+ }
13594
+ return true;
13595
+ }
13596
+ function wrapOpenRouterTool(tool) {
13597
+ if (isWrappedTool(tool) || !tool.function || typeof tool.function !== "object" || typeof tool.function.execute !== "function") {
13598
+ return tool;
13599
+ }
13600
+ const toolName = tool.function.name || "tool";
13601
+ const originalExecute = tool.function.execute;
13602
+ const wrappedTool = {
13603
+ ...tool,
13604
+ function: {
13605
+ ...tool.function,
13606
+ execute(...args) {
13607
+ return traceToolExecution({
13608
+ args,
13609
+ execute: () => Reflect.apply(originalExecute, this, args),
13610
+ toolCallId: getToolCallId(args[1]),
13611
+ toolName
13612
+ });
13613
+ }
13614
+ }
13615
+ };
13616
+ Object.defineProperty(wrappedTool, OPENROUTER_WRAPPED_TOOL, {
13617
+ value: true,
13618
+ enumerable: false,
13619
+ configurable: false
13620
+ });
13621
+ return wrappedTool;
13622
+ }
13623
+ function isWrappedTool(tool) {
13624
+ return Boolean(tool[OPENROUTER_WRAPPED_TOOL]);
13625
+ }
13626
+ function isWrappedCallModelResult(value) {
13627
+ return Boolean(
13628
+ isObject(value) && value[OPENROUTER_WRAPPED_CALL_MODEL_RESULT]
13629
+ );
13630
+ }
13631
+ function traceToolExecution(args) {
13632
+ const tracingChannel2 = openRouterChannels.toolExecute.tracingChannel();
13633
+ const input = args.args.length > 0 ? args.args[0] : void 0;
13634
+ const event = {
13635
+ arguments: [input],
13636
+ span_info: {
13637
+ name: args.toolName
13638
+ },
13639
+ toolCallId: args.toolCallId,
13640
+ toolName: args.toolName
13641
+ };
13642
+ tracingChannel2.start.publish(event);
13643
+ try {
13644
+ const result = args.execute();
13645
+ return publishToolResult(tracingChannel2, event, result);
13646
+ } catch (error) {
13647
+ event.error = normalizeError(error);
13648
+ tracingChannel2.error.publish(event);
13649
+ throw error;
13650
+ }
13651
+ }
13652
+ function publishToolResult(tracingChannel2, event, result) {
13653
+ if (isPromiseLike(result)) {
13654
+ return result.then(
13655
+ (resolved) => {
13656
+ event.result = resolved;
13657
+ tracingChannel2.asyncEnd.publish(event);
13658
+ return resolved;
13659
+ },
13660
+ (error) => {
13661
+ event.error = normalizeError(error);
13662
+ tracingChannel2.error.publish(event);
13663
+ throw error;
13664
+ }
13665
+ );
13666
+ }
13667
+ event.result = result;
13668
+ tracingChannel2.asyncEnd.publish(event);
13669
+ return result;
13670
+ }
13671
+ function getToolCallId(context) {
13672
+ const toolContext = context;
13673
+ return typeof toolContext?.toolCall?.id === "string" ? toolContext.toolCall.id : void 0;
13674
+ }
13675
+ function extractOpenRouterCallModelResultMetadata(response, turnCount) {
13676
+ const combined = {
13677
+ ...extractOpenRouterResponseMetadata(response) || {},
13678
+ ...turnCount !== void 0 ? { turn_count: turnCount } : {}
13679
+ };
13680
+ return Object.keys(combined).length > 0 ? combined : void 0;
13681
+ }
13682
+ function getFinalOpenRouterCallModelResponse(result, response) {
13683
+ if (isObject(response)) {
13684
+ return response;
13685
+ }
13686
+ return isObject(result.finalResponse) ? result.finalResponse : void 0;
13687
+ }
13688
+ function getOpenRouterCallModelRounds(result) {
13689
+ if (!Array.isArray(result.allToolExecutionRounds)) {
13690
+ return [];
13691
+ }
13692
+ return result.allToolExecutionRounds.filter((round) => isObject(round)).map((round) => ({
13693
+ response: isObject(round.response) ? round.response : void 0,
13694
+ round: typeof round.round === "number" ? round.round : void 0,
13695
+ toolResults: Array.isArray(round.toolResults) ? round.toolResults : []
13696
+ })).filter((round) => round.response !== void 0);
13697
+ }
13698
+ function aggregateOpenRouterCallModelMetrics(rounds, finalResponse) {
13699
+ const metrics = {};
13700
+ const responses = [
13701
+ ...rounds.map((round) => round.response).filter(isObject),
13702
+ finalResponse
13703
+ ];
13704
+ for (const response of responses) {
13705
+ const responseMetrics = parseOpenRouterMetricsFromUsage(response.usage);
13706
+ for (const [name, value] of Object.entries(responseMetrics)) {
13707
+ metrics[name] = (metrics[name] || 0) + value;
13708
+ }
13709
+ }
13710
+ return metrics;
13711
+ }
13712
+ function buildNextOpenRouterCallModelInput(currentInput, response, toolResults) {
13713
+ const normalizedInput = Array.isArray(currentInput) ? [...currentInput] : currentInput === void 0 ? [] : [currentInput];
13714
+ const responseOutput = Array.isArray(response.output) ? response.output : response.output === void 0 ? [] : [response.output];
13715
+ return [...normalizedInput, ...responseOutput, ...toolResults].map(
13716
+ (entry) => sanitizeOpenRouterLoggedValue(entry)
13717
+ );
13718
+ }
13719
+ function startOpenRouterCallModelTurnSpan(args) {
13720
+ const requestRecord = isObject(args.request) ? args.request : void 0;
13721
+ const metadata = requestRecord ? extractOpenRouterCallModelMetadata(requestRecord) : { provider: "openrouter" };
13722
+ if (isObject(metadata) && "tools" in metadata) {
13723
+ delete metadata.tools;
13724
+ }
13725
+ return startSpan({
13726
+ name: "openrouter.beta.responses.send",
13727
+ spanAttributes: {
13728
+ type: "llm" /* LLM */
13729
+ },
13730
+ event: {
13731
+ input: requestRecord ? extractOpenRouterCallModelInput(requestRecord) : void 0,
13732
+ metadata: {
13733
+ ...metadata,
13734
+ step: args.step,
13735
+ step_type: args.stepType
13736
+ }
13737
+ }
13738
+ });
13739
+ }
13740
+ function finishOpenRouterCallModelTurnSpan(args) {
13741
+ if (!isObject(args.response)) {
13742
+ args.span.end();
13743
+ return;
13744
+ }
13745
+ args.span.log({
13746
+ output: extractOpenRouterResponseOutput(args.response),
13747
+ ...extractOpenRouterResponseMetadata(args.response) ? {
13748
+ metadata: {
13749
+ ...extractOpenRouterResponseMetadata(args.response),
13750
+ ...args.step !== void 0 ? { step: args.step } : {},
13751
+ ...args.stepType ? { step_type: args.stepType } : {}
13752
+ }
13753
+ } : {},
13754
+ metrics: parseOpenRouterMetricsFromUsage(args.response.usage)
13755
+ });
13756
+ args.span.end();
13757
+ }
13758
+ function getOpenRouterResolvedRequest(result, request) {
13759
+ if (isObject(result.resolvedRequest)) {
13760
+ return result.resolvedRequest;
13761
+ }
13762
+ return request;
13763
+ }
13764
+ function buildOpenRouterFollowupRequest(request, currentResponse, toolResults) {
13765
+ if (!request) {
13766
+ return void 0;
13767
+ }
13768
+ return {
13769
+ ...request,
13770
+ input: buildNextOpenRouterCallModelInput(
13771
+ extractOpenRouterCallModelInput(request),
13772
+ isObject(currentResponse) ? currentResponse : {},
13773
+ toolResults
13774
+ ),
13775
+ stream: false
13776
+ };
13777
+ }
13778
+ function wrapAsyncIterableWithSpan(args) {
13779
+ return {
13780
+ [Symbol.asyncIterator]() {
13781
+ const iterator = args.iteratorFactory();
13782
+ return {
13783
+ next(value) {
13784
+ return withCurrent(
13785
+ args.span,
13786
+ () => value === void 0 ? iterator.next() : iterator.next(value)
13787
+ ).then(
13788
+ async (result) => {
13789
+ if (result.done) {
13790
+ await args.finalize();
13791
+ }
13792
+ return result;
13793
+ },
13794
+ (error) => {
13795
+ args.onError(error);
13796
+ throw error;
13797
+ }
13798
+ );
13799
+ },
13800
+ return(value) {
13801
+ if (typeof iterator.return !== "function") {
13802
+ return args.finalize().then(() => ({
13803
+ done: true,
13804
+ value
13805
+ }));
13806
+ }
13807
+ return withCurrent(args.span, () => iterator.return(value)).then(
13808
+ async (result) => {
13809
+ await args.finalize();
13810
+ return result;
13811
+ },
13812
+ (error) => {
13813
+ args.onError(error);
13814
+ throw error;
13815
+ }
13816
+ );
13817
+ },
13818
+ throw(error) {
13819
+ args.onError(error);
13820
+ if (typeof iterator.throw !== "function") {
13821
+ return Promise.reject(error);
13822
+ }
13823
+ return withCurrent(args.span, () => iterator.throw(error));
13824
+ },
13825
+ [Symbol.asyncIterator]() {
13826
+ return this;
13827
+ }
13828
+ };
13829
+ }
13830
+ };
13831
+ }
13832
+ function isAsyncIterable2(value) {
13833
+ return !!value && (typeof value === "object" || typeof value === "function") && Symbol.asyncIterator in value && typeof value[Symbol.asyncIterator] === "function";
13834
+ }
13835
+ function isPromiseLike(value) {
13836
+ return !!value && (typeof value === "object" || typeof value === "function") && "then" in value && typeof value.then === "function";
13837
+ }
13838
+ function normalizeError(error) {
13839
+ return error instanceof Error ? error : new Error(String(error));
13840
+ }
13841
+
13842
+ // src/instrumentation/plugins/openrouter-plugin.ts
13843
+ var OpenRouterPlugin = class extends BasePlugin {
13844
+ onEnable() {
13845
+ this.subscribeToOpenRouterChannels();
13846
+ }
13847
+ onDisable() {
13848
+ this.unsubscribers = unsubscribeAll(this.unsubscribers);
13849
+ }
13850
+ subscribeToOpenRouterChannels() {
13851
+ this.unsubscribers.push(
13852
+ traceStreamingChannel(openRouterChannels.chatSend, {
13853
+ name: "openrouter.chat.send",
13854
+ type: "llm" /* LLM */,
13855
+ extractInput: (args) => {
13856
+ const request = getOpenRouterRequestArg(args);
13857
+ const chatGenerationParams = isObject(request?.chatGenerationParams) ? request.chatGenerationParams : {};
13858
+ const httpReferer = request?.httpReferer;
13859
+ const xTitle = request?.xTitle;
13860
+ const { messages, ...metadata } = chatGenerationParams;
13861
+ return {
13862
+ input: messages,
13863
+ metadata: buildOpenRouterMetadata(metadata, httpReferer, xTitle)
13864
+ };
13865
+ },
13866
+ extractOutput: (result) => {
13867
+ return isObject(result) ? result.choices : void 0;
13868
+ },
13869
+ extractMetrics: (result, startTime) => {
13870
+ const metrics = parseOpenRouterMetricsFromUsage(result?.usage);
13871
+ if (startTime) {
13872
+ metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
13873
+ }
13874
+ return metrics;
13875
+ },
13876
+ aggregateChunks: aggregateOpenRouterChatChunks
13877
+ })
13878
+ );
13879
+ this.unsubscribers.push(
13880
+ traceAsyncChannel(openRouterChannels.embeddingsGenerate, {
13881
+ name: "openrouter.embeddings.generate",
13882
+ type: "llm" /* LLM */,
13883
+ extractInput: (args) => {
13884
+ const request = getOpenRouterRequestArg(args);
13885
+ const requestBody = isObject(request?.requestBody) ? request.requestBody : {};
13886
+ const httpReferer = request?.httpReferer;
13887
+ const xTitle = request?.xTitle;
13888
+ const { input, ...metadata } = requestBody;
13889
+ return {
13890
+ input,
13891
+ metadata: buildOpenRouterEmbeddingMetadata(
13892
+ metadata,
13893
+ httpReferer,
13894
+ xTitle
13895
+ )
13896
+ };
13897
+ },
13898
+ extractOutput: (result) => {
13899
+ if (!isObject(result)) {
13900
+ return void 0;
13901
+ }
13902
+ const embedding = result.data?.[0]?.embedding;
13903
+ return Array.isArray(embedding) ? { embedding_length: embedding.length } : void 0;
13904
+ },
13905
+ extractMetadata: (result) => {
13906
+ if (!isObject(result)) {
13907
+ return void 0;
13908
+ }
13909
+ return extractOpenRouterResponseMetadata(result);
13910
+ },
13911
+ extractMetrics: (result) => {
13912
+ return isObject(result) ? parseOpenRouterMetricsFromUsage(result.usage) : {};
13913
+ }
13914
+ })
13915
+ );
13916
+ this.unsubscribers.push(
13917
+ traceStreamingChannel(openRouterChannels.betaResponsesSend, {
13918
+ name: "openrouter.beta.responses.send",
13919
+ type: "llm" /* LLM */,
13920
+ extractInput: (args) => {
13921
+ const request = getOpenRouterRequestArg(args);
13922
+ const openResponsesRequest = isObject(request?.openResponsesRequest) ? request.openResponsesRequest : {};
13923
+ const httpReferer = request?.httpReferer;
13924
+ const xTitle = request?.xTitle;
13925
+ const { input, ...metadata } = openResponsesRequest;
13926
+ return {
13927
+ input,
13928
+ metadata: buildOpenRouterMetadata(metadata, httpReferer, xTitle)
13929
+ };
13930
+ },
13931
+ extractOutput: (result) => extractOpenRouterResponseOutput(result),
13932
+ extractMetadata: (result) => extractOpenRouterResponseMetadata(result),
13933
+ extractMetrics: (result, startTime) => {
13934
+ const metrics = parseOpenRouterMetricsFromUsage(result?.usage);
13935
+ if (startTime) {
13936
+ metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
13937
+ }
13938
+ return metrics;
13939
+ },
13940
+ aggregateChunks: aggregateOpenRouterResponseStreamEvents
13941
+ })
13942
+ );
13943
+ this.unsubscribers.push(
13944
+ traceSyncStreamChannel(openRouterChannels.callModel, {
13945
+ name: "openrouter.callModel",
13946
+ type: "llm" /* LLM */,
13947
+ extractInput: (args) => {
13948
+ const request = getOpenRouterCallModelRequestArg(args);
13949
+ return {
13950
+ input: request ? extractOpenRouterCallModelInput(request) : void 0,
13951
+ metadata: request ? extractOpenRouterCallModelMetadata(request) : { provider: "openrouter" }
13952
+ };
13953
+ },
13954
+ patchResult: ({ endEvent, result, span }) => {
13955
+ return patchOpenRouterCallModelResult(
13956
+ span,
13957
+ result,
13958
+ getOpenRouterCallModelRequestArg(endEvent.arguments)
13959
+ );
13960
+ }
13961
+ })
13962
+ );
13963
+ this.unsubscribers.push(
13964
+ traceStreamingChannel(openRouterChannels.toolExecute, {
13965
+ name: "openrouter.tool",
13966
+ type: "tool" /* TOOL */,
13967
+ extractInput: (args, event) => ({
13968
+ input: args[0],
13969
+ metadata: {
13970
+ provider: "openrouter",
13971
+ tool_name: event.toolName,
13972
+ ...event.toolCallId ? { tool_call_id: event.toolCallId } : {}
13973
+ }
13974
+ }),
13975
+ extractOutput: (result) => result,
13976
+ extractMetrics: () => ({}),
13977
+ aggregateChunks: (chunks) => ({
13978
+ output: chunks.length > 0 ? chunks[chunks.length - 1] : void 0,
13979
+ metrics: {}
13980
+ })
13981
+ })
13982
+ );
13983
+ const callModelChannel = openRouterChannels.callModel.tracingChannel();
13984
+ const callModelHandlers = {
13985
+ start: (event) => {
13986
+ const request = getOpenRouterCallModelRequestArg(event.arguments);
13987
+ if (!request) {
13988
+ return;
13989
+ }
13990
+ patchOpenRouterCallModelRequestTools(request);
13991
+ }
13992
+ };
13993
+ callModelChannel.subscribe(callModelHandlers);
13994
+ this.unsubscribers.push(() => {
13995
+ callModelChannel.unsubscribe(callModelHandlers);
13996
+ });
13997
+ }
13998
+ };
13999
+ function normalizeArgs(args) {
14000
+ if (Array.isArray(args)) {
14001
+ return args;
14002
+ }
14003
+ if (isArrayLike(args)) {
14004
+ return Array.from(args);
14005
+ }
14006
+ return [args];
14007
+ }
14008
+ function isArrayLike(value) {
14009
+ return isObject(value) && "length" in value && typeof value.length === "number" && Number.isInteger(value.length) && value.length >= 0;
14010
+ }
14011
+ function getOpenRouterRequestArg(args) {
14012
+ const normalizedArgs = normalizeArgs(args);
14013
+ const keyedCandidate = normalizedArgs.find(
14014
+ (arg) => isObject(arg) && ("chatGenerationParams" in arg || "requestBody" in arg || "openResponsesRequest" in arg)
14015
+ );
14016
+ if (isObject(keyedCandidate)) {
14017
+ return keyedCandidate;
14018
+ }
14019
+ const firstObjectArg = normalizedArgs.find((arg) => isObject(arg));
14020
+ return isObject(firstObjectArg) ? firstObjectArg : void 0;
14021
+ }
14022
+ function getOpenRouterCallModelRequestArg(args) {
14023
+ const firstObjectArg = normalizeArgs(args).find((arg) => isObject(arg));
14024
+ return isObject(firstObjectArg) ? firstObjectArg : void 0;
14025
+ }
14026
+ function aggregateOpenRouterChatChunks(chunks) {
14027
+ let role;
14028
+ let content = "";
14029
+ let toolCalls;
14030
+ let finishReason;
14031
+ let metrics = {};
14032
+ for (const chunk of chunks) {
14033
+ metrics = {
14034
+ ...metrics,
14035
+ ...parseOpenRouterMetricsFromUsage(chunk?.usage)
14036
+ };
14037
+ const choice = chunk?.choices?.[0];
14038
+ const delta = choice?.delta;
14039
+ if (!delta) {
14040
+ if (choice?.finish_reason !== void 0) {
14041
+ finishReason = choice.finish_reason;
14042
+ }
14043
+ continue;
14044
+ }
14045
+ if (!role && delta.role) {
14046
+ role = delta.role;
14047
+ }
14048
+ if (typeof delta.content === "string") {
14049
+ content += delta.content;
14050
+ }
14051
+ const choiceFinishReason = choice?.finishReason ?? choice?.finish_reason ?? void 0;
14052
+ const deltaFinishReason = delta.finishReason ?? delta.finish_reason ?? void 0;
14053
+ if (choiceFinishReason !== void 0) {
14054
+ finishReason = choiceFinishReason;
14055
+ } else if (deltaFinishReason !== void 0) {
14056
+ finishReason = deltaFinishReason;
14057
+ }
14058
+ const toolCallDeltas = Array.isArray(delta.toolCalls) ? delta.toolCalls : Array.isArray(delta.tool_calls) ? delta.tool_calls : void 0;
14059
+ if (!toolCallDeltas) {
14060
+ continue;
14061
+ }
14062
+ for (const toolDelta of toolCallDeltas) {
14063
+ if (!toolDelta?.function) {
14064
+ continue;
14065
+ }
14066
+ const toolIndex = toolDelta.index ?? 0;
14067
+ const existingToolCall = toolCalls?.[toolIndex];
14068
+ if (!existingToolCall || toolDelta.id && existingToolCall.id !== void 0 && existingToolCall.id !== toolDelta.id) {
14069
+ const nextToolCalls = [...toolCalls || []];
14070
+ nextToolCalls[toolIndex] = {
14071
+ index: toolIndex,
14072
+ id: toolDelta.id,
14073
+ type: toolDelta.type,
14074
+ function: {
14075
+ name: toolDelta.function.name,
14076
+ arguments: toolDelta.function.arguments || ""
14077
+ }
14078
+ };
14079
+ toolCalls = nextToolCalls;
14080
+ continue;
14081
+ }
14082
+ const current = existingToolCall;
14083
+ if (toolDelta.id && !current.id) {
14084
+ current.id = toolDelta.id;
14085
+ }
14086
+ if (toolDelta.type && !current.type) {
14087
+ current.type = toolDelta.type;
14088
+ }
14089
+ if (toolDelta.function.name && !current.function.name) {
14090
+ current.function.name = toolDelta.function.name;
14091
+ }
14092
+ current.function.arguments += toolDelta.function.arguments || "";
14093
+ }
14094
+ }
14095
+ return {
14096
+ output: [
14097
+ {
14098
+ index: 0,
14099
+ message: {
14100
+ role,
14101
+ content: content || void 0,
14102
+ ...toolCalls ? { tool_calls: toolCalls } : {}
14103
+ },
14104
+ logprobs: null,
14105
+ finish_reason: finishReason
14106
+ }
14107
+ ],
14108
+ metrics
14109
+ };
14110
+ }
14111
+ function aggregateOpenRouterResponseStreamEvents(chunks) {
14112
+ let finalResponse;
14113
+ for (const chunk of chunks) {
14114
+ const response = chunk?.response;
14115
+ if (!response) {
14116
+ continue;
14117
+ }
14118
+ if (chunk.type === "response.completed" || chunk.type === "response.incomplete" || chunk.type === "response.failed") {
14119
+ finalResponse = response;
14120
+ }
14121
+ }
14122
+ if (!finalResponse) {
14123
+ return {
14124
+ output: void 0,
14125
+ metrics: {}
14126
+ };
14127
+ }
14128
+ return {
14129
+ output: extractOpenRouterResponseOutput(finalResponse),
14130
+ metrics: parseOpenRouterMetricsFromUsage(finalResponse.usage),
14131
+ ...extractOpenRouterResponseMetadata(finalResponse) ? { metadata: extractOpenRouterResponseMetadata(finalResponse) } : {}
14132
+ };
14133
+ }
14134
+
14135
+ // src/instrumentation/braintrust-plugin.ts
14136
+ var BraintrustPlugin = class extends BasePlugin {
14137
+ config;
14138
+ openaiPlugin = null;
14139
+ anthropicPlugin = null;
14140
+ aiSDKPlugin = null;
14141
+ claudeAgentSDKPlugin = null;
14142
+ googleGenAIPlugin = null;
14143
+ openRouterPlugin = null;
14144
+ constructor(config = {}) {
14145
+ super();
14146
+ this.config = config;
14147
+ }
14148
+ onEnable() {
14149
+ const integrations = this.config.integrations || {};
14150
+ if (integrations.openai !== false) {
14151
+ this.openaiPlugin = new OpenAIPlugin();
14152
+ this.openaiPlugin.enable();
14153
+ }
14154
+ if (integrations.anthropic !== false) {
14155
+ this.anthropicPlugin = new AnthropicPlugin();
14156
+ this.anthropicPlugin.enable();
14157
+ }
14158
+ if (integrations.aisdk !== false && integrations.vercel !== false) {
14159
+ this.aiSDKPlugin = new AISDKPlugin();
14160
+ this.aiSDKPlugin.enable();
14161
+ }
14162
+ if (integrations.claudeAgentSDK !== false) {
14163
+ this.claudeAgentSDKPlugin = new ClaudeAgentSDKPlugin();
14164
+ this.claudeAgentSDKPlugin.enable();
14165
+ }
14166
+ if (integrations.googleGenAI !== false && integrations.google !== false) {
14167
+ this.googleGenAIPlugin = new GoogleGenAIPlugin();
14168
+ this.googleGenAIPlugin.enable();
14169
+ }
14170
+ if (integrations.openrouter !== false) {
14171
+ this.openRouterPlugin = new OpenRouterPlugin();
14172
+ this.openRouterPlugin.enable();
14173
+ }
14174
+ }
14175
+ onDisable() {
14176
+ if (this.openaiPlugin) {
14177
+ this.openaiPlugin.disable();
14178
+ this.openaiPlugin = null;
14179
+ }
14180
+ if (this.anthropicPlugin) {
14181
+ this.anthropicPlugin.disable();
14182
+ this.anthropicPlugin = null;
14183
+ }
14184
+ if (this.aiSDKPlugin) {
14185
+ this.aiSDKPlugin.disable();
14186
+ this.aiSDKPlugin = null;
14187
+ }
14188
+ if (this.claudeAgentSDKPlugin) {
14189
+ this.claudeAgentSDKPlugin.disable();
14190
+ this.claudeAgentSDKPlugin = null;
14191
+ }
14192
+ if (this.googleGenAIPlugin) {
14193
+ this.googleGenAIPlugin.disable();
14194
+ this.googleGenAIPlugin = null;
14195
+ }
14196
+ if (this.openRouterPlugin) {
14197
+ this.openRouterPlugin.disable();
14198
+ this.openRouterPlugin = null;
14199
+ }
14200
+ }
14201
+ };
14202
+
14203
+ // src/instrumentation/registry.ts
14204
+ var PluginRegistry = class {
14205
+ braintrustPlugin = null;
14206
+ config = {};
14207
+ enabled = false;
14208
+ /**
14209
+ * Configure which integrations should be enabled.
14210
+ * This must be called before any SDK imports to take effect.
14211
+ */
14212
+ configure(config) {
14213
+ if (this.enabled) {
14214
+ console.warn(
14215
+ "Braintrust: Cannot configure instrumentation after it has been enabled. Call configureInstrumentation() before importing any AI SDKs."
14216
+ );
14217
+ return;
14218
+ }
14219
+ this.config = { ...this.config, ...config };
14220
+ }
14221
+ /**
14222
+ * Enable all configured plugins.
14223
+ * Called automatically when the library is loaded.
14224
+ */
14225
+ enable() {
14226
+ if (this.enabled) {
14227
+ return;
14228
+ }
14229
+ this.enabled = true;
14230
+ const envConfig = this.readEnvConfig();
14231
+ const finalConfig = {
14232
+ integrations: {
14233
+ ...this.getDefaultConfig(),
14234
+ ...this.config.integrations,
14235
+ ...envConfig.integrations
14236
+ }
14237
+ };
14238
+ this.braintrustPlugin = new BraintrustPlugin(finalConfig);
14239
+ this.braintrustPlugin.enable();
14240
+ }
14241
+ /**
14242
+ * Disable all plugins.
14243
+ * Primarily used for testing.
14244
+ */
14245
+ disable() {
14246
+ if (!this.enabled) {
14247
+ return;
14248
+ }
14249
+ this.enabled = false;
14250
+ if (this.braintrustPlugin) {
14251
+ this.braintrustPlugin.disable();
14252
+ this.braintrustPlugin = null;
14253
+ }
14254
+ }
14255
+ /**
14256
+ * Check if instrumentation is enabled.
14257
+ */
14258
+ isEnabled() {
14259
+ return this.enabled;
14260
+ }
14261
+ /**
14262
+ * Get default configuration (all integrations enabled).
14263
+ */
14264
+ getDefaultConfig() {
14265
+ return {
14266
+ openai: true,
14267
+ anthropic: true,
14268
+ vercel: true,
14269
+ aisdk: true,
14270
+ google: true,
14271
+ claudeAgentSDK: true,
14272
+ openrouter: true
14273
+ };
14274
+ }
14275
+ /**
14276
+ * Read configuration from environment variables.
14277
+ * Supports: BRAINTRUST_DISABLE_INSTRUMENTATION=openai,anthropic,...
14278
+ */
14279
+ readEnvConfig() {
14280
+ const integrations = {};
14281
+ const disabledList = isomorph_default.getEnv("BRAINTRUST_DISABLE_INSTRUMENTATION");
14282
+ if (disabledList) {
14283
+ const disabled = disabledList.split(",").map((s) => s.trim().toLowerCase()).filter((s) => s.length > 0);
14284
+ for (const sdk of disabled) {
14285
+ integrations[sdk] = false;
14286
+ }
14287
+ }
14288
+ return { integrations };
14289
+ }
14290
+ };
14291
+ var registry = new PluginRegistry();
14292
+ function configureInstrumentation(config) {
14293
+ registry.configure(config);
14294
+ }
14295
+
14296
+ // src/node/config.ts
14297
+ function configureNode() {
14298
+ isomorph_default.buildType = "node";
14299
+ isomorph_default.getRepoInfo = getRepoInfo;
13159
14300
  isomorph_default.getPastNAncestors = getPastNAncestors;
13160
14301
  isomorph_default.getEnv = (name) => process.env[name];
13161
14302
  isomorph_default.getCallerLocation = getCallerLocation;
13162
14303
  isomorph_default.newAsyncLocalStorage = () => new AsyncLocalStorage();
13163
14304
  isomorph_default.newTracingChannel = (nameOrChannels) => diagnostics_channel.tracingChannel(nameOrChannels);
14305
+ patchTracingChannel(diagnostics_channel.tracingChannel);
13164
14306
  isomorph_default.processOn = (event, handler) => {
13165
14307
  process.on(event, handler);
13166
14308
  };
@@ -13323,6 +14465,7 @@ __export(exports_exports, {
13323
14465
  wrapMastraAgent: () => wrapMastraAgent,
13324
14466
  wrapOpenAI: () => wrapOpenAI,
13325
14467
  wrapOpenAIv4: () => wrapOpenAIv4,
14468
+ wrapOpenRouter: () => wrapOpenRouter,
13326
14469
  wrapTraced: () => wrapTraced,
13327
14470
  wrapVitest: () => wrapVitest
13328
14471
  });
@@ -13653,7 +14796,7 @@ function wrapOpenAIv4(openai) {
13653
14796
  return baseVal;
13654
14797
  }
13655
14798
  });
13656
- const chatProxy = new Proxy(typedOpenai.chat, {
14799
+ const chatProxy2 = new Proxy(typedOpenai.chat, {
13657
14800
  get(target, name, receiver) {
13658
14801
  if (name === "completions") {
13659
14802
  return completionProxy;
@@ -13663,7 +14806,7 @@ function wrapOpenAIv4(openai) {
13663
14806
  });
13664
14807
  const embeddingProxy = createEndpointProxy(typedOpenai.embeddings, wrapEmbeddings);
13665
14808
  const moderationProxy = createEndpointProxy(typedOpenai.moderations, wrapModerations);
13666
- let betaProxy2;
14809
+ let betaProxy3;
13667
14810
  if (typedOpenai.beta?.chat?.completions?.stream) {
13668
14811
  const betaChatCompletionProxy = new Proxy(
13669
14812
  typedOpenai?.beta?.chat.completions,
@@ -13687,7 +14830,7 @@ function wrapOpenAIv4(openai) {
13687
14830
  return Reflect.get(target, name, receiver);
13688
14831
  }
13689
14832
  });
13690
- betaProxy2 = new Proxy(typedOpenai.beta, {
14833
+ betaProxy3 = new Proxy(typedOpenai.beta, {
13691
14834
  get(target, name, receiver) {
13692
14835
  if (name === "chat") {
13693
14836
  return betaChatProxy;
@@ -13700,7 +14843,7 @@ function wrapOpenAIv4(openai) {
13700
14843
  get(target, name, receiver) {
13701
14844
  switch (name) {
13702
14845
  case "chat":
13703
- return chatProxy;
14846
+ return chatProxy2;
13704
14847
  case "embeddings":
13705
14848
  return embeddingProxy;
13706
14849
  case "moderations":
@@ -13708,8 +14851,8 @@ function wrapOpenAIv4(openai) {
13708
14851
  case "responses":
13709
14852
  return responsesProxy(typedOpenai);
13710
14853
  }
13711
- if (name === "beta" && betaProxy2) {
13712
- return betaProxy2;
14854
+ if (name === "beta" && betaProxy3) {
14855
+ return betaProxy3;
13713
14856
  }
13714
14857
  return Reflect.get(target, name, receiver);
13715
14858
  }
@@ -14673,10 +15816,10 @@ function extractGatewayRoutingInfo2(result) {
14673
15816
  }
14674
15817
  return null;
14675
15818
  }
14676
- var isZodSchema2 = (value) => {
15819
+ var isZodSchema3 = (value) => {
14677
15820
  return value != null && typeof value === "object" && "_def" in value && typeof value._def === "object";
14678
15821
  };
14679
- var serializeZodSchema2 = (schema) => {
15822
+ var serializeZodSchema3 = (schema) => {
14680
15823
  try {
14681
15824
  return zodToJsonSchema(schema);
14682
15825
  } catch {
@@ -14724,10 +15867,10 @@ var serializeOutputObject = (output, model) => {
14724
15867
  if (typeof responseFormat.then === "function") {
14725
15868
  result.response_format = Promise.resolve(responseFormat).then(
14726
15869
  (resolved) => {
14727
- if (resolved.schema && isZodSchema2(resolved.schema)) {
15870
+ if (resolved.schema && isZodSchema3(resolved.schema)) {
14728
15871
  return {
14729
15872
  ...resolved,
14730
- schema: serializeZodSchema2(resolved.schema)
15873
+ schema: serializeZodSchema3(resolved.schema)
14731
15874
  };
14732
15875
  }
14733
15876
  return resolved;
@@ -14735,10 +15878,10 @@ var serializeOutputObject = (output, model) => {
14735
15878
  );
14736
15879
  } else {
14737
15880
  const syncResponseFormat = responseFormat;
14738
- if (syncResponseFormat.schema && isZodSchema2(syncResponseFormat.schema)) {
15881
+ if (syncResponseFormat.schema && isZodSchema3(syncResponseFormat.schema)) {
14739
15882
  responseFormat = {
14740
15883
  ...syncResponseFormat,
14741
- schema: serializeZodSchema2(syncResponseFormat.schema)
15884
+ schema: serializeZodSchema3(syncResponseFormat.schema)
14742
15885
  };
14743
15886
  }
14744
15887
  result.response_format = responseFormat;
@@ -14764,11 +15907,11 @@ var processInputAttachmentsSync = (input) => {
14764
15907
  processed.prompt = processPromptContent(input.prompt);
14765
15908
  }
14766
15909
  }
14767
- if (input.schema && isZodSchema2(input.schema)) {
14768
- processed.schema = serializeZodSchema2(input.schema);
15910
+ if (input.schema && isZodSchema3(input.schema)) {
15911
+ processed.schema = serializeZodSchema3(input.schema);
14769
15912
  }
14770
- if (input.callOptionsSchema && isZodSchema2(input.callOptionsSchema)) {
14771
- processed.callOptionsSchema = serializeZodSchema2(input.callOptionsSchema);
15913
+ if (input.callOptionsSchema && isZodSchema3(input.callOptionsSchema)) {
15914
+ processed.callOptionsSchema = serializeZodSchema3(input.callOptionsSchema);
14772
15915
  }
14773
15916
  if (input.tools) {
14774
15917
  processed.tools = serializeAISDKToolsForLogging(input.tools);
@@ -14805,11 +15948,11 @@ var processInputAttachments2 = async (input) => {
14805
15948
  processed.prompt = processPromptContent(input.prompt);
14806
15949
  }
14807
15950
  }
14808
- if (input.schema && isZodSchema2(input.schema)) {
14809
- processed.schema = serializeZodSchema2(input.schema);
15951
+ if (input.schema && isZodSchema3(input.schema)) {
15952
+ processed.schema = serializeZodSchema3(input.schema);
14810
15953
  }
14811
- if (input.callOptionsSchema && isZodSchema2(input.callOptionsSchema)) {
14812
- processed.callOptionsSchema = serializeZodSchema2(input.callOptionsSchema);
15954
+ if (input.callOptionsSchema && isZodSchema3(input.callOptionsSchema)) {
15955
+ processed.callOptionsSchema = serializeZodSchema3(input.callOptionsSchema);
14813
15956
  }
14814
15957
  if (input.tools) {
14815
15958
  processed.tools = serializeAISDKToolsForLogging(input.tools);
@@ -15578,14 +16721,14 @@ function extractModelFromResult(result) {
15578
16721
  function extractModelFromWrapGenerateCallback(model) {
15579
16722
  return model?.modelId;
15580
16723
  }
15581
- function camelToSnake(str) {
16724
+ function camelToSnake2(str) {
15582
16725
  return str.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`);
15583
16726
  }
15584
16727
  function extractModelParameters(params, excludeKeys) {
15585
16728
  const modelParams = {};
15586
16729
  for (const [key, value] of Object.entries(params)) {
15587
16730
  if (value !== void 0 && !excludeKeys.has(key)) {
15588
- const snakeKey = camelToSnake(key);
16731
+ const snakeKey = camelToSnake2(key);
15589
16732
  modelParams[snakeKey] = value;
15590
16733
  }
15591
16734
  }
@@ -16445,7 +17588,7 @@ function filterSerializableOptions2(options) {
16445
17588
  }
16446
17589
  return filtered;
16447
17590
  }
16448
- function isAsyncIterable2(value) {
17591
+ function isAsyncIterable3(value) {
16449
17592
  return value !== null && typeof value === "object" && Symbol.asyncIterator in value && typeof value[Symbol.asyncIterator] === "function";
16450
17593
  }
16451
17594
  function wrapClaudeAgentQuery(queryFn, defaultThis) {
@@ -16453,7 +17596,7 @@ function wrapClaudeAgentQuery(queryFn, defaultThis) {
16453
17596
  apply(target, thisArg, argArray) {
16454
17597
  const params = argArray[0] ?? {};
16455
17598
  const { prompt, options = {} } = params;
16456
- const promptIsAsyncIterable = isAsyncIterable2(prompt);
17599
+ const promptIsAsyncIterable = isAsyncIterable3(prompt);
16457
17600
  let capturedPromptMessages;
16458
17601
  let promptForQuery = prompt;
16459
17602
  let promptStarted = false;
@@ -17302,6 +18445,111 @@ function tryToDict2(obj) {
17302
18445
  return null;
17303
18446
  }
17304
18447
 
18448
+ // src/wrappers/openrouter.ts
18449
+ function wrapOpenRouter(openrouter) {
18450
+ const or = openrouter;
18451
+ 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")) {
18452
+ return openRouterProxy(or);
18453
+ }
18454
+ console.warn("Unsupported OpenRouter library. Not wrapping.");
18455
+ return openrouter;
18456
+ }
18457
+ function openRouterProxy(openrouter) {
18458
+ return new Proxy(openrouter, {
18459
+ get(target, prop, receiver) {
18460
+ switch (prop) {
18461
+ case "chat":
18462
+ return target.chat ? chatProxy(target.chat) : target.chat;
18463
+ case "embeddings":
18464
+ return target.embeddings ? embeddingsProxy(target.embeddings) : target.embeddings;
18465
+ case "beta":
18466
+ return target.beta ? betaProxy2(target.beta) : target.beta;
18467
+ case "callModel":
18468
+ return typeof target.callModel === "function" ? wrapCallModel(target.callModel.bind(target)) : target.callModel;
18469
+ default:
18470
+ return Reflect.get(target, prop, receiver);
18471
+ }
18472
+ }
18473
+ });
18474
+ }
18475
+ function betaProxy2(beta) {
18476
+ return new Proxy(beta, {
18477
+ get(target, prop, receiver) {
18478
+ if (prop === "responses") {
18479
+ return target.responses ? responsesProxy2(target.responses) : void 0;
18480
+ }
18481
+ return Reflect.get(target, prop, receiver);
18482
+ }
18483
+ });
18484
+ }
18485
+ function chatProxy(chat) {
18486
+ return new Proxy(chat, {
18487
+ get(target, prop, receiver) {
18488
+ if (prop === "send") {
18489
+ return wrapChatSend(target.send.bind(target));
18490
+ }
18491
+ return Reflect.get(target, prop, receiver);
18492
+ }
18493
+ });
18494
+ }
18495
+ function embeddingsProxy(embeddings) {
18496
+ return new Proxy(embeddings, {
18497
+ get(target, prop, receiver) {
18498
+ if (prop === "generate") {
18499
+ return wrapEmbeddingsGenerate(target.generate.bind(target));
18500
+ }
18501
+ return Reflect.get(target, prop, receiver);
18502
+ }
18503
+ });
18504
+ }
18505
+ function responsesProxy2(responses) {
18506
+ return new Proxy(responses, {
18507
+ get(target, prop, receiver) {
18508
+ if (prop === "send") {
18509
+ return wrapResponsesSend(target.send.bind(target));
18510
+ }
18511
+ return Reflect.get(target, prop, receiver);
18512
+ }
18513
+ });
18514
+ }
18515
+ function wrapChatSend(send) {
18516
+ return (request, options) => openRouterChannels.chatSend.tracePromise(() => send(request, options), {
18517
+ arguments: [request]
18518
+ });
18519
+ }
18520
+ function wrapEmbeddingsGenerate(generate) {
18521
+ return (request, options) => openRouterChannels.embeddingsGenerate.tracePromise(
18522
+ () => generate(request, options),
18523
+ { arguments: [request] }
18524
+ );
18525
+ }
18526
+ function wrapResponsesSend(send) {
18527
+ return (request, options) => openRouterChannels.betaResponsesSend.tracePromise(
18528
+ () => send(request, options),
18529
+ { arguments: [request] }
18530
+ );
18531
+ }
18532
+ function wrapCallModel(callModel) {
18533
+ return (request, options) => {
18534
+ const patchedRequest = { ...request };
18535
+ patchOpenRouterCallModelRequestTools(patchedRequest);
18536
+ const span = startOpenRouterCallModelSpan(patchedRequest);
18537
+ try {
18538
+ const result = callModel(patchedRequest, options);
18539
+ if (!patchOpenRouterCallModelResult(span, result, patchedRequest)) {
18540
+ span.end();
18541
+ }
18542
+ return result;
18543
+ } catch (error) {
18544
+ span.log({
18545
+ error: error instanceof Error ? error.message : String(error)
18546
+ });
18547
+ span.end();
18548
+ throw error;
18549
+ }
18550
+ };
18551
+ }
18552
+
17305
18553
  // src/wrappers/vitest/context-manager.ts
17306
18554
  var VitestContextManager = class {
17307
18555
  /**
@@ -18272,7 +19520,7 @@ function isAsync(fn) {
18272
19520
  function isAsyncGenerator3(fn) {
18273
19521
  return fn[Symbol.toStringTag] === "AsyncGenerator";
18274
19522
  }
18275
- function isAsyncIterable3(obj) {
19523
+ function isAsyncIterable4(obj) {
18276
19524
  return typeof obj[Symbol.asyncIterator] === "function";
18277
19525
  }
18278
19526
  function wrapAsync(asyncFn) {
@@ -18322,7 +19570,7 @@ function _asyncMap(eachfn, arr, iteratee, callback) {
18322
19570
  callback(err, results);
18323
19571
  });
18324
19572
  }
18325
- function isArrayLike(value) {
19573
+ function isArrayLike2(value) {
18326
19574
  return value && typeof value.length === "number" && value.length >= 0 && value.length % 1 === 0;
18327
19575
  }
18328
19576
  var breakLoop = {};
@@ -18370,7 +19618,7 @@ function createObjectIterator(obj) {
18370
19618
  };
18371
19619
  }
18372
19620
  function createIterator(coll) {
18373
- if (isArrayLike(coll)) {
19621
+ if (isArrayLike2(coll)) {
18374
19622
  return createArrayIterator(coll);
18375
19623
  }
18376
19624
  var iterator = getIterator(coll);
@@ -18444,7 +19692,7 @@ var eachOfLimit$2 = (limit) => {
18444
19692
  if (isAsyncGenerator3(obj)) {
18445
19693
  return asyncEachOfLimit(obj, limit, iteratee, callback);
18446
19694
  }
18447
- if (isAsyncIterable3(obj)) {
19695
+ if (isAsyncIterable4(obj)) {
18448
19696
  return asyncEachOfLimit(obj[Symbol.asyncIterator](), limit, iteratee, callback);
18449
19697
  }
18450
19698
  var nextElem = createIterator(obj);
@@ -18516,7 +19764,7 @@ function eachOfGeneric(coll, iteratee, callback) {
18516
19764
  return eachOfLimit$1(coll, Infinity, iteratee, callback);
18517
19765
  }
18518
19766
  function eachOf(coll, iteratee, callback) {
18519
- var eachOfImplementation = isArrayLike(coll) ? eachOfArrayLike : eachOfGeneric;
19767
+ var eachOfImplementation = isArrayLike2(coll) ? eachOfArrayLike : eachOfGeneric;
18520
19768
  return eachOfImplementation(coll, wrapAsync(iteratee), callback);
18521
19769
  }
18522
19770
  var eachOf$1 = awaitify(eachOf, 3);
@@ -19031,7 +20279,7 @@ function filterGeneric(eachfn, coll, iteratee, callback) {
19031
20279
  });
19032
20280
  }
19033
20281
  function _filter(eachfn, coll, iteratee, callback) {
19034
- var filter2 = isArrayLike(coll) ? filterArray : filterGeneric;
20282
+ var filter2 = isArrayLike2(coll) ? filterArray : filterGeneric;
19035
20283
  return filter2(eachfn, coll, wrapAsync(iteratee), callback);
19036
20284
  }
19037
20285
  function filter(coll, iteratee, callback) {
@@ -19106,7 +20354,7 @@ if (hasNextTick) {
19106
20354
  }
19107
20355
  var nextTick = wrap(_defer);
19108
20356
  var _parallel = awaitify((eachfn, tasks, callback) => {
19109
- var results = isArrayLike(tasks) ? [] : {};
20357
+ var results = isArrayLike2(tasks) ? [] : {};
19110
20358
  eachfn(tasks, (task, key, taskCb) => {
19111
20359
  wrapAsync(task)((err, ...result) => {
19112
20360
  if (result.length < 2) {
@@ -19711,7 +20959,7 @@ function callEvaluatorData(data) {
19711
20959
  baseExperiment
19712
20960
  };
19713
20961
  }
19714
- function isAsyncIterable4(value) {
20962
+ function isAsyncIterable5(value) {
19715
20963
  return typeof value === "object" && value !== null && Symbol.asyncIterator in value && typeof value[Symbol.asyncIterator] === "function";
19716
20964
  }
19717
20965
  function isIterable(value) {
@@ -19935,7 +21183,7 @@ async function runEvaluatorInternal(experiment, evaluator, progressReporter, fil
19935
21183
  }
19936
21184
  const resolvedDataResult = dataResult instanceof Promise ? await dataResult : dataResult;
19937
21185
  const dataIterable = (() => {
19938
- if (isAsyncIterable4(resolvedDataResult)) {
21186
+ if (isAsyncIterable5(resolvedDataResult)) {
19939
21187
  return resolvedDataResult;
19940
21188
  }
19941
21189
  if (Array.isArray(resolvedDataResult) || isIterable(resolvedDataResult)) {
@@ -21144,6 +22392,7 @@ export {
21144
22392
  wrapMastraAgent,
21145
22393
  wrapOpenAI,
21146
22394
  wrapOpenAIv4,
22395
+ wrapOpenRouter,
21147
22396
  wrapTraced,
21148
22397
  wrapVitest
21149
22398
  };