braintrust 3.7.0 → 3.8.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 (53) hide show
  1. package/LICENSE +201 -0
  2. package/dev/dist/index.d.mts +144 -2
  3. package/dev/dist/index.d.ts +144 -2
  4. package/dev/dist/index.js +3322 -799
  5. package/dev/dist/index.mjs +3214 -691
  6. package/dist/auto-instrumentations/bundler/esbuild.cjs +377 -13
  7. package/dist/auto-instrumentations/bundler/esbuild.mjs +2 -2
  8. package/dist/auto-instrumentations/bundler/rollup.cjs +377 -13
  9. package/dist/auto-instrumentations/bundler/rollup.mjs +2 -2
  10. package/dist/auto-instrumentations/bundler/vite.cjs +377 -13
  11. package/dist/auto-instrumentations/bundler/vite.mjs +2 -2
  12. package/dist/auto-instrumentations/bundler/webpack-loader.cjs +377 -13
  13. package/dist/auto-instrumentations/bundler/webpack-loader.d.ts +11 -9
  14. package/dist/auto-instrumentations/bundler/webpack.cjs +377 -13
  15. package/dist/auto-instrumentations/bundler/webpack.mjs +2 -2
  16. package/dist/auto-instrumentations/{chunk-EVUKFMHG.mjs → chunk-ITP7RAUY.mjs} +21 -3
  17. package/dist/auto-instrumentations/{chunk-ZK2IYER2.mjs → chunk-MD7W27YH.mjs} +5 -1
  18. package/dist/auto-instrumentations/{chunk-AKEXR4AL.mjs → chunk-OLBMPZXE.mjs} +378 -14
  19. package/dist/auto-instrumentations/{chunk-VLEJ5AEK.mjs → chunk-P5YLNB2A.mjs} +21 -3
  20. package/dist/auto-instrumentations/hook.mjs +393 -19
  21. package/dist/auto-instrumentations/index.cjs +379 -13
  22. package/dist/auto-instrumentations/index.d.mts +5 -1
  23. package/dist/auto-instrumentations/index.d.ts +5 -1
  24. package/dist/auto-instrumentations/index.mjs +5 -1
  25. package/dist/auto-instrumentations/loader/cjs-patch.cjs +34 -6
  26. package/dist/auto-instrumentations/loader/cjs-patch.d.mts +1 -0
  27. package/dist/auto-instrumentations/loader/cjs-patch.d.ts +1 -0
  28. package/dist/auto-instrumentations/loader/cjs-patch.mjs +15 -5
  29. package/dist/auto-instrumentations/loader/esm-hook.mjs +8 -3
  30. package/dist/auto-instrumentations/loader/get-package-version.cjs +20 -2
  31. package/dist/auto-instrumentations/loader/get-package-version.mjs +1 -1
  32. package/dist/browser.d.mts +199 -44
  33. package/dist/browser.d.ts +199 -44
  34. package/dist/browser.js +7086 -6747
  35. package/dist/browser.mjs +7086 -6747
  36. package/dist/cli.js +3200 -677
  37. package/dist/edge-light.d.mts +1 -1
  38. package/dist/edge-light.d.ts +1 -1
  39. package/dist/edge-light.js +12645 -12215
  40. package/dist/edge-light.mjs +12645 -12215
  41. package/dist/index.d.mts +199 -44
  42. package/dist/index.d.ts +199 -44
  43. package/dist/index.js +7173 -6834
  44. package/dist/index.mjs +7022 -6683
  45. package/dist/instrumentation/index.d.mts +7 -0
  46. package/dist/instrumentation/index.d.ts +7 -0
  47. package/dist/instrumentation/index.js +3170 -669
  48. package/dist/instrumentation/index.mjs +3170 -669
  49. package/dist/workerd.d.mts +1 -1
  50. package/dist/workerd.d.ts +1 -1
  51. package/dist/workerd.js +12645 -12215
  52. package/dist/workerd.mjs +12645 -12215
  53. package/package.json +45 -45
@@ -165,7 +165,7 @@ var DefaultTracingChannel = class {
165
165
  }
166
166
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
167
167
  tracePromise(fn, _message, thisArg, ...args) {
168
- return Promise.resolve(fn.apply(thisArg, args));
168
+ return fn.apply(thisArg, args);
169
169
  }
170
170
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
171
171
  traceCallback(fn, _position, _message, thisArg, ...args) {
@@ -185,6 +185,7 @@ var iso = {
185
185
  processOn: (_0, _1) => {
186
186
  },
187
187
  basename: (filepath) => filepath.split(/[\\/]/).pop() || filepath,
188
+ // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage.
188
189
  writeln: (text) => console.log(text)
189
190
  };
190
191
  var isomorph_default = iso;
@@ -1881,6 +1882,15 @@ var InternalAbortError = class extends Error {
1881
1882
  this.name = "InternalAbortError";
1882
1883
  }
1883
1884
  };
1885
+ function filterFrom(record, keys) {
1886
+ const out = {};
1887
+ for (const k of Object.keys(record)) {
1888
+ if (!keys.includes(k)) {
1889
+ out[k] = record[k];
1890
+ }
1891
+ }
1892
+ return out;
1893
+ }
1884
1894
 
1885
1895
  // src/generated_types.ts
1886
1896
  import { z as z6 } from "zod/v3";
@@ -2092,6 +2102,16 @@ var NullableSavedFunctionId = z6.union([
2092
2102
  }),
2093
2103
  z6.null()
2094
2104
  ]);
2105
+ var TopicMapGenerationSettings = z6.object({
2106
+ algorithm: z6.enum(["hdbscan", "kmeans"]),
2107
+ dimension_reduction: z6.enum(["umap", "pca", "none"]),
2108
+ sample_size: z6.number().int().gt(0).optional(),
2109
+ n_clusters: z6.number().int().gt(0).optional(),
2110
+ min_cluster_size: z6.number().int().gt(0).optional(),
2111
+ min_samples: z6.number().int().gt(0).optional(),
2112
+ hierarchy_threshold: z6.number().int().gt(0).optional(),
2113
+ naming_model: z6.string().optional()
2114
+ });
2095
2115
  var TopicMapData = z6.object({
2096
2116
  type: z6.literal("topic_map"),
2097
2117
  source_facet: z6.string(),
@@ -2099,6 +2119,7 @@ var TopicMapData = z6.object({
2099
2119
  bundle_key: z6.string().optional(),
2100
2120
  report_key: z6.string().optional(),
2101
2121
  topic_names: z6.record(z6.string()).optional(),
2122
+ generation_settings: TopicMapGenerationSettings.optional(),
2102
2123
  distance_threshold: z6.number().optional()
2103
2124
  });
2104
2125
  var BatchedFacetData = z6.object({
@@ -2323,6 +2344,7 @@ var Dataset = z6.object({
2323
2344
  created: z6.union([z6.string(), z6.null()]).optional(),
2324
2345
  deleted_at: z6.union([z6.string(), z6.null()]).optional(),
2325
2346
  user_id: z6.union([z6.string(), z6.null()]).optional(),
2347
+ tags: z6.union([z6.array(z6.string()), z6.null()]).optional(),
2326
2348
  metadata: z6.union([z6.object({}).partial().passthrough(), z6.null()]).optional(),
2327
2349
  url_slug: z6.string()
2328
2350
  });
@@ -2405,6 +2427,14 @@ var DatasetEvent = z6.object({
2405
2427
  z6.null()
2406
2428
  ]).optional()
2407
2429
  });
2430
+ var DatasetSnapshot = z6.object({
2431
+ id: z6.string().uuid(),
2432
+ dataset_id: z6.string().uuid(),
2433
+ name: z6.string(),
2434
+ description: z6.union([z6.string(), z6.null()]),
2435
+ xact_id: z6.string(),
2436
+ created: z6.union([z6.string(), z6.null()])
2437
+ });
2408
2438
  var EnvVar = z6.object({
2409
2439
  id: z6.string().uuid(),
2410
2440
  object_type: z6.enum(["organization", "project", "function"]),
@@ -3163,6 +3193,8 @@ var TopicAutomationConfig = z6.object({
3163
3193
  scope: z6.union([SpanScope, TraceScope, GroupScope, z6.null()]).optional(),
3164
3194
  data_scope: TopicAutomationDataScope.optional(),
3165
3195
  btql_filter: z6.union([z6.string(), z6.null()]).optional(),
3196
+ rerun_seconds: z6.union([z6.number(), z6.null()]).optional(),
3197
+ relabel_overlap_seconds: z6.union([z6.number(), z6.null()]).optional(),
3166
3198
  backfill_time_range: z6.union([
3167
3199
  z6.string(),
3168
3200
  z6.object({ from: z6.string(), to: z6.string() }),
@@ -3499,7 +3531,8 @@ var User = z6.object({
3499
3531
  family_name: z6.union([z6.string(), z6.null()]).optional(),
3500
3532
  email: z6.union([z6.string(), z6.null()]).optional(),
3501
3533
  avatar_url: z6.union([z6.string(), z6.null()]).optional(),
3502
- created: z6.union([z6.string(), z6.null()]).optional()
3534
+ created: z6.union([z6.string(), z6.null()]).optional(),
3535
+ last_active_at: z6.union([z6.number(), z6.null()]).optional()
3503
3536
  });
3504
3537
  var ViewDataSearch = z6.union([
3505
3538
  z6.object({
@@ -4659,6 +4692,15 @@ var BRAINTRUST_CURRENT_SPAN_STORE = Symbol.for(
4659
4692
  "braintrust.currentSpanStore"
4660
4693
  );
4661
4694
  var ContextManager = class {
4695
+ /**
4696
+ * Returns the value to store in the ALS bound to a TracingChannel's start event.
4697
+ * In default mode this is the Span itself; in OTEL mode it is the OTEL Context
4698
+ * containing the span so that OTEL's own ALS stores a proper Context object.
4699
+ */
4700
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
4701
+ wrapSpanForStore(span) {
4702
+ return span;
4703
+ }
4662
4704
  };
4663
4705
  var BraintrustContextManager = class extends ContextManager {
4664
4706
  _currentSpan;
@@ -8874,7 +8916,7 @@ function patchStreamIfNeeded(stream, options) {
8874
8916
  if (!completed) {
8875
8917
  completed = true;
8876
8918
  try {
8877
- options.onComplete(chunks);
8919
+ await options.onComplete(chunks);
8878
8920
  } catch (error) {
8879
8921
  console.error("Error in stream onComplete handler:", error);
8880
8922
  }
@@ -8886,7 +8928,7 @@ function patchStreamIfNeeded(stream, options) {
8886
8928
  chunks.push(chunk);
8887
8929
  if (options.onChunk) {
8888
8930
  try {
8889
- options.onChunk(chunk);
8931
+ await options.onChunk(chunk);
8890
8932
  } catch (error) {
8891
8933
  console.error("Error in stream onChunk handler:", error);
8892
8934
  }
@@ -8899,7 +8941,7 @@ function patchStreamIfNeeded(stream, options) {
8899
8941
  completed = true;
8900
8942
  if (options.onError) {
8901
8943
  try {
8902
- options.onError(
8944
+ await options.onError(
8903
8945
  error instanceof Error ? error : new Error(String(error)),
8904
8946
  chunks
8905
8947
  );
@@ -8917,7 +8959,7 @@ function patchStreamIfNeeded(stream, options) {
8917
8959
  if (!completed) {
8918
8960
  completed = true;
8919
8961
  try {
8920
- options.onComplete(chunks);
8962
+ await options.onComplete(chunks);
8921
8963
  } catch (error) {
8922
8964
  console.error("Error in stream onComplete handler:", error);
8923
8965
  }
@@ -8934,7 +8976,7 @@ function patchStreamIfNeeded(stream, options) {
8934
8976
  const error = rawError instanceof Error ? rawError : new Error(String(rawError));
8935
8977
  if (options.onError) {
8936
8978
  try {
8937
- options.onError(error, chunks);
8979
+ await options.onError(error, chunks);
8938
8980
  } catch (handlerError) {
8939
8981
  console.error("Error in stream onError handler:", handlerError);
8940
8982
  }
@@ -9391,18 +9433,22 @@ function ensureSpanStateForEvent(states, config, event, channelName) {
9391
9433
  function bindCurrentSpanStoreToStart(tracingChannel2, states, config, channelName) {
9392
9434
  const state = _internalGetGlobalState();
9393
9435
  const startChannel = tracingChannel2.start;
9394
- const currentSpanStore = state?.contextManager ? state.contextManager[BRAINTRUST_CURRENT_SPAN_STORE] : void 0;
9436
+ const contextManager = state?.contextManager;
9437
+ const currentSpanStore = contextManager ? contextManager[BRAINTRUST_CURRENT_SPAN_STORE] : void 0;
9395
9438
  if (!currentSpanStore || !startChannel) {
9396
9439
  return void 0;
9397
9440
  }
9398
9441
  startChannel.bindStore(
9399
9442
  currentSpanStore,
9400
- (event) => ensureSpanStateForEvent(
9401
- states,
9402
- config,
9403
- event,
9404
- channelName
9405
- ).span
9443
+ (event) => {
9444
+ const span = ensureSpanStateForEvent(
9445
+ states,
9446
+ config,
9447
+ event,
9448
+ channelName
9449
+ ).span;
9450
+ return contextManager.wrapSpanForStore(span);
9451
+ }
9406
9452
  );
9407
9453
  return () => {
9408
9454
  startChannel.unbindStore(currentSpanStore);
@@ -9419,6 +9465,26 @@ function logErrorAndEnd(states, event) {
9419
9465
  spanData.span.end();
9420
9466
  states.delete(event);
9421
9467
  }
9468
+ function runStreamingCompletionHook(args) {
9469
+ if (!args.config.onComplete) {
9470
+ return;
9471
+ }
9472
+ try {
9473
+ args.config.onComplete({
9474
+ channelName: args.channelName,
9475
+ ...args.chunks ? { chunks: args.chunks } : {},
9476
+ endEvent: args.endEvent,
9477
+ ...args.metadata !== void 0 ? { metadata: args.metadata } : {},
9478
+ metrics: args.metrics,
9479
+ output: args.output,
9480
+ result: args.result,
9481
+ span: args.span,
9482
+ startTime: args.startTime
9483
+ });
9484
+ } catch (error) {
9485
+ console.error(`Error in onComplete hook for ${args.channelName}:`, error);
9486
+ }
9487
+ }
9422
9488
  function traceAsyncChannel(channel2, config) {
9423
9489
  const tracingChannel2 = channel2.tracingChannel();
9424
9490
  const states = /* @__PURE__ */ new WeakMap();
@@ -9546,6 +9612,18 @@ function traceStreamingChannel(channel2, config) {
9546
9612
  } else if (metrics.time_to_first_token === void 0 && chunks.length > 0) {
9547
9613
  metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
9548
9614
  }
9615
+ runStreamingCompletionHook({
9616
+ channelName,
9617
+ chunks,
9618
+ config,
9619
+ endEvent: asyncEndEvent,
9620
+ ...metadata !== void 0 ? { metadata } : {},
9621
+ metrics,
9622
+ output,
9623
+ result: asyncEndEvent.result,
9624
+ span,
9625
+ startTime
9626
+ });
9549
9627
  span.log({
9550
9628
  output,
9551
9629
  ...metadata !== void 0 ? { metadata } : {},
@@ -9595,6 +9673,17 @@ function traceStreamingChannel(channel2, config) {
9595
9673
  asyncEndEvent.result,
9596
9674
  asyncEndEvent
9597
9675
  );
9676
+ runStreamingCompletionHook({
9677
+ channelName,
9678
+ config,
9679
+ endEvent: asyncEndEvent,
9680
+ ...normalizeMetadata(metadata) !== void 0 ? { metadata: normalizeMetadata(metadata) } : {},
9681
+ metrics,
9682
+ output,
9683
+ result: asyncEndEvent.result,
9684
+ span,
9685
+ startTime
9686
+ });
9598
9687
  span.log({
9599
9688
  output,
9600
9689
  ...normalizeMetadata(metadata) !== void 0 ? { metadata: normalizeMetadata(metadata) } : {},
@@ -9643,51 +9732,28 @@ function traceSyncStreamChannel(channel2, config) {
9643
9732
  }
9644
9733
  const { span, startTime } = spanData;
9645
9734
  const endEvent = event;
9646
- if (config.patchResult?.({
9647
- channelName,
9648
- endEvent,
9649
- result: endEvent.result,
9650
- span,
9651
- startTime
9652
- })) {
9653
- return;
9654
- }
9655
- const stream = endEvent.result;
9656
- if (!isSyncStreamLike(stream)) {
9657
- span.end();
9658
- states.delete(event);
9659
- return;
9660
- }
9661
- let first = true;
9662
- stream.on("chunk", () => {
9663
- if (first) {
9664
- span.log({
9665
- metrics: {
9666
- time_to_first_token: getCurrentUnixTimestamp() - startTime
9667
- }
9668
- });
9669
- first = false;
9670
- }
9671
- });
9672
- stream.on("chatCompletion", (completion) => {
9673
- try {
9674
- if (hasChoices(completion)) {
9675
- span.log({
9676
- output: completion.choices
9677
- });
9678
- }
9679
- } catch (error) {
9680
- console.error(
9681
- `Error extracting chatCompletion for ${channelName}:`,
9682
- error
9683
- );
9735
+ const handleResolvedResult = (result) => {
9736
+ const resolvedEndEvent = {
9737
+ ...endEvent,
9738
+ result
9739
+ };
9740
+ if (config.patchResult?.({
9741
+ channelName,
9742
+ endEvent: resolvedEndEvent,
9743
+ result,
9744
+ span,
9745
+ startTime
9746
+ })) {
9747
+ return;
9684
9748
  }
9685
- });
9686
- stream.on("event", (streamEvent) => {
9687
- if (!config.extractFromEvent) {
9749
+ const stream = result;
9750
+ if (!isSyncStreamLike(stream)) {
9751
+ span.end();
9752
+ states.delete(event);
9688
9753
  return;
9689
9754
  }
9690
- try {
9755
+ let first = true;
9756
+ stream.on("chunk", () => {
9691
9757
  if (first) {
9692
9758
  span.log({
9693
9759
  metrics: {
@@ -9696,25 +9762,55 @@ function traceSyncStreamChannel(channel2, config) {
9696
9762
  });
9697
9763
  first = false;
9698
9764
  }
9699
- const extracted = config.extractFromEvent(streamEvent);
9700
- if (extracted && Object.keys(extracted).length > 0) {
9701
- span.log(extracted);
9765
+ });
9766
+ stream.on("chatCompletion", (completion) => {
9767
+ try {
9768
+ if (hasChoices(completion)) {
9769
+ span.log({
9770
+ output: completion.choices
9771
+ });
9772
+ }
9773
+ } catch (error) {
9774
+ console.error(
9775
+ `Error extracting chatCompletion for ${channelName}:`,
9776
+ error
9777
+ );
9702
9778
  }
9703
- } catch (error) {
9704
- console.error(`Error extracting event for ${channelName}:`, error);
9705
- }
9706
- });
9707
- stream.on("end", () => {
9708
- span.end();
9709
- states.delete(event);
9710
- });
9711
- stream.on("error", (error) => {
9712
- span.log({
9713
- error: error.message
9714
9779
  });
9715
- span.end();
9716
- states.delete(event);
9717
- });
9780
+ stream.on("event", (streamEvent) => {
9781
+ if (!config.extractFromEvent) {
9782
+ return;
9783
+ }
9784
+ try {
9785
+ if (first) {
9786
+ span.log({
9787
+ metrics: {
9788
+ time_to_first_token: getCurrentUnixTimestamp() - startTime
9789
+ }
9790
+ });
9791
+ first = false;
9792
+ }
9793
+ const extracted = config.extractFromEvent(streamEvent);
9794
+ if (extracted && Object.keys(extracted).length > 0) {
9795
+ span.log(extracted);
9796
+ }
9797
+ } catch (error) {
9798
+ console.error(`Error extracting event for ${channelName}:`, error);
9799
+ }
9800
+ });
9801
+ stream.on("end", () => {
9802
+ span.end();
9803
+ states.delete(event);
9804
+ });
9805
+ stream.on("error", (error) => {
9806
+ span.log({
9807
+ error: error.message
9808
+ });
9809
+ span.end();
9810
+ states.delete(event);
9811
+ });
9812
+ };
9813
+ handleResolvedResult(endEvent.result);
9718
9814
  },
9719
9815
  error: (event) => {
9720
9816
  logErrorAndEnd(states, event);
@@ -9971,6 +10067,10 @@ var openAIChannels = defineChannels("openai", {
9971
10067
  responsesParse: channel({
9972
10068
  channelName: "responses.parse",
9973
10069
  kind: "async"
10070
+ }),
10071
+ responsesCompact: channel({
10072
+ channelName: "responses.compact",
10073
+ kind: "async"
9974
10074
  })
9975
10075
  });
9976
10076
 
@@ -10250,6 +10350,40 @@ var OpenAIPlugin = class extends BasePlugin {
10250
10350
  aggregateChunks: aggregateResponseStreamEvents
10251
10351
  })
10252
10352
  );
10353
+ this.unsubscribers.push(
10354
+ traceAsyncChannel(openAIChannels.responsesCompact, {
10355
+ name: "openai.responses.compact",
10356
+ type: "llm" /* LLM */,
10357
+ extractInput: ([params]) => {
10358
+ const { input, ...metadata } = params;
10359
+ return {
10360
+ input: processInputAttachments(input),
10361
+ metadata: { ...metadata, provider: "openai" }
10362
+ };
10363
+ },
10364
+ extractOutput: (result) => {
10365
+ return processImagesInOutput(result?.output);
10366
+ },
10367
+ extractMetadata: (result) => {
10368
+ if (!result) {
10369
+ return void 0;
10370
+ }
10371
+ const { output: _output, usage: _usage, ...metadata } = result;
10372
+ return Object.keys(metadata).length > 0 ? metadata : void 0;
10373
+ },
10374
+ extractMetrics: (result, startTime, endEvent) => {
10375
+ const metrics = withCachedMetric(
10376
+ parseMetricsFromUsage(result?.usage),
10377
+ result,
10378
+ endEvent
10379
+ );
10380
+ if (startTime) {
10381
+ metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
10382
+ }
10383
+ return metrics;
10384
+ }
10385
+ })
10386
+ );
10253
10387
  }
10254
10388
  onDisable() {
10255
10389
  this.unsubscribers = unsubscribeAll(this.unsubscribers);
@@ -10537,28 +10671,40 @@ function aggregateAnthropicStreamChunks(chunks) {
10537
10671
  case "content_block_start":
10538
10672
  if (event.content_block) {
10539
10673
  contentBlocks[event.index] = event.content_block;
10540
- contentBlockDeltas[event.index] = [];
10674
+ contentBlockDeltas[event.index] = { textDeltas: [], citations: [] };
10541
10675
  }
10542
10676
  break;
10543
- case "content_block_delta":
10544
- if (event.delta?.type === "text_delta") {
10545
- const text = event.delta.text;
10677
+ case "content_block_delta": {
10678
+ const acc = contentBlockDeltas[event.index];
10679
+ const delta = event.delta;
10680
+ if (!delta) break;
10681
+ if (delta.type === "text_delta" && "text" in delta) {
10682
+ const text = delta.text;
10546
10683
  if (text) {
10547
- if (contentBlocks[event.index] !== void 0 || contentBlockDeltas[event.index] !== void 0) {
10548
- contentBlockDeltas[event.index] ??= [];
10549
- contentBlockDeltas[event.index].push(text);
10684
+ if (acc !== void 0) {
10685
+ acc.textDeltas.push(text);
10550
10686
  } else {
10551
10687
  fallbackTextDeltas.push(text);
10552
10688
  }
10553
10689
  }
10554
- } else if (event.delta?.type === "input_json_delta") {
10555
- const partialJson = event.delta.partial_json;
10556
- if (partialJson) {
10557
- contentBlockDeltas[event.index] ??= [];
10558
- contentBlockDeltas[event.index].push(partialJson);
10690
+ } else if (delta.type === "input_json_delta" && "partial_json" in delta) {
10691
+ const partialJson = delta.partial_json;
10692
+ if (partialJson && acc !== void 0) {
10693
+ acc.textDeltas.push(partialJson);
10694
+ }
10695
+ } else if (delta.type === "thinking_delta" && "thinking" in delta) {
10696
+ const thinking = delta.thinking;
10697
+ if (thinking && acc !== void 0) {
10698
+ acc.textDeltas.push(thinking);
10699
+ }
10700
+ } else if (delta.type === "citations_delta" && "citation" in delta) {
10701
+ const citation = delta.citation;
10702
+ if (citation && acc !== void 0) {
10703
+ acc.citations.push(citation);
10559
10704
  }
10560
10705
  }
10561
10706
  break;
10707
+ }
10562
10708
  case "content_block_stop":
10563
10709
  finalizeContentBlock(
10564
10710
  event.index,
@@ -10584,7 +10730,7 @@ function aggregateAnthropicStreamChunks(chunks) {
10584
10730
  })).filter(({ block }) => block !== void 0).sort((left, right) => left.index - right.index).map(({ block }) => block);
10585
10731
  let output = fallbackTextDeltas.join("");
10586
10732
  if (orderedContent.length > 0) {
10587
- if (orderedContent.every(isTextContentBlock)) {
10733
+ if (orderedContent.every(isTextContentBlock) && orderedContent.every((block) => !block.citations?.length)) {
10588
10734
  output = orderedContent.map((block) => block.text).join("");
10589
10735
  } else {
10590
10736
  output = {
@@ -10610,7 +10756,8 @@ function finalizeContentBlock(index, contentBlocks, contentBlockDeltas, fallback
10610
10756
  if (!contentBlock) {
10611
10757
  return;
10612
10758
  }
10613
- const text = contentBlockDeltas[index]?.join("") ?? "";
10759
+ const acc = contentBlockDeltas[index];
10760
+ const text = acc?.textDeltas.join("") ?? "";
10614
10761
  if (isToolUseContentBlock(contentBlock)) {
10615
10762
  if (!text) {
10616
10763
  return;
@@ -10627,20 +10774,28 @@ function finalizeContentBlock(index, contentBlocks, contentBlockDeltas, fallback
10627
10774
  return;
10628
10775
  }
10629
10776
  if (isTextContentBlock(contentBlock)) {
10777
+ if (!text) {
10778
+ delete contentBlocks[index];
10779
+ return;
10780
+ }
10781
+ const updated = { ...contentBlock, text };
10782
+ if (acc?.citations.length) {
10783
+ updated.citations = acc.citations;
10784
+ }
10785
+ contentBlocks[index] = updated;
10786
+ return;
10787
+ }
10788
+ if (isThinkingContentBlock(contentBlock)) {
10630
10789
  if (!text) {
10631
10790
  delete contentBlocks[index];
10632
10791
  return;
10633
10792
  }
10634
10793
  contentBlocks[index] = {
10635
10794
  ...contentBlock,
10636
- text
10795
+ thinking: text
10637
10796
  };
10638
10797
  return;
10639
10798
  }
10640
- if (text) {
10641
- fallbackTextDeltas.push(text);
10642
- }
10643
- delete contentBlocks[index];
10644
10799
  }
10645
10800
  function isTextContentBlock(contentBlock) {
10646
10801
  return contentBlock.type === "text";
@@ -10648,6 +10803,9 @@ function isTextContentBlock(contentBlock) {
10648
10803
  function isToolUseContentBlock(contentBlock) {
10649
10804
  return contentBlock.type === "tool_use";
10650
10805
  }
10806
+ function isThinkingContentBlock(contentBlock) {
10807
+ return contentBlock.type === "thinking";
10808
+ }
10651
10809
  function isAnthropicBase64ContentBlock(input) {
10652
10810
  return (input.type === "image" || input.type === "document") && isObject(input.source) && input.source.type === "base64";
10653
10811
  }
@@ -10702,15 +10860,6 @@ function coalesceInput(messages, system) {
10702
10860
  }
10703
10861
  return input;
10704
10862
  }
10705
- function filterFrom(obj, fieldsToRemove) {
10706
- const result = {};
10707
- for (const [key, value] of Object.entries(obj)) {
10708
- if (!fieldsToRemove.includes(key)) {
10709
- result[key] = value;
10710
- }
10711
- }
10712
- return result;
10713
- }
10714
10863
 
10715
10864
  // src/wrappers/ai-sdk/normalize-logged-output.ts
10716
10865
  var REMOVE_NORMALIZED_VALUE = Symbol("braintrust.ai-sdk.remove-normalized");
@@ -10840,6 +10989,16 @@ var aiSDKChannels = defineChannels("ai", {
10840
10989
  channelName: "streamObject.sync",
10841
10990
  kind: "sync-stream"
10842
10991
  }),
10992
+ embed: channel(
10993
+ {
10994
+ channelName: "embed",
10995
+ kind: "async"
10996
+ }
10997
+ ),
10998
+ embedMany: channel({
10999
+ channelName: "embedMany",
11000
+ kind: "async"
11001
+ }),
10843
11002
  agentGenerate: channel({
10844
11003
  channelName: "Agent.generate",
10845
11004
  kind: "async"
@@ -10848,6 +11007,10 @@ var aiSDKChannels = defineChannels("ai", {
10848
11007
  channelName: "Agent.stream",
10849
11008
  kind: "async"
10850
11009
  }),
11010
+ agentStreamSync: channel({
11011
+ channelName: "Agent.stream.sync",
11012
+ kind: "sync-stream"
11013
+ }),
10851
11014
  toolLoopAgentGenerate: channel({
10852
11015
  channelName: "ToolLoopAgent.generate",
10853
11016
  kind: "async"
@@ -10875,6 +11038,9 @@ var DEFAULT_DENY_OUTPUT_PATHS = [
10875
11038
  ];
10876
11039
  var AUTO_PATCHED_MODEL = Symbol.for("braintrust.ai-sdk.auto-patched-model");
10877
11040
  var AUTO_PATCHED_TOOL = Symbol.for("braintrust.ai-sdk.auto-patched-tool");
11041
+ var RUNTIME_DENY_OUTPUT_PATHS = Symbol.for(
11042
+ "braintrust.ai-sdk.deny-output-paths"
11043
+ );
10878
11044
  var AISDKPlugin = class extends BasePlugin {
10879
11045
  config;
10880
11046
  constructor(config = {}) {
@@ -10893,10 +11059,13 @@ var AISDKPlugin = class extends BasePlugin {
10893
11059
  traceStreamingChannel(aiSDKChannels.generateText, {
10894
11060
  name: "generateText",
10895
11061
  type: "llm" /* LLM */,
10896
- extractInput: ([params], event, span) => prepareAISDKInput(params, event, span, denyOutputPaths),
11062
+ extractInput: ([params], event, span) => prepareAISDKCallInput(params, event, span, denyOutputPaths),
10897
11063
  extractOutput: (result, endEvent) => {
10898
11064
  finalizeAISDKChildTracing(endEvent);
10899
- return processAISDKOutput(result, denyOutputPaths);
11065
+ return processAISDKOutput(
11066
+ result,
11067
+ resolveDenyOutputPaths(endEvent, denyOutputPaths)
11068
+ );
10900
11069
  },
10901
11070
  extractMetrics: (result, _startTime, endEvent) => extractTopLevelAISDKMetrics(result, endEvent),
10902
11071
  aggregateChunks: aggregateAISDKChunks
@@ -10906,12 +11075,15 @@ var AISDKPlugin = class extends BasePlugin {
10906
11075
  traceStreamingChannel(aiSDKChannels.streamText, {
10907
11076
  name: "streamText",
10908
11077
  type: "llm" /* LLM */,
10909
- extractInput: ([params], event, span) => prepareAISDKInput(params, event, span, denyOutputPaths),
10910
- extractOutput: (result) => processAISDKOutput(result, denyOutputPaths),
11078
+ extractInput: ([params], event, span) => prepareAISDKCallInput(params, event, span, denyOutputPaths),
11079
+ extractOutput: (result, endEvent) => processAISDKOutput(
11080
+ result,
11081
+ resolveDenyOutputPaths(endEvent, denyOutputPaths)
11082
+ ),
10911
11083
  extractMetrics: (result, startTime, endEvent) => extractTopLevelAISDKMetrics(result, endEvent, startTime),
10912
11084
  aggregateChunks: aggregateAISDKChunks,
10913
11085
  patchResult: ({ endEvent, result, span, startTime }) => patchAISDKStreamingResult({
10914
- denyOutputPaths,
11086
+ defaultDenyOutputPaths: denyOutputPaths,
10915
11087
  endEvent,
10916
11088
  result,
10917
11089
  span,
@@ -10923,9 +11095,9 @@ var AISDKPlugin = class extends BasePlugin {
10923
11095
  traceSyncStreamChannel(aiSDKChannels.streamTextSync, {
10924
11096
  name: "streamText",
10925
11097
  type: "llm" /* LLM */,
10926
- extractInput: ([params], event, span) => prepareAISDKInput(params, event, span, denyOutputPaths),
11098
+ extractInput: ([params], event, span) => prepareAISDKCallInput(params, event, span, denyOutputPaths),
10927
11099
  patchResult: ({ endEvent, result, span, startTime }) => patchAISDKStreamingResult({
10928
- denyOutputPaths,
11100
+ defaultDenyOutputPaths: denyOutputPaths,
10929
11101
  endEvent,
10930
11102
  result,
10931
11103
  span,
@@ -10937,10 +11109,13 @@ var AISDKPlugin = class extends BasePlugin {
10937
11109
  traceStreamingChannel(aiSDKChannels.generateObject, {
10938
11110
  name: "generateObject",
10939
11111
  type: "llm" /* LLM */,
10940
- extractInput: ([params], event, span) => prepareAISDKInput(params, event, span, denyOutputPaths),
11112
+ extractInput: ([params], event, span) => prepareAISDKCallInput(params, event, span, denyOutputPaths),
10941
11113
  extractOutput: (result, endEvent) => {
10942
11114
  finalizeAISDKChildTracing(endEvent);
10943
- return processAISDKOutput(result, denyOutputPaths);
11115
+ return processAISDKOutput(
11116
+ result,
11117
+ resolveDenyOutputPaths(endEvent, denyOutputPaths)
11118
+ );
10944
11119
  },
10945
11120
  extractMetrics: (result, _startTime, endEvent) => extractTopLevelAISDKMetrics(result, endEvent),
10946
11121
  aggregateChunks: aggregateAISDKChunks
@@ -10950,12 +11125,15 @@ var AISDKPlugin = class extends BasePlugin {
10950
11125
  traceStreamingChannel(aiSDKChannels.streamObject, {
10951
11126
  name: "streamObject",
10952
11127
  type: "llm" /* LLM */,
10953
- extractInput: ([params], event, span) => prepareAISDKInput(params, event, span, denyOutputPaths),
10954
- extractOutput: (result) => processAISDKOutput(result, denyOutputPaths),
11128
+ extractInput: ([params], event, span) => prepareAISDKCallInput(params, event, span, denyOutputPaths),
11129
+ extractOutput: (result, endEvent) => processAISDKOutput(
11130
+ result,
11131
+ resolveDenyOutputPaths(endEvent, denyOutputPaths)
11132
+ ),
10955
11133
  extractMetrics: (result, startTime, endEvent) => extractTopLevelAISDKMetrics(result, endEvent, startTime),
10956
11134
  aggregateChunks: aggregateAISDKChunks,
10957
11135
  patchResult: ({ endEvent, result, span, startTime }) => patchAISDKStreamingResult({
10958
- denyOutputPaths,
11136
+ defaultDenyOutputPaths: denyOutputPaths,
10959
11137
  endEvent,
10960
11138
  result,
10961
11139
  span,
@@ -10967,9 +11145,9 @@ var AISDKPlugin = class extends BasePlugin {
10967
11145
  traceSyncStreamChannel(aiSDKChannels.streamObjectSync, {
10968
11146
  name: "streamObject",
10969
11147
  type: "llm" /* LLM */,
10970
- extractInput: ([params], event, span) => prepareAISDKInput(params, event, span, denyOutputPaths),
11148
+ extractInput: ([params], event, span) => prepareAISDKCallInput(params, event, span, denyOutputPaths),
10971
11149
  patchResult: ({ endEvent, result, span, startTime }) => patchAISDKStreamingResult({
10972
- denyOutputPaths,
11150
+ defaultDenyOutputPaths: denyOutputPaths,
10973
11151
  endEvent,
10974
11152
  result,
10975
11153
  span,
@@ -10977,14 +11155,41 @@ var AISDKPlugin = class extends BasePlugin {
10977
11155
  })
10978
11156
  })
10979
11157
  );
11158
+ this.unsubscribers.push(
11159
+ traceAsyncChannel(aiSDKChannels.embed, {
11160
+ name: "embed",
11161
+ type: "llm" /* LLM */,
11162
+ extractInput: ([params], event) => prepareAISDKEmbedInput(params, event.self),
11163
+ extractOutput: (result, endEvent) => processAISDKEmbeddingOutput(
11164
+ result,
11165
+ resolveDenyOutputPaths(endEvent, denyOutputPaths)
11166
+ ),
11167
+ extractMetrics: (result, _startTime, endEvent) => extractTopLevelAISDKMetrics(result, endEvent)
11168
+ })
11169
+ );
11170
+ this.unsubscribers.push(
11171
+ traceAsyncChannel(aiSDKChannels.embedMany, {
11172
+ name: "embedMany",
11173
+ type: "llm" /* LLM */,
11174
+ extractInput: ([params], event) => prepareAISDKEmbedInput(params, event.self),
11175
+ extractOutput: (result, endEvent) => processAISDKEmbeddingOutput(
11176
+ result,
11177
+ resolveDenyOutputPaths(endEvent, denyOutputPaths)
11178
+ ),
11179
+ extractMetrics: (result, _startTime, endEvent) => extractTopLevelAISDKMetrics(result, endEvent)
11180
+ })
11181
+ );
10980
11182
  this.unsubscribers.push(
10981
11183
  traceStreamingChannel(aiSDKChannels.agentGenerate, {
10982
11184
  name: "Agent.generate",
10983
11185
  type: "llm" /* LLM */,
10984
- extractInput: ([params], event, span) => prepareAISDKInput(params, event, span, denyOutputPaths),
11186
+ extractInput: ([params], event, span) => prepareAISDKCallInput(params, event, span, denyOutputPaths),
10985
11187
  extractOutput: (result, endEvent) => {
10986
11188
  finalizeAISDKChildTracing(endEvent);
10987
- return processAISDKOutput(result, denyOutputPaths);
11189
+ return processAISDKOutput(
11190
+ result,
11191
+ resolveDenyOutputPaths(endEvent, denyOutputPaths)
11192
+ );
10988
11193
  },
10989
11194
  extractMetrics: (result, _startTime, endEvent) => extractTopLevelAISDKMetrics(result, endEvent),
10990
11195
  aggregateChunks: aggregateAISDKChunks
@@ -10994,12 +11199,29 @@ var AISDKPlugin = class extends BasePlugin {
10994
11199
  traceStreamingChannel(aiSDKChannels.agentStream, {
10995
11200
  name: "Agent.stream",
10996
11201
  type: "llm" /* LLM */,
10997
- extractInput: ([params], event, span) => prepareAISDKInput(params, event, span, denyOutputPaths),
10998
- extractOutput: (result) => processAISDKOutput(result, denyOutputPaths),
11202
+ extractInput: ([params], event, span) => prepareAISDKCallInput(params, event, span, denyOutputPaths),
11203
+ extractOutput: (result, endEvent) => processAISDKOutput(
11204
+ result,
11205
+ resolveDenyOutputPaths(endEvent, denyOutputPaths)
11206
+ ),
10999
11207
  extractMetrics: (result, startTime, endEvent) => extractTopLevelAISDKMetrics(result, endEvent, startTime),
11000
11208
  aggregateChunks: aggregateAISDKChunks,
11001
11209
  patchResult: ({ endEvent, result, span, startTime }) => patchAISDKStreamingResult({
11002
- denyOutputPaths,
11210
+ defaultDenyOutputPaths: denyOutputPaths,
11211
+ endEvent,
11212
+ result,
11213
+ span,
11214
+ startTime
11215
+ })
11216
+ })
11217
+ );
11218
+ this.unsubscribers.push(
11219
+ traceSyncStreamChannel(aiSDKChannels.agentStreamSync, {
11220
+ name: "Agent.stream",
11221
+ type: "llm" /* LLM */,
11222
+ extractInput: ([params], event, span) => prepareAISDKCallInput(params, event, span, denyOutputPaths),
11223
+ patchResult: ({ endEvent, result, span, startTime }) => patchAISDKStreamingResult({
11224
+ defaultDenyOutputPaths: denyOutputPaths,
11003
11225
  endEvent,
11004
11226
  result,
11005
11227
  span,
@@ -11011,10 +11233,13 @@ var AISDKPlugin = class extends BasePlugin {
11011
11233
  traceStreamingChannel(aiSDKChannels.toolLoopAgentGenerate, {
11012
11234
  name: "ToolLoopAgent.generate",
11013
11235
  type: "llm" /* LLM */,
11014
- extractInput: ([params], event, span) => prepareAISDKInput(params, event, span, denyOutputPaths),
11236
+ extractInput: ([params], event, span) => prepareAISDKCallInput(params, event, span, denyOutputPaths),
11015
11237
  extractOutput: (result, endEvent) => {
11016
11238
  finalizeAISDKChildTracing(endEvent);
11017
- return processAISDKOutput(result, denyOutputPaths);
11239
+ return processAISDKOutput(
11240
+ result,
11241
+ resolveDenyOutputPaths(endEvent, denyOutputPaths)
11242
+ );
11018
11243
  },
11019
11244
  extractMetrics: (result, _startTime, endEvent) => extractTopLevelAISDKMetrics(result, endEvent),
11020
11245
  aggregateChunks: aggregateAISDKChunks
@@ -11024,12 +11249,15 @@ var AISDKPlugin = class extends BasePlugin {
11024
11249
  traceStreamingChannel(aiSDKChannels.toolLoopAgentStream, {
11025
11250
  name: "ToolLoopAgent.stream",
11026
11251
  type: "llm" /* LLM */,
11027
- extractInput: ([params], event, span) => prepareAISDKInput(params, event, span, denyOutputPaths),
11028
- extractOutput: (result) => processAISDKOutput(result, denyOutputPaths),
11252
+ extractInput: ([params], event, span) => prepareAISDKCallInput(params, event, span, denyOutputPaths),
11253
+ extractOutput: (result, endEvent) => processAISDKOutput(
11254
+ result,
11255
+ resolveDenyOutputPaths(endEvent, denyOutputPaths)
11256
+ ),
11029
11257
  extractMetrics: (result, startTime, endEvent) => extractTopLevelAISDKMetrics(result, endEvent, startTime),
11030
11258
  aggregateChunks: aggregateAISDKChunks,
11031
11259
  patchResult: ({ endEvent, result, span, startTime }) => patchAISDKStreamingResult({
11032
- denyOutputPaths,
11260
+ defaultDenyOutputPaths: denyOutputPaths,
11033
11261
  endEvent,
11034
11262
  result,
11035
11263
  span,
@@ -11039,75 +11267,391 @@ var AISDKPlugin = class extends BasePlugin {
11039
11267
  );
11040
11268
  }
11041
11269
  };
11042
- function processAISDKInput(params) {
11043
- if (!params) return params;
11044
- const input = processInputAttachments(params);
11045
- if (!input || typeof input !== "object" || Array.isArray(input)) {
11046
- return input;
11270
+ function resolveDenyOutputPaths(event, defaultDenyOutputPaths) {
11271
+ if (Array.isArray(event?.denyOutputPaths)) {
11272
+ return event.denyOutputPaths;
11047
11273
  }
11048
- const { tools: _tools, ...rest } = input;
11049
- return rest;
11050
- }
11051
- function prepareAISDKInput(params, event, span, denyOutputPaths) {
11052
- const input = processAISDKInput(params);
11053
- const metadata = extractMetadataFromParams(params, event.self);
11054
- const childTracing = prepareAISDKChildTracing(
11055
- params,
11056
- event.self,
11057
- span,
11058
- denyOutputPaths
11059
- );
11060
- event.__braintrust_ai_sdk_model_wrapped = childTracing.modelWrapped;
11061
- if (childTracing.cleanup) {
11062
- event.__braintrust_ai_sdk_cleanup = childTracing.cleanup;
11274
+ const firstArgument = event?.arguments && event.arguments.length > 0 ? event.arguments[0] : void 0;
11275
+ if (!firstArgument || typeof firstArgument !== "object") {
11276
+ return defaultDenyOutputPaths;
11063
11277
  }
11064
- return {
11065
- input,
11066
- metadata
11067
- };
11068
- }
11069
- function extractTopLevelAISDKMetrics(result, event, startTime) {
11070
- const metrics = hasModelChildTracing(event) ? {} : extractTokenMetrics(result);
11071
- if (startTime) {
11072
- metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
11278
+ const runtimeDenyOutputPaths = firstArgument[RUNTIME_DENY_OUTPUT_PATHS];
11279
+ if (Array.isArray(runtimeDenyOutputPaths) && runtimeDenyOutputPaths.every((path2) => typeof path2 === "string")) {
11280
+ return runtimeDenyOutputPaths;
11073
11281
  }
11074
- return metrics;
11075
- }
11076
- function hasModelChildTracing(event) {
11077
- return event?.__braintrust_ai_sdk_model_wrapped === true;
11282
+ return defaultDenyOutputPaths;
11078
11283
  }
11079
- function extractMetadataFromParams(params, self) {
11080
- const metadata = {
11081
- braintrust: {
11082
- integration_name: "ai-sdk",
11083
- sdk_language: "typescript"
11084
- }
11085
- };
11086
- 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;
11087
- const { model, provider } = serializeModelWithProvider(
11088
- params.model ?? agentModel
11089
- );
11090
- if (model) {
11091
- metadata.model = model;
11284
+ var isZodSchema2 = (value) => {
11285
+ return value != null && typeof value === "object" && "_def" in value && typeof value._def === "object";
11286
+ };
11287
+ var serializeZodSchema2 = (schema) => {
11288
+ try {
11289
+ return zodToJsonSchema(schema);
11290
+ } catch {
11291
+ return {
11292
+ type: "object",
11293
+ description: "Zod schema (conversion failed)"
11294
+ };
11092
11295
  }
11093
- if (provider) {
11094
- metadata.provider = provider;
11296
+ };
11297
+ var isOutputObject = (value) => {
11298
+ if (value == null || typeof value !== "object") {
11299
+ return false;
11095
11300
  }
11301
+ const output = value;
11302
+ if (!("responseFormat" in output)) {
11303
+ return false;
11304
+ }
11305
+ if (output.type === "object" || output.type === "text") {
11306
+ return true;
11307
+ }
11308
+ if (typeof output.responseFormat === "function" || typeof output.responseFormat === "object") {
11309
+ return true;
11310
+ }
11311
+ return false;
11312
+ };
11313
+ var serializeOutputObject = (output, model) => {
11314
+ try {
11315
+ const result = {
11316
+ response_format: null
11317
+ };
11318
+ if (output.type) {
11319
+ result.type = output.type;
11320
+ }
11321
+ let responseFormat;
11322
+ if (typeof output.responseFormat === "function") {
11323
+ const mockModelForSchema = {
11324
+ supportsStructuredOutputs: true,
11325
+ ...model && typeof model === "object" ? model : {}
11326
+ };
11327
+ responseFormat = output.responseFormat({ model: mockModelForSchema });
11328
+ } else if (output.responseFormat != null && typeof output.responseFormat === "object") {
11329
+ responseFormat = output.responseFormat;
11330
+ }
11331
+ if (responseFormat) {
11332
+ if (typeof responseFormat.then === "function") {
11333
+ result.response_format = Promise.resolve(responseFormat).then(
11334
+ (resolved) => {
11335
+ if (resolved.schema && isZodSchema2(resolved.schema)) {
11336
+ return {
11337
+ ...resolved,
11338
+ schema: serializeZodSchema2(resolved.schema)
11339
+ };
11340
+ }
11341
+ return resolved;
11342
+ }
11343
+ );
11344
+ } else {
11345
+ const syncResponseFormat = responseFormat;
11346
+ if (syncResponseFormat.schema && isZodSchema2(syncResponseFormat.schema)) {
11347
+ responseFormat = {
11348
+ ...syncResponseFormat,
11349
+ schema: serializeZodSchema2(syncResponseFormat.schema)
11350
+ };
11351
+ }
11352
+ result.response_format = responseFormat;
11353
+ }
11354
+ }
11355
+ return result;
11356
+ } catch {
11357
+ return {
11358
+ response_format: null
11359
+ };
11360
+ }
11361
+ };
11362
+ var processInputAttachmentsSync = (input) => {
11363
+ if (!input) return { input };
11364
+ const processed = { ...input };
11365
+ if (input.messages && Array.isArray(input.messages)) {
11366
+ processed.messages = input.messages.map(processMessage);
11367
+ }
11368
+ if (input.prompt && typeof input.prompt === "object") {
11369
+ if (Array.isArray(input.prompt)) {
11370
+ processed.prompt = input.prompt.map(processMessage);
11371
+ } else {
11372
+ processed.prompt = processPromptContent(input.prompt);
11373
+ }
11374
+ }
11375
+ if (input.schema && isZodSchema2(input.schema)) {
11376
+ processed.schema = serializeZodSchema2(input.schema);
11377
+ }
11378
+ if (input.callOptionsSchema && isZodSchema2(input.callOptionsSchema)) {
11379
+ processed.callOptionsSchema = serializeZodSchema2(input.callOptionsSchema);
11380
+ }
11381
+ if (input.tools) {
11382
+ processed.tools = serializeAISDKToolsForLogging(input.tools);
11383
+ }
11384
+ let outputPromise;
11385
+ if (input.output && isOutputObject(input.output)) {
11386
+ const serialized = serializeOutputObject(input.output, input.model);
11387
+ if (serialized.response_format && typeof serialized.response_format.then === "function") {
11388
+ processed.output = { ...serialized, response_format: {} };
11389
+ outputPromise = serialized.response_format.then(
11390
+ (resolvedFormat) => ({
11391
+ output: { ...serialized, response_format: resolvedFormat }
11392
+ })
11393
+ );
11394
+ } else {
11395
+ processed.output = serialized;
11396
+ }
11397
+ }
11398
+ if ("prepareCall" in processed && typeof processed.prepareCall === "function") {
11399
+ processed.prepareCall = "[Function]";
11400
+ }
11401
+ return { input: processed, outputPromise };
11402
+ };
11403
+ var processMessage = (message) => {
11404
+ if (!message || typeof message !== "object") return message;
11405
+ if (Array.isArray(message.content)) {
11406
+ return {
11407
+ ...message,
11408
+ content: message.content.map(processContentPart)
11409
+ };
11410
+ }
11411
+ if (typeof message.content === "object" && message.content !== null) {
11412
+ return {
11413
+ ...message,
11414
+ content: processContentPart(message.content)
11415
+ };
11416
+ }
11417
+ return message;
11418
+ };
11419
+ var processPromptContent = (prompt) => {
11420
+ if (Array.isArray(prompt)) {
11421
+ return prompt.map(processContentPart);
11422
+ }
11423
+ if (prompt.content) {
11424
+ if (Array.isArray(prompt.content)) {
11425
+ return {
11426
+ ...prompt,
11427
+ content: prompt.content.map(processContentPart)
11428
+ };
11429
+ } else if (typeof prompt.content === "object") {
11430
+ return {
11431
+ ...prompt,
11432
+ content: processContentPart(prompt.content)
11433
+ };
11434
+ }
11435
+ }
11436
+ return prompt;
11437
+ };
11438
+ var processContentPart = (part) => {
11439
+ if (!part || typeof part !== "object") return part;
11440
+ try {
11441
+ if (part.type === "image" && part.image) {
11442
+ const imageAttachment = convertImageToAttachment(
11443
+ part.image,
11444
+ part.mimeType || part.mediaType
11445
+ );
11446
+ if (imageAttachment) {
11447
+ return {
11448
+ ...part,
11449
+ image: imageAttachment
11450
+ };
11451
+ }
11452
+ }
11453
+ if (part.type === "file" && part.data && (part.mimeType || part.mediaType)) {
11454
+ const fileAttachment = convertDataToAttachment(
11455
+ part.data,
11456
+ part.mimeType || part.mediaType,
11457
+ part.name || part.filename
11458
+ );
11459
+ if (fileAttachment) {
11460
+ return {
11461
+ ...part,
11462
+ data: fileAttachment
11463
+ };
11464
+ }
11465
+ }
11466
+ if (part.type === "image_url" && part.image_url) {
11467
+ if (typeof part.image_url === "object" && part.image_url.url) {
11468
+ const imageAttachment = convertImageToAttachment(part.image_url.url);
11469
+ if (imageAttachment) {
11470
+ return {
11471
+ ...part,
11472
+ image_url: {
11473
+ ...part.image_url,
11474
+ url: imageAttachment
11475
+ }
11476
+ };
11477
+ }
11478
+ }
11479
+ }
11480
+ } catch (error) {
11481
+ console.warn("Error processing content part:", error);
11482
+ }
11483
+ return part;
11484
+ };
11485
+ var convertImageToAttachment = (image, explicitMimeType) => {
11486
+ try {
11487
+ if (typeof image === "string" && image.startsWith("data:")) {
11488
+ const [mimeTypeSection, base64Data] = image.split(",");
11489
+ const mimeType = mimeTypeSection.match(/data:(.*?);/)?.[1];
11490
+ if (mimeType && base64Data) {
11491
+ const blob = convertDataToBlob(base64Data, mimeType);
11492
+ if (blob) {
11493
+ return new Attachment({
11494
+ data: blob,
11495
+ filename: `image.${getExtensionFromMediaType(mimeType)}`,
11496
+ contentType: mimeType
11497
+ });
11498
+ }
11499
+ }
11500
+ }
11501
+ if (explicitMimeType) {
11502
+ if (image instanceof Uint8Array) {
11503
+ return new Attachment({
11504
+ data: new Blob([image], { type: explicitMimeType }),
11505
+ filename: `image.${getExtensionFromMediaType(explicitMimeType)}`,
11506
+ contentType: explicitMimeType
11507
+ });
11508
+ }
11509
+ if (typeof Buffer !== "undefined" && Buffer.isBuffer(image)) {
11510
+ return new Attachment({
11511
+ data: new Blob([image], { type: explicitMimeType }),
11512
+ filename: `image.${getExtensionFromMediaType(explicitMimeType)}`,
11513
+ contentType: explicitMimeType
11514
+ });
11515
+ }
11516
+ }
11517
+ if (image instanceof Blob && image.type) {
11518
+ return new Attachment({
11519
+ data: image,
11520
+ filename: `image.${getExtensionFromMediaType(image.type)}`,
11521
+ contentType: image.type
11522
+ });
11523
+ }
11524
+ if (image instanceof Attachment) {
11525
+ return image;
11526
+ }
11527
+ } catch (error) {
11528
+ console.warn("Error converting image to attachment:", error);
11529
+ }
11530
+ return null;
11531
+ };
11532
+ var convertDataToAttachment = (data, mimeType, filename) => {
11533
+ if (!mimeType) return null;
11534
+ try {
11535
+ let blob = null;
11536
+ if (typeof data === "string" && data.startsWith("data:")) {
11537
+ const [, base64Data] = data.split(",");
11538
+ if (base64Data) {
11539
+ blob = convertDataToBlob(base64Data, mimeType);
11540
+ }
11541
+ } else if (typeof data === "string" && data.length > 0) {
11542
+ blob = convertDataToBlob(data, mimeType);
11543
+ } else if (data instanceof Uint8Array) {
11544
+ blob = new Blob([data], { type: mimeType });
11545
+ } else if (typeof Buffer !== "undefined" && Buffer.isBuffer(data)) {
11546
+ blob = new Blob([data], { type: mimeType });
11547
+ } else if (data instanceof Blob) {
11548
+ blob = data;
11549
+ }
11550
+ if (blob) {
11551
+ return new Attachment({
11552
+ data: blob,
11553
+ filename: filename || `file.${getExtensionFromMediaType(mimeType)}`,
11554
+ contentType: mimeType
11555
+ });
11556
+ }
11557
+ } catch (error) {
11558
+ console.warn("Error converting data to attachment:", error);
11559
+ }
11560
+ return null;
11561
+ };
11562
+ function processAISDKCallInput(params) {
11563
+ return processInputAttachmentsSync(params);
11564
+ }
11565
+ function prepareAISDKCallInput(params, event, span, defaultDenyOutputPaths) {
11566
+ const { input, outputPromise } = processAISDKCallInput(params);
11567
+ if (outputPromise && input && typeof input === "object") {
11568
+ outputPromise.then((resolvedData) => {
11569
+ span.log({
11570
+ input: {
11571
+ ...input,
11572
+ ...resolvedData
11573
+ }
11574
+ });
11575
+ }).catch(() => {
11576
+ });
11577
+ }
11578
+ const metadata = extractMetadataFromCallParams(params, event.self);
11579
+ const childTracing = prepareAISDKChildTracing(
11580
+ params,
11581
+ event.self,
11582
+ span,
11583
+ defaultDenyOutputPaths,
11584
+ event.aiSDK
11585
+ );
11586
+ event.modelWrapped = childTracing.modelWrapped;
11587
+ if (childTracing.cleanup) {
11588
+ event.__braintrust_ai_sdk_cleanup = childTracing.cleanup;
11589
+ }
11590
+ return {
11591
+ input,
11592
+ metadata
11593
+ };
11594
+ }
11595
+ function prepareAISDKEmbedInput(params, self) {
11596
+ return {
11597
+ input: { ...params },
11598
+ metadata: extractMetadataFromEmbedParams(params, self)
11599
+ };
11600
+ }
11601
+ function extractTopLevelAISDKMetrics(result, event, startTime) {
11602
+ const metrics = hasModelChildTracing(event) ? {} : extractTokenMetrics(result);
11603
+ if (startTime) {
11604
+ metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
11605
+ }
11606
+ return metrics;
11607
+ }
11608
+ function hasModelChildTracing(event) {
11609
+ return event?.modelWrapped === true || event?.__braintrust_ai_sdk_model_wrapped === true;
11610
+ }
11611
+ function createAISDKIntegrationMetadata() {
11612
+ return {
11613
+ braintrust: {
11614
+ integration_name: "ai-sdk",
11615
+ sdk_language: "typescript"
11616
+ }
11617
+ };
11618
+ }
11619
+ function resolveModelFromSelf(self) {
11620
+ return 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;
11621
+ }
11622
+ function extractBaseMetadata(model, self) {
11623
+ const metadata = createAISDKIntegrationMetadata();
11624
+ const { model: modelId, provider } = serializeModelWithProvider(
11625
+ model ?? resolveModelFromSelf(self)
11626
+ );
11627
+ if (modelId) {
11628
+ metadata.model = modelId;
11629
+ }
11630
+ if (provider) {
11631
+ metadata.provider = provider;
11632
+ }
11633
+ return metadata;
11634
+ }
11635
+ function extractMetadataFromCallParams(params, self) {
11636
+ const metadata = extractBaseMetadata(params.model, self);
11096
11637
  const tools = serializeAISDKToolsForLogging(params.tools);
11097
11638
  if (tools) {
11098
11639
  metadata.tools = tools;
11099
11640
  }
11100
11641
  return metadata;
11101
11642
  }
11102
- function prepareAISDKChildTracing(params, self, parentSpan, denyOutputPaths) {
11643
+ function extractMetadataFromEmbedParams(params, self) {
11644
+ return extractBaseMetadata(params.model, self);
11645
+ }
11646
+ function prepareAISDKChildTracing(params, self, parentSpan, denyOutputPaths, aiSDK) {
11103
11647
  const cleanup = [];
11104
11648
  const patchedModels = /* @__PURE__ */ new WeakSet();
11105
11649
  const patchedTools = /* @__PURE__ */ new WeakSet();
11106
11650
  let modelWrapped = false;
11107
11651
  const patchModel = (model) => {
11108
- const resolvedModel = resolveAISDKModel(model);
11652
+ const resolvedModel = resolveAISDKModel(model, aiSDK);
11109
11653
  if (!resolvedModel || typeof resolvedModel !== "object" || typeof resolvedModel.doGenerate !== "function" || patchedModels.has(resolvedModel) || resolvedModel[AUTO_PATCHED_MODEL]) {
11110
- return;
11654
+ return resolvedModel;
11111
11655
  }
11112
11656
  patchedModels.add(resolvedModel);
11113
11657
  resolvedModel[AUTO_PATCHED_MODEL] = true;
@@ -11136,7 +11680,7 @@ function prepareAISDKChildTracing(params, self, parentSpan, denyOutputPaths) {
11136
11680
  type: "llm" /* LLM */
11137
11681
  },
11138
11682
  event: {
11139
- input: processAISDKInput(options),
11683
+ input: processAISDKCallInput(options).input,
11140
11684
  metadata: baseMetadata
11141
11685
  }
11142
11686
  }
@@ -11150,7 +11694,7 @@ function prepareAISDKChildTracing(params, self, parentSpan, denyOutputPaths) {
11150
11694
  type: "llm" /* LLM */
11151
11695
  },
11152
11696
  event: {
11153
- input: processAISDKInput(options),
11697
+ input: processAISDKCallInput(options).input,
11154
11698
  metadata: baseMetadata
11155
11699
  }
11156
11700
  });
@@ -11158,6 +11702,8 @@ function prepareAISDKChildTracing(params, self, parentSpan, denyOutputPaths) {
11158
11702
  span,
11159
11703
  () => Reflect.apply(originalDoStream, resolvedModel, [options])
11160
11704
  );
11705
+ const streamStartTime = getCurrentUnixTimestamp();
11706
+ let firstChunkTime;
11161
11707
  const output = {};
11162
11708
  let text = "";
11163
11709
  let reasoning = "";
@@ -11165,6 +11711,9 @@ function prepareAISDKChildTracing(params, self, parentSpan, denyOutputPaths) {
11165
11711
  let object = void 0;
11166
11712
  const transformStream = new TransformStream({
11167
11713
  transform(chunk, controller) {
11714
+ if (firstChunkTime === void 0) {
11715
+ firstChunkTime = getCurrentUnixTimestamp();
11716
+ }
11168
11717
  switch (chunk.type) {
11169
11718
  case "text-delta":
11170
11719
  text += extractTextDelta(chunk);
@@ -11205,12 +11754,19 @@ function prepareAISDKChildTracing(params, self, parentSpan, denyOutputPaths) {
11205
11754
  if (object !== void 0) {
11206
11755
  output.object = object;
11207
11756
  }
11757
+ const metrics = extractTokenMetrics(output);
11758
+ if (firstChunkTime !== void 0) {
11759
+ metrics.time_to_first_token = Math.max(
11760
+ firstChunkTime - streamStartTime,
11761
+ 1e-6
11762
+ );
11763
+ }
11208
11764
  span.log({
11209
11765
  output: processAISDKOutput(
11210
11766
  output,
11211
11767
  denyOutputPaths
11212
11768
  ),
11213
- metrics: extractTokenMetrics(output),
11769
+ metrics,
11214
11770
  ...buildResolvedMetadataPayload(output)
11215
11771
  });
11216
11772
  span.end();
@@ -11232,6 +11788,7 @@ function prepareAISDKChildTracing(params, self, parentSpan, denyOutputPaths) {
11232
11788
  }
11233
11789
  delete resolvedModel[AUTO_PATCHED_MODEL];
11234
11790
  });
11791
+ return resolvedModel;
11235
11792
  };
11236
11793
  const patchTool = (tool, name) => {
11237
11794
  if (tool == null || typeof tool !== "object" || !("execute" in tool) || typeof tool.execute !== "function" || patchedTools.has(tool) || tool[AUTO_PATCHED_TOOL]) {
@@ -11304,17 +11861,26 @@ function prepareAISDKChildTracing(params, self, parentSpan, denyOutputPaths) {
11304
11861
  }
11305
11862
  };
11306
11863
  if (params && typeof params === "object") {
11307
- patchModel(params.model);
11864
+ const patchedParamModel = patchModel(params.model);
11865
+ if (typeof params.model === "string" && patchedParamModel && typeof patchedParamModel === "object") {
11866
+ params.model = patchedParamModel;
11867
+ }
11308
11868
  patchTools(params.tools);
11309
11869
  }
11310
11870
  if (self && typeof self === "object") {
11311
11871
  const selfRecord = self;
11312
11872
  if (selfRecord.model !== void 0) {
11313
- patchModel(selfRecord.model);
11873
+ const patchedSelfModel = patchModel(selfRecord.model);
11874
+ if (typeof selfRecord.model === "string" && patchedSelfModel && typeof patchedSelfModel === "object") {
11875
+ selfRecord.model = patchedSelfModel;
11876
+ }
11314
11877
  }
11315
11878
  if (selfRecord.settings && typeof selfRecord.settings === "object") {
11316
11879
  if (selfRecord.settings.model !== void 0) {
11317
- patchModel(selfRecord.settings.model);
11880
+ const patchedSettingsModel = patchModel(selfRecord.settings.model);
11881
+ if (typeof selfRecord.settings.model === "string" && patchedSettingsModel && typeof patchedSettingsModel === "object") {
11882
+ selfRecord.settings.model = patchedSettingsModel;
11883
+ }
11318
11884
  }
11319
11885
  if (selfRecord.settings.tools !== void 0) {
11320
11886
  patchTools(selfRecord.settings.tools);
@@ -11338,63 +11904,178 @@ function finalizeAISDKChildTracing(event) {
11338
11904
  }
11339
11905
  }
11340
11906
  function patchAISDKStreamingResult(args) {
11341
- const { denyOutputPaths, endEvent, result, span, startTime } = args;
11907
+ const { defaultDenyOutputPaths, endEvent, result, span, startTime } = args;
11342
11908
  if (!result || typeof result !== "object") {
11343
11909
  return false;
11344
11910
  }
11345
11911
  const resultRecord = result;
11346
- if (!isReadableStreamLike(resultRecord.baseStream)) {
11912
+ attachKnownResultPromiseHandlers(resultRecord);
11913
+ if (isReadableStreamLike(resultRecord.baseStream)) {
11914
+ let firstChunkTime2;
11915
+ const wrappedBaseStream = resultRecord.baseStream.pipeThrough(
11916
+ new TransformStream({
11917
+ transform(chunk, controller) {
11918
+ if (firstChunkTime2 === void 0) {
11919
+ firstChunkTime2 = getCurrentUnixTimestamp();
11920
+ }
11921
+ controller.enqueue(chunk);
11922
+ },
11923
+ async flush() {
11924
+ const metrics = extractTopLevelAISDKMetrics(result, endEvent);
11925
+ if (metrics.time_to_first_token === void 0 && firstChunkTime2 !== void 0) {
11926
+ metrics.time_to_first_token = firstChunkTime2 - startTime;
11927
+ }
11928
+ const output = await processAISDKStreamingOutput(
11929
+ result,
11930
+ resolveDenyOutputPaths(endEvent, defaultDenyOutputPaths)
11931
+ );
11932
+ const metadata = buildResolvedMetadataPayload(result).metadata;
11933
+ span.log({
11934
+ output,
11935
+ ...metadata ? { metadata } : {},
11936
+ metrics
11937
+ });
11938
+ finalizeAISDKChildTracing(endEvent);
11939
+ span.end();
11940
+ }
11941
+ })
11942
+ );
11943
+ Object.defineProperty(resultRecord, "baseStream", {
11944
+ configurable: true,
11945
+ enumerable: true,
11946
+ value: wrappedBaseStream,
11947
+ writable: true
11948
+ });
11949
+ return true;
11950
+ }
11951
+ const streamField = findAsyncIterableField(resultRecord, [
11952
+ "partialObjectStream",
11953
+ "textStream",
11954
+ "fullStream",
11955
+ "stream"
11956
+ ]);
11957
+ if (!streamField) {
11347
11958
  return false;
11348
11959
  }
11349
11960
  let firstChunkTime;
11350
- const wrappedBaseStream = resultRecord.baseStream.pipeThrough(
11351
- new TransformStream({
11352
- transform(chunk, controller) {
11353
- if (firstChunkTime === void 0) {
11354
- firstChunkTime = getCurrentUnixTimestamp();
11355
- }
11356
- controller.enqueue(chunk);
11357
- },
11358
- async flush() {
11359
- const metrics = extractTopLevelAISDKMetrics(result, endEvent);
11360
- if (metrics.time_to_first_token === void 0 && firstChunkTime !== void 0) {
11361
- metrics.time_to_first_token = firstChunkTime - startTime;
11362
- }
11363
- const output = await processAISDKStreamingOutput(
11364
- result,
11365
- denyOutputPaths
11366
- );
11367
- const metadata = buildResolvedMetadataPayload(result).metadata;
11368
- span.log({
11369
- output,
11370
- ...metadata ? { metadata } : {},
11371
- metrics
11372
- });
11373
- finalizeAISDKChildTracing(endEvent);
11374
- span.end();
11961
+ const wrappedStream = createPatchedAsyncIterable(streamField.stream, {
11962
+ onChunk: () => {
11963
+ if (firstChunkTime === void 0) {
11964
+ firstChunkTime = getCurrentUnixTimestamp();
11375
11965
  }
11376
- })
11377
- );
11378
- Object.defineProperty(resultRecord, "baseStream", {
11966
+ },
11967
+ onComplete: async () => {
11968
+ const metrics = extractTopLevelAISDKMetrics(result, endEvent);
11969
+ if (metrics.time_to_first_token === void 0 && firstChunkTime !== void 0) {
11970
+ metrics.time_to_first_token = firstChunkTime - startTime;
11971
+ }
11972
+ const output = await processAISDKStreamingOutput(
11973
+ result,
11974
+ resolveDenyOutputPaths(endEvent, defaultDenyOutputPaths)
11975
+ );
11976
+ const metadata = buildResolvedMetadataPayload(result).metadata;
11977
+ span.log({
11978
+ output,
11979
+ ...metadata ? { metadata } : {},
11980
+ metrics
11981
+ });
11982
+ finalizeAISDKChildTracing(endEvent);
11983
+ span.end();
11984
+ },
11985
+ onError: (error) => {
11986
+ span.log({
11987
+ error: error.message
11988
+ });
11989
+ finalizeAISDKChildTracing(endEvent);
11990
+ span.end();
11991
+ }
11992
+ });
11993
+ Object.defineProperty(resultRecord, streamField.field, {
11379
11994
  configurable: true,
11380
11995
  enumerable: true,
11381
- value: wrappedBaseStream,
11996
+ value: wrappedStream,
11382
11997
  writable: true
11383
11998
  });
11384
11999
  return true;
11385
12000
  }
12001
+ function attachKnownResultPromiseHandlers(result) {
12002
+ const promiseLikeFields = [
12003
+ "content",
12004
+ "text",
12005
+ "object",
12006
+ "value",
12007
+ "values",
12008
+ "finishReason",
12009
+ "embedding",
12010
+ "embeddings",
12011
+ "usage",
12012
+ "totalUsage",
12013
+ "responses",
12014
+ "steps"
12015
+ ];
12016
+ for (const field of promiseLikeFields) {
12017
+ try {
12018
+ if (!(field in result)) {
12019
+ continue;
12020
+ }
12021
+ const value = result[field];
12022
+ if (isPromiseLike(value)) {
12023
+ void Promise.resolve(value).catch(() => {
12024
+ });
12025
+ }
12026
+ } catch {
12027
+ }
12028
+ }
12029
+ }
11386
12030
  function isReadableStreamLike(value) {
11387
12031
  return value != null && typeof value === "object" && typeof value.pipeThrough === "function";
11388
12032
  }
12033
+ function isAsyncIterableLike(value) {
12034
+ return value != null && typeof value === "object" && typeof value[Symbol.asyncIterator] === "function";
12035
+ }
12036
+ function findAsyncIterableField(result, candidateFields) {
12037
+ for (const field of candidateFields) {
12038
+ try {
12039
+ const stream = result[field];
12040
+ if (isAsyncIterableLike(stream)) {
12041
+ return { field, stream };
12042
+ }
12043
+ } catch {
12044
+ }
12045
+ }
12046
+ return null;
12047
+ }
12048
+ function createPatchedAsyncIterable(stream, hooks) {
12049
+ return {
12050
+ async *[Symbol.asyncIterator]() {
12051
+ try {
12052
+ for await (const chunk of stream) {
12053
+ hooks.onChunk(chunk);
12054
+ yield chunk;
12055
+ }
12056
+ await hooks.onComplete();
12057
+ } catch (error) {
12058
+ hooks.onError(
12059
+ error instanceof Error ? error : new Error(String(error))
12060
+ );
12061
+ throw error;
12062
+ }
12063
+ }
12064
+ };
12065
+ }
11389
12066
  async function processAISDKStreamingOutput(result, denyOutputPaths) {
11390
12067
  const output = processAISDKOutput(result, denyOutputPaths);
11391
12068
  if (!output || typeof output !== "object") {
11392
12069
  return output;
11393
12070
  }
11394
12071
  const outputRecord = output;
12072
+ const isObjectStreamingResult = result != null && typeof result === "object" && "partialObjectStream" in result;
11395
12073
  try {
11396
- if ("text" in result && typeof result.text === "string") {
11397
- outputRecord.text = result.text;
12074
+ if (!isObjectStreamingResult && "text" in result) {
12075
+ const resolvedText = await Promise.resolve(result.text);
12076
+ if (typeof resolvedText === "string") {
12077
+ outputRecord.text = resolvedText;
12078
+ }
11398
12079
  }
11399
12080
  } catch {
11400
12081
  }
@@ -11407,6 +12088,15 @@ async function processAISDKStreamingOutput(result, denyOutputPaths) {
11407
12088
  }
11408
12089
  } catch {
11409
12090
  }
12091
+ try {
12092
+ if ("finishReason" in result) {
12093
+ const resolvedFinishReason = await Promise.resolve(result.finishReason);
12094
+ if (resolvedFinishReason !== void 0) {
12095
+ outputRecord.finishReason = resolvedFinishReason;
12096
+ }
12097
+ }
12098
+ } catch {
12099
+ }
11410
12100
  return outputRecord;
11411
12101
  }
11412
12102
  function buildAISDKChildMetadata(model) {
@@ -11429,16 +12119,25 @@ function buildResolvedMetadataPayload(result) {
11429
12119
  if (gatewayInfo?.model) {
11430
12120
  metadata.model = gatewayInfo.model;
11431
12121
  }
11432
- if (result.finishReason !== void 0) {
11433
- metadata.finish_reason = result.finishReason;
12122
+ let finishReason;
12123
+ try {
12124
+ finishReason = result.finishReason;
12125
+ } catch {
12126
+ finishReason = void 0;
12127
+ }
12128
+ if (isPromiseLike(finishReason)) {
12129
+ void Promise.resolve(finishReason).catch(() => {
12130
+ });
12131
+ } else if (finishReason !== void 0) {
12132
+ metadata.finish_reason = finishReason;
11434
12133
  }
11435
12134
  return Object.keys(metadata).length > 0 ? { metadata } : {};
11436
12135
  }
11437
- function resolveAISDKModel(model) {
12136
+ function resolveAISDKModel(model, aiSDK) {
11438
12137
  if (typeof model !== "string") {
11439
12138
  return model;
11440
12139
  }
11441
- const provider = globalThis.AI_SDK_DEFAULT_PROVIDER ?? null;
12140
+ const provider = globalThis.AI_SDK_DEFAULT_PROVIDER ?? aiSDK?.gateway ?? null;
11442
12141
  if (provider && typeof provider.languageModel === "function") {
11443
12142
  return provider.languageModel(model);
11444
12143
  }
@@ -11459,23 +12158,55 @@ function processAISDKOutput(output, denyOutputPaths) {
11459
12158
  const merged = extractSerializableOutputFields(output);
11460
12159
  return normalizeAISDKLoggedOutput(omit(merged, denyOutputPaths));
11461
12160
  }
11462
- function extractTokenMetrics(result) {
11463
- const metrics = {};
11464
- let usage = result?.totalUsage || result?.usage;
11465
- if (!usage && result) {
11466
- try {
11467
- if ("totalUsage" in result && typeof result.totalUsage !== "function") {
11468
- usage = result.totalUsage;
11469
- } else if ("usage" in result && typeof result.usage !== "function") {
11470
- usage = result.usage;
11471
- }
11472
- } catch {
11473
- }
11474
- }
11475
- if (!usage) {
11476
- return metrics;
12161
+ function processAISDKEmbeddingOutput(output, denyOutputPaths) {
12162
+ if (!output || typeof output !== "object") {
12163
+ return output;
11477
12164
  }
11478
- const promptTokens = firstNumber(
12165
+ const summarized = {};
12166
+ const whitelistedFields = [
12167
+ "usage",
12168
+ "totalUsage",
12169
+ "warnings",
12170
+ "providerMetadata",
12171
+ "experimental_providerMetadata"
12172
+ ];
12173
+ for (const field of whitelistedFields) {
12174
+ const value = safeSerializableFieldRead(output, field);
12175
+ if (value !== void 0 && isSerializableOutputValue(value)) {
12176
+ summarized[field] = value;
12177
+ }
12178
+ }
12179
+ const embedding = safeSerializableFieldRead(output, "embedding");
12180
+ if (Array.isArray(embedding)) {
12181
+ summarized.embedding_length = embedding.length;
12182
+ }
12183
+ const embeddings = safeSerializableFieldRead(output, "embeddings");
12184
+ if (Array.isArray(embeddings)) {
12185
+ summarized.embedding_count = embeddings.length;
12186
+ const firstEmbedding = embeddings.find((item) => Array.isArray(item));
12187
+ if (Array.isArray(firstEmbedding)) {
12188
+ summarized.embedding_length = firstEmbedding.length;
12189
+ }
12190
+ }
12191
+ return normalizeAISDKLoggedOutput(omit(summarized, denyOutputPaths));
12192
+ }
12193
+ function extractTokenMetrics(result) {
12194
+ const metrics = {};
12195
+ let usage;
12196
+ const totalUsageValue = safeResultFieldRead(result, "totalUsage");
12197
+ if (totalUsageValue !== void 0 && !isPromiseLike(totalUsageValue)) {
12198
+ usage = totalUsageValue;
12199
+ }
12200
+ if (!usage) {
12201
+ const usageValue = safeResultFieldRead(result, "usage");
12202
+ if (usageValue !== void 0 && !isPromiseLike(usageValue)) {
12203
+ usage = usageValue;
12204
+ }
12205
+ }
12206
+ if (!usage) {
12207
+ return metrics;
12208
+ }
12209
+ const promptTokens = firstNumber(
11479
12210
  usage.inputTokens?.total,
11480
12211
  usage.inputTokens,
11481
12212
  usage.promptTokens,
@@ -11507,6 +12238,22 @@ function extractTokenMetrics(result) {
11507
12238
  }
11508
12239
  return metrics;
11509
12240
  }
12241
+ function safeResultFieldRead(result, field) {
12242
+ return safeSerializableFieldRead(result, field);
12243
+ }
12244
+ function safeSerializableFieldRead(obj, field) {
12245
+ try {
12246
+ const value = obj?.[field];
12247
+ if (isPromiseLike(value)) {
12248
+ void Promise.resolve(value).catch(() => {
12249
+ });
12250
+ return void 0;
12251
+ }
12252
+ return value;
12253
+ } catch {
12254
+ return void 0;
12255
+ }
12256
+ }
11510
12257
  function aggregateAISDKChunks(chunks, _result, endEvent) {
11511
12258
  const lastChunk = chunks[chunks.length - 1];
11512
12259
  const output = {};
@@ -11515,17 +12262,21 @@ function aggregateAISDKChunks(chunks, _result, endEvent) {
11515
12262
  if (lastChunk) {
11516
12263
  metrics = hasModelChildTracing(endEvent) ? {} : extractTokenMetrics(lastChunk);
11517
12264
  metadata = buildResolvedMetadataPayload(lastChunk).metadata;
11518
- if (lastChunk.text !== void 0) {
11519
- output.text = lastChunk.text;
12265
+ const text = safeSerializableFieldRead(lastChunk, "text");
12266
+ if (text !== void 0) {
12267
+ output.text = text;
11520
12268
  }
11521
- if (lastChunk.object !== void 0) {
11522
- output.object = lastChunk.object;
12269
+ const objectValue = safeSerializableFieldRead(lastChunk, "object");
12270
+ if (objectValue !== void 0) {
12271
+ output.object = objectValue;
11523
12272
  }
11524
- if (lastChunk.finishReason !== void 0) {
11525
- output.finishReason = lastChunk.finishReason;
12273
+ const finishReason = safeSerializableFieldRead(lastChunk, "finishReason");
12274
+ if (finishReason !== void 0) {
12275
+ output.finishReason = finishReason;
11526
12276
  }
11527
- if (lastChunk.toolCalls !== void 0) {
11528
- output.toolCalls = lastChunk.toolCalls;
12277
+ const toolCalls = safeSerializableFieldRead(lastChunk, "toolCalls");
12278
+ if (toolCalls !== void 0) {
12279
+ output.toolCalls = toolCalls;
11529
12280
  }
11530
12281
  }
11531
12282
  finalizeAISDKChildTracing(endEvent);
@@ -11534,14 +12285,20 @@ function aggregateAISDKChunks(chunks, _result, endEvent) {
11534
12285
  function extractGetterValues(obj) {
11535
12286
  const getterValues = {};
11536
12287
  const getterNames = [
12288
+ "content",
11537
12289
  "text",
11538
12290
  "object",
12291
+ "value",
12292
+ "values",
12293
+ "embedding",
12294
+ "embeddings",
11539
12295
  "finishReason",
11540
12296
  "usage",
11541
12297
  "totalUsage",
11542
12298
  "toolCalls",
11543
12299
  "toolResults",
11544
12300
  "warnings",
12301
+ "responses",
11545
12302
  "experimental_providerMetadata",
11546
12303
  "providerMetadata",
11547
12304
  "rawResponse",
@@ -11549,8 +12306,17 @@ function extractGetterValues(obj) {
11549
12306
  ];
11550
12307
  for (const name of getterNames) {
11551
12308
  try {
11552
- if (obj && name in obj && isSerializableOutputValue(obj[name])) {
11553
- getterValues[name] = obj[name];
12309
+ if (!obj || !(name in obj)) {
12310
+ continue;
12311
+ }
12312
+ const value = obj[name];
12313
+ if (isPromiseLike(value)) {
12314
+ void Promise.resolve(value).catch(() => {
12315
+ });
12316
+ continue;
12317
+ }
12318
+ if (isSerializableOutputValue(value)) {
12319
+ getterValues[name] = value;
11554
12320
  }
11555
12321
  } catch {
11556
12322
  }
@@ -11572,6 +12338,11 @@ function extractSerializableOutputFields(output) {
11572
12338
  for (const name of directFieldNames) {
11573
12339
  try {
11574
12340
  const value = output?.[name];
12341
+ if (isPromiseLike(value)) {
12342
+ void Promise.resolve(value).catch(() => {
12343
+ });
12344
+ continue;
12345
+ }
11575
12346
  if (isSerializableOutputValue(value)) {
11576
12347
  serialized[name] = value;
11577
12348
  }
@@ -11583,6 +12354,9 @@ function extractSerializableOutputFields(output) {
11583
12354
  ...extractGetterValues(output)
11584
12355
  };
11585
12356
  }
12357
+ function isPromiseLike(value) {
12358
+ return value != null && typeof value === "object" && typeof value.then === "function";
12359
+ }
11586
12360
  function isSerializableOutputValue(value) {
11587
12361
  if (typeof value === "function") {
11588
12362
  return false;
@@ -11624,8 +12398,9 @@ function parseGatewayModelString(modelString) {
11624
12398
  return { model: modelString };
11625
12399
  }
11626
12400
  function extractGatewayRoutingInfo(result) {
11627
- if (result?.steps && Array.isArray(result.steps) && result.steps.length > 0) {
11628
- const routing2 = result.steps[0]?.providerMetadata?.gateway?.routing;
12401
+ const steps = safeSerializableFieldRead(result, "steps");
12402
+ if (Array.isArray(steps) && steps.length > 0) {
12403
+ const routing2 = steps[0]?.providerMetadata?.gateway?.routing;
11629
12404
  if (routing2) {
11630
12405
  return {
11631
12406
  provider: routing2.resolvedProvider || routing2.finalProvider,
@@ -11633,7 +12408,11 @@ function extractGatewayRoutingInfo(result) {
11633
12408
  };
11634
12409
  }
11635
12410
  }
11636
- const routing = result?.providerMetadata?.gateway?.routing;
12411
+ const providerMetadata = safeSerializableFieldRead(
12412
+ result,
12413
+ "providerMetadata"
12414
+ );
12415
+ const routing = providerMetadata?.gateway?.routing;
11637
12416
  if (routing) {
11638
12417
  return {
11639
12418
  provider: routing.resolvedProvider || routing.finalProvider,
@@ -11643,10 +12422,11 @@ function extractGatewayRoutingInfo(result) {
11643
12422
  return null;
11644
12423
  }
11645
12424
  function extractCostFromResult(result) {
11646
- if (result?.steps && Array.isArray(result.steps) && result.steps.length > 0) {
12425
+ const steps = safeSerializableFieldRead(result, "steps");
12426
+ if (Array.isArray(steps) && steps.length > 0) {
11647
12427
  let totalCost = 0;
11648
12428
  let foundCost = false;
11649
- for (const step of result.steps) {
12429
+ for (const step of steps) {
11650
12430
  const gateway2 = step?.providerMetadata?.gateway;
11651
12431
  const stepCost = parseGatewayCost(gateway2?.cost) || parseGatewayCost(gateway2?.marketCost);
11652
12432
  if (stepCost !== void 0 && stepCost > 0) {
@@ -11658,7 +12438,11 @@ function extractCostFromResult(result) {
11658
12438
  return totalCost;
11659
12439
  }
11660
12440
  }
11661
- const gateway = result?.providerMetadata?.gateway;
12441
+ const providerMetadata = safeSerializableFieldRead(
12442
+ result,
12443
+ "providerMetadata"
12444
+ );
12445
+ const gateway = providerMetadata?.gateway;
11662
12446
  const directCost = parseGatewayCost(gateway?.cost) || parseGatewayCost(gateway?.marketCost);
11663
12447
  if (directCost !== void 0 && directCost > 0) {
11664
12448
  return directCost;
@@ -11775,7 +12559,307 @@ var claudeAgentSDKChannels = defineChannels(
11775
12559
  }
11776
12560
  );
11777
12561
 
12562
+ // src/instrumentation/plugins/claude-agent-sdk-instrumentation-constants.ts
12563
+ var CLAUDE_AGENT_SDK_SKIP_LOCAL_TOOL_HOOKS_OPTION = "__braintrust_skip_local_tool_hooks";
12564
+
12565
+ // src/instrumentation/plugins/claude-agent-sdk-local-tool-context.ts
12566
+ var LOCAL_TOOL_CONTEXT_ASYNC_ITERATOR_PATCHED = Symbol.for(
12567
+ "braintrust.claude_agent_sdk.local_tool_context_async_iterator_patched"
12568
+ );
12569
+ function createLocalToolContextStore() {
12570
+ const maybeIsoWithAsyncLocalStorage = isomorph_default;
12571
+ if (typeof maybeIsoWithAsyncLocalStorage.newAsyncLocalStorage === "function") {
12572
+ return maybeIsoWithAsyncLocalStorage.newAsyncLocalStorage();
12573
+ }
12574
+ let currentStore;
12575
+ return {
12576
+ enterWith(store) {
12577
+ currentStore = store;
12578
+ },
12579
+ getStore() {
12580
+ return currentStore;
12581
+ },
12582
+ run(store, callback) {
12583
+ const previousStore = currentStore;
12584
+ currentStore = store;
12585
+ try {
12586
+ return callback();
12587
+ } finally {
12588
+ currentStore = previousStore;
12589
+ }
12590
+ }
12591
+ };
12592
+ }
12593
+ var localToolContextStore = createLocalToolContextStore();
12594
+ var fallbackLocalToolParentResolver;
12595
+ function createClaudeLocalToolContext() {
12596
+ return {};
12597
+ }
12598
+ function runWithClaudeLocalToolContext(callback, context) {
12599
+ return localToolContextStore.run(
12600
+ context ?? createClaudeLocalToolContext(),
12601
+ callback
12602
+ );
12603
+ }
12604
+ function ensureClaudeLocalToolContext() {
12605
+ const existing = localToolContextStore.getStore();
12606
+ if (existing) {
12607
+ return existing;
12608
+ }
12609
+ const created = {};
12610
+ localToolContextStore.enterWith(created);
12611
+ return created;
12612
+ }
12613
+ function setClaudeLocalToolParentResolver(resolver) {
12614
+ fallbackLocalToolParentResolver = resolver;
12615
+ const context = ensureClaudeLocalToolContext();
12616
+ if (!context) {
12617
+ return;
12618
+ }
12619
+ context.resolveLocalToolParent = resolver;
12620
+ }
12621
+ function getClaudeLocalToolParentResolver() {
12622
+ return localToolContextStore.getStore()?.resolveLocalToolParent ?? fallbackLocalToolParentResolver;
12623
+ }
12624
+ function isAsyncIterable2(value) {
12625
+ return value !== null && typeof value === "object" && Symbol.asyncIterator in value && typeof value[Symbol.asyncIterator] === "function";
12626
+ }
12627
+ function bindClaudeLocalToolContextToAsyncIterable(result, localToolContext) {
12628
+ if (!isAsyncIterable2(result) || Object.isFrozen(result) || Object.isSealed(result)) {
12629
+ return result;
12630
+ }
12631
+ const stream = result;
12632
+ const originalAsyncIterator = stream[Symbol.asyncIterator];
12633
+ if (originalAsyncIterator[LOCAL_TOOL_CONTEXT_ASYNC_ITERATOR_PATCHED]) {
12634
+ return result;
12635
+ }
12636
+ const patchedAsyncIterator = function() {
12637
+ return runWithClaudeLocalToolContext(() => {
12638
+ const iterator = Reflect.apply(originalAsyncIterator, this, []);
12639
+ if (!iterator || typeof iterator !== "object") {
12640
+ return iterator;
12641
+ }
12642
+ const patchMethod = (methodName) => {
12643
+ const originalMethod = Reflect.get(iterator, methodName);
12644
+ if (typeof originalMethod !== "function") {
12645
+ return;
12646
+ }
12647
+ Reflect.set(
12648
+ iterator,
12649
+ methodName,
12650
+ (...args) => runWithClaudeLocalToolContext(
12651
+ () => Reflect.apply(
12652
+ originalMethod,
12653
+ iterator,
12654
+ args
12655
+ ),
12656
+ localToolContext
12657
+ )
12658
+ );
12659
+ };
12660
+ patchMethod("next");
12661
+ patchMethod("return");
12662
+ patchMethod("throw");
12663
+ return iterator;
12664
+ }, localToolContext);
12665
+ };
12666
+ Object.defineProperty(
12667
+ patchedAsyncIterator,
12668
+ LOCAL_TOOL_CONTEXT_ASYNC_ITERATOR_PATCHED,
12669
+ {
12670
+ configurable: false,
12671
+ enumerable: false,
12672
+ value: true,
12673
+ writable: false
12674
+ }
12675
+ );
12676
+ Reflect.set(stream, Symbol.asyncIterator, patchedAsyncIterator);
12677
+ return result;
12678
+ }
12679
+
12680
+ // src/instrumentation/plugins/claude-agent-sdk-local-tool-spans.ts
12681
+ var LOCAL_TOOL_HANDLER_WRAPPED = Symbol.for(
12682
+ "braintrust.claude_agent_sdk.local_tool_handler_wrapped"
12683
+ );
12684
+ function toErrorMessage(error) {
12685
+ return error instanceof Error ? error.message : String(error);
12686
+ }
12687
+ function isPromiseLike2(value) {
12688
+ return value !== null && typeof value === "object" && "then" in value && typeof value.then === "function";
12689
+ }
12690
+ function getToolUseIdFromExtra(extra) {
12691
+ if (!extra || typeof extra !== "object" || !("_meta" in extra)) {
12692
+ return void 0;
12693
+ }
12694
+ const meta = Reflect.get(extra, "_meta");
12695
+ if (!meta || typeof meta !== "object") {
12696
+ return void 0;
12697
+ }
12698
+ const toolUseId = Reflect.get(meta, "claudecode/toolUseId");
12699
+ return typeof toolUseId === "string" ? toolUseId : void 0;
12700
+ }
12701
+ function wrapLocalClaudeToolHandler(handler, getMetadata) {
12702
+ if (handler[LOCAL_TOOL_HANDLER_WRAPPED]) {
12703
+ return handler;
12704
+ }
12705
+ const wrappedHandler = function wrappedLocalToolHandler(...handlerArgs) {
12706
+ const metadata = getMetadata();
12707
+ const rawToolName = metadata.serverName ? `mcp__${metadata.serverName}__${metadata.toolName}` : metadata.toolName;
12708
+ const toolUseId = getToolUseIdFromExtra(handlerArgs[1]);
12709
+ const localToolParentResolver = getClaudeLocalToolParentResolver();
12710
+ const spanName = metadata.serverName ? `tool: ${metadata.serverName}/${metadata.toolName}` : `tool: ${metadata.toolName}`;
12711
+ const runWithResolvedParent = async () => {
12712
+ const parent = toolUseId && localToolParentResolver ? await localToolParentResolver(toolUseId).catch(() => void 0) : void 0;
12713
+ const span = startSpan({
12714
+ event: {
12715
+ input: handlerArgs[0],
12716
+ metadata: {
12717
+ "claude_agent_sdk.raw_tool_name": rawToolName,
12718
+ "gen_ai.tool.name": metadata.toolName,
12719
+ ...toolUseId && { "gen_ai.tool.call.id": toolUseId },
12720
+ ...metadata.serverName && {
12721
+ "mcp.server": metadata.serverName
12722
+ }
12723
+ }
12724
+ },
12725
+ name: spanName,
12726
+ ...parent && { parent },
12727
+ spanAttributes: { type: "tool" /* TOOL */ }
12728
+ });
12729
+ const runHandler = () => Reflect.apply(handler, this, handlerArgs);
12730
+ const finalizeSuccess = (result) => {
12731
+ span.log({ output: result });
12732
+ span.end();
12733
+ return result;
12734
+ };
12735
+ const finalizeError = (error) => {
12736
+ span.log({ error: toErrorMessage(error) });
12737
+ span.end();
12738
+ throw error;
12739
+ };
12740
+ return withCurrent(span, () => {
12741
+ try {
12742
+ const result = runHandler();
12743
+ if (isPromiseLike2(result)) {
12744
+ return result.then(finalizeSuccess, finalizeError);
12745
+ }
12746
+ return finalizeSuccess(result);
12747
+ } catch (error) {
12748
+ return finalizeError(error);
12749
+ }
12750
+ });
12751
+ };
12752
+ return runWithResolvedParent();
12753
+ };
12754
+ Object.defineProperty(wrappedHandler, LOCAL_TOOL_HANDLER_WRAPPED, {
12755
+ configurable: false,
12756
+ enumerable: false,
12757
+ value: true,
12758
+ writable: false
12759
+ });
12760
+ return wrappedHandler;
12761
+ }
12762
+ function getRegisteredTools(instance) {
12763
+ if (!instance || typeof instance !== "object") {
12764
+ return void 0;
12765
+ }
12766
+ if (!("_registeredTools" in instance)) {
12767
+ return void 0;
12768
+ }
12769
+ const registeredTools = Reflect.get(instance, "_registeredTools");
12770
+ if (registeredTools instanceof Map) {
12771
+ return registeredTools;
12772
+ }
12773
+ if (registeredTools && typeof registeredTools === "object") {
12774
+ return registeredTools;
12775
+ }
12776
+ return void 0;
12777
+ }
12778
+ function wrapLocalMcpServerToolHandlers(serverName, serverConfig) {
12779
+ if (!serverConfig || typeof serverConfig !== "object") {
12780
+ return false;
12781
+ }
12782
+ if (!("instance" in serverConfig)) {
12783
+ return false;
12784
+ }
12785
+ const instance = Reflect.get(serverConfig, "instance");
12786
+ const registeredTools = getRegisteredTools(instance);
12787
+ if (!registeredTools) {
12788
+ return false;
12789
+ }
12790
+ let wrappedAny = false;
12791
+ const wrapHandler = (toolName, registration) => {
12792
+ if (!registration || typeof registration !== "object") {
12793
+ return;
12794
+ }
12795
+ const handler = Reflect.get(registration, "handler");
12796
+ if (typeof handler !== "function") {
12797
+ return;
12798
+ }
12799
+ const wrappedHandler = wrapLocalClaudeToolHandler(handler, () => ({
12800
+ serverName,
12801
+ toolName
12802
+ }));
12803
+ if (wrappedHandler !== handler) {
12804
+ Reflect.set(registration, "handler", wrappedHandler);
12805
+ wrappedAny = true;
12806
+ }
12807
+ };
12808
+ if (registeredTools instanceof Map) {
12809
+ for (const [toolName, registration] of registeredTools.entries()) {
12810
+ wrapHandler(toolName, registration);
12811
+ }
12812
+ return wrappedAny;
12813
+ }
12814
+ for (const [toolName, registration] of Object.entries(registeredTools)) {
12815
+ wrapHandler(toolName, registration);
12816
+ }
12817
+ return wrappedAny;
12818
+ }
12819
+ function collectLocalMcpServerToolHookNames(serverName, serverConfig) {
12820
+ const toolNames = /* @__PURE__ */ new Set();
12821
+ if (!serverConfig || typeof serverConfig !== "object") {
12822
+ return toolNames;
12823
+ }
12824
+ if ("instance" in serverConfig) {
12825
+ const instance = Reflect.get(serverConfig, "instance");
12826
+ const registeredTools = getRegisteredTools(instance);
12827
+ if (registeredTools instanceof Map) {
12828
+ for (const toolName of registeredTools.keys()) {
12829
+ toolNames.add(toolName);
12830
+ toolNames.add(`mcp__${serverName}__${toolName}`);
12831
+ }
12832
+ } else if (registeredTools) {
12833
+ for (const toolName of Object.keys(registeredTools)) {
12834
+ toolNames.add(toolName);
12835
+ toolNames.add(`mcp__${serverName}__${toolName}`);
12836
+ }
12837
+ }
12838
+ }
12839
+ if ("tools" in serverConfig) {
12840
+ const rawTools = Reflect.get(serverConfig, "tools");
12841
+ if (Array.isArray(rawTools)) {
12842
+ for (const tool of rawTools) {
12843
+ if (!tool || typeof tool !== "object") {
12844
+ continue;
12845
+ }
12846
+ const toolName = Reflect.get(tool, "name");
12847
+ if (typeof toolName !== "string") {
12848
+ continue;
12849
+ }
12850
+ toolNames.add(toolName);
12851
+ toolNames.add(`mcp__${serverName}__${toolName}`);
12852
+ }
12853
+ }
12854
+ }
12855
+ return toolNames;
12856
+ }
12857
+
11778
12858
  // src/instrumentation/plugins/claude-agent-sdk-plugin.ts
12859
+ var ROOT_LLM_PARENT_KEY = "__root__";
12860
+ function llmParentKey(parentToolUseId) {
12861
+ return parentToolUseId ?? ROOT_LLM_PARENT_KEY;
12862
+ }
11779
12863
  function isSubAgentToolName(toolName) {
11780
12864
  return toolName === "Agent" || toolName === "Task";
11781
12865
  }
@@ -11861,7 +12945,7 @@ function buildLLMInput(prompt, conversationHistory, capturedPromptMessages) {
11861
12945
  function formatCapturedMessages(messages) {
11862
12946
  return messages.length > 0 ? messages : [];
11863
12947
  }
11864
- async function createLLMSpanForMessages(messages, prompt, conversationHistory, options, startTime, capturedPromptMessages, parentSpan) {
12948
+ async function createLLMSpanForMessages(messages, prompt, conversationHistory, options, startTime, capturedPromptMessages, parentSpan, existingSpan) {
11865
12949
  if (messages.length === 0) {
11866
12950
  return void 0;
11867
12951
  }
@@ -11881,7 +12965,7 @@ async function createLLMSpanForMessages(messages, prompt, conversationHistory, o
11881
12965
  ).filter(
11882
12966
  (c) => c !== void 0
11883
12967
  );
11884
- const span = startSpan({
12968
+ const span = existingSpan ?? startSpan({
11885
12969
  name: "anthropic.messages.create",
11886
12970
  parent: parentSpan,
11887
12971
  spanAttributes: {
@@ -11895,8 +12979,13 @@ async function createLLMSpanForMessages(messages, prompt, conversationHistory, o
11895
12979
  metrics: usage,
11896
12980
  output: outputs
11897
12981
  });
12982
+ const spanExport = await span.export();
11898
12983
  await span.end();
11899
- return lastMessage.message?.content && lastMessage.message?.role ? { content: lastMessage.message.content, role: lastMessage.message.role } : void 0;
12984
+ const finalMessage = lastMessage.message?.content && lastMessage.message?.role ? { content: lastMessage.message.content, role: lastMessage.message.role } : void 0;
12985
+ return {
12986
+ finalMessage,
12987
+ spanExport
12988
+ };
11900
12989
  }
11901
12990
  function getMcpServerMetadata(serverName, mcpServers) {
11902
12991
  if (!serverName || !mcpServers) {
@@ -11940,11 +13029,51 @@ function parseToolName(rawToolName) {
11940
13029
  toolName: rawToolName
11941
13030
  };
11942
13031
  }
11943
- function createToolTracingHooks(resolveParentSpan, activeToolSpans, mcpServers, subAgentSpans, endedSubAgentSpans) {
13032
+ function isLocalToolUse(rawToolName, mcpServers) {
13033
+ const parsed = parseToolName(rawToolName);
13034
+ if (!parsed.mcpServer || !mcpServers) {
13035
+ return false;
13036
+ }
13037
+ const serverConfig = mcpServers[parsed.mcpServer];
13038
+ if (!serverConfig || typeof serverConfig !== "object") {
13039
+ return false;
13040
+ }
13041
+ return serverConfig.type === "sdk" || "transport" in serverConfig;
13042
+ }
13043
+ function prepareLocalToolHandlersInMcpServers(mcpServers) {
13044
+ const localToolHookNames = /* @__PURE__ */ new Set();
13045
+ if (!mcpServers) {
13046
+ return {
13047
+ hasLocalToolHandlers: false,
13048
+ localToolHookNames
13049
+ };
13050
+ }
13051
+ let hasLocalToolHandlers = false;
13052
+ for (const [serverName, serverConfig] of Object.entries(mcpServers)) {
13053
+ const toolNames = collectLocalMcpServerToolHookNames(
13054
+ serverName,
13055
+ serverConfig
13056
+ );
13057
+ for (const toolName of toolNames) {
13058
+ localToolHookNames.add(toolName);
13059
+ }
13060
+ if (toolNames.size > 0) {
13061
+ hasLocalToolHandlers = true;
13062
+ }
13063
+ if (wrapLocalMcpServerToolHandlers(serverName, serverConfig)) {
13064
+ hasLocalToolHandlers = true;
13065
+ }
13066
+ }
13067
+ return { hasLocalToolHandlers, localToolHookNames };
13068
+ }
13069
+ function createToolTracingHooks(resolveParentSpan, activeToolSpans, mcpServers, localToolHookNames, skipLocalToolHooks, subAgentSpans, endedSubAgentSpans) {
11944
13070
  const preToolUse = async (input, toolUseID) => {
11945
13071
  if (input.hook_event_name !== "PreToolUse" || !toolUseID) {
11946
13072
  return {};
11947
13073
  }
13074
+ if (skipLocalToolHooks && (isLocalToolUse(input.tool_name, mcpServers) || localToolHookNames.has(input.tool_name))) {
13075
+ return {};
13076
+ }
11948
13077
  if (isSubAgentToolName(input.tool_name)) {
11949
13078
  return {};
11950
13079
  }
@@ -11973,6 +13102,9 @@ function createToolTracingHooks(resolveParentSpan, activeToolSpans, mcpServers,
11973
13102
  if (input.hook_event_name !== "PostToolUse" || !toolUseID) {
11974
13103
  return {};
11975
13104
  }
13105
+ if (skipLocalToolHooks && (isLocalToolUse(input.tool_name, mcpServers) || localToolHookNames.has(input.tool_name))) {
13106
+ return {};
13107
+ }
11976
13108
  const subAgentSpan = subAgentSpans.get(toolUseID);
11977
13109
  if (subAgentSpan) {
11978
13110
  try {
@@ -12013,6 +13145,9 @@ function createToolTracingHooks(resolveParentSpan, activeToolSpans, mcpServers,
12013
13145
  if (input.hook_event_name !== "PostToolUseFailure" || !toolUseID) {
12014
13146
  return {};
12015
13147
  }
13148
+ if (skipLocalToolHooks && (isLocalToolUse(input.tool_name, mcpServers) || localToolHookNames.has(input.tool_name))) {
13149
+ return {};
13150
+ }
12016
13151
  const subAgentSpan = subAgentSpans.get(toolUseID);
12017
13152
  if (subAgentSpan) {
12018
13153
  try {
@@ -12047,11 +13182,13 @@ function createToolTracingHooks(resolveParentSpan, activeToolSpans, mcpServers,
12047
13182
  };
12048
13183
  return { postToolUse, postToolUseFailure, preToolUse };
12049
13184
  }
12050
- function injectTracingHooks(options, resolveParentSpan, activeToolSpans, subAgentSpans, endedSubAgentSpans) {
13185
+ function injectTracingHooks(options, resolveParentSpan, activeToolSpans, localToolHookNames, skipLocalToolHooks, subAgentSpans, endedSubAgentSpans) {
12051
13186
  const { preToolUse, postToolUse, postToolUseFailure } = createToolTracingHooks(
12052
13187
  resolveParentSpan,
12053
13188
  activeToolSpans,
12054
13189
  options.mcpServers,
13190
+ localToolHookNames,
13191
+ skipLocalToolHooks,
12055
13192
  subAgentSpans,
12056
13193
  endedSubAgentSpans
12057
13194
  );
@@ -12082,6 +13219,7 @@ async function finalizeCurrentMessageGroup(state) {
12082
13219
  return;
12083
13220
  }
12084
13221
  const parentToolUseId = state.currentMessages[0]?.parent_tool_use_id ?? null;
13222
+ const parentKey = llmParentKey(parentToolUseId);
12085
13223
  let parentSpan = await state.span.export();
12086
13224
  if (parentToolUseId) {
12087
13225
  const subAgentSpan = state.subAgentSpans.get(parentToolUseId);
@@ -12089,17 +13227,30 @@ async function finalizeCurrentMessageGroup(state) {
12089
13227
  parentSpan = await subAgentSpan.export();
12090
13228
  }
12091
13229
  }
12092
- const finalMessage = await createLLMSpanForMessages(
13230
+ const existingLlmSpan = state.activeLlmSpansByParentToolUse.get(parentKey);
13231
+ const llmSpanResult = await createLLMSpanForMessages(
12093
13232
  state.currentMessages,
12094
13233
  state.originalPrompt,
12095
13234
  state.finalResults,
12096
13235
  state.options,
12097
13236
  state.currentMessageStartTime,
12098
13237
  state.capturedPromptMessages,
12099
- parentSpan
13238
+ parentSpan,
13239
+ existingLlmSpan
12100
13240
  );
12101
- if (finalMessage) {
12102
- state.finalResults.push(finalMessage);
13241
+ state.activeLlmSpansByParentToolUse.delete(parentKey);
13242
+ if (llmSpanResult) {
13243
+ if (parentToolUseId) {
13244
+ state.latestLlmParentBySubAgentToolUse.set(
13245
+ parentToolUseId,
13246
+ llmSpanResult.spanExport
13247
+ );
13248
+ } else {
13249
+ state.latestRootLlmParentRef.value = llmSpanResult.spanExport;
13250
+ }
13251
+ if (llmSpanResult.finalMessage) {
13252
+ state.finalResults.push(llmSpanResult.finalMessage);
13253
+ }
12103
13254
  }
12104
13255
  const lastMessage = state.currentMessages[state.currentMessages.length - 1];
12105
13256
  if (lastMessage?.message?.usage) {
@@ -12167,6 +13318,29 @@ async function handleStreamMessage(state, message) {
12167
13318
  state.currentMessageStartTime = getCurrentUnixTimestamp();
12168
13319
  }
12169
13320
  if (message.type === "assistant" && message.message?.usage) {
13321
+ const parentToolUseId = message.parent_tool_use_id ?? null;
13322
+ const parentKey = llmParentKey(parentToolUseId);
13323
+ if (!state.activeLlmSpansByParentToolUse.has(parentKey)) {
13324
+ let llmParentSpan = await state.span.export();
13325
+ if (parentToolUseId) {
13326
+ const subAgentSpan = await ensureSubAgentSpan(
13327
+ state.pendingSubAgentNames,
13328
+ state.span,
13329
+ state.subAgentSpans,
13330
+ parentToolUseId
13331
+ );
13332
+ llmParentSpan = await subAgentSpan.export();
13333
+ }
13334
+ const llmSpan = startSpan({
13335
+ name: "anthropic.messages.create",
13336
+ parent: llmParentSpan,
13337
+ spanAttributes: {
13338
+ type: "llm" /* LLM */
13339
+ },
13340
+ startTime: state.currentMessageStartTime
13341
+ });
13342
+ state.activeLlmSpansByParentToolUse.set(parentKey, llmSpan);
13343
+ }
12170
13344
  state.currentMessages.push(message);
12171
13345
  }
12172
13346
  if (message.type !== "result" || !message.usage) {
@@ -12227,6 +13401,10 @@ async function finalizeQuerySpan(state) {
12227
13401
  }
12228
13402
  }
12229
13403
  } finally {
13404
+ for (const llmSpan of state.activeLlmSpansByParentToolUse.values()) {
13405
+ llmSpan.end();
13406
+ }
13407
+ state.activeLlmSpansByParentToolUse.clear();
12230
13408
  for (const [id, subAgentSpan] of state.subAgentSpans) {
12231
13409
  if (!state.endedSubAgentSpans.has(id)) {
12232
13410
  subAgentSpan.end();
@@ -12292,26 +13470,51 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
12292
13470
  console.error("Error extracting input for Claude Agent SDK:", error);
12293
13471
  }
12294
13472
  const activeToolSpans = /* @__PURE__ */ new Map();
13473
+ const activeLlmSpansByParentToolUse = /* @__PURE__ */ new Map();
12295
13474
  const subAgentSpans = /* @__PURE__ */ new Map();
12296
13475
  const endedSubAgentSpans = /* @__PURE__ */ new Set();
12297
13476
  const toolUseToParent = /* @__PURE__ */ new Map();
13477
+ const latestLlmParentBySubAgentToolUse = /* @__PURE__ */ new Map();
13478
+ const latestRootLlmParentRef = {
13479
+ value: void 0
13480
+ };
12298
13481
  const pendingSubAgentNames = /* @__PURE__ */ new Map();
13482
+ const localToolContext = createClaudeLocalToolContext();
13483
+ const { hasLocalToolHandlers, localToolHookNames } = prepareLocalToolHandlersInMcpServers(options.mcpServers);
13484
+ const skipLocalToolHooks = options[CLAUDE_AGENT_SDK_SKIP_LOCAL_TOOL_HOOKS_OPTION] === true || hasLocalToolHandlers;
13485
+ const resolveToolUseParentSpan = async (toolUseID) => {
13486
+ const parentToolUseId = toolUseToParent.get(toolUseID) ?? null;
13487
+ const parentKey = llmParentKey(parentToolUseId);
13488
+ const activeLlmSpan = activeLlmSpansByParentToolUse.get(parentKey);
13489
+ if (activeLlmSpan) {
13490
+ return activeLlmSpan.export();
13491
+ }
13492
+ if (parentToolUseId) {
13493
+ const parentLlm = latestLlmParentBySubAgentToolUse.get(parentToolUseId);
13494
+ if (parentLlm) {
13495
+ return parentLlm;
13496
+ }
13497
+ const subAgentSpan = await ensureSubAgentSpan(
13498
+ pendingSubAgentNames,
13499
+ span,
13500
+ subAgentSpans,
13501
+ parentToolUseId
13502
+ );
13503
+ return subAgentSpan.export();
13504
+ }
13505
+ if (latestRootLlmParentRef.value) {
13506
+ return latestRootLlmParentRef.value;
13507
+ }
13508
+ return span.export();
13509
+ };
13510
+ localToolContext.resolveLocalToolParent = resolveToolUseParentSpan;
13511
+ setClaudeLocalToolParentResolver(resolveToolUseParentSpan);
12299
13512
  const optionsWithHooks = injectTracingHooks(
12300
13513
  options,
12301
- async (toolUseID) => {
12302
- const parentToolUseId = toolUseToParent.get(toolUseID);
12303
- if (parentToolUseId) {
12304
- const subAgentSpan = await ensureSubAgentSpan(
12305
- pendingSubAgentNames,
12306
- span,
12307
- subAgentSpans,
12308
- parentToolUseId
12309
- );
12310
- return subAgentSpan.export();
12311
- }
12312
- return span.export();
12313
- },
13514
+ resolveToolUseParentSpan,
12314
13515
  activeToolSpans,
13516
+ localToolHookNames,
13517
+ skipLocalToolHooks,
12315
13518
  subAgentSpans,
12316
13519
  endedSubAgentSpans
12317
13520
  );
@@ -12319,6 +13522,7 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
12319
13522
  event.arguments[0] = params;
12320
13523
  spans.set(event, {
12321
13524
  accumulatedOutputTokens: 0,
13525
+ activeLlmSpansByParentToolUse,
12322
13526
  activeToolSpans,
12323
13527
  capturedPromptMessages,
12324
13528
  currentMessageId: void 0,
@@ -12334,7 +13538,10 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
12334
13538
  promptStarted: () => promptStarted,
12335
13539
  span,
12336
13540
  subAgentSpans,
12337
- toolUseToParent
13541
+ latestLlmParentBySubAgentToolUse,
13542
+ latestRootLlmParentRef,
13543
+ toolUseToParent,
13544
+ localToolContext
12338
13545
  });
12339
13546
  },
12340
13547
  end: (event) => {
@@ -12342,7 +13549,10 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
12342
13549
  if (!state) {
12343
13550
  return;
12344
13551
  }
12345
- const eventResult = event.result;
13552
+ const eventResult = bindClaudeLocalToolContextToAsyncIterable(
13553
+ event.result,
13554
+ state.localToolContext
13555
+ );
12346
13556
  if (eventResult === void 0) {
12347
13557
  state.span.end();
12348
13558
  spans.delete(event);
@@ -12359,20 +13569,16 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
12359
13569
  );
12360
13570
  });
12361
13571
  },
12362
- onComplete: () => {
12363
- void state.processing.then(() => finalizeQuerySpan(state)).finally(() => {
12364
- spans.delete(event);
12365
- });
12366
- },
12367
- onError: (error) => {
12368
- void state.processing.then(() => {
12369
- state.span.log({
12370
- error: error.message
12371
- });
12372
- }).then(() => finalizeQuerySpan(state)).finally(() => {
12373
- spans.delete(event);
13572
+ onComplete: () => state.processing.then(() => finalizeQuerySpan(state)).finally(() => {
13573
+ spans.delete(event);
13574
+ }),
13575
+ onError: (error) => state.processing.then(() => {
13576
+ state.span.log({
13577
+ error: error.message
12374
13578
  });
12375
- }
13579
+ }).then(() => finalizeQuerySpan(state)).finally(() => {
13580
+ spans.delete(event);
13581
+ })
12376
13582
  });
12377
13583
  return;
12378
13584
  }
@@ -12520,12 +13726,14 @@ var GoogleGenAIPlugin = class extends BasePlugin {
12520
13726
  const params = event.arguments[0];
12521
13727
  streamEvent.googleGenAIInput = serializeInput(params);
12522
13728
  streamEvent.googleGenAIMetadata = extractMetadata(params);
13729
+ streamEvent.googleGenAIStartTime = getCurrentUnixTimestamp();
12523
13730
  },
12524
13731
  asyncEnd: (event) => {
12525
13732
  const streamEvent = event;
12526
13733
  patchGoogleGenAIStreamingResult({
12527
13734
  input: streamEvent.googleGenAIInput,
12528
13735
  metadata: streamEvent.googleGenAIMetadata,
13736
+ startTime: streamEvent.googleGenAIStartTime,
12529
13737
  result: streamEvent.result
12530
13738
  });
12531
13739
  },
@@ -12549,19 +13757,20 @@ function ensureSpanState(states, event, create) {
12549
13757
  }
12550
13758
  function bindCurrentSpanStoreToStart2(tracingChannel2, states, create) {
12551
13759
  const state = _internalGetGlobalState();
13760
+ const contextManager = state?.contextManager;
12552
13761
  const startChannel = tracingChannel2.start;
12553
- const currentSpanStore = state?.contextManager ? state.contextManager[BRAINTRUST_CURRENT_SPAN_STORE] : void 0;
13762
+ const currentSpanStore = contextManager ? contextManager[BRAINTRUST_CURRENT_SPAN_STORE] : void 0;
12554
13763
  if (!startChannel?.bindStore || !currentSpanStore) {
12555
13764
  return void 0;
12556
13765
  }
12557
- startChannel.bindStore(
12558
- currentSpanStore,
12559
- (event) => ensureSpanState(
13766
+ startChannel.bindStore(currentSpanStore, (event) => {
13767
+ const span = ensureSpanState(
12560
13768
  states,
12561
13769
  event,
12562
13770
  () => create(event)
12563
- ).span
12564
- );
13771
+ ).span;
13772
+ return contextManager.wrapSpanForStore(span);
13773
+ });
12565
13774
  return () => {
12566
13775
  startChannel.unbindStore?.(currentSpanStore);
12567
13776
  };
@@ -12578,7 +13787,7 @@ function logErrorAndEndSpan(states, event) {
12578
13787
  states.delete(event);
12579
13788
  }
12580
13789
  function patchGoogleGenAIStreamingResult(args) {
12581
- const { input, metadata, result } = args;
13790
+ const { input, metadata, result, startTime } = args;
12582
13791
  if (!input || !metadata || !result || typeof result !== "object" || typeof result.next !== "function") {
12583
13792
  return false;
12584
13793
  }
@@ -12586,7 +13795,7 @@ function patchGoogleGenAIStreamingResult(args) {
12586
13795
  let firstTokenTime = null;
12587
13796
  let finalized = false;
12588
13797
  let span = null;
12589
- let startTime = null;
13798
+ const requestStartTime = startTime ?? getCurrentUnixTimestamp();
12590
13799
  const ensureSpan = () => {
12591
13800
  if (!span) {
12592
13801
  span = startSpan({
@@ -12599,7 +13808,6 @@ function patchGoogleGenAIStreamingResult(args) {
12599
13808
  metadata
12600
13809
  }
12601
13810
  });
12602
- startTime = getCurrentUnixTimestamp();
12603
13811
  }
12604
13812
  return span;
12605
13813
  };
@@ -12653,11 +13861,11 @@ function patchGoogleGenAIStreamingResult(args) {
12653
13861
  }
12654
13862
  chunks.push(nextResult.value);
12655
13863
  }
12656
- if (nextResult.done && startTime !== null) {
13864
+ if (nextResult.done) {
12657
13865
  finalize({
12658
13866
  result: aggregateGenerateContentChunks(
12659
13867
  chunks,
12660
- startTime,
13868
+ requestStartTime,
12661
13869
  firstTokenTime
12662
13870
  )
12663
13871
  });
@@ -12677,13 +13885,13 @@ function patchGoogleGenAIStreamingResult(args) {
12677
13885
  ...returnArgs
12678
13886
  );
12679
13887
  } finally {
12680
- if (startTime !== null) {
13888
+ if (chunks.length > 0) {
12681
13889
  finalize({
12682
- result: chunks.length > 0 ? aggregateGenerateContentChunks(
13890
+ result: aggregateGenerateContentChunks(
12683
13891
  chunks,
12684
- startTime,
13892
+ requestStartTime,
12685
13893
  firstTokenTime
12686
- ) : void 0
13894
+ )
12687
13895
  });
12688
13896
  } else {
12689
13897
  finalize({});
@@ -12957,46 +14165,161 @@ function tryToDict(obj) {
12957
14165
  return null;
12958
14166
  }
12959
14167
 
12960
- // src/instrumentation/plugins/openrouter-channels.ts
12961
- var openRouterChannels = defineChannels("@openrouter/sdk", {
12962
- chatSend: channel({
12963
- channelName: "chat.send",
12964
- kind: "async"
12965
- }),
12966
- embeddingsGenerate: channel({
12967
- channelName: "embeddings.generate",
12968
- kind: "async"
12969
- }),
12970
- betaResponsesSend: channel({
12971
- channelName: "beta.responses.send",
12972
- kind: "async"
12973
- }),
14168
+ // src/instrumentation/plugins/openrouter-agent-channels.ts
14169
+ var openRouterAgentChannels = defineChannels("@openrouter/agent", {
12974
14170
  callModel: channel({
12975
14171
  channelName: "callModel",
12976
14172
  kind: "sync-stream"
12977
14173
  }),
14174
+ callModelTurn: channel({
14175
+ channelName: "callModel.turn",
14176
+ kind: "async"
14177
+ }),
12978
14178
  toolExecute: channel({
12979
14179
  channelName: "tool.execute",
12980
14180
  kind: "async"
12981
14181
  })
12982
14182
  });
12983
14183
 
12984
- // src/openrouter-utils.ts
12985
- var TOKEN_NAME_MAP2 = {
12986
- promptTokens: "prompt_tokens",
12987
- inputTokens: "prompt_tokens",
12988
- completionTokens: "completion_tokens",
12989
- outputTokens: "completion_tokens",
12990
- totalTokens: "tokens",
12991
- prompt_tokens: "prompt_tokens",
12992
- input_tokens: "prompt_tokens",
12993
- completion_tokens: "completion_tokens",
12994
- output_tokens: "completion_tokens",
12995
- total_tokens: "tokens"
12996
- };
12997
- var TOKEN_DETAIL_PREFIX_MAP = {
12998
- promptTokensDetails: "prompt",
12999
- inputTokensDetails: "prompt",
14184
+ // src/instrumentation/plugins/openrouter-agent-plugin.ts
14185
+ var OpenRouterAgentPlugin = class extends BasePlugin {
14186
+ onEnable() {
14187
+ this.subscribeToOpenRouterAgentChannels();
14188
+ }
14189
+ onDisable() {
14190
+ this.unsubscribers = unsubscribeAll(this.unsubscribers);
14191
+ }
14192
+ subscribeToOpenRouterAgentChannels() {
14193
+ this.unsubscribers.push(
14194
+ traceSyncStreamChannel(openRouterAgentChannels.callModel, {
14195
+ name: "openrouter.callModel",
14196
+ type: "llm" /* LLM */,
14197
+ extractInput: (args) => {
14198
+ const request = getOpenRouterCallModelRequestArg(args);
14199
+ return {
14200
+ input: request ? extractOpenRouterCallModelInput(request) : void 0,
14201
+ metadata: request ? extractOpenRouterCallModelMetadata(request) : { provider: "openrouter" }
14202
+ };
14203
+ },
14204
+ patchResult: ({ endEvent, result, span }) => {
14205
+ return patchOpenRouterCallModelResult({
14206
+ request: getOpenRouterCallModelRequestArg(endEvent.arguments),
14207
+ result,
14208
+ span
14209
+ });
14210
+ }
14211
+ })
14212
+ );
14213
+ this.unsubscribers.push(
14214
+ traceAsyncChannel(openRouterAgentChannels.callModelTurn, {
14215
+ name: "openrouter.beta.responses.send",
14216
+ type: "llm" /* LLM */,
14217
+ extractInput: (args, event) => {
14218
+ const request = getOpenRouterCallModelRequestArg(args);
14219
+ const metadata = request ? extractOpenRouterCallModelMetadata(request) : { provider: "openrouter" };
14220
+ if (isObject(metadata) && "tools" in metadata) {
14221
+ delete metadata.tools;
14222
+ }
14223
+ return {
14224
+ input: request ? extractOpenRouterCallModelInput(request) : void 0,
14225
+ metadata: {
14226
+ ...metadata,
14227
+ step: event.step,
14228
+ step_type: event.stepType
14229
+ }
14230
+ };
14231
+ },
14232
+ extractOutput: (result) => extractOpenRouterResponseOutput(result),
14233
+ extractMetadata: (result, event) => {
14234
+ if (!isObject(result)) {
14235
+ return {
14236
+ step: event?.step,
14237
+ step_type: event?.stepType
14238
+ };
14239
+ }
14240
+ return {
14241
+ ...extractOpenRouterResponseMetadata(result) || {},
14242
+ ...event?.step !== void 0 ? { step: event.step } : {},
14243
+ ...event?.stepType ? { step_type: event.stepType } : {}
14244
+ };
14245
+ },
14246
+ extractMetrics: (result) => isObject(result) ? parseOpenRouterMetricsFromUsage(result.usage) : {}
14247
+ })
14248
+ );
14249
+ this.unsubscribers.push(
14250
+ traceStreamingChannel(openRouterAgentChannels.toolExecute, {
14251
+ name: "openrouter.tool",
14252
+ type: "tool" /* TOOL */,
14253
+ extractInput: (args, event) => ({
14254
+ input: args[0],
14255
+ metadata: {
14256
+ provider: "openrouter",
14257
+ tool_name: event.toolName,
14258
+ ...event.toolCallId ? { tool_call_id: event.toolCallId } : {}
14259
+ }
14260
+ }),
14261
+ extractOutput: (result) => result,
14262
+ extractMetrics: () => ({}),
14263
+ aggregateChunks: (chunks) => ({
14264
+ output: chunks.length > 0 ? chunks[chunks.length - 1] : void 0,
14265
+ metrics: {}
14266
+ })
14267
+ })
14268
+ );
14269
+ const callModelChannel = openRouterAgentChannels.callModel.tracingChannel();
14270
+ const callModelHandlers = {
14271
+ start: (event) => {
14272
+ const request = getOpenRouterCallModelRequestArg(event.arguments);
14273
+ if (!request) {
14274
+ return;
14275
+ }
14276
+ patchOpenRouterCallModelRequestTools(request);
14277
+ }
14278
+ };
14279
+ callModelChannel.subscribe(callModelHandlers);
14280
+ this.unsubscribers.push(() => {
14281
+ callModelChannel.unsubscribe(callModelHandlers);
14282
+ });
14283
+ }
14284
+ };
14285
+ function normalizeArgs(args) {
14286
+ if (Array.isArray(args)) {
14287
+ return args;
14288
+ }
14289
+ if (isArrayLike(args)) {
14290
+ return Array.from(args);
14291
+ }
14292
+ return [args];
14293
+ }
14294
+ function isArrayLike(value) {
14295
+ return isObject(value) && "length" in value && typeof value.length === "number" && Number.isInteger(value.length) && value.length >= 0;
14296
+ }
14297
+ function getOpenRouterCallModelRequestArg(args) {
14298
+ const normalizedArgs = normalizeArgs(args);
14299
+ const keyedRequestArg = normalizedArgs.find(
14300
+ (arg) => isObject(arg) && ("input" in arg || "model" in arg || "tools" in arg)
14301
+ );
14302
+ if (isObject(keyedRequestArg)) {
14303
+ return keyedRequestArg;
14304
+ }
14305
+ const firstObjectArg = normalizedArgs.find((arg) => isObject(arg));
14306
+ return isObject(firstObjectArg) ? firstObjectArg : void 0;
14307
+ }
14308
+ var TOKEN_NAME_MAP2 = {
14309
+ promptTokens: "prompt_tokens",
14310
+ inputTokens: "prompt_tokens",
14311
+ completionTokens: "completion_tokens",
14312
+ outputTokens: "completion_tokens",
14313
+ totalTokens: "tokens",
14314
+ prompt_tokens: "prompt_tokens",
14315
+ input_tokens: "prompt_tokens",
14316
+ completion_tokens: "completion_tokens",
14317
+ output_tokens: "completion_tokens",
14318
+ total_tokens: "tokens"
14319
+ };
14320
+ var TOKEN_DETAIL_PREFIX_MAP = {
14321
+ promptTokensDetails: "prompt",
14322
+ inputTokensDetails: "prompt",
13000
14323
  completionTokensDetails: "completion",
13001
14324
  outputTokensDetails: "completion",
13002
14325
  costDetails: "cost",
@@ -13047,8 +14370,6 @@ function extractOpenRouterUsageMetadata(usage) {
13047
14370
  }
13048
14371
  return Object.keys(metadata).length > 0 ? metadata : void 0;
13049
14372
  }
13050
-
13051
- // src/openrouter-logging.ts
13052
14373
  var OMITTED_OPENROUTER_KEYS = /* @__PURE__ */ new Set([
13053
14374
  "execute",
13054
14375
  "render",
@@ -13068,10 +14389,10 @@ function parseOpenRouterModelString(model) {
13068
14389
  }
13069
14390
  return { model };
13070
14391
  }
13071
- function isZodSchema2(value) {
14392
+ function isZodSchema3(value) {
13072
14393
  return value != null && typeof value === "object" && "_def" in value && typeof value._def === "object";
13073
14394
  }
13074
- function serializeZodSchema2(schema) {
14395
+ function serializeZodSchema3(schema) {
13075
14396
  try {
13076
14397
  return zodToJsonSchema(schema);
13077
14398
  } catch {
@@ -13105,8 +14426,8 @@ function serializeOpenRouterToolsForLogging(tools) {
13105
14426
  return tools.map((tool) => serializeOpenRouterTool(tool));
13106
14427
  }
13107
14428
  function sanitizeOpenRouterLoggedValue(value) {
13108
- if (isZodSchema2(value)) {
13109
- return serializeZodSchema2(value);
14429
+ if (isZodSchema3(value)) {
14430
+ return serializeZodSchema3(value);
13110
14431
  }
13111
14432
  if (typeof value === "function") {
13112
14433
  return "[Function]";
@@ -13130,7 +14451,7 @@ function sanitizeOpenRouterLoggedValue(value) {
13130
14451
  }
13131
14452
  return sanitized;
13132
14453
  }
13133
- function buildOpenRouterMetadata(metadata, httpReferer, xTitle) {
14454
+ function buildOpenRouterMetadata(metadata, httpReferer, appTitle, appCategories, xTitle) {
13134
14455
  const sanitized = sanitizeOpenRouterLoggedValue(metadata);
13135
14456
  const metadataRecord = isObject(sanitized) ? sanitized : {};
13136
14457
  const { model, provider: providerRouting, ...rest } = metadataRecord;
@@ -13140,17 +14461,12 @@ function buildOpenRouterMetadata(metadata, httpReferer, xTitle) {
13140
14461
  ...normalizedModel.model !== void 0 ? { model: normalizedModel.model } : {},
13141
14462
  ...providerRouting !== void 0 ? { providerRouting } : {},
13142
14463
  ...httpReferer !== void 0 ? { httpReferer } : {},
14464
+ ...appTitle !== void 0 ? { appTitle } : {},
14465
+ ...appCategories !== void 0 ? { appCategories } : {},
13143
14466
  ...xTitle !== void 0 ? { xTitle } : {},
13144
14467
  provider: normalizedModel.provider || "openrouter"
13145
14468
  };
13146
14469
  }
13147
- function buildOpenRouterEmbeddingMetadata(metadata, httpReferer, xTitle) {
13148
- const normalized = buildOpenRouterMetadata(metadata, httpReferer, xTitle);
13149
- return typeof normalized.model === "string" ? {
13150
- ...normalized,
13151
- embedding_model: normalized.model
13152
- } : normalized;
13153
- }
13154
14470
  function extractOpenRouterCallModelInput(request) {
13155
14471
  return isObject(request) && "input" in request ? sanitizeOpenRouterLoggedValue(request.input) : void 0;
13156
14472
  }
@@ -13159,7 +14475,13 @@ function extractOpenRouterCallModelMetadata(request) {
13159
14475
  return { provider: "openrouter" };
13160
14476
  }
13161
14477
  const { input: _input, ...metadata } = request;
13162
- return buildOpenRouterMetadata(metadata, void 0, void 0);
14478
+ return buildOpenRouterMetadata(
14479
+ metadata,
14480
+ void 0,
14481
+ void 0,
14482
+ void 0,
14483
+ void 0
14484
+ );
13163
14485
  }
13164
14486
  function extractOpenRouterResponseMetadata(result) {
13165
14487
  if (!isObject(result)) {
@@ -13189,9 +14511,101 @@ function extractOpenRouterResponseOutput(response, fallbackOutput) {
13189
14511
  }
13190
14512
  return void 0;
13191
14513
  }
13192
-
13193
- // src/openrouter-tool-wrapping.ts
13194
14514
  var OPENROUTER_WRAPPED_TOOL = Symbol("braintrust.openrouter.wrappedTool");
14515
+ function patchOpenRouterCallModelRequestTools(request) {
14516
+ if (!Array.isArray(request.tools) || request.tools.length === 0) {
14517
+ return void 0;
14518
+ }
14519
+ const originalTools = request.tools;
14520
+ const wrappedTools = originalTools.map((tool) => wrapOpenRouterTool(tool));
14521
+ const didPatch = wrappedTools.some(
14522
+ (tool, index) => tool !== originalTools[index]
14523
+ );
14524
+ if (!didPatch) {
14525
+ return void 0;
14526
+ }
14527
+ request.tools = wrappedTools;
14528
+ return () => {
14529
+ request.tools = originalTools;
14530
+ };
14531
+ }
14532
+ function wrapOpenRouterTool(tool) {
14533
+ if (isWrappedTool(tool) || !tool.function || typeof tool.function !== "object" || typeof tool.function.execute !== "function") {
14534
+ return tool;
14535
+ }
14536
+ const toolName = tool.function.name || "tool";
14537
+ const originalExecute = tool.function.execute;
14538
+ const wrappedTool = {
14539
+ ...tool,
14540
+ function: {
14541
+ ...tool.function,
14542
+ execute(...args) {
14543
+ return traceToolExecution({
14544
+ args,
14545
+ execute: () => Reflect.apply(originalExecute, this, args),
14546
+ toolCallId: getToolCallId(args[1]),
14547
+ toolName
14548
+ });
14549
+ }
14550
+ }
14551
+ };
14552
+ Object.defineProperty(wrappedTool, OPENROUTER_WRAPPED_TOOL, {
14553
+ value: true,
14554
+ enumerable: false,
14555
+ configurable: false
14556
+ });
14557
+ return wrappedTool;
14558
+ }
14559
+ function isWrappedTool(tool) {
14560
+ return Boolean(tool[OPENROUTER_WRAPPED_TOOL]);
14561
+ }
14562
+ function traceToolExecution(args) {
14563
+ const tracingChannel2 = openRouterAgentChannels.toolExecute.tracingChannel();
14564
+ const input = args.args.length > 0 ? args.args[0] : void 0;
14565
+ const event = {
14566
+ arguments: [input],
14567
+ span_info: {
14568
+ name: args.toolName
14569
+ },
14570
+ toolCallId: args.toolCallId,
14571
+ toolName: args.toolName
14572
+ };
14573
+ tracingChannel2.start.publish(event);
14574
+ try {
14575
+ const result = args.execute();
14576
+ return publishToolResult(tracingChannel2, event, result);
14577
+ } catch (error) {
14578
+ event.error = normalizeError(error);
14579
+ tracingChannel2.error.publish(event);
14580
+ throw error;
14581
+ }
14582
+ }
14583
+ function publishToolResult(tracingChannel2, event, result) {
14584
+ if (isPromiseLike3(result)) {
14585
+ return result.then(
14586
+ (resolved) => {
14587
+ event.result = resolved;
14588
+ tracingChannel2.asyncEnd.publish(event);
14589
+ return resolved;
14590
+ },
14591
+ (error) => {
14592
+ event.error = normalizeError(error);
14593
+ tracingChannel2.error.publish(event);
14594
+ throw error;
14595
+ }
14596
+ );
14597
+ }
14598
+ event.result = result;
14599
+ tracingChannel2.asyncEnd.publish(event);
14600
+ return result;
14601
+ }
14602
+ function getToolCallId(context) {
14603
+ const toolContext = context;
14604
+ return typeof toolContext?.toolCall?.id === "string" ? toolContext.toolCall.id : void 0;
14605
+ }
14606
+ function isPromiseLike3(value) {
14607
+ return !!value && (typeof value === "object" || typeof value === "function") && "then" in value && typeof value.then === "function";
14608
+ }
13195
14609
  var OPENROUTER_WRAPPED_CALL_MODEL_RESULT = Symbol(
13196
14610
  "braintrust.openrouter.wrappedCallModelResult"
13197
14611
  );
@@ -13211,24 +14625,8 @@ var OPENROUTER_CALL_MODEL_CONTEXT_METHODS = [
13211
14625
  "getToolCalls",
13212
14626
  "requiresApproval"
13213
14627
  ];
13214
- function patchOpenRouterCallModelRequestTools(request) {
13215
- if (!Array.isArray(request.tools) || request.tools.length === 0) {
13216
- return void 0;
13217
- }
13218
- const originalTools = request.tools;
13219
- const wrappedTools = originalTools.map((tool) => wrapOpenRouterTool(tool));
13220
- const didPatch = wrappedTools.some(
13221
- (tool, index) => tool !== originalTools[index]
13222
- );
13223
- if (!didPatch) {
13224
- return void 0;
13225
- }
13226
- request.tools = wrappedTools;
13227
- return () => {
13228
- request.tools = originalTools;
13229
- };
13230
- }
13231
- function patchOpenRouterCallModelResult(span, result, request) {
14628
+ function patchOpenRouterCallModelResult(args) {
14629
+ const { request, result, span } = args;
13232
14630
  if (!isObject(result) || isWrappedCallModelResult(result)) {
13233
14631
  return false;
13234
14632
  }
@@ -13301,10 +14699,10 @@ function patchOpenRouterCallModelResult(span, result, request) {
13301
14699
  }
13302
14700
  };
13303
14701
  if (originalGetResponse) {
13304
- resultLike.getResponse = async (...args) => {
14702
+ resultLike.getResponse = async (...args2) => {
13305
14703
  return await withCurrent(span, async () => {
13306
14704
  try {
13307
- const response = await originalGetResponse(...args);
14705
+ const response = await originalGetResponse(...args2);
13308
14706
  await endSpanWithResult(response);
13309
14707
  return response;
13310
14708
  } catch (error) {
@@ -13316,10 +14714,10 @@ function patchOpenRouterCallModelResult(span, result, request) {
13316
14714
  }
13317
14715
  if (typeof resultLike.getText === "function") {
13318
14716
  const originalGetText = resultLike.getText.bind(resultLike);
13319
- resultLike.getText = async (...args) => {
14717
+ resultLike.getText = async (...args2) => {
13320
14718
  return await withCurrent(span, async () => {
13321
14719
  try {
13322
- const text = await originalGetText(...args);
14720
+ const text = await originalGetText(...args2);
13323
14721
  await finalizeFromResponse(text);
13324
14722
  return text;
13325
14723
  } catch (error) {
@@ -13334,9 +14732,9 @@ function patchOpenRouterCallModelResult(span, result, request) {
13334
14732
  continue;
13335
14733
  }
13336
14734
  const originalMethod = resultLike[methodName];
13337
- resultLike[methodName] = async (...args) => {
14735
+ resultLike[methodName] = async (...args2) => {
13338
14736
  return await withCurrent(span, async () => {
13339
- return await originalMethod.apply(resultLike, args);
14737
+ return await originalMethod.apply(resultLike, args2);
13340
14738
  });
13341
14739
  };
13342
14740
  }
@@ -13345,12 +14743,12 @@ function patchOpenRouterCallModelResult(span, result, request) {
13345
14743
  continue;
13346
14744
  }
13347
14745
  const originalMethod = resultLike[methodName];
13348
- resultLike[methodName] = (...args) => {
14746
+ resultLike[methodName] = (...args2) => {
13349
14747
  const stream = withCurrent(
13350
14748
  span,
13351
- () => originalMethod.apply(resultLike, args)
14749
+ () => originalMethod.apply(resultLike, args2)
13352
14750
  );
13353
- if (!isAsyncIterable2(stream)) {
14751
+ if (!isAsyncIterable3(stream)) {
13354
14752
  return stream;
13355
14753
  }
13356
14754
  return wrapAsyncIterableWithSpan({
@@ -13363,157 +14761,70 @@ function patchOpenRouterCallModelResult(span, result, request) {
13363
14761
  }
13364
14762
  if (originalGetInitialResponse) {
13365
14763
  let initialTurnTraced = false;
13366
- resultLike.getInitialResponse = async (...args) => {
14764
+ resultLike.getInitialResponse = async (...args2) => {
13367
14765
  if (initialTurnTraced) {
13368
14766
  return await withCurrent(span, async () => {
13369
- return await originalGetInitialResponse(...args);
14767
+ return await originalGetInitialResponse(...args2);
13370
14768
  });
13371
14769
  }
13372
14770
  initialTurnTraced = true;
13373
- const resolvedRequest = getOpenRouterResolvedRequest(resultLike, request);
13374
- const childSpan = startOpenRouterCallModelTurnSpan({
13375
- request: resolvedRequest,
13376
- step: tracedTurnCount + 1,
13377
- stepType: tracedTurnCount === 0 ? "initial" : "continue"
13378
- });
13379
- return await withCurrent(childSpan, async () => {
13380
- try {
13381
- const response = await originalGetInitialResponse(...args);
14771
+ const step = tracedTurnCount + 1;
14772
+ const stepType = tracedTurnCount === 0 ? "initial" : "continue";
14773
+ const response = await traceOpenRouterCallModelTurn({
14774
+ fn: async () => {
14775
+ const nextResponse = await originalGetInitialResponse(...args2);
13382
14776
  tracedTurnCount++;
13383
- finishOpenRouterCallModelTurnSpan({
13384
- response,
13385
- step: tracedTurnCount,
13386
- stepType: tracedTurnCount === 1 ? "initial" : "continue",
13387
- span: childSpan
13388
- });
13389
- return response;
13390
- } catch (error) {
13391
- childSpan.log({
13392
- error: normalizeError(error).message
13393
- });
13394
- childSpan.end();
13395
- throw error;
13396
- }
14777
+ return nextResponse;
14778
+ },
14779
+ parentSpan: span,
14780
+ request: getOpenRouterResolvedRequest(resultLike, request),
14781
+ step,
14782
+ stepType
13397
14783
  });
14784
+ return response;
13398
14785
  };
13399
14786
  }
13400
14787
  if (originalMakeFollowupRequest) {
13401
- resultLike.makeFollowupRequest = async (...args) => {
13402
- const currentResponse = args[0];
13403
- const toolResults = Array.isArray(args[1]) ? args[1] : [];
13404
- const resolvedRequest = getOpenRouterResolvedRequest(resultLike, request);
13405
- const followupRequest = buildOpenRouterFollowupRequest(
13406
- resolvedRequest,
13407
- currentResponse,
13408
- toolResults
13409
- );
13410
- const childSpan = startOpenRouterCallModelTurnSpan({
13411
- request: followupRequest,
13412
- step: tracedTurnCount + 1,
13413
- stepType: "continue"
13414
- });
13415
- return await withCurrent(childSpan, async () => {
13416
- try {
13417
- const response = await originalMakeFollowupRequest(...args);
14788
+ resultLike.makeFollowupRequest = async (...args2) => {
14789
+ const currentResponse = args2[0];
14790
+ const toolResults = Array.isArray(args2[1]) ? args2[1] : [];
14791
+ const step = tracedTurnCount + 1;
14792
+ const response = await traceOpenRouterCallModelTurn({
14793
+ fn: async () => {
14794
+ const nextResponse = await originalMakeFollowupRequest(...args2);
13418
14795
  tracedTurnCount++;
13419
- finishOpenRouterCallModelTurnSpan({
13420
- response,
13421
- step: tracedTurnCount,
13422
- stepType: "continue",
13423
- span: childSpan
13424
- });
13425
- return response;
13426
- } catch (error) {
13427
- childSpan.log({
13428
- error: normalizeError(error).message
13429
- });
13430
- childSpan.end();
13431
- throw error;
13432
- }
14796
+ return nextResponse;
14797
+ },
14798
+ parentSpan: span,
14799
+ request: buildOpenRouterFollowupRequest(
14800
+ getOpenRouterResolvedRequest(resultLike, request),
14801
+ currentResponse,
14802
+ toolResults
14803
+ ),
14804
+ step,
14805
+ stepType: "continue"
13433
14806
  });
14807
+ return response;
13434
14808
  };
13435
14809
  }
13436
14810
  return true;
13437
14811
  }
13438
- function wrapOpenRouterTool(tool) {
13439
- if (isWrappedTool(tool) || !tool.function || typeof tool.function !== "object" || typeof tool.function.execute !== "function") {
13440
- return tool;
13441
- }
13442
- const toolName = tool.function.name || "tool";
13443
- const originalExecute = tool.function.execute;
13444
- const wrappedTool = {
13445
- ...tool,
13446
- function: {
13447
- ...tool.function,
13448
- execute(...args) {
13449
- return traceToolExecution({
13450
- args,
13451
- execute: () => Reflect.apply(originalExecute, this, args),
13452
- toolCallId: getToolCallId(args[1]),
13453
- toolName
13454
- });
13455
- }
13456
- }
14812
+ async function traceOpenRouterCallModelTurn(args) {
14813
+ const context = {
14814
+ arguments: [args.request],
14815
+ step: args.step,
14816
+ stepType: args.stepType
13457
14817
  };
13458
- Object.defineProperty(wrappedTool, OPENROUTER_WRAPPED_TOOL, {
13459
- value: true,
13460
- enumerable: false,
13461
- configurable: false
13462
- });
13463
- return wrappedTool;
13464
- }
13465
- function isWrappedTool(tool) {
13466
- return Boolean(tool[OPENROUTER_WRAPPED_TOOL]);
14818
+ return await withCurrent(
14819
+ args.parentSpan,
14820
+ () => openRouterAgentChannels.callModelTurn.tracePromise(args.fn, context)
14821
+ );
13467
14822
  }
13468
14823
  function isWrappedCallModelResult(value) {
13469
14824
  return Boolean(
13470
14825
  isObject(value) && value[OPENROUTER_WRAPPED_CALL_MODEL_RESULT]
13471
14826
  );
13472
14827
  }
13473
- function traceToolExecution(args) {
13474
- const tracingChannel2 = openRouterChannels.toolExecute.tracingChannel();
13475
- const input = args.args.length > 0 ? args.args[0] : void 0;
13476
- const event = {
13477
- arguments: [input],
13478
- span_info: {
13479
- name: args.toolName
13480
- },
13481
- toolCallId: args.toolCallId,
13482
- toolName: args.toolName
13483
- };
13484
- tracingChannel2.start.publish(event);
13485
- try {
13486
- const result = args.execute();
13487
- return publishToolResult(tracingChannel2, event, result);
13488
- } catch (error) {
13489
- event.error = normalizeError(error);
13490
- tracingChannel2.error.publish(event);
13491
- throw error;
13492
- }
13493
- }
13494
- function publishToolResult(tracingChannel2, event, result) {
13495
- if (isPromiseLike(result)) {
13496
- return result.then(
13497
- (resolved) => {
13498
- event.result = resolved;
13499
- tracingChannel2.asyncEnd.publish(event);
13500
- return resolved;
13501
- },
13502
- (error) => {
13503
- event.error = normalizeError(error);
13504
- tracingChannel2.error.publish(event);
13505
- throw error;
13506
- }
13507
- );
13508
- }
13509
- event.result = result;
13510
- tracingChannel2.asyncEnd.publish(event);
13511
- return result;
13512
- }
13513
- function getToolCallId(context) {
13514
- const toolContext = context;
13515
- return typeof toolContext?.toolCall?.id === "string" ? toolContext.toolCall.id : void 0;
13516
- }
13517
14828
  function extractOpenRouterCallModelResultMetadata(response, turnCount) {
13518
14829
  const combined = {
13519
14830
  ...extractOpenRouterResponseMetadata(response) || {},
@@ -13558,45 +14869,6 @@ function buildNextOpenRouterCallModelInput(currentInput, response, toolResults)
13558
14869
  (entry) => sanitizeOpenRouterLoggedValue(entry)
13559
14870
  );
13560
14871
  }
13561
- function startOpenRouterCallModelTurnSpan(args) {
13562
- const requestRecord = isObject(args.request) ? args.request : void 0;
13563
- const metadata = requestRecord ? extractOpenRouterCallModelMetadata(requestRecord) : { provider: "openrouter" };
13564
- if (isObject(metadata) && "tools" in metadata) {
13565
- delete metadata.tools;
13566
- }
13567
- return startSpan({
13568
- name: "openrouter.beta.responses.send",
13569
- spanAttributes: {
13570
- type: "llm" /* LLM */
13571
- },
13572
- event: {
13573
- input: requestRecord ? extractOpenRouterCallModelInput(requestRecord) : void 0,
13574
- metadata: {
13575
- ...metadata,
13576
- step: args.step,
13577
- step_type: args.stepType
13578
- }
13579
- }
13580
- });
13581
- }
13582
- function finishOpenRouterCallModelTurnSpan(args) {
13583
- if (!isObject(args.response)) {
13584
- args.span.end();
13585
- return;
13586
- }
13587
- args.span.log({
13588
- output: extractOpenRouterResponseOutput(args.response),
13589
- ...extractOpenRouterResponseMetadata(args.response) ? {
13590
- metadata: {
13591
- ...extractOpenRouterResponseMetadata(args.response),
13592
- ...args.step !== void 0 ? { step: args.step } : {},
13593
- ...args.stepType ? { step_type: args.stepType } : {}
13594
- }
13595
- } : {},
13596
- metrics: parseOpenRouterMetricsFromUsage(args.response.usage)
13597
- });
13598
- args.span.end();
13599
- }
13600
14872
  function getOpenRouterResolvedRequest(result, request) {
13601
14873
  if (isObject(result.resolvedRequest)) {
13602
14874
  return result.resolvedRequest;
@@ -13671,16 +14943,41 @@ function wrapAsyncIterableWithSpan(args) {
13671
14943
  }
13672
14944
  };
13673
14945
  }
13674
- function isAsyncIterable2(value) {
14946
+ function isAsyncIterable3(value) {
13675
14947
  return !!value && (typeof value === "object" || typeof value === "function") && Symbol.asyncIterator in value && typeof value[Symbol.asyncIterator] === "function";
13676
14948
  }
13677
- function isPromiseLike(value) {
13678
- return !!value && (typeof value === "object" || typeof value === "function") && "then" in value && typeof value.then === "function";
13679
- }
13680
14949
  function normalizeError(error) {
13681
14950
  return error instanceof Error ? error : new Error(String(error));
13682
14951
  }
13683
14952
 
14953
+ // src/instrumentation/plugins/openrouter-channels.ts
14954
+ var openRouterChannels = defineChannels("@openrouter/sdk", {
14955
+ chatSend: channel({
14956
+ channelName: "chat.send",
14957
+ kind: "async"
14958
+ }),
14959
+ embeddingsGenerate: channel({
14960
+ channelName: "embeddings.generate",
14961
+ kind: "async"
14962
+ }),
14963
+ betaResponsesSend: channel({
14964
+ channelName: "beta.responses.send",
14965
+ kind: "async"
14966
+ }),
14967
+ callModel: channel({
14968
+ channelName: "callModel",
14969
+ kind: "sync-stream"
14970
+ }),
14971
+ callModelTurn: channel({
14972
+ channelName: "callModel.turn",
14973
+ kind: "async"
14974
+ }),
14975
+ toolExecute: channel({
14976
+ channelName: "tool.execute",
14977
+ kind: "async"
14978
+ })
14979
+ });
14980
+
13684
14981
  // src/instrumentation/plugins/openrouter-plugin.ts
13685
14982
  var OpenRouterPlugin = class extends BasePlugin {
13686
14983
  onEnable() {
@@ -13702,14 +14999,14 @@ var OpenRouterPlugin = class extends BasePlugin {
13702
14999
  const { messages, ...metadata } = chatGenerationParams;
13703
15000
  return {
13704
15001
  input: messages,
13705
- metadata: buildOpenRouterMetadata(metadata, httpReferer, xTitle)
15002
+ metadata: buildOpenRouterMetadata2(metadata, httpReferer, xTitle)
13706
15003
  };
13707
15004
  },
13708
15005
  extractOutput: (result) => {
13709
15006
  return isObject(result) ? result.choices : void 0;
13710
15007
  },
13711
15008
  extractMetrics: (result, startTime) => {
13712
- const metrics = parseOpenRouterMetricsFromUsage(result?.usage);
15009
+ const metrics = parseOpenRouterMetricsFromUsage2(result?.usage);
13713
15010
  if (startTime) {
13714
15011
  metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
13715
15012
  }
@@ -13748,10 +15045,10 @@ var OpenRouterPlugin = class extends BasePlugin {
13748
15045
  if (!isObject(result)) {
13749
15046
  return void 0;
13750
15047
  }
13751
- return extractOpenRouterResponseMetadata(result);
15048
+ return extractOpenRouterResponseMetadata2(result);
13752
15049
  },
13753
15050
  extractMetrics: (result) => {
13754
- return isObject(result) ? parseOpenRouterMetricsFromUsage(result.usage) : {};
15051
+ return isObject(result) ? parseOpenRouterMetricsFromUsage2(result.usage) : {};
13755
15052
  }
13756
15053
  })
13757
15054
  );
@@ -13767,13 +15064,13 @@ var OpenRouterPlugin = class extends BasePlugin {
13767
15064
  const { input, ...metadata } = openResponsesRequest;
13768
15065
  return {
13769
15066
  input,
13770
- metadata: buildOpenRouterMetadata(metadata, httpReferer, xTitle)
15067
+ metadata: buildOpenRouterMetadata2(metadata, httpReferer, xTitle)
13771
15068
  };
13772
15069
  },
13773
- extractOutput: (result) => extractOpenRouterResponseOutput(result),
13774
- extractMetadata: (result) => extractOpenRouterResponseMetadata(result),
15070
+ extractOutput: (result) => extractOpenRouterResponseOutput2(result),
15071
+ extractMetadata: (result) => extractOpenRouterResponseMetadata2(result),
13775
15072
  extractMetrics: (result, startTime) => {
13776
- const metrics = parseOpenRouterMetricsFromUsage(result?.usage);
15073
+ const metrics = parseOpenRouterMetricsFromUsage2(result?.usage);
13777
15074
  if (startTime) {
13778
15075
  metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
13779
15076
  }
@@ -13787,21 +15084,57 @@ var OpenRouterPlugin = class extends BasePlugin {
13787
15084
  name: "openrouter.callModel",
13788
15085
  type: "llm" /* LLM */,
13789
15086
  extractInput: (args) => {
13790
- const request = getOpenRouterCallModelRequestArg(args);
15087
+ const request = getOpenRouterCallModelRequestArg2(args);
13791
15088
  return {
13792
- input: request ? extractOpenRouterCallModelInput(request) : void 0,
13793
- metadata: request ? extractOpenRouterCallModelMetadata(request) : { provider: "openrouter" }
15089
+ input: request ? extractOpenRouterCallModelInput2(request) : void 0,
15090
+ metadata: request ? extractOpenRouterCallModelMetadata2(request) : { provider: "openrouter" }
13794
15091
  };
13795
15092
  },
13796
15093
  patchResult: ({ endEvent, result, span }) => {
13797
- return patchOpenRouterCallModelResult(
13798
- span,
15094
+ return patchOpenRouterCallModelResult2({
15095
+ request: getOpenRouterCallModelRequestArg2(endEvent.arguments),
13799
15096
  result,
13800
- getOpenRouterCallModelRequestArg(endEvent.arguments)
13801
- );
15097
+ span
15098
+ });
13802
15099
  }
13803
15100
  })
13804
15101
  );
15102
+ this.unsubscribers.push(
15103
+ traceAsyncChannel(openRouterChannels.callModelTurn, {
15104
+ name: "openrouter.beta.responses.send",
15105
+ type: "llm" /* LLM */,
15106
+ extractInput: (args, event) => {
15107
+ const request = getOpenRouterCallModelRequestArg2(args);
15108
+ const metadata = request ? extractOpenRouterCallModelMetadata2(request) : { provider: "openrouter" };
15109
+ if (isObject(metadata) && "tools" in metadata) {
15110
+ delete metadata.tools;
15111
+ }
15112
+ return {
15113
+ input: request ? extractOpenRouterCallModelInput2(request) : void 0,
15114
+ metadata: {
15115
+ ...metadata,
15116
+ step: event.step,
15117
+ step_type: event.stepType
15118
+ }
15119
+ };
15120
+ },
15121
+ extractOutput: (result) => extractOpenRouterResponseOutput2(result),
15122
+ extractMetadata: (result, event) => {
15123
+ if (!isObject(result)) {
15124
+ return {
15125
+ step: event?.step,
15126
+ step_type: event?.stepType
15127
+ };
15128
+ }
15129
+ return {
15130
+ ...extractOpenRouterResponseMetadata2(result) || {},
15131
+ ...event?.step !== void 0 ? { step: event.step } : {},
15132
+ ...event?.stepType ? { step_type: event.stepType } : {}
15133
+ };
15134
+ },
15135
+ extractMetrics: (result) => isObject(result) ? parseOpenRouterMetricsFromUsage2(result.usage) : {}
15136
+ })
15137
+ );
13805
15138
  this.unsubscribers.push(
13806
15139
  traceStreamingChannel(openRouterChannels.toolExecute, {
13807
15140
  name: "openrouter.tool",
@@ -13822,155 +15155,1303 @@ var OpenRouterPlugin = class extends BasePlugin {
13822
15155
  })
13823
15156
  })
13824
15157
  );
13825
- const callModelChannel = openRouterChannels.callModel.tracingChannel();
13826
- const callModelHandlers = {
13827
- start: (event) => {
13828
- const request = getOpenRouterCallModelRequestArg(event.arguments);
13829
- if (!request) {
13830
- return;
13831
- }
13832
- patchOpenRouterCallModelRequestTools(request);
13833
- }
13834
- };
13835
- callModelChannel.subscribe(callModelHandlers);
13836
- this.unsubscribers.push(() => {
13837
- callModelChannel.unsubscribe(callModelHandlers);
13838
- });
15158
+ const callModelChannel = openRouterChannels.callModel.tracingChannel();
15159
+ const callModelHandlers = {
15160
+ start: (event) => {
15161
+ const request = getOpenRouterCallModelRequestArg2(event.arguments);
15162
+ if (!request) {
15163
+ return;
15164
+ }
15165
+ patchOpenRouterCallModelRequestTools2(request);
15166
+ }
15167
+ };
15168
+ callModelChannel.subscribe(callModelHandlers);
15169
+ this.unsubscribers.push(() => {
15170
+ callModelChannel.unsubscribe(callModelHandlers);
15171
+ });
15172
+ }
15173
+ };
15174
+ function normalizeArgs2(args) {
15175
+ if (Array.isArray(args)) {
15176
+ return args;
15177
+ }
15178
+ if (isArrayLike2(args)) {
15179
+ return Array.from(args);
15180
+ }
15181
+ return [args];
15182
+ }
15183
+ function isArrayLike2(value) {
15184
+ return isObject(value) && "length" in value && typeof value.length === "number" && Number.isInteger(value.length) && value.length >= 0;
15185
+ }
15186
+ function getOpenRouterRequestArg(args) {
15187
+ const normalizedArgs = normalizeArgs2(args);
15188
+ const keyedCandidate = normalizedArgs.find(
15189
+ (arg) => isObject(arg) && ("chatGenerationParams" in arg || "requestBody" in arg || "openResponsesRequest" in arg)
15190
+ );
15191
+ if (isObject(keyedCandidate)) {
15192
+ return keyedCandidate;
15193
+ }
15194
+ const firstObjectArg = normalizedArgs.find((arg) => isObject(arg));
15195
+ return isObject(firstObjectArg) ? firstObjectArg : void 0;
15196
+ }
15197
+ function getOpenRouterCallModelRequestArg2(args) {
15198
+ const firstObjectArg = normalizeArgs2(args).find((arg) => isObject(arg));
15199
+ return isObject(firstObjectArg) ? firstObjectArg : void 0;
15200
+ }
15201
+ var TOKEN_NAME_MAP3 = {
15202
+ promptTokens: "prompt_tokens",
15203
+ inputTokens: "prompt_tokens",
15204
+ completionTokens: "completion_tokens",
15205
+ outputTokens: "completion_tokens",
15206
+ totalTokens: "tokens",
15207
+ prompt_tokens: "prompt_tokens",
15208
+ input_tokens: "prompt_tokens",
15209
+ completion_tokens: "completion_tokens",
15210
+ output_tokens: "completion_tokens",
15211
+ total_tokens: "tokens"
15212
+ };
15213
+ var TOKEN_DETAIL_PREFIX_MAP2 = {
15214
+ promptTokensDetails: "prompt",
15215
+ inputTokensDetails: "prompt",
15216
+ completionTokensDetails: "completion",
15217
+ outputTokensDetails: "completion",
15218
+ costDetails: "cost",
15219
+ prompt_tokens_details: "prompt",
15220
+ input_tokens_details: "prompt",
15221
+ completion_tokens_details: "completion",
15222
+ output_tokens_details: "completion",
15223
+ cost_details: "cost"
15224
+ };
15225
+ function camelToSnake2(value) {
15226
+ return value.replace(/[A-Z]/g, (match) => `_${match.toLowerCase()}`);
15227
+ }
15228
+ function parseOpenRouterMetricsFromUsage2(usage) {
15229
+ if (!isObject(usage)) {
15230
+ return {};
15231
+ }
15232
+ const metrics = {};
15233
+ for (const [name, value] of Object.entries(usage)) {
15234
+ if (typeof value === "number") {
15235
+ metrics[TOKEN_NAME_MAP3[name] || camelToSnake2(name)] = value;
15236
+ continue;
15237
+ }
15238
+ if (!isObject(value)) {
15239
+ continue;
15240
+ }
15241
+ const prefix = TOKEN_DETAIL_PREFIX_MAP2[name];
15242
+ if (!prefix) {
15243
+ continue;
15244
+ }
15245
+ for (const [nestedName, nestedValue] of Object.entries(value)) {
15246
+ if (typeof nestedValue !== "number") {
15247
+ continue;
15248
+ }
15249
+ metrics[`${prefix}_${camelToSnake2(nestedName)}`] = nestedValue;
15250
+ }
15251
+ }
15252
+ return metrics;
15253
+ }
15254
+ function extractOpenRouterUsageMetadata2(usage) {
15255
+ if (!isObject(usage)) {
15256
+ return void 0;
15257
+ }
15258
+ const metadata = {};
15259
+ if (typeof usage.isByok === "boolean") {
15260
+ metadata.is_byok = usage.isByok;
15261
+ } else if (typeof usage.is_byok === "boolean") {
15262
+ metadata.is_byok = usage.is_byok;
15263
+ }
15264
+ return Object.keys(metadata).length > 0 ? metadata : void 0;
15265
+ }
15266
+ var OMITTED_OPENROUTER_KEYS2 = /* @__PURE__ */ new Set([
15267
+ "execute",
15268
+ "render",
15269
+ "nextTurnParams",
15270
+ "requireApproval"
15271
+ ]);
15272
+ function parseOpenRouterModelString2(model) {
15273
+ if (typeof model !== "string") {
15274
+ return { model };
15275
+ }
15276
+ const slashIndex = model.indexOf("/");
15277
+ if (slashIndex > 0 && slashIndex < model.length - 1) {
15278
+ return {
15279
+ provider: model.substring(0, slashIndex),
15280
+ model: model.substring(slashIndex + 1)
15281
+ };
15282
+ }
15283
+ return { model };
15284
+ }
15285
+ function isZodSchema4(value) {
15286
+ return value != null && typeof value === "object" && "_def" in value && typeof value._def === "object";
15287
+ }
15288
+ function serializeZodSchema4(schema) {
15289
+ try {
15290
+ return zodToJsonSchema(schema);
15291
+ } catch {
15292
+ return {
15293
+ type: "object",
15294
+ description: "Zod schema (conversion failed)"
15295
+ };
15296
+ }
15297
+ }
15298
+ function serializeOpenRouterTool2(tool) {
15299
+ if (!isObject(tool)) {
15300
+ return tool;
15301
+ }
15302
+ const serialized = {};
15303
+ for (const [key, value] of Object.entries(tool)) {
15304
+ if (OMITTED_OPENROUTER_KEYS2.has(key)) {
15305
+ continue;
15306
+ }
15307
+ if (key === "function" && isObject(value)) {
15308
+ serialized.function = sanitizeOpenRouterLoggedValue2(value);
15309
+ continue;
15310
+ }
15311
+ serialized[key] = sanitizeOpenRouterLoggedValue2(value);
15312
+ }
15313
+ return serialized;
15314
+ }
15315
+ function serializeOpenRouterToolsForLogging2(tools) {
15316
+ if (!Array.isArray(tools)) {
15317
+ return void 0;
15318
+ }
15319
+ return tools.map((tool) => serializeOpenRouterTool2(tool));
15320
+ }
15321
+ function sanitizeOpenRouterLoggedValue2(value) {
15322
+ if (isZodSchema4(value)) {
15323
+ return serializeZodSchema4(value);
15324
+ }
15325
+ if (typeof value === "function") {
15326
+ return "[Function]";
15327
+ }
15328
+ if (Array.isArray(value)) {
15329
+ return value.map((entry) => sanitizeOpenRouterLoggedValue2(entry));
15330
+ }
15331
+ if (!isObject(value)) {
15332
+ return value;
15333
+ }
15334
+ const sanitized = {};
15335
+ for (const [key, entry] of Object.entries(value)) {
15336
+ if (OMITTED_OPENROUTER_KEYS2.has(key)) {
15337
+ continue;
15338
+ }
15339
+ if (key === "tools" && Array.isArray(entry)) {
15340
+ sanitized.tools = serializeOpenRouterToolsForLogging2(entry);
15341
+ continue;
15342
+ }
15343
+ sanitized[key] = sanitizeOpenRouterLoggedValue2(entry);
15344
+ }
15345
+ return sanitized;
15346
+ }
15347
+ function buildOpenRouterMetadata2(metadata, httpReferer, xTitle) {
15348
+ const sanitized = sanitizeOpenRouterLoggedValue2(metadata);
15349
+ const metadataRecord = isObject(sanitized) ? sanitized : {};
15350
+ const { model, provider: providerRouting, ...rest } = metadataRecord;
15351
+ const normalizedModel = parseOpenRouterModelString2(model);
15352
+ return {
15353
+ ...rest,
15354
+ ...normalizedModel.model !== void 0 ? { model: normalizedModel.model } : {},
15355
+ ...providerRouting !== void 0 ? { providerRouting } : {},
15356
+ ...httpReferer !== void 0 ? { httpReferer } : {},
15357
+ ...xTitle !== void 0 ? { xTitle } : {},
15358
+ provider: normalizedModel.provider || "openrouter"
15359
+ };
15360
+ }
15361
+ function buildOpenRouterEmbeddingMetadata(metadata, httpReferer, xTitle) {
15362
+ const normalized = buildOpenRouterMetadata2(metadata, httpReferer, xTitle);
15363
+ return typeof normalized.model === "string" ? {
15364
+ ...normalized,
15365
+ embedding_model: normalized.model
15366
+ } : normalized;
15367
+ }
15368
+ function extractOpenRouterCallModelInput2(request) {
15369
+ return isObject(request) && "input" in request ? sanitizeOpenRouterLoggedValue2(request.input) : void 0;
15370
+ }
15371
+ function extractOpenRouterCallModelMetadata2(request) {
15372
+ if (!isObject(request)) {
15373
+ return { provider: "openrouter" };
15374
+ }
15375
+ const { input: _input, ...metadata } = request;
15376
+ return buildOpenRouterMetadata2(metadata, void 0, void 0);
15377
+ }
15378
+ function extractOpenRouterResponseMetadata2(result) {
15379
+ if (!isObject(result)) {
15380
+ return void 0;
15381
+ }
15382
+ const { output: _output, data: _data, usage, ...metadata } = result;
15383
+ const sanitized = sanitizeOpenRouterLoggedValue2(metadata);
15384
+ const metadataRecord = isObject(sanitized) ? sanitized : {};
15385
+ const { model, provider, ...rest } = metadataRecord;
15386
+ const normalizedModel = parseOpenRouterModelString2(model);
15387
+ const normalizedProvider = (typeof provider === "string" ? provider : void 0) || normalizedModel.provider;
15388
+ const usageMetadata = extractOpenRouterUsageMetadata2(usage);
15389
+ const combined = {
15390
+ ...rest,
15391
+ ...normalizedModel.model !== void 0 ? { model: normalizedModel.model } : {},
15392
+ ...usageMetadata || {},
15393
+ ...normalizedProvider !== void 0 ? { provider: normalizedProvider } : {}
15394
+ };
15395
+ return Object.keys(combined).length > 0 ? combined : void 0;
15396
+ }
15397
+ function extractOpenRouterResponseOutput2(response, fallbackOutput) {
15398
+ if (isObject(response) && "output" in response && response.output !== void 0) {
15399
+ return sanitizeOpenRouterLoggedValue2(response.output);
15400
+ }
15401
+ if (fallbackOutput !== void 0) {
15402
+ return sanitizeOpenRouterLoggedValue2(fallbackOutput);
15403
+ }
15404
+ return void 0;
15405
+ }
15406
+ var OPENROUTER_WRAPPED_TOOL2 = Symbol("braintrust.openrouter.wrappedTool");
15407
+ function patchOpenRouterCallModelRequestTools2(request) {
15408
+ if (!Array.isArray(request.tools) || request.tools.length === 0) {
15409
+ return void 0;
15410
+ }
15411
+ const originalTools = request.tools;
15412
+ const wrappedTools = originalTools.map((tool) => wrapOpenRouterTool2(tool));
15413
+ const didPatch = wrappedTools.some(
15414
+ (tool, index) => tool !== originalTools[index]
15415
+ );
15416
+ if (!didPatch) {
15417
+ return void 0;
15418
+ }
15419
+ request.tools = wrappedTools;
15420
+ return () => {
15421
+ request.tools = originalTools;
15422
+ };
15423
+ }
15424
+ function wrapOpenRouterTool2(tool) {
15425
+ if (isWrappedTool2(tool) || !tool.function || typeof tool.function !== "object" || typeof tool.function.execute !== "function") {
15426
+ return tool;
15427
+ }
15428
+ const toolName = tool.function.name || "tool";
15429
+ const originalExecute = tool.function.execute;
15430
+ const wrappedTool = {
15431
+ ...tool,
15432
+ function: {
15433
+ ...tool.function,
15434
+ execute(...args) {
15435
+ return traceToolExecution2({
15436
+ args,
15437
+ execute: () => Reflect.apply(originalExecute, this, args),
15438
+ toolCallId: getToolCallId2(args[1]),
15439
+ toolName
15440
+ });
15441
+ }
15442
+ }
15443
+ };
15444
+ Object.defineProperty(wrappedTool, OPENROUTER_WRAPPED_TOOL2, {
15445
+ value: true,
15446
+ enumerable: false,
15447
+ configurable: false
15448
+ });
15449
+ return wrappedTool;
15450
+ }
15451
+ function isWrappedTool2(tool) {
15452
+ return Boolean(tool[OPENROUTER_WRAPPED_TOOL2]);
15453
+ }
15454
+ function traceToolExecution2(args) {
15455
+ const tracingChannel2 = openRouterChannels.toolExecute.tracingChannel();
15456
+ const input = args.args.length > 0 ? args.args[0] : void 0;
15457
+ const event = {
15458
+ arguments: [input],
15459
+ span_info: {
15460
+ name: args.toolName
15461
+ },
15462
+ toolCallId: args.toolCallId,
15463
+ toolName: args.toolName
15464
+ };
15465
+ tracingChannel2.start.publish(event);
15466
+ try {
15467
+ const result = args.execute();
15468
+ return publishToolResult2(tracingChannel2, event, result);
15469
+ } catch (error) {
15470
+ event.error = normalizeError2(error);
15471
+ tracingChannel2.error.publish(event);
15472
+ throw error;
15473
+ }
15474
+ }
15475
+ function publishToolResult2(tracingChannel2, event, result) {
15476
+ if (isPromiseLike4(result)) {
15477
+ return result.then(
15478
+ (resolved) => {
15479
+ event.result = resolved;
15480
+ tracingChannel2.asyncEnd.publish(event);
15481
+ return resolved;
15482
+ },
15483
+ (error) => {
15484
+ event.error = normalizeError2(error);
15485
+ tracingChannel2.error.publish(event);
15486
+ throw error;
15487
+ }
15488
+ );
15489
+ }
15490
+ event.result = result;
15491
+ tracingChannel2.asyncEnd.publish(event);
15492
+ return result;
15493
+ }
15494
+ function getToolCallId2(context) {
15495
+ const toolContext = context;
15496
+ return typeof toolContext?.toolCall?.id === "string" ? toolContext.toolCall.id : void 0;
15497
+ }
15498
+ function isPromiseLike4(value) {
15499
+ return !!value && (typeof value === "object" || typeof value === "function") && "then" in value && typeof value.then === "function";
15500
+ }
15501
+ function aggregateOpenRouterChatChunks(chunks) {
15502
+ let role;
15503
+ let content = "";
15504
+ let toolCalls;
15505
+ let finishReason;
15506
+ let metrics = {};
15507
+ for (const chunk of chunks) {
15508
+ metrics = {
15509
+ ...metrics,
15510
+ ...parseOpenRouterMetricsFromUsage2(chunk?.usage)
15511
+ };
15512
+ const choice = chunk?.choices?.[0];
15513
+ const delta = choice?.delta;
15514
+ if (!delta) {
15515
+ if (choice?.finish_reason !== void 0) {
15516
+ finishReason = choice.finish_reason;
15517
+ }
15518
+ continue;
15519
+ }
15520
+ if (!role && delta.role) {
15521
+ role = delta.role;
15522
+ }
15523
+ if (typeof delta.content === "string") {
15524
+ content += delta.content;
15525
+ }
15526
+ const choiceFinishReason = choice?.finishReason ?? choice?.finish_reason ?? void 0;
15527
+ const deltaFinishReason = delta.finishReason ?? delta.finish_reason ?? void 0;
15528
+ if (choiceFinishReason !== void 0) {
15529
+ finishReason = choiceFinishReason;
15530
+ } else if (deltaFinishReason !== void 0) {
15531
+ finishReason = deltaFinishReason;
15532
+ }
15533
+ const toolCallDeltas = Array.isArray(delta.toolCalls) ? delta.toolCalls : Array.isArray(delta.tool_calls) ? delta.tool_calls : void 0;
15534
+ if (!toolCallDeltas) {
15535
+ continue;
15536
+ }
15537
+ for (const toolDelta of toolCallDeltas) {
15538
+ if (!toolDelta?.function) {
15539
+ continue;
15540
+ }
15541
+ const toolIndex = toolDelta.index ?? 0;
15542
+ const existingToolCall = toolCalls?.[toolIndex];
15543
+ if (!existingToolCall || toolDelta.id && existingToolCall.id !== void 0 && existingToolCall.id !== toolDelta.id) {
15544
+ const nextToolCalls = [...toolCalls || []];
15545
+ nextToolCalls[toolIndex] = {
15546
+ index: toolIndex,
15547
+ id: toolDelta.id,
15548
+ type: toolDelta.type,
15549
+ function: {
15550
+ name: toolDelta.function.name,
15551
+ arguments: toolDelta.function.arguments || ""
15552
+ }
15553
+ };
15554
+ toolCalls = nextToolCalls;
15555
+ continue;
15556
+ }
15557
+ const current = existingToolCall;
15558
+ if (toolDelta.id && !current.id) {
15559
+ current.id = toolDelta.id;
15560
+ }
15561
+ if (toolDelta.type && !current.type) {
15562
+ current.type = toolDelta.type;
15563
+ }
15564
+ if (toolDelta.function.name && !current.function.name) {
15565
+ current.function.name = toolDelta.function.name;
15566
+ }
15567
+ current.function.arguments += toolDelta.function.arguments || "";
15568
+ }
15569
+ }
15570
+ return {
15571
+ output: [
15572
+ {
15573
+ index: 0,
15574
+ message: {
15575
+ role,
15576
+ content: content || void 0,
15577
+ ...toolCalls ? { tool_calls: toolCalls } : {}
15578
+ },
15579
+ logprobs: null,
15580
+ finish_reason: finishReason
15581
+ }
15582
+ ],
15583
+ metrics
15584
+ };
15585
+ }
15586
+ function aggregateOpenRouterResponseStreamEvents(chunks) {
15587
+ let finalResponse;
15588
+ for (const chunk of chunks) {
15589
+ const response = chunk?.response;
15590
+ if (!response) {
15591
+ continue;
15592
+ }
15593
+ if (chunk.type === "response.completed" || chunk.type === "response.incomplete" || chunk.type === "response.failed") {
15594
+ finalResponse = response;
15595
+ }
15596
+ }
15597
+ if (!finalResponse) {
15598
+ return {
15599
+ output: void 0,
15600
+ metrics: {}
15601
+ };
15602
+ }
15603
+ return {
15604
+ output: extractOpenRouterResponseOutput2(finalResponse),
15605
+ metrics: parseOpenRouterMetricsFromUsage2(finalResponse.usage),
15606
+ ...extractOpenRouterResponseMetadata2(finalResponse) ? { metadata: extractOpenRouterResponseMetadata2(finalResponse) } : {}
15607
+ };
15608
+ }
15609
+ var OPENROUTER_WRAPPED_CALL_MODEL_RESULT2 = Symbol(
15610
+ "braintrust.openrouter.wrappedCallModelResult"
15611
+ );
15612
+ var OPENROUTER_CALL_MODEL_STREAM_METHODS2 = [
15613
+ "getFullResponsesStream",
15614
+ "getItemsStream",
15615
+ "getNewMessagesStream",
15616
+ "getReasoningStream",
15617
+ "getTextStream",
15618
+ "getToolCallsStream",
15619
+ "getToolStream"
15620
+ ];
15621
+ var OPENROUTER_CALL_MODEL_CONTEXT_METHODS2 = [
15622
+ "cancel",
15623
+ "getPendingToolCalls",
15624
+ "getState",
15625
+ "getToolCalls",
15626
+ "requiresApproval"
15627
+ ];
15628
+ function patchOpenRouterCallModelResult2(args) {
15629
+ const { request, result, span } = args;
15630
+ if (!isObject(result) || isWrappedCallModelResult2(result)) {
15631
+ return false;
15632
+ }
15633
+ const resultLike = result;
15634
+ const hasInstrumentableMethod = typeof resultLike.getResponse === "function" || typeof resultLike.getText === "function" || OPENROUTER_CALL_MODEL_STREAM_METHODS2.some(
15635
+ (methodName) => typeof resultLike[methodName] === "function"
15636
+ );
15637
+ if (!hasInstrumentableMethod) {
15638
+ return false;
15639
+ }
15640
+ Object.defineProperty(resultLike, OPENROUTER_WRAPPED_CALL_MODEL_RESULT2, {
15641
+ value: true,
15642
+ enumerable: false,
15643
+ configurable: false
15644
+ });
15645
+ const originalGetResponse = typeof resultLike.getResponse === "function" ? resultLike.getResponse.bind(resultLike) : void 0;
15646
+ const originalGetInitialResponse = typeof resultLike.getInitialResponse === "function" ? resultLike.getInitialResponse.bind(resultLike) : void 0;
15647
+ const originalMakeFollowupRequest = typeof resultLike.makeFollowupRequest === "function" ? resultLike.makeFollowupRequest.bind(resultLike) : void 0;
15648
+ let ended = false;
15649
+ let tracedTurnCount = 0;
15650
+ const endSpanWithResult = async (response, fallbackOutput) => {
15651
+ if (ended) {
15652
+ return;
15653
+ }
15654
+ ended = true;
15655
+ const finalResponse = getFinalOpenRouterCallModelResponse2(
15656
+ resultLike,
15657
+ response
15658
+ );
15659
+ if (finalResponse) {
15660
+ const rounds = getOpenRouterCallModelRounds2(resultLike);
15661
+ const metadata = extractOpenRouterCallModelResultMetadata2(
15662
+ finalResponse,
15663
+ rounds.length + 1
15664
+ );
15665
+ span.log({
15666
+ output: extractOpenRouterResponseOutput2(finalResponse, fallbackOutput),
15667
+ ...metadata ? { metadata } : {},
15668
+ metrics: aggregateOpenRouterCallModelMetrics2(rounds, finalResponse)
15669
+ });
15670
+ span.end();
15671
+ return;
15672
+ }
15673
+ if (fallbackOutput !== void 0) {
15674
+ span.log({
15675
+ output: fallbackOutput
15676
+ });
15677
+ }
15678
+ span.end();
15679
+ };
15680
+ const endSpanWithError = (error) => {
15681
+ if (ended) {
15682
+ return;
15683
+ }
15684
+ ended = true;
15685
+ span.log({
15686
+ error: normalizeError2(error).message
15687
+ });
15688
+ span.end();
15689
+ };
15690
+ const finalizeFromResponse = async (fallbackOutput) => {
15691
+ if (!originalGetResponse) {
15692
+ await endSpanWithResult(void 0, fallbackOutput);
15693
+ return;
15694
+ }
15695
+ try {
15696
+ await endSpanWithResult(await originalGetResponse(), fallbackOutput);
15697
+ } catch {
15698
+ await endSpanWithResult(void 0, fallbackOutput);
15699
+ }
15700
+ };
15701
+ if (originalGetResponse) {
15702
+ resultLike.getResponse = async (...args2) => {
15703
+ return await withCurrent(span, async () => {
15704
+ try {
15705
+ const response = await originalGetResponse(...args2);
15706
+ await endSpanWithResult(response);
15707
+ return response;
15708
+ } catch (error) {
15709
+ endSpanWithError(error);
15710
+ throw error;
15711
+ }
15712
+ });
15713
+ };
15714
+ }
15715
+ if (typeof resultLike.getText === "function") {
15716
+ const originalGetText = resultLike.getText.bind(resultLike);
15717
+ resultLike.getText = async (...args2) => {
15718
+ return await withCurrent(span, async () => {
15719
+ try {
15720
+ const text = await originalGetText(...args2);
15721
+ await finalizeFromResponse(text);
15722
+ return text;
15723
+ } catch (error) {
15724
+ endSpanWithError(error);
15725
+ throw error;
15726
+ }
15727
+ });
15728
+ };
15729
+ }
15730
+ for (const methodName of OPENROUTER_CALL_MODEL_CONTEXT_METHODS2) {
15731
+ if (typeof resultLike[methodName] !== "function") {
15732
+ continue;
15733
+ }
15734
+ const originalMethod = resultLike[methodName];
15735
+ resultLike[methodName] = async (...args2) => {
15736
+ return await withCurrent(span, async () => {
15737
+ return await originalMethod.apply(resultLike, args2);
15738
+ });
15739
+ };
15740
+ }
15741
+ for (const methodName of OPENROUTER_CALL_MODEL_STREAM_METHODS2) {
15742
+ if (typeof resultLike[methodName] !== "function") {
15743
+ continue;
15744
+ }
15745
+ const originalMethod = resultLike[methodName];
15746
+ resultLike[methodName] = (...args2) => {
15747
+ const stream = withCurrent(
15748
+ span,
15749
+ () => originalMethod.apply(resultLike, args2)
15750
+ );
15751
+ if (!isAsyncIterable4(stream)) {
15752
+ return stream;
15753
+ }
15754
+ return wrapAsyncIterableWithSpan2({
15755
+ finalize: finalizeFromResponse,
15756
+ iteratorFactory: () => stream[Symbol.asyncIterator](),
15757
+ onError: endSpanWithError,
15758
+ span
15759
+ });
15760
+ };
15761
+ }
15762
+ if (originalGetInitialResponse) {
15763
+ let initialTurnTraced = false;
15764
+ resultLike.getInitialResponse = async (...args2) => {
15765
+ if (initialTurnTraced) {
15766
+ return await withCurrent(span, async () => {
15767
+ return await originalGetInitialResponse(...args2);
15768
+ });
15769
+ }
15770
+ initialTurnTraced = true;
15771
+ const step = tracedTurnCount + 1;
15772
+ const stepType = tracedTurnCount === 0 ? "initial" : "continue";
15773
+ const response = await traceOpenRouterCallModelTurn2({
15774
+ fn: async () => {
15775
+ const nextResponse = await originalGetInitialResponse(...args2);
15776
+ tracedTurnCount++;
15777
+ return nextResponse;
15778
+ },
15779
+ parentSpan: span,
15780
+ request: getOpenRouterResolvedRequest2(resultLike, request),
15781
+ step,
15782
+ stepType
15783
+ });
15784
+ return response;
15785
+ };
15786
+ }
15787
+ if (originalMakeFollowupRequest) {
15788
+ resultLike.makeFollowupRequest = async (...args2) => {
15789
+ const currentResponse = args2[0];
15790
+ const toolResults = Array.isArray(args2[1]) ? args2[1] : [];
15791
+ const step = tracedTurnCount + 1;
15792
+ const response = await traceOpenRouterCallModelTurn2({
15793
+ fn: async () => {
15794
+ const nextResponse = await originalMakeFollowupRequest(...args2);
15795
+ tracedTurnCount++;
15796
+ return nextResponse;
15797
+ },
15798
+ parentSpan: span,
15799
+ request: buildOpenRouterFollowupRequest2(
15800
+ getOpenRouterResolvedRequest2(resultLike, request),
15801
+ currentResponse,
15802
+ toolResults
15803
+ ),
15804
+ step,
15805
+ stepType: "continue"
15806
+ });
15807
+ return response;
15808
+ };
15809
+ }
15810
+ return true;
15811
+ }
15812
+ async function traceOpenRouterCallModelTurn2(args) {
15813
+ const context = {
15814
+ arguments: [args.request],
15815
+ step: args.step,
15816
+ stepType: args.stepType
15817
+ };
15818
+ return await withCurrent(
15819
+ args.parentSpan,
15820
+ () => openRouterChannels.callModelTurn.tracePromise(args.fn, context)
15821
+ );
15822
+ }
15823
+ function isWrappedCallModelResult2(value) {
15824
+ return Boolean(
15825
+ isObject(value) && value[OPENROUTER_WRAPPED_CALL_MODEL_RESULT2]
15826
+ );
15827
+ }
15828
+ function extractOpenRouterCallModelResultMetadata2(response, turnCount) {
15829
+ const combined = {
15830
+ ...extractOpenRouterResponseMetadata2(response) || {},
15831
+ ...turnCount !== void 0 ? { turn_count: turnCount } : {}
15832
+ };
15833
+ return Object.keys(combined).length > 0 ? combined : void 0;
15834
+ }
15835
+ function getFinalOpenRouterCallModelResponse2(result, response) {
15836
+ if (isObject(response)) {
15837
+ return response;
15838
+ }
15839
+ return isObject(result.finalResponse) ? result.finalResponse : void 0;
15840
+ }
15841
+ function getOpenRouterCallModelRounds2(result) {
15842
+ if (!Array.isArray(result.allToolExecutionRounds)) {
15843
+ return [];
15844
+ }
15845
+ return result.allToolExecutionRounds.filter((round) => isObject(round)).map((round) => ({
15846
+ response: isObject(round.response) ? round.response : void 0,
15847
+ round: typeof round.round === "number" ? round.round : void 0,
15848
+ toolResults: Array.isArray(round.toolResults) ? round.toolResults : []
15849
+ })).filter((round) => round.response !== void 0);
15850
+ }
15851
+ function aggregateOpenRouterCallModelMetrics2(rounds, finalResponse) {
15852
+ const metrics = {};
15853
+ const responses = [
15854
+ ...rounds.map((round) => round.response).filter(isObject),
15855
+ finalResponse
15856
+ ];
15857
+ for (const response of responses) {
15858
+ const responseMetrics = parseOpenRouterMetricsFromUsage2(response.usage);
15859
+ for (const [name, value] of Object.entries(responseMetrics)) {
15860
+ metrics[name] = (metrics[name] || 0) + value;
15861
+ }
15862
+ }
15863
+ return metrics;
15864
+ }
15865
+ function buildNextOpenRouterCallModelInput2(currentInput, response, toolResults) {
15866
+ const normalizedInput = Array.isArray(currentInput) ? [...currentInput] : currentInput === void 0 ? [] : [currentInput];
15867
+ const responseOutput = Array.isArray(response.output) ? response.output : response.output === void 0 ? [] : [response.output];
15868
+ return [...normalizedInput, ...responseOutput, ...toolResults].map(
15869
+ (entry) => sanitizeOpenRouterLoggedValue2(entry)
15870
+ );
15871
+ }
15872
+ function getOpenRouterResolvedRequest2(result, request) {
15873
+ if (isObject(result.resolvedRequest)) {
15874
+ return result.resolvedRequest;
15875
+ }
15876
+ return request;
15877
+ }
15878
+ function buildOpenRouterFollowupRequest2(request, currentResponse, toolResults) {
15879
+ if (!request) {
15880
+ return void 0;
15881
+ }
15882
+ return {
15883
+ ...request,
15884
+ input: buildNextOpenRouterCallModelInput2(
15885
+ extractOpenRouterCallModelInput2(request),
15886
+ isObject(currentResponse) ? currentResponse : {},
15887
+ toolResults
15888
+ ),
15889
+ stream: false
15890
+ };
15891
+ }
15892
+ function wrapAsyncIterableWithSpan2(args) {
15893
+ return {
15894
+ [Symbol.asyncIterator]() {
15895
+ const iterator = args.iteratorFactory();
15896
+ return {
15897
+ next(value) {
15898
+ return withCurrent(
15899
+ args.span,
15900
+ () => value === void 0 ? iterator.next() : iterator.next(value)
15901
+ ).then(
15902
+ async (result) => {
15903
+ if (result.done) {
15904
+ await args.finalize();
15905
+ }
15906
+ return result;
15907
+ },
15908
+ (error) => {
15909
+ args.onError(error);
15910
+ throw error;
15911
+ }
15912
+ );
15913
+ },
15914
+ return(value) {
15915
+ if (typeof iterator.return !== "function") {
15916
+ return args.finalize().then(() => ({
15917
+ done: true,
15918
+ value
15919
+ }));
15920
+ }
15921
+ return withCurrent(args.span, () => iterator.return(value)).then(
15922
+ async (result) => {
15923
+ await args.finalize();
15924
+ return result;
15925
+ },
15926
+ (error) => {
15927
+ args.onError(error);
15928
+ throw error;
15929
+ }
15930
+ );
15931
+ },
15932
+ throw(error) {
15933
+ args.onError(error);
15934
+ if (typeof iterator.throw !== "function") {
15935
+ return Promise.reject(error);
15936
+ }
15937
+ return withCurrent(args.span, () => iterator.throw(error));
15938
+ },
15939
+ [Symbol.asyncIterator]() {
15940
+ return this;
15941
+ }
15942
+ };
15943
+ }
15944
+ };
15945
+ }
15946
+ function isAsyncIterable4(value) {
15947
+ return !!value && (typeof value === "object" || typeof value === "function") && Symbol.asyncIterator in value && typeof value[Symbol.asyncIterator] === "function";
15948
+ }
15949
+ function normalizeError2(error) {
15950
+ return error instanceof Error ? error : new Error(String(error));
15951
+ }
15952
+
15953
+ // src/instrumentation/plugins/mistral-channels.ts
15954
+ var mistralChannels = defineChannels("@mistralai/mistralai", {
15955
+ chatComplete: channel({
15956
+ channelName: "chat.complete",
15957
+ kind: "async"
15958
+ }),
15959
+ chatStream: channel({
15960
+ channelName: "chat.stream",
15961
+ kind: "async"
15962
+ }),
15963
+ embeddingsCreate: channel({
15964
+ channelName: "embeddings.create",
15965
+ kind: "async"
15966
+ }),
15967
+ fimComplete: channel({
15968
+ channelName: "fim.complete",
15969
+ kind: "async"
15970
+ }),
15971
+ fimStream: channel({
15972
+ channelName: "fim.stream",
15973
+ kind: "async"
15974
+ }),
15975
+ agentsComplete: channel({
15976
+ channelName: "agents.complete",
15977
+ kind: "async"
15978
+ }),
15979
+ agentsStream: channel({
15980
+ channelName: "agents.stream",
15981
+ kind: "async"
15982
+ })
15983
+ });
15984
+
15985
+ // src/instrumentation/plugins/mistral-plugin.ts
15986
+ var MistralPlugin = class extends BasePlugin {
15987
+ onEnable() {
15988
+ this.subscribeToMistralChannels();
15989
+ }
15990
+ onDisable() {
15991
+ this.unsubscribers = unsubscribeAll(this.unsubscribers);
15992
+ }
15993
+ subscribeToMistralChannels() {
15994
+ this.unsubscribers.push(
15995
+ traceStreamingChannel(mistralChannels.chatComplete, {
15996
+ name: "mistral.chat.complete",
15997
+ type: "llm" /* LLM */,
15998
+ extractInput: extractMessagesInputWithMetadata,
15999
+ extractOutput: (result) => {
16000
+ return result?.choices;
16001
+ },
16002
+ extractMetadata: (result) => extractMistralResponseMetadata(result),
16003
+ extractMetrics: (result, startTime) => extractMistralMetrics(result?.usage, startTime)
16004
+ })
16005
+ );
16006
+ this.unsubscribers.push(
16007
+ traceStreamingChannel(mistralChannels.chatStream, {
16008
+ name: "mistral.chat.stream",
16009
+ type: "llm" /* LLM */,
16010
+ extractInput: extractMessagesInputWithMetadata,
16011
+ extractOutput: extractMistralStreamOutput,
16012
+ extractMetadata: (result) => extractMistralResponseMetadata(result),
16013
+ extractMetrics: (result, startTime) => extractMistralStreamingMetrics(result, startTime),
16014
+ aggregateChunks: aggregateMistralStreamChunks
16015
+ })
16016
+ );
16017
+ this.unsubscribers.push(
16018
+ traceAsyncChannel(mistralChannels.embeddingsCreate, {
16019
+ name: "mistral.embeddings.create",
16020
+ type: "llm" /* LLM */,
16021
+ extractInput: extractEmbeddingInputWithMetadata,
16022
+ extractOutput: (result) => {
16023
+ const embedding = result?.data?.[0]?.embedding;
16024
+ return Array.isArray(embedding) ? { embedding_length: embedding.length } : void 0;
16025
+ },
16026
+ extractMetadata: (result) => extractMistralResponseMetadata(result),
16027
+ extractMetrics: (result) => parseMistralMetricsFromUsage(result?.usage)
16028
+ })
16029
+ );
16030
+ this.unsubscribers.push(
16031
+ traceStreamingChannel(mistralChannels.fimComplete, {
16032
+ name: "mistral.fim.complete",
16033
+ type: "llm" /* LLM */,
16034
+ extractInput: extractPromptInputWithMetadata,
16035
+ extractOutput: (result) => {
16036
+ return result?.choices;
16037
+ },
16038
+ extractMetadata: (result) => extractMistralResponseMetadata(result),
16039
+ extractMetrics: (result, startTime) => extractMistralMetrics(result?.usage, startTime)
16040
+ })
16041
+ );
16042
+ this.unsubscribers.push(
16043
+ traceStreamingChannel(mistralChannels.fimStream, {
16044
+ name: "mistral.fim.stream",
16045
+ type: "llm" /* LLM */,
16046
+ extractInput: extractPromptInputWithMetadata,
16047
+ extractOutput: extractMistralStreamOutput,
16048
+ extractMetadata: (result) => extractMistralResponseMetadata(result),
16049
+ extractMetrics: (result, startTime) => extractMistralStreamingMetrics(result, startTime),
16050
+ aggregateChunks: aggregateMistralStreamChunks
16051
+ })
16052
+ );
16053
+ this.unsubscribers.push(
16054
+ traceStreamingChannel(mistralChannels.agentsComplete, {
16055
+ name: "mistral.agents.complete",
16056
+ type: "llm" /* LLM */,
16057
+ extractInput: extractMessagesInputWithMetadata,
16058
+ extractOutput: (result) => {
16059
+ return result?.choices;
16060
+ },
16061
+ extractMetadata: (result) => extractMistralResponseMetadata(result),
16062
+ extractMetrics: (result, startTime) => extractMistralMetrics(result?.usage, startTime)
16063
+ })
16064
+ );
16065
+ this.unsubscribers.push(
16066
+ traceStreamingChannel(mistralChannels.agentsStream, {
16067
+ name: "mistral.agents.stream",
16068
+ type: "llm" /* LLM */,
16069
+ extractInput: extractMessagesInputWithMetadata,
16070
+ extractOutput: extractMistralStreamOutput,
16071
+ extractMetadata: (result) => extractMistralResponseMetadata(result),
16072
+ extractMetrics: (result, startTime) => extractMistralStreamingMetrics(result, startTime),
16073
+ aggregateChunks: aggregateMistralStreamChunks
16074
+ })
16075
+ );
13839
16076
  }
13840
16077
  };
13841
- function normalizeArgs(args) {
16078
+ var TOKEN_NAME_MAP4 = {
16079
+ promptTokens: "prompt_tokens",
16080
+ inputTokens: "prompt_tokens",
16081
+ completionTokens: "completion_tokens",
16082
+ outputTokens: "completion_tokens",
16083
+ totalTokens: "tokens",
16084
+ prompt_tokens: "prompt_tokens",
16085
+ input_tokens: "prompt_tokens",
16086
+ completion_tokens: "completion_tokens",
16087
+ output_tokens: "completion_tokens",
16088
+ total_tokens: "tokens",
16089
+ promptAudioSeconds: "prompt_audio_seconds",
16090
+ prompt_audio_seconds: "prompt_audio_seconds"
16091
+ };
16092
+ var TOKEN_DETAIL_PREFIX_MAP3 = {
16093
+ promptTokensDetails: "prompt",
16094
+ inputTokensDetails: "prompt",
16095
+ completionTokensDetails: "completion",
16096
+ outputTokensDetails: "completion",
16097
+ prompt_tokens_details: "prompt",
16098
+ input_tokens_details: "prompt",
16099
+ completion_tokens_details: "completion",
16100
+ output_tokens_details: "completion"
16101
+ };
16102
+ var MISTRAL_REQUEST_METADATA_ALLOWLIST = /* @__PURE__ */ new Set([
16103
+ "agentId",
16104
+ "agent_id",
16105
+ "encodingFormat",
16106
+ "encoding_format",
16107
+ "frequencyPenalty",
16108
+ "frequency_penalty",
16109
+ "maxTokens",
16110
+ "max_tokens",
16111
+ "model",
16112
+ "n",
16113
+ "presencePenalty",
16114
+ "presence_penalty",
16115
+ "randomSeed",
16116
+ "random_seed",
16117
+ "responseFormat",
16118
+ "response_format",
16119
+ "safePrompt",
16120
+ "safe_prompt",
16121
+ "stream",
16122
+ "stop",
16123
+ "temperature",
16124
+ "toolChoice",
16125
+ "tool_choice",
16126
+ "topP",
16127
+ "top_p"
16128
+ ]);
16129
+ var MISTRAL_RESPONSE_METADATA_ALLOWLIST = /* @__PURE__ */ new Set([
16130
+ "agentId",
16131
+ "agent_id",
16132
+ "created",
16133
+ "id",
16134
+ "model",
16135
+ "object"
16136
+ ]);
16137
+ function camelToSnake3(value) {
16138
+ return value.replace(/[A-Z]/g, (match) => `_${match.toLowerCase()}`);
16139
+ }
16140
+ function normalizeArgs3(args) {
13842
16141
  if (Array.isArray(args)) {
13843
16142
  return args;
13844
16143
  }
13845
- if (isArrayLike(args)) {
16144
+ if (isArrayLike3(args)) {
13846
16145
  return Array.from(args);
13847
16146
  }
13848
16147
  return [args];
13849
16148
  }
13850
- function isArrayLike(value) {
16149
+ function isArrayLike3(value) {
13851
16150
  return isObject(value) && "length" in value && typeof value.length === "number" && Number.isInteger(value.length) && value.length >= 0;
13852
16151
  }
13853
- function getOpenRouterRequestArg(args) {
13854
- const normalizedArgs = normalizeArgs(args);
13855
- const keyedCandidate = normalizedArgs.find(
13856
- (arg) => isObject(arg) && ("chatGenerationParams" in arg || "requestBody" in arg || "openResponsesRequest" in arg)
16152
+ function getMistralRequestArg(args) {
16153
+ const firstObjectArg = normalizeArgs3(args).find((arg) => isObject(arg));
16154
+ return isObject(firstObjectArg) ? firstObjectArg : void 0;
16155
+ }
16156
+ function addMistralProviderMetadata(metadata) {
16157
+ return {
16158
+ ...metadata,
16159
+ provider: "mistral"
16160
+ };
16161
+ }
16162
+ function pickAllowedMetadata(metadata, allowlist) {
16163
+ if (!metadata) {
16164
+ return {};
16165
+ }
16166
+ const picked = {};
16167
+ for (const key of allowlist) {
16168
+ const value = metadata[key];
16169
+ if (value !== void 0) {
16170
+ picked[key] = value;
16171
+ }
16172
+ }
16173
+ return picked;
16174
+ }
16175
+ function extractMistralRequestMetadata(metadata) {
16176
+ return pickAllowedMetadata(metadata, MISTRAL_REQUEST_METADATA_ALLOWLIST);
16177
+ }
16178
+ function isMistralChatCompletionChunk(value) {
16179
+ return isObject(value);
16180
+ }
16181
+ function isMistralChunkChoice(value) {
16182
+ return isObject(value);
16183
+ }
16184
+ function extractMessagesInputWithMetadata(args) {
16185
+ const params = getMistralRequestArg(args);
16186
+ const { messages, ...rawMetadata } = params || {};
16187
+ return {
16188
+ input: processInputAttachments(messages),
16189
+ metadata: addMistralProviderMetadata(
16190
+ extractMistralRequestMetadata(rawMetadata)
16191
+ )
16192
+ };
16193
+ }
16194
+ function extractEmbeddingInputWithMetadata(args) {
16195
+ const params = getMistralRequestArg(args);
16196
+ const { inputs, ...rawMetadata } = params || {};
16197
+ return {
16198
+ input: inputs,
16199
+ metadata: addMistralProviderMetadata(
16200
+ extractMistralRequestMetadata(rawMetadata)
16201
+ )
16202
+ };
16203
+ }
16204
+ function extractPromptInputWithMetadata(args) {
16205
+ const params = getMistralRequestArg(args);
16206
+ const { prompt, ...rawMetadata } = params || {};
16207
+ return {
16208
+ input: prompt,
16209
+ metadata: addMistralProviderMetadata(
16210
+ extractMistralRequestMetadata(rawMetadata)
16211
+ )
16212
+ };
16213
+ }
16214
+ function extractMistralResponseMetadata(result) {
16215
+ if (!isObject(result)) {
16216
+ return void 0;
16217
+ }
16218
+ const { choices: _choices, usage: _usage, data: _data, ...metadata } = result;
16219
+ const picked = pickAllowedMetadata(
16220
+ metadata,
16221
+ MISTRAL_RESPONSE_METADATA_ALLOWLIST
13857
16222
  );
13858
- if (isObject(keyedCandidate)) {
13859
- return keyedCandidate;
16223
+ return Object.keys(picked).length > 0 ? picked : void 0;
16224
+ }
16225
+ function extractMistralMetrics(usage, startTime) {
16226
+ const metrics = parseMistralMetricsFromUsage(usage);
16227
+ if (startTime) {
16228
+ metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
13860
16229
  }
13861
- const firstObjectArg = normalizedArgs.find((arg) => isObject(arg));
13862
- return isObject(firstObjectArg) ? firstObjectArg : void 0;
16230
+ return metrics;
13863
16231
  }
13864
- function getOpenRouterCallModelRequestArg(args) {
13865
- const firstObjectArg = normalizeArgs(args).find((arg) => isObject(arg));
13866
- return isObject(firstObjectArg) ? firstObjectArg : void 0;
16232
+ function extractMistralStreamOutput(result) {
16233
+ return isObject(result) ? result.choices : void 0;
13867
16234
  }
13868
- function aggregateOpenRouterChatChunks(chunks) {
13869
- let role;
13870
- let content = "";
13871
- let toolCalls;
13872
- let finishReason;
13873
- let metrics = {};
13874
- for (const chunk of chunks) {
13875
- metrics = {
13876
- ...metrics,
13877
- ...parseOpenRouterMetricsFromUsage(chunk?.usage)
13878
- };
13879
- const choice = chunk?.choices?.[0];
13880
- const delta = choice?.delta;
13881
- if (!delta) {
13882
- if (choice?.finish_reason !== void 0) {
13883
- finishReason = choice.finish_reason;
16235
+ function extractMistralStreamingMetrics(result, startTime) {
16236
+ const metrics = isObject(result) ? parseMistralMetricsFromUsage(result.usage) : {};
16237
+ if (startTime) {
16238
+ metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
16239
+ }
16240
+ return metrics;
16241
+ }
16242
+ function extractDeltaText(content) {
16243
+ if (typeof content === "string") {
16244
+ return content;
16245
+ }
16246
+ if (!Array.isArray(content)) {
16247
+ return void 0;
16248
+ }
16249
+ const textParts = content.map((part) => {
16250
+ if (!isObject(part) || part.type !== "text") {
16251
+ return "";
16252
+ }
16253
+ return typeof part.text === "string" ? part.text : "";
16254
+ }).filter((part) => part.length > 0);
16255
+ return textParts.length > 0 ? textParts.join("") : void 0;
16256
+ }
16257
+ function getDeltaToolCalls(delta) {
16258
+ const toolCalls = Array.isArray(delta.toolCalls) && delta.toolCalls || Array.isArray(delta.tool_calls) && delta.tool_calls || [];
16259
+ return toolCalls.filter((toolCall) => isObject(toolCall));
16260
+ }
16261
+ function getToolCallIndex(toolCall) {
16262
+ return typeof toolCall.index === "number" && toolCall.index >= 0 ? toolCall.index : void 0;
16263
+ }
16264
+ function createMergedToolCallDelta(delta) {
16265
+ return {
16266
+ ...delta,
16267
+ function: {
16268
+ ...delta.function,
16269
+ arguments: typeof delta.function?.arguments === "string" ? delta.function.arguments : ""
16270
+ }
16271
+ };
16272
+ }
16273
+ function mergeToolCallDeltaPair(current, delta) {
16274
+ const currentArguments = typeof current.function?.arguments === "string" ? current.function.arguments : "";
16275
+ const deltaArguments = typeof delta.function?.arguments === "string" ? delta.function.arguments : "";
16276
+ return {
16277
+ ...current,
16278
+ ...delta,
16279
+ function: {
16280
+ ...current.function || {},
16281
+ ...delta.function || {},
16282
+ arguments: `${currentArguments}${deltaArguments}`
16283
+ }
16284
+ };
16285
+ }
16286
+ function mergeToolCallDeltas(toolCalls, deltas) {
16287
+ if (deltas.length === 0) {
16288
+ return toolCalls;
16289
+ }
16290
+ const merged = toolCalls ? [...toolCalls] : [];
16291
+ const indexToPosition = /* @__PURE__ */ new Map();
16292
+ const idToPosition = /* @__PURE__ */ new Map();
16293
+ for (const [position, toolCall] of merged.entries()) {
16294
+ const index = getToolCallIndex(toolCall);
16295
+ if (index !== void 0 && !indexToPosition.has(index)) {
16296
+ indexToPosition.set(index, position);
16297
+ }
16298
+ if (typeof toolCall.id === "string" && !idToPosition.has(toolCall.id)) {
16299
+ idToPosition.set(toolCall.id, position);
16300
+ }
16301
+ }
16302
+ for (const delta of deltas) {
16303
+ const deltaIndex = getToolCallIndex(delta);
16304
+ const existingByIndex = deltaIndex !== void 0 ? indexToPosition.get(deltaIndex) : void 0;
16305
+ const existingById = typeof delta.id === "string" ? idToPosition.get(delta.id) : void 0;
16306
+ const existingPosition = existingByIndex ?? existingById;
16307
+ if (existingPosition === void 0) {
16308
+ const newToolCall = createMergedToolCallDelta(delta);
16309
+ merged.push(newToolCall);
16310
+ const newPosition = merged.length - 1;
16311
+ const newIndex = getToolCallIndex(newToolCall);
16312
+ if (newIndex !== void 0 && !indexToPosition.has(newIndex)) {
16313
+ indexToPosition.set(newIndex, newPosition);
16314
+ }
16315
+ if (typeof newToolCall.id === "string" && !idToPosition.has(newToolCall.id)) {
16316
+ idToPosition.set(newToolCall.id, newPosition);
13884
16317
  }
13885
16318
  continue;
13886
16319
  }
13887
- if (!role && delta.role) {
13888
- role = delta.role;
16320
+ const mergedToolCall = mergeToolCallDeltaPair(
16321
+ merged[existingPosition],
16322
+ delta
16323
+ );
16324
+ merged[existingPosition] = mergedToolCall;
16325
+ const mergedIndex = getToolCallIndex(mergedToolCall);
16326
+ if (mergedIndex !== void 0 && !indexToPosition.has(mergedIndex)) {
16327
+ indexToPosition.set(mergedIndex, existingPosition);
13889
16328
  }
13890
- if (typeof delta.content === "string") {
13891
- content += delta.content;
16329
+ if (typeof mergedToolCall.id === "string" && !idToPosition.has(mergedToolCall.id)) {
16330
+ idToPosition.set(mergedToolCall.id, existingPosition);
13892
16331
  }
13893
- const choiceFinishReason = choice?.finishReason ?? choice?.finish_reason ?? void 0;
13894
- const deltaFinishReason = delta.finishReason ?? delta.finish_reason ?? void 0;
13895
- if (choiceFinishReason !== void 0) {
13896
- finishReason = choiceFinishReason;
13897
- } else if (deltaFinishReason !== void 0) {
13898
- finishReason = deltaFinishReason;
16332
+ }
16333
+ return merged.length > 0 ? merged : void 0;
16334
+ }
16335
+ function getChoiceFinishReason(choice) {
16336
+ if (typeof choice.finishReason === "string" || choice.finishReason === null) {
16337
+ return choice.finishReason;
16338
+ }
16339
+ if (typeof choice.finish_reason === "string" || choice.finish_reason === null) {
16340
+ return choice.finish_reason;
16341
+ }
16342
+ return void 0;
16343
+ }
16344
+ function parseMistralMetricsFromUsage(usage) {
16345
+ if (!isObject(usage)) {
16346
+ return {};
16347
+ }
16348
+ const metrics = {};
16349
+ for (const [name, value] of Object.entries(usage)) {
16350
+ if (typeof value === "number") {
16351
+ metrics[TOKEN_NAME_MAP4[name] || camelToSnake3(name)] = value;
16352
+ continue;
13899
16353
  }
13900
- const toolCallDeltas = Array.isArray(delta.toolCalls) ? delta.toolCalls : Array.isArray(delta.tool_calls) ? delta.tool_calls : void 0;
13901
- if (!toolCallDeltas) {
16354
+ if (!isObject(value)) {
13902
16355
  continue;
13903
16356
  }
13904
- for (const toolDelta of toolCallDeltas) {
13905
- if (!toolDelta?.function) {
16357
+ const prefix = TOKEN_DETAIL_PREFIX_MAP3[name];
16358
+ if (!prefix) {
16359
+ continue;
16360
+ }
16361
+ for (const [nestedName, nestedValue] of Object.entries(value)) {
16362
+ if (typeof nestedValue !== "number") {
13906
16363
  continue;
13907
16364
  }
13908
- const toolIndex = toolDelta.index ?? 0;
13909
- const existingToolCall = toolCalls?.[toolIndex];
13910
- if (!existingToolCall || toolDelta.id && existingToolCall.id !== void 0 && existingToolCall.id !== toolDelta.id) {
13911
- const nextToolCalls = [...toolCalls || []];
13912
- nextToolCalls[toolIndex] = {
13913
- index: toolIndex,
13914
- id: toolDelta.id,
13915
- type: toolDelta.type,
13916
- function: {
13917
- name: toolDelta.function.name,
13918
- arguments: toolDelta.function.arguments || ""
13919
- }
13920
- };
13921
- toolCalls = nextToolCalls;
16365
+ metrics[`${prefix}_${camelToSnake3(nestedName)}`] = nestedValue;
16366
+ }
16367
+ }
16368
+ return metrics;
16369
+ }
16370
+ function aggregateMistralStreamChunks(chunks) {
16371
+ const choiceAccumulators = /* @__PURE__ */ new Map();
16372
+ const indexToAccumulatorKey = /* @__PURE__ */ new Map();
16373
+ const positionToAccumulatorKey = /* @__PURE__ */ new Map();
16374
+ let nextAccumulatorOrder = 0;
16375
+ let metrics = {};
16376
+ let metadata;
16377
+ for (const event of chunks) {
16378
+ const chunk = isMistralChatCompletionChunk(event?.data) ? event.data : void 0;
16379
+ if (!chunk) {
16380
+ continue;
16381
+ }
16382
+ if (isObject(chunk.usage)) {
16383
+ metrics = {
16384
+ ...metrics,
16385
+ ...parseMistralMetricsFromUsage(chunk.usage)
16386
+ };
16387
+ }
16388
+ const chunkMetadata = extractMistralResponseMetadata(chunk);
16389
+ if (chunkMetadata) {
16390
+ metadata = { ...metadata || {}, ...chunkMetadata };
16391
+ }
16392
+ for (const [choicePosition, rawChoice] of (chunk.choices || []).entries()) {
16393
+ if (!isMistralChunkChoice(rawChoice)) {
13922
16394
  continue;
13923
16395
  }
13924
- const current = existingToolCall;
13925
- if (toolDelta.id && !current.id) {
13926
- current.id = toolDelta.id;
16396
+ const choice = rawChoice;
16397
+ const choiceIndex = typeof choice.index === "number" && choice.index >= 0 ? choice.index : void 0;
16398
+ let accumulatorKey = choiceIndex !== void 0 ? indexToAccumulatorKey.get(choiceIndex) : void 0;
16399
+ if (!accumulatorKey) {
16400
+ accumulatorKey = positionToAccumulatorKey.get(choicePosition);
16401
+ }
16402
+ if (!accumulatorKey) {
16403
+ const initialIndex = choiceIndex ?? choicePosition;
16404
+ const keyPrefix = choiceIndex !== void 0 ? "index" : "position";
16405
+ accumulatorKey = `${keyPrefix}:${initialIndex}`;
16406
+ choiceAccumulators.set(accumulatorKey, {
16407
+ index: initialIndex,
16408
+ order: nextAccumulatorOrder++
16409
+ });
13927
16410
  }
13928
- if (toolDelta.type && !current.type) {
13929
- current.type = toolDelta.type;
16411
+ const accumulator = choiceAccumulators.get(accumulatorKey);
16412
+ if (!accumulator) {
16413
+ continue;
13930
16414
  }
13931
- if (toolDelta.function.name && !current.function.name) {
13932
- current.function.name = toolDelta.function.name;
16415
+ if (choiceIndex !== void 0) {
16416
+ accumulator.index = choiceIndex;
16417
+ indexToAccumulatorKey.set(choiceIndex, accumulatorKey);
13933
16418
  }
13934
- current.function.arguments += toolDelta.function.arguments || "";
13935
- }
13936
- }
13937
- return {
13938
- output: [
13939
- {
13940
- index: 0,
13941
- message: {
13942
- role,
13943
- content: content || void 0,
13944
- ...toolCalls ? { tool_calls: toolCalls } : {}
13945
- },
13946
- logprobs: null,
13947
- finish_reason: finishReason
16419
+ positionToAccumulatorKey.set(choicePosition, accumulatorKey);
16420
+ const delta = isObject(choice.delta) ? choice.delta : void 0;
16421
+ if (delta) {
16422
+ if (!accumulator.role && typeof delta.role === "string") {
16423
+ accumulator.role = delta.role;
16424
+ }
16425
+ const deltaText = extractDeltaText(delta.content);
16426
+ if (deltaText) {
16427
+ accumulator.content = `${accumulator.content || ""}${deltaText}`;
16428
+ }
16429
+ accumulator.toolCalls = mergeToolCallDeltas(
16430
+ accumulator.toolCalls,
16431
+ getDeltaToolCalls(delta)
16432
+ );
16433
+ }
16434
+ const choiceFinishReason = getChoiceFinishReason(choice);
16435
+ if (choiceFinishReason !== void 0) {
16436
+ accumulator.finishReason = choiceFinishReason;
13948
16437
  }
13949
- ],
13950
- metrics
13951
- };
13952
- }
13953
- function aggregateOpenRouterResponseStreamEvents(chunks) {
13954
- let finalResponse;
13955
- for (const chunk of chunks) {
13956
- const response = chunk?.response;
13957
- if (!response) {
13958
- continue;
13959
- }
13960
- if (chunk.type === "response.completed" || chunk.type === "response.incomplete" || chunk.type === "response.failed") {
13961
- finalResponse = response;
13962
16438
  }
13963
16439
  }
13964
- if (!finalResponse) {
13965
- return {
13966
- output: void 0,
13967
- metrics: {}
13968
- };
13969
- }
16440
+ const output = Array.from(choiceAccumulators.values()).sort(
16441
+ (left, right) => left.index === right.index ? left.order - right.order : left.index - right.index
16442
+ ).map((choice) => ({
16443
+ index: choice.index,
16444
+ message: {
16445
+ ...choice.role ? { role: choice.role } : {},
16446
+ content: choice.content ?? null,
16447
+ ...choice.toolCalls ? { toolCalls: choice.toolCalls } : {}
16448
+ },
16449
+ ...choice.finishReason !== void 0 ? { finishReason: choice.finishReason } : {}
16450
+ }));
13970
16451
  return {
13971
- output: extractOpenRouterResponseOutput(finalResponse),
13972
- metrics: parseOpenRouterMetricsFromUsage(finalResponse.usage),
13973
- ...extractOpenRouterResponseMetadata(finalResponse) ? { metadata: extractOpenRouterResponseMetadata(finalResponse) } : {}
16452
+ output,
16453
+ metrics,
16454
+ ...metadata ? { metadata } : {}
13974
16455
  };
13975
16456
  }
13976
16457
 
@@ -13983,6 +16464,8 @@ var BraintrustPlugin = class extends BasePlugin {
13983
16464
  claudeAgentSDKPlugin = null;
13984
16465
  googleGenAIPlugin = null;
13985
16466
  openRouterPlugin = null;
16467
+ openRouterAgentPlugin = null;
16468
+ mistralPlugin = null;
13986
16469
  constructor(config = {}) {
13987
16470
  super();
13988
16471
  this.config = config;
@@ -14013,6 +16496,14 @@ var BraintrustPlugin = class extends BasePlugin {
14013
16496
  this.openRouterPlugin = new OpenRouterPlugin();
14014
16497
  this.openRouterPlugin.enable();
14015
16498
  }
16499
+ if (integrations.openrouterAgent !== false) {
16500
+ this.openRouterAgentPlugin = new OpenRouterAgentPlugin();
16501
+ this.openRouterAgentPlugin.enable();
16502
+ }
16503
+ if (integrations.mistral !== false) {
16504
+ this.mistralPlugin = new MistralPlugin();
16505
+ this.mistralPlugin.enable();
16506
+ }
14016
16507
  }
14017
16508
  onDisable() {
14018
16509
  if (this.openaiPlugin) {
@@ -14039,6 +16530,14 @@ var BraintrustPlugin = class extends BasePlugin {
14039
16530
  this.openRouterPlugin.disable();
14040
16531
  this.openRouterPlugin = null;
14041
16532
  }
16533
+ if (this.openRouterAgentPlugin) {
16534
+ this.openRouterAgentPlugin.disable();
16535
+ this.openRouterAgentPlugin = null;
16536
+ }
16537
+ if (this.mistralPlugin) {
16538
+ this.mistralPlugin.disable();
16539
+ this.mistralPlugin = null;
16540
+ }
14042
16541
  }
14043
16542
  };
14044
16543
 
@@ -14111,7 +16610,9 @@ var PluginRegistry = class {
14111
16610
  aisdk: true,
14112
16611
  google: true,
14113
16612
  claudeAgentSDK: true,
14114
- openrouter: true
16613
+ openrouter: true,
16614
+ openrouterAgent: true,
16615
+ mistral: true
14115
16616
  };
14116
16617
  }
14117
16618
  /**
@@ -14246,7 +16747,7 @@ function isAsync(fn) {
14246
16747
  function isAsyncGenerator2(fn) {
14247
16748
  return fn[Symbol.toStringTag] === "AsyncGenerator";
14248
16749
  }
14249
- function isAsyncIterable3(obj) {
16750
+ function isAsyncIterable5(obj) {
14250
16751
  return typeof obj[Symbol.asyncIterator] === "function";
14251
16752
  }
14252
16753
  function wrapAsync(asyncFn) {
@@ -14296,7 +16797,7 @@ function _asyncMap(eachfn, arr, iteratee, callback) {
14296
16797
  callback(err, results);
14297
16798
  });
14298
16799
  }
14299
- function isArrayLike2(value) {
16800
+ function isArrayLike4(value) {
14300
16801
  return value && typeof value.length === "number" && value.length >= 0 && value.length % 1 === 0;
14301
16802
  }
14302
16803
  var breakLoop = {};
@@ -14344,7 +16845,7 @@ function createObjectIterator(obj) {
14344
16845
  };
14345
16846
  }
14346
16847
  function createIterator(coll) {
14347
- if (isArrayLike2(coll)) {
16848
+ if (isArrayLike4(coll)) {
14348
16849
  return createArrayIterator(coll);
14349
16850
  }
14350
16851
  var iterator = getIterator(coll);
@@ -14418,7 +16919,7 @@ var eachOfLimit$2 = (limit) => {
14418
16919
  if (isAsyncGenerator2(obj)) {
14419
16920
  return asyncEachOfLimit(obj, limit, iteratee, callback);
14420
16921
  }
14421
- if (isAsyncIterable3(obj)) {
16922
+ if (isAsyncIterable5(obj)) {
14422
16923
  return asyncEachOfLimit(obj[Symbol.asyncIterator](), limit, iteratee, callback);
14423
16924
  }
14424
16925
  var nextElem = createIterator(obj);
@@ -14490,7 +16991,7 @@ function eachOfGeneric(coll, iteratee, callback) {
14490
16991
  return eachOfLimit$1(coll, Infinity, iteratee, callback);
14491
16992
  }
14492
16993
  function eachOf(coll, iteratee, callback) {
14493
- var eachOfImplementation = isArrayLike2(coll) ? eachOfArrayLike : eachOfGeneric;
16994
+ var eachOfImplementation = isArrayLike4(coll) ? eachOfArrayLike : eachOfGeneric;
14494
16995
  return eachOfImplementation(coll, wrapAsync(iteratee), callback);
14495
16996
  }
14496
16997
  var eachOf$1 = awaitify(eachOf, 3);
@@ -15005,7 +17506,7 @@ function filterGeneric(eachfn, coll, iteratee, callback) {
15005
17506
  });
15006
17507
  }
15007
17508
  function _filter(eachfn, coll, iteratee, callback) {
15008
- var filter2 = isArrayLike2(coll) ? filterArray : filterGeneric;
17509
+ var filter2 = isArrayLike4(coll) ? filterArray : filterGeneric;
15009
17510
  return filter2(eachfn, coll, wrapAsync(iteratee), callback);
15010
17511
  }
15011
17512
  function filter(coll, iteratee, callback) {
@@ -15080,7 +17581,7 @@ if (hasNextTick) {
15080
17581
  }
15081
17582
  var nextTick = wrap(_defer);
15082
17583
  var _parallel = awaitify((eachfn, tasks, callback) => {
15083
- var results = isArrayLike2(tasks) ? [] : {};
17584
+ var results = isArrayLike4(tasks) ? [] : {};
15084
17585
  eachfn(tasks, (task, key, taskCb) => {
15085
17586
  wrapAsync(task)((err, ...result) => {
15086
17587
  if (result.length < 2) {
@@ -15695,7 +18196,28 @@ function validateParametersWithJsonSchema(parameters, schema) {
15695
18196
  }).join(", ");
15696
18197
  throw Error(`Invalid parameters: ${errorMessages}`);
15697
18198
  }
15698
- return parameters;
18199
+ return rehydrateRemoteParameters(parameters, schema);
18200
+ }
18201
+ function rehydrateRemoteParameters(parameters, schema) {
18202
+ const schemaProperties = schema.properties;
18203
+ if (typeof schemaProperties !== "object" || schemaProperties === null) {
18204
+ return parameters;
18205
+ }
18206
+ return Object.fromEntries(
18207
+ Object.entries(parameters).map(([name, value]) => {
18208
+ const propertySchema = Reflect.get(schemaProperties, name);
18209
+ if (typeof propertySchema !== "object" || propertySchema === null) {
18210
+ return [name, value];
18211
+ }
18212
+ if (Reflect.get(propertySchema, "x-bt-type") === "prompt") {
18213
+ return [
18214
+ name,
18215
+ Prompt2.fromPromptData(name, PromptData.parse(value))
18216
+ ];
18217
+ }
18218
+ return [name, value];
18219
+ })
18220
+ );
15699
18221
  }
15700
18222
 
15701
18223
  // src/framework.ts
@@ -15761,7 +18283,7 @@ function callEvaluatorData(data) {
15761
18283
  baseExperiment
15762
18284
  };
15763
18285
  }
15764
- function isAsyncIterable4(value) {
18286
+ function isAsyncIterable6(value) {
15765
18287
  return typeof value === "object" && value !== null && Symbol.asyncIterator in value && typeof value[Symbol.asyncIterator] === "function";
15766
18288
  }
15767
18289
  function isIterable(value) {
@@ -15966,7 +18488,7 @@ async function runEvaluatorInternal(experiment, evaluator, progressReporter, fil
15966
18488
  }
15967
18489
  const resolvedDataResult = dataResult instanceof Promise ? await dataResult : dataResult;
15968
18490
  const dataIterable = (() => {
15969
- if (isAsyncIterable4(resolvedDataResult)) {
18491
+ if (isAsyncIterable6(resolvedDataResult)) {
15970
18492
  return resolvedDataResult;
15971
18493
  }
15972
18494
  if (Array.isArray(resolvedDataResult) || isIterable(resolvedDataResult)) {
@@ -16766,7 +19288,7 @@ var parametersContainerSchema = z12.object({
16766
19288
  var staticParametersContainerSchema = z12.object({
16767
19289
  type: z12.literal("braintrust.staticParameters"),
16768
19290
  schema: staticParametersSchema,
16769
- source: z12.null()
19291
+ source: z12.null().nullish()
16770
19292
  });
16771
19293
  var serializedParametersContainerSchema = z12.union([
16772
19294
  parametersContainerSchema,
@@ -16930,7 +19452,8 @@ var ScorerBuilder = class {
16930
19452
  type: "llm_classifier",
16931
19453
  use_cot: opts.useCot,
16932
19454
  choice_scores: opts.choiceScores
16933
- }
19455
+ },
19456
+ ...opts.templateFormat ? { template_format: opts.templateFormat } : {}
16934
19457
  };
16935
19458
  const codePrompt = new CodePrompt(
16936
19459
  this.project,