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
package/dist/cli.js CHANGED
@@ -1232,7 +1232,7 @@ var require_package = __commonJS({
1232
1232
  "package.json"(exports2, module2) {
1233
1233
  module2.exports = {
1234
1234
  name: "braintrust",
1235
- version: "3.7.0",
1235
+ version: "3.8.0",
1236
1236
  description: "SDK for integrating Braintrust",
1237
1237
  repository: {
1238
1238
  type: "git",
@@ -1346,7 +1346,7 @@ var require_package = __commonJS({
1346
1346
  "check:typings": "tsc --noEmit",
1347
1347
  watch: "tsup --watch",
1348
1348
  clean: "rm -r dist/* && rm -r dev/dist/*",
1349
- docs: "npx typedoc --options typedoc.json src/node/index.ts",
1349
+ docs: "typedoc --options typedoc.json src/node/index.ts",
1350
1350
  test: 'vitest run --exclude "src/wrappers/**/*.test.ts" --exclude "src/otel/**/*.test.ts" --exclude "smoke/**/*.test.ts" --exclude "src/zod/**/*.test.ts" --exclude "tests/api-compatibility/**"',
1351
1351
  "test:core": "pnpm prune && pnpm test",
1352
1352
  "test:checks": "pnpm run test:core && pnpm run test:vitest",
@@ -1374,8 +1374,8 @@ var require_package = __commonJS({
1374
1374
  "test:claude-agent-sdk": "pnpm --filter @braintrust/claude-agent-sdk-tests test",
1375
1375
  "test:vitest": "pnpm --filter @braintrust/vitest-wrapper-tests test",
1376
1376
  "test:output": "tsx scripts/test-output.ts --with-comparison --with-metrics --with-progress",
1377
- bench: "npx tsx src/queue.bench.ts",
1378
- "publish:validate": "./scripts/validate-release.sh && pnpm install --frozen-lockfile && pnpm run build && npm publish",
1377
+ bench: "tsx src/queue.bench.ts",
1378
+ "publish:validate": "./scripts/validate-release.sh && pnpm install --frozen-lockfile && pnpm run build && pnpm publish",
1379
1379
  lint: "eslint .",
1380
1380
  "fix:lint": "eslint --fix .",
1381
1381
  playground: "tsx playground.ts",
@@ -1425,7 +1425,7 @@ var require_package = __commonJS({
1425
1425
  typescript: "5.4.4",
1426
1426
  vite: "^6.4.1",
1427
1427
  "vite-tsconfig-paths": "^4.3.2",
1428
- vitest: "^4.1.0",
1428
+ vitest: "^4.1.2",
1429
1429
  webpack: "^5.97.1",
1430
1430
  zod: "^3.25.34"
1431
1431
  },
@@ -1561,7 +1561,7 @@ var DefaultTracingChannel = class {
1561
1561
  }
1562
1562
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
1563
1563
  tracePromise(fn, _message, thisArg, ...args) {
1564
- return Promise.resolve(fn.apply(thisArg, args));
1564
+ return fn.apply(thisArg, args);
1565
1565
  }
1566
1566
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
1567
1567
  traceCallback(fn, _position, _message, thisArg, ...args) {
@@ -1581,6 +1581,7 @@ var iso = {
1581
1581
  processOn: (_0, _1) => {
1582
1582
  },
1583
1583
  basename: (filepath) => filepath.split(/[\\/]/).pop() || filepath,
1584
+ // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage.
1584
1585
  writeln: (text) => console.log(text)
1585
1586
  };
1586
1587
  var isomorph_default = iso;
@@ -3072,6 +3073,15 @@ var InternalAbortError = class extends Error {
3072
3073
  this.name = "InternalAbortError";
3073
3074
  }
3074
3075
  };
3076
+ function filterFrom(record, keys) {
3077
+ const out = {};
3078
+ for (const k of Object.keys(record)) {
3079
+ if (!keys.includes(k)) {
3080
+ out[k] = record[k];
3081
+ }
3082
+ }
3083
+ return out;
3084
+ }
3075
3085
 
3076
3086
  // src/generated_types.ts
3077
3087
  var import_v36 = require("zod/v3");
@@ -3283,6 +3293,16 @@ var NullableSavedFunctionId = import_v36.z.union([
3283
3293
  }),
3284
3294
  import_v36.z.null()
3285
3295
  ]);
3296
+ var TopicMapGenerationSettings = import_v36.z.object({
3297
+ algorithm: import_v36.z.enum(["hdbscan", "kmeans"]),
3298
+ dimension_reduction: import_v36.z.enum(["umap", "pca", "none"]),
3299
+ sample_size: import_v36.z.number().int().gt(0).optional(),
3300
+ n_clusters: import_v36.z.number().int().gt(0).optional(),
3301
+ min_cluster_size: import_v36.z.number().int().gt(0).optional(),
3302
+ min_samples: import_v36.z.number().int().gt(0).optional(),
3303
+ hierarchy_threshold: import_v36.z.number().int().gt(0).optional(),
3304
+ naming_model: import_v36.z.string().optional()
3305
+ });
3286
3306
  var TopicMapData = import_v36.z.object({
3287
3307
  type: import_v36.z.literal("topic_map"),
3288
3308
  source_facet: import_v36.z.string(),
@@ -3290,6 +3310,7 @@ var TopicMapData = import_v36.z.object({
3290
3310
  bundle_key: import_v36.z.string().optional(),
3291
3311
  report_key: import_v36.z.string().optional(),
3292
3312
  topic_names: import_v36.z.record(import_v36.z.string()).optional(),
3313
+ generation_settings: TopicMapGenerationSettings.optional(),
3293
3314
  distance_threshold: import_v36.z.number().optional()
3294
3315
  });
3295
3316
  var BatchedFacetData = import_v36.z.object({
@@ -3514,6 +3535,7 @@ var Dataset = import_v36.z.object({
3514
3535
  created: import_v36.z.union([import_v36.z.string(), import_v36.z.null()]).optional(),
3515
3536
  deleted_at: import_v36.z.union([import_v36.z.string(), import_v36.z.null()]).optional(),
3516
3537
  user_id: import_v36.z.union([import_v36.z.string(), import_v36.z.null()]).optional(),
3538
+ tags: import_v36.z.union([import_v36.z.array(import_v36.z.string()), import_v36.z.null()]).optional(),
3517
3539
  metadata: import_v36.z.union([import_v36.z.object({}).partial().passthrough(), import_v36.z.null()]).optional(),
3518
3540
  url_slug: import_v36.z.string()
3519
3541
  });
@@ -3596,6 +3618,14 @@ var DatasetEvent = import_v36.z.object({
3596
3618
  import_v36.z.null()
3597
3619
  ]).optional()
3598
3620
  });
3621
+ var DatasetSnapshot = import_v36.z.object({
3622
+ id: import_v36.z.string().uuid(),
3623
+ dataset_id: import_v36.z.string().uuid(),
3624
+ name: import_v36.z.string(),
3625
+ description: import_v36.z.union([import_v36.z.string(), import_v36.z.null()]),
3626
+ xact_id: import_v36.z.string(),
3627
+ created: import_v36.z.union([import_v36.z.string(), import_v36.z.null()])
3628
+ });
3599
3629
  var EnvVar = import_v36.z.object({
3600
3630
  id: import_v36.z.string().uuid(),
3601
3631
  object_type: import_v36.z.enum(["organization", "project", "function"]),
@@ -4354,6 +4384,8 @@ var TopicAutomationConfig = import_v36.z.object({
4354
4384
  scope: import_v36.z.union([SpanScope, TraceScope, GroupScope, import_v36.z.null()]).optional(),
4355
4385
  data_scope: TopicAutomationDataScope.optional(),
4356
4386
  btql_filter: import_v36.z.union([import_v36.z.string(), import_v36.z.null()]).optional(),
4387
+ rerun_seconds: import_v36.z.union([import_v36.z.number(), import_v36.z.null()]).optional(),
4388
+ relabel_overlap_seconds: import_v36.z.union([import_v36.z.number(), import_v36.z.null()]).optional(),
4357
4389
  backfill_time_range: import_v36.z.union([
4358
4390
  import_v36.z.string(),
4359
4391
  import_v36.z.object({ from: import_v36.z.string(), to: import_v36.z.string() }),
@@ -4690,7 +4722,8 @@ var User = import_v36.z.object({
4690
4722
  family_name: import_v36.z.union([import_v36.z.string(), import_v36.z.null()]).optional(),
4691
4723
  email: import_v36.z.union([import_v36.z.string(), import_v36.z.null()]).optional(),
4692
4724
  avatar_url: import_v36.z.union([import_v36.z.string(), import_v36.z.null()]).optional(),
4693
- created: import_v36.z.union([import_v36.z.string(), import_v36.z.null()]).optional()
4725
+ created: import_v36.z.union([import_v36.z.string(), import_v36.z.null()]).optional(),
4726
+ last_active_at: import_v36.z.union([import_v36.z.number(), import_v36.z.null()]).optional()
4694
4727
  });
4695
4728
  var ViewDataSearch = import_v36.z.union([
4696
4729
  import_v36.z.object({
@@ -5848,6 +5881,15 @@ var BRAINTRUST_CURRENT_SPAN_STORE = Symbol.for(
5848
5881
  "braintrust.currentSpanStore"
5849
5882
  );
5850
5883
  var ContextManager = class {
5884
+ /**
5885
+ * Returns the value to store in the ALS bound to a TracingChannel's start event.
5886
+ * In default mode this is the Span itself; in OTEL mode it is the OTEL Context
5887
+ * containing the span so that OTEL's own ALS stores a proper Context object.
5888
+ */
5889
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
5890
+ wrapSpanForStore(span) {
5891
+ return span;
5892
+ }
5851
5893
  };
5852
5894
  var BraintrustContextManager = class extends ContextManager {
5853
5895
  _currentSpan;
@@ -11599,7 +11641,28 @@ function validateParametersWithJsonSchema(parameters, schema) {
11599
11641
  }).join(", ");
11600
11642
  throw Error(`Invalid parameters: ${errorMessages}`);
11601
11643
  }
11602
- return parameters;
11644
+ return rehydrateRemoteParameters(parameters, schema);
11645
+ }
11646
+ function rehydrateRemoteParameters(parameters, schema) {
11647
+ const schemaProperties = schema.properties;
11648
+ if (typeof schemaProperties !== "object" || schemaProperties === null) {
11649
+ return parameters;
11650
+ }
11651
+ return Object.fromEntries(
11652
+ Object.entries(parameters).map(([name, value]) => {
11653
+ const propertySchema = Reflect.get(schemaProperties, name);
11654
+ if (typeof propertySchema !== "object" || propertySchema === null) {
11655
+ return [name, value];
11656
+ }
11657
+ if (Reflect.get(propertySchema, "x-bt-type") === "prompt") {
11658
+ return [
11659
+ name,
11660
+ Prompt2.fromPromptData(name, PromptData.parse(value))
11661
+ ];
11662
+ }
11663
+ return [name, value];
11664
+ })
11665
+ );
11603
11666
  }
11604
11667
 
11605
11668
  // src/framework.ts
@@ -12947,7 +13010,7 @@ function patchStreamIfNeeded(stream, options) {
12947
13010
  if (!completed) {
12948
13011
  completed = true;
12949
13012
  try {
12950
- options.onComplete(chunks);
13013
+ await options.onComplete(chunks);
12951
13014
  } catch (error2) {
12952
13015
  console.error("Error in stream onComplete handler:", error2);
12953
13016
  }
@@ -12959,7 +13022,7 @@ function patchStreamIfNeeded(stream, options) {
12959
13022
  chunks.push(chunk);
12960
13023
  if (options.onChunk) {
12961
13024
  try {
12962
- options.onChunk(chunk);
13025
+ await options.onChunk(chunk);
12963
13026
  } catch (error2) {
12964
13027
  console.error("Error in stream onChunk handler:", error2);
12965
13028
  }
@@ -12972,7 +13035,7 @@ function patchStreamIfNeeded(stream, options) {
12972
13035
  completed = true;
12973
13036
  if (options.onError) {
12974
13037
  try {
12975
- options.onError(
13038
+ await options.onError(
12976
13039
  error2 instanceof Error ? error2 : new Error(String(error2)),
12977
13040
  chunks
12978
13041
  );
@@ -12990,7 +13053,7 @@ function patchStreamIfNeeded(stream, options) {
12990
13053
  if (!completed) {
12991
13054
  completed = true;
12992
13055
  try {
12993
- options.onComplete(chunks);
13056
+ await options.onComplete(chunks);
12994
13057
  } catch (error2) {
12995
13058
  console.error("Error in stream onComplete handler:", error2);
12996
13059
  }
@@ -13007,7 +13070,7 @@ function patchStreamIfNeeded(stream, options) {
13007
13070
  const error2 = rawError instanceof Error ? rawError : new Error(String(rawError));
13008
13071
  if (options.onError) {
13009
13072
  try {
13010
- options.onError(error2, chunks);
13073
+ await options.onError(error2, chunks);
13011
13074
  } catch (handlerError) {
13012
13075
  console.error("Error in stream onError handler:", handlerError);
13013
13076
  }
@@ -13464,18 +13527,22 @@ function ensureSpanStateForEvent(states, config3, event, channelName) {
13464
13527
  function bindCurrentSpanStoreToStart(tracingChannel2, states, config3, channelName) {
13465
13528
  const state = _internalGetGlobalState();
13466
13529
  const startChannel = tracingChannel2.start;
13467
- const currentSpanStore = state?.contextManager ? state.contextManager[BRAINTRUST_CURRENT_SPAN_STORE] : void 0;
13530
+ const contextManager = state?.contextManager;
13531
+ const currentSpanStore = contextManager ? contextManager[BRAINTRUST_CURRENT_SPAN_STORE] : void 0;
13468
13532
  if (!currentSpanStore || !startChannel) {
13469
13533
  return void 0;
13470
13534
  }
13471
13535
  startChannel.bindStore(
13472
13536
  currentSpanStore,
13473
- (event) => ensureSpanStateForEvent(
13474
- states,
13475
- config3,
13476
- event,
13477
- channelName
13478
- ).span
13537
+ (event) => {
13538
+ const span = ensureSpanStateForEvent(
13539
+ states,
13540
+ config3,
13541
+ event,
13542
+ channelName
13543
+ ).span;
13544
+ return contextManager.wrapSpanForStore(span);
13545
+ }
13479
13546
  );
13480
13547
  return () => {
13481
13548
  startChannel.unbindStore(currentSpanStore);
@@ -13492,6 +13559,26 @@ function logErrorAndEnd(states, event) {
13492
13559
  spanData.span.end();
13493
13560
  states.delete(event);
13494
13561
  }
13562
+ function runStreamingCompletionHook(args) {
13563
+ if (!args.config.onComplete) {
13564
+ return;
13565
+ }
13566
+ try {
13567
+ args.config.onComplete({
13568
+ channelName: args.channelName,
13569
+ ...args.chunks ? { chunks: args.chunks } : {},
13570
+ endEvent: args.endEvent,
13571
+ ...args.metadata !== void 0 ? { metadata: args.metadata } : {},
13572
+ metrics: args.metrics,
13573
+ output: args.output,
13574
+ result: args.result,
13575
+ span: args.span,
13576
+ startTime: args.startTime
13577
+ });
13578
+ } catch (error2) {
13579
+ console.error(`Error in onComplete hook for ${args.channelName}:`, error2);
13580
+ }
13581
+ }
13495
13582
  function traceAsyncChannel(channel2, config3) {
13496
13583
  const tracingChannel2 = channel2.tracingChannel();
13497
13584
  const states = /* @__PURE__ */ new WeakMap();
@@ -13619,6 +13706,18 @@ function traceStreamingChannel(channel2, config3) {
13619
13706
  } else if (metrics.time_to_first_token === void 0 && chunks.length > 0) {
13620
13707
  metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
13621
13708
  }
13709
+ runStreamingCompletionHook({
13710
+ channelName,
13711
+ chunks,
13712
+ config: config3,
13713
+ endEvent: asyncEndEvent,
13714
+ ...metadata !== void 0 ? { metadata } : {},
13715
+ metrics,
13716
+ output,
13717
+ result: asyncEndEvent.result,
13718
+ span,
13719
+ startTime
13720
+ });
13622
13721
  span.log({
13623
13722
  output,
13624
13723
  ...metadata !== void 0 ? { metadata } : {},
@@ -13668,6 +13767,17 @@ function traceStreamingChannel(channel2, config3) {
13668
13767
  asyncEndEvent.result,
13669
13768
  asyncEndEvent
13670
13769
  );
13770
+ runStreamingCompletionHook({
13771
+ channelName,
13772
+ config: config3,
13773
+ endEvent: asyncEndEvent,
13774
+ ...normalizeMetadata(metadata) !== void 0 ? { metadata: normalizeMetadata(metadata) } : {},
13775
+ metrics,
13776
+ output,
13777
+ result: asyncEndEvent.result,
13778
+ span,
13779
+ startTime
13780
+ });
13671
13781
  span.log({
13672
13782
  output,
13673
13783
  ...normalizeMetadata(metadata) !== void 0 ? { metadata: normalizeMetadata(metadata) } : {},
@@ -13716,51 +13826,28 @@ function traceSyncStreamChannel(channel2, config3) {
13716
13826
  }
13717
13827
  const { span, startTime } = spanData;
13718
13828
  const endEvent = event;
13719
- if (config3.patchResult?.({
13720
- channelName,
13721
- endEvent,
13722
- result: endEvent.result,
13723
- span,
13724
- startTime
13725
- })) {
13726
- return;
13727
- }
13728
- const stream = endEvent.result;
13729
- if (!isSyncStreamLike(stream)) {
13730
- span.end();
13731
- states.delete(event);
13732
- return;
13733
- }
13734
- let first = true;
13735
- stream.on("chunk", () => {
13736
- if (first) {
13737
- span.log({
13738
- metrics: {
13739
- time_to_first_token: getCurrentUnixTimestamp() - startTime
13740
- }
13741
- });
13742
- first = false;
13743
- }
13744
- });
13745
- stream.on("chatCompletion", (completion) => {
13746
- try {
13747
- if (hasChoices(completion)) {
13748
- span.log({
13749
- output: completion.choices
13750
- });
13751
- }
13752
- } catch (error2) {
13753
- console.error(
13754
- `Error extracting chatCompletion for ${channelName}:`,
13755
- error2
13756
- );
13829
+ const handleResolvedResult = (result) => {
13830
+ const resolvedEndEvent = {
13831
+ ...endEvent,
13832
+ result
13833
+ };
13834
+ if (config3.patchResult?.({
13835
+ channelName,
13836
+ endEvent: resolvedEndEvent,
13837
+ result,
13838
+ span,
13839
+ startTime
13840
+ })) {
13841
+ return;
13757
13842
  }
13758
- });
13759
- stream.on("event", (streamEvent) => {
13760
- if (!config3.extractFromEvent) {
13843
+ const stream = result;
13844
+ if (!isSyncStreamLike(stream)) {
13845
+ span.end();
13846
+ states.delete(event);
13761
13847
  return;
13762
13848
  }
13763
- try {
13849
+ let first = true;
13850
+ stream.on("chunk", () => {
13764
13851
  if (first) {
13765
13852
  span.log({
13766
13853
  metrics: {
@@ -13769,25 +13856,55 @@ function traceSyncStreamChannel(channel2, config3) {
13769
13856
  });
13770
13857
  first = false;
13771
13858
  }
13772
- const extracted = config3.extractFromEvent(streamEvent);
13773
- if (extracted && Object.keys(extracted).length > 0) {
13774
- span.log(extracted);
13859
+ });
13860
+ stream.on("chatCompletion", (completion) => {
13861
+ try {
13862
+ if (hasChoices(completion)) {
13863
+ span.log({
13864
+ output: completion.choices
13865
+ });
13866
+ }
13867
+ } catch (error2) {
13868
+ console.error(
13869
+ `Error extracting chatCompletion for ${channelName}:`,
13870
+ error2
13871
+ );
13872
+ }
13873
+ });
13874
+ stream.on("event", (streamEvent) => {
13875
+ if (!config3.extractFromEvent) {
13876
+ return;
13877
+ }
13878
+ try {
13879
+ if (first) {
13880
+ span.log({
13881
+ metrics: {
13882
+ time_to_first_token: getCurrentUnixTimestamp() - startTime
13883
+ }
13884
+ });
13885
+ first = false;
13886
+ }
13887
+ const extracted = config3.extractFromEvent(streamEvent);
13888
+ if (extracted && Object.keys(extracted).length > 0) {
13889
+ span.log(extracted);
13890
+ }
13891
+ } catch (error2) {
13892
+ console.error(`Error extracting event for ${channelName}:`, error2);
13775
13893
  }
13776
- } catch (error2) {
13777
- console.error(`Error extracting event for ${channelName}:`, error2);
13778
- }
13779
- });
13780
- stream.on("end", () => {
13781
- span.end();
13782
- states.delete(event);
13783
- });
13784
- stream.on("error", (error2) => {
13785
- span.log({
13786
- error: error2.message
13787
13894
  });
13788
- span.end();
13789
- states.delete(event);
13790
- });
13895
+ stream.on("end", () => {
13896
+ span.end();
13897
+ states.delete(event);
13898
+ });
13899
+ stream.on("error", (error2) => {
13900
+ span.log({
13901
+ error: error2.message
13902
+ });
13903
+ span.end();
13904
+ states.delete(event);
13905
+ });
13906
+ };
13907
+ handleResolvedResult(endEvent.result);
13791
13908
  },
13792
13909
  error: (event) => {
13793
13910
  logErrorAndEnd(states, event);
@@ -14044,6 +14161,10 @@ var openAIChannels = defineChannels("openai", {
14044
14161
  responsesParse: channel({
14045
14162
  channelName: "responses.parse",
14046
14163
  kind: "async"
14164
+ }),
14165
+ responsesCompact: channel({
14166
+ channelName: "responses.compact",
14167
+ kind: "async"
14047
14168
  })
14048
14169
  });
14049
14170
 
@@ -14323,6 +14444,40 @@ var OpenAIPlugin = class extends BasePlugin {
14323
14444
  aggregateChunks: aggregateResponseStreamEvents
14324
14445
  })
14325
14446
  );
14447
+ this.unsubscribers.push(
14448
+ traceAsyncChannel(openAIChannels.responsesCompact, {
14449
+ name: "openai.responses.compact",
14450
+ type: "llm" /* LLM */,
14451
+ extractInput: ([params]) => {
14452
+ const { input, ...metadata } = params;
14453
+ return {
14454
+ input: processInputAttachments(input),
14455
+ metadata: { ...metadata, provider: "openai" }
14456
+ };
14457
+ },
14458
+ extractOutput: (result) => {
14459
+ return processImagesInOutput(result?.output);
14460
+ },
14461
+ extractMetadata: (result) => {
14462
+ if (!result) {
14463
+ return void 0;
14464
+ }
14465
+ const { output: _output, usage: _usage, ...metadata } = result;
14466
+ return Object.keys(metadata).length > 0 ? metadata : void 0;
14467
+ },
14468
+ extractMetrics: (result, startTime, endEvent) => {
14469
+ const metrics = withCachedMetric(
14470
+ parseMetricsFromUsage(result?.usage),
14471
+ result,
14472
+ endEvent
14473
+ );
14474
+ if (startTime) {
14475
+ metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
14476
+ }
14477
+ return metrics;
14478
+ }
14479
+ })
14480
+ );
14326
14481
  }
14327
14482
  onDisable() {
14328
14483
  this.unsubscribers = unsubscribeAll(this.unsubscribers);
@@ -14610,28 +14765,40 @@ function aggregateAnthropicStreamChunks(chunks) {
14610
14765
  case "content_block_start":
14611
14766
  if (event.content_block) {
14612
14767
  contentBlocks[event.index] = event.content_block;
14613
- contentBlockDeltas[event.index] = [];
14768
+ contentBlockDeltas[event.index] = { textDeltas: [], citations: [] };
14614
14769
  }
14615
14770
  break;
14616
- case "content_block_delta":
14617
- if (event.delta?.type === "text_delta") {
14618
- const text = event.delta.text;
14771
+ case "content_block_delta": {
14772
+ const acc = contentBlockDeltas[event.index];
14773
+ const delta = event.delta;
14774
+ if (!delta) break;
14775
+ if (delta.type === "text_delta" && "text" in delta) {
14776
+ const text = delta.text;
14619
14777
  if (text) {
14620
- if (contentBlocks[event.index] !== void 0 || contentBlockDeltas[event.index] !== void 0) {
14621
- contentBlockDeltas[event.index] ??= [];
14622
- contentBlockDeltas[event.index].push(text);
14778
+ if (acc !== void 0) {
14779
+ acc.textDeltas.push(text);
14623
14780
  } else {
14624
14781
  fallbackTextDeltas.push(text);
14625
14782
  }
14626
14783
  }
14627
- } else if (event.delta?.type === "input_json_delta") {
14628
- const partialJson = event.delta.partial_json;
14629
- if (partialJson) {
14630
- contentBlockDeltas[event.index] ??= [];
14631
- contentBlockDeltas[event.index].push(partialJson);
14784
+ } else if (delta.type === "input_json_delta" && "partial_json" in delta) {
14785
+ const partialJson = delta.partial_json;
14786
+ if (partialJson && acc !== void 0) {
14787
+ acc.textDeltas.push(partialJson);
14788
+ }
14789
+ } else if (delta.type === "thinking_delta" && "thinking" in delta) {
14790
+ const thinking = delta.thinking;
14791
+ if (thinking && acc !== void 0) {
14792
+ acc.textDeltas.push(thinking);
14793
+ }
14794
+ } else if (delta.type === "citations_delta" && "citation" in delta) {
14795
+ const citation = delta.citation;
14796
+ if (citation && acc !== void 0) {
14797
+ acc.citations.push(citation);
14632
14798
  }
14633
14799
  }
14634
14800
  break;
14801
+ }
14635
14802
  case "content_block_stop":
14636
14803
  finalizeContentBlock(
14637
14804
  event.index,
@@ -14657,7 +14824,7 @@ function aggregateAnthropicStreamChunks(chunks) {
14657
14824
  })).filter(({ block }) => block !== void 0).sort((left, right) => left.index - right.index).map(({ block }) => block);
14658
14825
  let output = fallbackTextDeltas.join("");
14659
14826
  if (orderedContent.length > 0) {
14660
- if (orderedContent.every(isTextContentBlock)) {
14827
+ if (orderedContent.every(isTextContentBlock) && orderedContent.every((block) => !block.citations?.length)) {
14661
14828
  output = orderedContent.map((block) => block.text).join("");
14662
14829
  } else {
14663
14830
  output = {
@@ -14683,7 +14850,8 @@ function finalizeContentBlock(index, contentBlocks, contentBlockDeltas, fallback
14683
14850
  if (!contentBlock) {
14684
14851
  return;
14685
14852
  }
14686
- const text = contentBlockDeltas[index]?.join("") ?? "";
14853
+ const acc = contentBlockDeltas[index];
14854
+ const text = acc?.textDeltas.join("") ?? "";
14687
14855
  if (isToolUseContentBlock(contentBlock)) {
14688
14856
  if (!text) {
14689
14857
  return;
@@ -14700,20 +14868,28 @@ function finalizeContentBlock(index, contentBlocks, contentBlockDeltas, fallback
14700
14868
  return;
14701
14869
  }
14702
14870
  if (isTextContentBlock(contentBlock)) {
14871
+ if (!text) {
14872
+ delete contentBlocks[index];
14873
+ return;
14874
+ }
14875
+ const updated = { ...contentBlock, text };
14876
+ if (acc?.citations.length) {
14877
+ updated.citations = acc.citations;
14878
+ }
14879
+ contentBlocks[index] = updated;
14880
+ return;
14881
+ }
14882
+ if (isThinkingContentBlock(contentBlock)) {
14703
14883
  if (!text) {
14704
14884
  delete contentBlocks[index];
14705
14885
  return;
14706
14886
  }
14707
14887
  contentBlocks[index] = {
14708
14888
  ...contentBlock,
14709
- text
14889
+ thinking: text
14710
14890
  };
14711
14891
  return;
14712
14892
  }
14713
- if (text) {
14714
- fallbackTextDeltas.push(text);
14715
- }
14716
- delete contentBlocks[index];
14717
14893
  }
14718
14894
  function isTextContentBlock(contentBlock) {
14719
14895
  return contentBlock.type === "text";
@@ -14721,6 +14897,9 @@ function isTextContentBlock(contentBlock) {
14721
14897
  function isToolUseContentBlock(contentBlock) {
14722
14898
  return contentBlock.type === "tool_use";
14723
14899
  }
14900
+ function isThinkingContentBlock(contentBlock) {
14901
+ return contentBlock.type === "thinking";
14902
+ }
14724
14903
  function isAnthropicBase64ContentBlock(input) {
14725
14904
  return (input.type === "image" || input.type === "document") && isObject(input.source) && input.source.type === "base64";
14726
14905
  }
@@ -14775,15 +14954,6 @@ function coalesceInput(messages, system) {
14775
14954
  }
14776
14955
  return input;
14777
14956
  }
14778
- function filterFrom(obj, fieldsToRemove) {
14779
- const result = {};
14780
- for (const [key, value] of Object.entries(obj)) {
14781
- if (!fieldsToRemove.includes(key)) {
14782
- result[key] = value;
14783
- }
14784
- }
14785
- return result;
14786
- }
14787
14957
 
14788
14958
  // src/wrappers/ai-sdk/normalize-logged-output.ts
14789
14959
  var REMOVE_NORMALIZED_VALUE = Symbol("braintrust.ai-sdk.remove-normalized");
@@ -14913,6 +15083,16 @@ var aiSDKChannels = defineChannels("ai", {
14913
15083
  channelName: "streamObject.sync",
14914
15084
  kind: "sync-stream"
14915
15085
  }),
15086
+ embed: channel(
15087
+ {
15088
+ channelName: "embed",
15089
+ kind: "async"
15090
+ }
15091
+ ),
15092
+ embedMany: channel({
15093
+ channelName: "embedMany",
15094
+ kind: "async"
15095
+ }),
14916
15096
  agentGenerate: channel({
14917
15097
  channelName: "Agent.generate",
14918
15098
  kind: "async"
@@ -14921,6 +15101,10 @@ var aiSDKChannels = defineChannels("ai", {
14921
15101
  channelName: "Agent.stream",
14922
15102
  kind: "async"
14923
15103
  }),
15104
+ agentStreamSync: channel({
15105
+ channelName: "Agent.stream.sync",
15106
+ kind: "sync-stream"
15107
+ }),
14924
15108
  toolLoopAgentGenerate: channel({
14925
15109
  channelName: "ToolLoopAgent.generate",
14926
15110
  kind: "async"
@@ -14948,6 +15132,9 @@ var DEFAULT_DENY_OUTPUT_PATHS = [
14948
15132
  ];
14949
15133
  var AUTO_PATCHED_MODEL = Symbol.for("braintrust.ai-sdk.auto-patched-model");
14950
15134
  var AUTO_PATCHED_TOOL = Symbol.for("braintrust.ai-sdk.auto-patched-tool");
15135
+ var RUNTIME_DENY_OUTPUT_PATHS = Symbol.for(
15136
+ "braintrust.ai-sdk.deny-output-paths"
15137
+ );
14951
15138
  var AISDKPlugin = class extends BasePlugin {
14952
15139
  config;
14953
15140
  constructor(config3 = {}) {
@@ -14966,10 +15153,13 @@ var AISDKPlugin = class extends BasePlugin {
14966
15153
  traceStreamingChannel(aiSDKChannels.generateText, {
14967
15154
  name: "generateText",
14968
15155
  type: "llm" /* LLM */,
14969
- extractInput: ([params], event, span) => prepareAISDKInput(params, event, span, denyOutputPaths),
15156
+ extractInput: ([params], event, span) => prepareAISDKCallInput(params, event, span, denyOutputPaths),
14970
15157
  extractOutput: (result, endEvent) => {
14971
15158
  finalizeAISDKChildTracing(endEvent);
14972
- return processAISDKOutput(result, denyOutputPaths);
15159
+ return processAISDKOutput(
15160
+ result,
15161
+ resolveDenyOutputPaths(endEvent, denyOutputPaths)
15162
+ );
14973
15163
  },
14974
15164
  extractMetrics: (result, _startTime, endEvent) => extractTopLevelAISDKMetrics(result, endEvent),
14975
15165
  aggregateChunks: aggregateAISDKChunks
@@ -14979,12 +15169,15 @@ var AISDKPlugin = class extends BasePlugin {
14979
15169
  traceStreamingChannel(aiSDKChannels.streamText, {
14980
15170
  name: "streamText",
14981
15171
  type: "llm" /* LLM */,
14982
- extractInput: ([params], event, span) => prepareAISDKInput(params, event, span, denyOutputPaths),
14983
- extractOutput: (result) => processAISDKOutput(result, denyOutputPaths),
15172
+ extractInput: ([params], event, span) => prepareAISDKCallInput(params, event, span, denyOutputPaths),
15173
+ extractOutput: (result, endEvent) => processAISDKOutput(
15174
+ result,
15175
+ resolveDenyOutputPaths(endEvent, denyOutputPaths)
15176
+ ),
14984
15177
  extractMetrics: (result, startTime, endEvent) => extractTopLevelAISDKMetrics(result, endEvent, startTime),
14985
15178
  aggregateChunks: aggregateAISDKChunks,
14986
15179
  patchResult: ({ endEvent, result, span, startTime }) => patchAISDKStreamingResult({
14987
- denyOutputPaths,
15180
+ defaultDenyOutputPaths: denyOutputPaths,
14988
15181
  endEvent,
14989
15182
  result,
14990
15183
  span,
@@ -14996,9 +15189,9 @@ var AISDKPlugin = class extends BasePlugin {
14996
15189
  traceSyncStreamChannel(aiSDKChannels.streamTextSync, {
14997
15190
  name: "streamText",
14998
15191
  type: "llm" /* LLM */,
14999
- extractInput: ([params], event, span) => prepareAISDKInput(params, event, span, denyOutputPaths),
15192
+ extractInput: ([params], event, span) => prepareAISDKCallInput(params, event, span, denyOutputPaths),
15000
15193
  patchResult: ({ endEvent, result, span, startTime }) => patchAISDKStreamingResult({
15001
- denyOutputPaths,
15194
+ defaultDenyOutputPaths: denyOutputPaths,
15002
15195
  endEvent,
15003
15196
  result,
15004
15197
  span,
@@ -15010,10 +15203,13 @@ var AISDKPlugin = class extends BasePlugin {
15010
15203
  traceStreamingChannel(aiSDKChannels.generateObject, {
15011
15204
  name: "generateObject",
15012
15205
  type: "llm" /* LLM */,
15013
- extractInput: ([params], event, span) => prepareAISDKInput(params, event, span, denyOutputPaths),
15206
+ extractInput: ([params], event, span) => prepareAISDKCallInput(params, event, span, denyOutputPaths),
15014
15207
  extractOutput: (result, endEvent) => {
15015
15208
  finalizeAISDKChildTracing(endEvent);
15016
- return processAISDKOutput(result, denyOutputPaths);
15209
+ return processAISDKOutput(
15210
+ result,
15211
+ resolveDenyOutputPaths(endEvent, denyOutputPaths)
15212
+ );
15017
15213
  },
15018
15214
  extractMetrics: (result, _startTime, endEvent) => extractTopLevelAISDKMetrics(result, endEvent),
15019
15215
  aggregateChunks: aggregateAISDKChunks
@@ -15023,12 +15219,15 @@ var AISDKPlugin = class extends BasePlugin {
15023
15219
  traceStreamingChannel(aiSDKChannels.streamObject, {
15024
15220
  name: "streamObject",
15025
15221
  type: "llm" /* LLM */,
15026
- extractInput: ([params], event, span) => prepareAISDKInput(params, event, span, denyOutputPaths),
15027
- extractOutput: (result) => processAISDKOutput(result, denyOutputPaths),
15222
+ extractInput: ([params], event, span) => prepareAISDKCallInput(params, event, span, denyOutputPaths),
15223
+ extractOutput: (result, endEvent) => processAISDKOutput(
15224
+ result,
15225
+ resolveDenyOutputPaths(endEvent, denyOutputPaths)
15226
+ ),
15028
15227
  extractMetrics: (result, startTime, endEvent) => extractTopLevelAISDKMetrics(result, endEvent, startTime),
15029
15228
  aggregateChunks: aggregateAISDKChunks,
15030
15229
  patchResult: ({ endEvent, result, span, startTime }) => patchAISDKStreamingResult({
15031
- denyOutputPaths,
15230
+ defaultDenyOutputPaths: denyOutputPaths,
15032
15231
  endEvent,
15033
15232
  result,
15034
15233
  span,
@@ -15040,9 +15239,9 @@ var AISDKPlugin = class extends BasePlugin {
15040
15239
  traceSyncStreamChannel(aiSDKChannels.streamObjectSync, {
15041
15240
  name: "streamObject",
15042
15241
  type: "llm" /* LLM */,
15043
- extractInput: ([params], event, span) => prepareAISDKInput(params, event, span, denyOutputPaths),
15242
+ extractInput: ([params], event, span) => prepareAISDKCallInput(params, event, span, denyOutputPaths),
15044
15243
  patchResult: ({ endEvent, result, span, startTime }) => patchAISDKStreamingResult({
15045
- denyOutputPaths,
15244
+ defaultDenyOutputPaths: denyOutputPaths,
15046
15245
  endEvent,
15047
15246
  result,
15048
15247
  span,
@@ -15050,14 +15249,41 @@ var AISDKPlugin = class extends BasePlugin {
15050
15249
  })
15051
15250
  })
15052
15251
  );
15252
+ this.unsubscribers.push(
15253
+ traceAsyncChannel(aiSDKChannels.embed, {
15254
+ name: "embed",
15255
+ type: "llm" /* LLM */,
15256
+ extractInput: ([params], event) => prepareAISDKEmbedInput(params, event.self),
15257
+ extractOutput: (result, endEvent) => processAISDKEmbeddingOutput(
15258
+ result,
15259
+ resolveDenyOutputPaths(endEvent, denyOutputPaths)
15260
+ ),
15261
+ extractMetrics: (result, _startTime, endEvent) => extractTopLevelAISDKMetrics(result, endEvent)
15262
+ })
15263
+ );
15264
+ this.unsubscribers.push(
15265
+ traceAsyncChannel(aiSDKChannels.embedMany, {
15266
+ name: "embedMany",
15267
+ type: "llm" /* LLM */,
15268
+ extractInput: ([params], event) => prepareAISDKEmbedInput(params, event.self),
15269
+ extractOutput: (result, endEvent) => processAISDKEmbeddingOutput(
15270
+ result,
15271
+ resolveDenyOutputPaths(endEvent, denyOutputPaths)
15272
+ ),
15273
+ extractMetrics: (result, _startTime, endEvent) => extractTopLevelAISDKMetrics(result, endEvent)
15274
+ })
15275
+ );
15053
15276
  this.unsubscribers.push(
15054
15277
  traceStreamingChannel(aiSDKChannels.agentGenerate, {
15055
15278
  name: "Agent.generate",
15056
15279
  type: "llm" /* LLM */,
15057
- extractInput: ([params], event, span) => prepareAISDKInput(params, event, span, denyOutputPaths),
15280
+ extractInput: ([params], event, span) => prepareAISDKCallInput(params, event, span, denyOutputPaths),
15058
15281
  extractOutput: (result, endEvent) => {
15059
15282
  finalizeAISDKChildTracing(endEvent);
15060
- return processAISDKOutput(result, denyOutputPaths);
15283
+ return processAISDKOutput(
15284
+ result,
15285
+ resolveDenyOutputPaths(endEvent, denyOutputPaths)
15286
+ );
15061
15287
  },
15062
15288
  extractMetrics: (result, _startTime, endEvent) => extractTopLevelAISDKMetrics(result, endEvent),
15063
15289
  aggregateChunks: aggregateAISDKChunks
@@ -15067,12 +15293,29 @@ var AISDKPlugin = class extends BasePlugin {
15067
15293
  traceStreamingChannel(aiSDKChannels.agentStream, {
15068
15294
  name: "Agent.stream",
15069
15295
  type: "llm" /* LLM */,
15070
- extractInput: ([params], event, span) => prepareAISDKInput(params, event, span, denyOutputPaths),
15071
- extractOutput: (result) => processAISDKOutput(result, denyOutputPaths),
15296
+ extractInput: ([params], event, span) => prepareAISDKCallInput(params, event, span, denyOutputPaths),
15297
+ extractOutput: (result, endEvent) => processAISDKOutput(
15298
+ result,
15299
+ resolveDenyOutputPaths(endEvent, denyOutputPaths)
15300
+ ),
15072
15301
  extractMetrics: (result, startTime, endEvent) => extractTopLevelAISDKMetrics(result, endEvent, startTime),
15073
15302
  aggregateChunks: aggregateAISDKChunks,
15074
15303
  patchResult: ({ endEvent, result, span, startTime }) => patchAISDKStreamingResult({
15075
- denyOutputPaths,
15304
+ defaultDenyOutputPaths: denyOutputPaths,
15305
+ endEvent,
15306
+ result,
15307
+ span,
15308
+ startTime
15309
+ })
15310
+ })
15311
+ );
15312
+ this.unsubscribers.push(
15313
+ traceSyncStreamChannel(aiSDKChannels.agentStreamSync, {
15314
+ name: "Agent.stream",
15315
+ type: "llm" /* LLM */,
15316
+ extractInput: ([params], event, span) => prepareAISDKCallInput(params, event, span, denyOutputPaths),
15317
+ patchResult: ({ endEvent, result, span, startTime }) => patchAISDKStreamingResult({
15318
+ defaultDenyOutputPaths: denyOutputPaths,
15076
15319
  endEvent,
15077
15320
  result,
15078
15321
  span,
@@ -15084,10 +15327,13 @@ var AISDKPlugin = class extends BasePlugin {
15084
15327
  traceStreamingChannel(aiSDKChannels.toolLoopAgentGenerate, {
15085
15328
  name: "ToolLoopAgent.generate",
15086
15329
  type: "llm" /* LLM */,
15087
- extractInput: ([params], event, span) => prepareAISDKInput(params, event, span, denyOutputPaths),
15330
+ extractInput: ([params], event, span) => prepareAISDKCallInput(params, event, span, denyOutputPaths),
15088
15331
  extractOutput: (result, endEvent) => {
15089
15332
  finalizeAISDKChildTracing(endEvent);
15090
- return processAISDKOutput(result, denyOutputPaths);
15333
+ return processAISDKOutput(
15334
+ result,
15335
+ resolveDenyOutputPaths(endEvent, denyOutputPaths)
15336
+ );
15091
15337
  },
15092
15338
  extractMetrics: (result, _startTime, endEvent) => extractTopLevelAISDKMetrics(result, endEvent),
15093
15339
  aggregateChunks: aggregateAISDKChunks
@@ -15097,12 +15343,15 @@ var AISDKPlugin = class extends BasePlugin {
15097
15343
  traceStreamingChannel(aiSDKChannels.toolLoopAgentStream, {
15098
15344
  name: "ToolLoopAgent.stream",
15099
15345
  type: "llm" /* LLM */,
15100
- extractInput: ([params], event, span) => prepareAISDKInput(params, event, span, denyOutputPaths),
15101
- extractOutput: (result) => processAISDKOutput(result, denyOutputPaths),
15346
+ extractInput: ([params], event, span) => prepareAISDKCallInput(params, event, span, denyOutputPaths),
15347
+ extractOutput: (result, endEvent) => processAISDKOutput(
15348
+ result,
15349
+ resolveDenyOutputPaths(endEvent, denyOutputPaths)
15350
+ ),
15102
15351
  extractMetrics: (result, startTime, endEvent) => extractTopLevelAISDKMetrics(result, endEvent, startTime),
15103
15352
  aggregateChunks: aggregateAISDKChunks,
15104
15353
  patchResult: ({ endEvent, result, span, startTime }) => patchAISDKStreamingResult({
15105
- denyOutputPaths,
15354
+ defaultDenyOutputPaths: denyOutputPaths,
15106
15355
  endEvent,
15107
15356
  result,
15108
15357
  span,
@@ -15112,75 +15361,391 @@ var AISDKPlugin = class extends BasePlugin {
15112
15361
  );
15113
15362
  }
15114
15363
  };
15115
- function processAISDKInput(params) {
15116
- if (!params) return params;
15117
- const input = processInputAttachments(params);
15118
- if (!input || typeof input !== "object" || Array.isArray(input)) {
15119
- return input;
15364
+ function resolveDenyOutputPaths(event, defaultDenyOutputPaths) {
15365
+ if (Array.isArray(event?.denyOutputPaths)) {
15366
+ return event.denyOutputPaths;
15120
15367
  }
15121
- const { tools: _tools, ...rest } = input;
15122
- return rest;
15123
- }
15124
- function prepareAISDKInput(params, event, span, denyOutputPaths) {
15125
- const input = processAISDKInput(params);
15126
- const metadata = extractMetadataFromParams(params, event.self);
15127
- const childTracing = prepareAISDKChildTracing(
15128
- params,
15129
- event.self,
15130
- span,
15131
- denyOutputPaths
15132
- );
15133
- event.__braintrust_ai_sdk_model_wrapped = childTracing.modelWrapped;
15134
- if (childTracing.cleanup) {
15135
- event.__braintrust_ai_sdk_cleanup = childTracing.cleanup;
15368
+ const firstArgument = event?.arguments && event.arguments.length > 0 ? event.arguments[0] : void 0;
15369
+ if (!firstArgument || typeof firstArgument !== "object") {
15370
+ return defaultDenyOutputPaths;
15136
15371
  }
15137
- return {
15138
- input,
15139
- metadata
15140
- };
15141
- }
15142
- function extractTopLevelAISDKMetrics(result, event, startTime) {
15143
- const metrics = hasModelChildTracing(event) ? {} : extractTokenMetrics(result);
15144
- if (startTime) {
15145
- metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
15372
+ const runtimeDenyOutputPaths = firstArgument[RUNTIME_DENY_OUTPUT_PATHS];
15373
+ if (Array.isArray(runtimeDenyOutputPaths) && runtimeDenyOutputPaths.every((path8) => typeof path8 === "string")) {
15374
+ return runtimeDenyOutputPaths;
15146
15375
  }
15147
- return metrics;
15148
- }
15149
- function hasModelChildTracing(event) {
15150
- return event?.__braintrust_ai_sdk_model_wrapped === true;
15376
+ return defaultDenyOutputPaths;
15151
15377
  }
15152
- function extractMetadataFromParams(params, self) {
15153
- const metadata = {
15154
- braintrust: {
15155
- integration_name: "ai-sdk",
15156
- sdk_language: "typescript"
15157
- }
15158
- };
15159
- 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;
15160
- const { model, provider } = serializeModelWithProvider(
15161
- params.model ?? agentModel
15162
- );
15163
- if (model) {
15164
- metadata.model = model;
15165
- }
15166
- if (provider) {
15378
+ var isZodSchema2 = (value) => {
15379
+ return value != null && typeof value === "object" && "_def" in value && typeof value._def === "object";
15380
+ };
15381
+ var serializeZodSchema2 = (schema) => {
15382
+ try {
15383
+ return zodToJsonSchema(schema);
15384
+ } catch {
15385
+ return {
15386
+ type: "object",
15387
+ description: "Zod schema (conversion failed)"
15388
+ };
15389
+ }
15390
+ };
15391
+ var isOutputObject = (value) => {
15392
+ if (value == null || typeof value !== "object") {
15393
+ return false;
15394
+ }
15395
+ const output = value;
15396
+ if (!("responseFormat" in output)) {
15397
+ return false;
15398
+ }
15399
+ if (output.type === "object" || output.type === "text") {
15400
+ return true;
15401
+ }
15402
+ if (typeof output.responseFormat === "function" || typeof output.responseFormat === "object") {
15403
+ return true;
15404
+ }
15405
+ return false;
15406
+ };
15407
+ var serializeOutputObject = (output, model) => {
15408
+ try {
15409
+ const result = {
15410
+ response_format: null
15411
+ };
15412
+ if (output.type) {
15413
+ result.type = output.type;
15414
+ }
15415
+ let responseFormat;
15416
+ if (typeof output.responseFormat === "function") {
15417
+ const mockModelForSchema = {
15418
+ supportsStructuredOutputs: true,
15419
+ ...model && typeof model === "object" ? model : {}
15420
+ };
15421
+ responseFormat = output.responseFormat({ model: mockModelForSchema });
15422
+ } else if (output.responseFormat != null && typeof output.responseFormat === "object") {
15423
+ responseFormat = output.responseFormat;
15424
+ }
15425
+ if (responseFormat) {
15426
+ if (typeof responseFormat.then === "function") {
15427
+ result.response_format = Promise.resolve(responseFormat).then(
15428
+ (resolved) => {
15429
+ if (resolved.schema && isZodSchema2(resolved.schema)) {
15430
+ return {
15431
+ ...resolved,
15432
+ schema: serializeZodSchema2(resolved.schema)
15433
+ };
15434
+ }
15435
+ return resolved;
15436
+ }
15437
+ );
15438
+ } else {
15439
+ const syncResponseFormat = responseFormat;
15440
+ if (syncResponseFormat.schema && isZodSchema2(syncResponseFormat.schema)) {
15441
+ responseFormat = {
15442
+ ...syncResponseFormat,
15443
+ schema: serializeZodSchema2(syncResponseFormat.schema)
15444
+ };
15445
+ }
15446
+ result.response_format = responseFormat;
15447
+ }
15448
+ }
15449
+ return result;
15450
+ } catch {
15451
+ return {
15452
+ response_format: null
15453
+ };
15454
+ }
15455
+ };
15456
+ var processInputAttachmentsSync = (input) => {
15457
+ if (!input) return { input };
15458
+ const processed = { ...input };
15459
+ if (input.messages && Array.isArray(input.messages)) {
15460
+ processed.messages = input.messages.map(processMessage);
15461
+ }
15462
+ if (input.prompt && typeof input.prompt === "object") {
15463
+ if (Array.isArray(input.prompt)) {
15464
+ processed.prompt = input.prompt.map(processMessage);
15465
+ } else {
15466
+ processed.prompt = processPromptContent(input.prompt);
15467
+ }
15468
+ }
15469
+ if (input.schema && isZodSchema2(input.schema)) {
15470
+ processed.schema = serializeZodSchema2(input.schema);
15471
+ }
15472
+ if (input.callOptionsSchema && isZodSchema2(input.callOptionsSchema)) {
15473
+ processed.callOptionsSchema = serializeZodSchema2(input.callOptionsSchema);
15474
+ }
15475
+ if (input.tools) {
15476
+ processed.tools = serializeAISDKToolsForLogging(input.tools);
15477
+ }
15478
+ let outputPromise;
15479
+ if (input.output && isOutputObject(input.output)) {
15480
+ const serialized = serializeOutputObject(input.output, input.model);
15481
+ if (serialized.response_format && typeof serialized.response_format.then === "function") {
15482
+ processed.output = { ...serialized, response_format: {} };
15483
+ outputPromise = serialized.response_format.then(
15484
+ (resolvedFormat) => ({
15485
+ output: { ...serialized, response_format: resolvedFormat }
15486
+ })
15487
+ );
15488
+ } else {
15489
+ processed.output = serialized;
15490
+ }
15491
+ }
15492
+ if ("prepareCall" in processed && typeof processed.prepareCall === "function") {
15493
+ processed.prepareCall = "[Function]";
15494
+ }
15495
+ return { input: processed, outputPromise };
15496
+ };
15497
+ var processMessage = (message) => {
15498
+ if (!message || typeof message !== "object") return message;
15499
+ if (Array.isArray(message.content)) {
15500
+ return {
15501
+ ...message,
15502
+ content: message.content.map(processContentPart)
15503
+ };
15504
+ }
15505
+ if (typeof message.content === "object" && message.content !== null) {
15506
+ return {
15507
+ ...message,
15508
+ content: processContentPart(message.content)
15509
+ };
15510
+ }
15511
+ return message;
15512
+ };
15513
+ var processPromptContent = (prompt) => {
15514
+ if (Array.isArray(prompt)) {
15515
+ return prompt.map(processContentPart);
15516
+ }
15517
+ if (prompt.content) {
15518
+ if (Array.isArray(prompt.content)) {
15519
+ return {
15520
+ ...prompt,
15521
+ content: prompt.content.map(processContentPart)
15522
+ };
15523
+ } else if (typeof prompt.content === "object") {
15524
+ return {
15525
+ ...prompt,
15526
+ content: processContentPart(prompt.content)
15527
+ };
15528
+ }
15529
+ }
15530
+ return prompt;
15531
+ };
15532
+ var processContentPart = (part) => {
15533
+ if (!part || typeof part !== "object") return part;
15534
+ try {
15535
+ if (part.type === "image" && part.image) {
15536
+ const imageAttachment = convertImageToAttachment(
15537
+ part.image,
15538
+ part.mimeType || part.mediaType
15539
+ );
15540
+ if (imageAttachment) {
15541
+ return {
15542
+ ...part,
15543
+ image: imageAttachment
15544
+ };
15545
+ }
15546
+ }
15547
+ if (part.type === "file" && part.data && (part.mimeType || part.mediaType)) {
15548
+ const fileAttachment = convertDataToAttachment(
15549
+ part.data,
15550
+ part.mimeType || part.mediaType,
15551
+ part.name || part.filename
15552
+ );
15553
+ if (fileAttachment) {
15554
+ return {
15555
+ ...part,
15556
+ data: fileAttachment
15557
+ };
15558
+ }
15559
+ }
15560
+ if (part.type === "image_url" && part.image_url) {
15561
+ if (typeof part.image_url === "object" && part.image_url.url) {
15562
+ const imageAttachment = convertImageToAttachment(part.image_url.url);
15563
+ if (imageAttachment) {
15564
+ return {
15565
+ ...part,
15566
+ image_url: {
15567
+ ...part.image_url,
15568
+ url: imageAttachment
15569
+ }
15570
+ };
15571
+ }
15572
+ }
15573
+ }
15574
+ } catch (error2) {
15575
+ console.warn("Error processing content part:", error2);
15576
+ }
15577
+ return part;
15578
+ };
15579
+ var convertImageToAttachment = (image, explicitMimeType) => {
15580
+ try {
15581
+ if (typeof image === "string" && image.startsWith("data:")) {
15582
+ const [mimeTypeSection, base64Data] = image.split(",");
15583
+ const mimeType = mimeTypeSection.match(/data:(.*?);/)?.[1];
15584
+ if (mimeType && base64Data) {
15585
+ const blob = convertDataToBlob(base64Data, mimeType);
15586
+ if (blob) {
15587
+ return new Attachment({
15588
+ data: blob,
15589
+ filename: `image.${getExtensionFromMediaType(mimeType)}`,
15590
+ contentType: mimeType
15591
+ });
15592
+ }
15593
+ }
15594
+ }
15595
+ if (explicitMimeType) {
15596
+ if (image instanceof Uint8Array) {
15597
+ return new Attachment({
15598
+ data: new Blob([image], { type: explicitMimeType }),
15599
+ filename: `image.${getExtensionFromMediaType(explicitMimeType)}`,
15600
+ contentType: explicitMimeType
15601
+ });
15602
+ }
15603
+ if (typeof Buffer !== "undefined" && Buffer.isBuffer(image)) {
15604
+ return new Attachment({
15605
+ data: new Blob([image], { type: explicitMimeType }),
15606
+ filename: `image.${getExtensionFromMediaType(explicitMimeType)}`,
15607
+ contentType: explicitMimeType
15608
+ });
15609
+ }
15610
+ }
15611
+ if (image instanceof Blob && image.type) {
15612
+ return new Attachment({
15613
+ data: image,
15614
+ filename: `image.${getExtensionFromMediaType(image.type)}`,
15615
+ contentType: image.type
15616
+ });
15617
+ }
15618
+ if (image instanceof Attachment) {
15619
+ return image;
15620
+ }
15621
+ } catch (error2) {
15622
+ console.warn("Error converting image to attachment:", error2);
15623
+ }
15624
+ return null;
15625
+ };
15626
+ var convertDataToAttachment = (data, mimeType, filename) => {
15627
+ if (!mimeType) return null;
15628
+ try {
15629
+ let blob = null;
15630
+ if (typeof data === "string" && data.startsWith("data:")) {
15631
+ const [, base64Data] = data.split(",");
15632
+ if (base64Data) {
15633
+ blob = convertDataToBlob(base64Data, mimeType);
15634
+ }
15635
+ } else if (typeof data === "string" && data.length > 0) {
15636
+ blob = convertDataToBlob(data, mimeType);
15637
+ } else if (data instanceof Uint8Array) {
15638
+ blob = new Blob([data], { type: mimeType });
15639
+ } else if (typeof Buffer !== "undefined" && Buffer.isBuffer(data)) {
15640
+ blob = new Blob([data], { type: mimeType });
15641
+ } else if (data instanceof Blob) {
15642
+ blob = data;
15643
+ }
15644
+ if (blob) {
15645
+ return new Attachment({
15646
+ data: blob,
15647
+ filename: filename || `file.${getExtensionFromMediaType(mimeType)}`,
15648
+ contentType: mimeType
15649
+ });
15650
+ }
15651
+ } catch (error2) {
15652
+ console.warn("Error converting data to attachment:", error2);
15653
+ }
15654
+ return null;
15655
+ };
15656
+ function processAISDKCallInput(params) {
15657
+ return processInputAttachmentsSync(params);
15658
+ }
15659
+ function prepareAISDKCallInput(params, event, span, defaultDenyOutputPaths) {
15660
+ const { input, outputPromise } = processAISDKCallInput(params);
15661
+ if (outputPromise && input && typeof input === "object") {
15662
+ outputPromise.then((resolvedData) => {
15663
+ span.log({
15664
+ input: {
15665
+ ...input,
15666
+ ...resolvedData
15667
+ }
15668
+ });
15669
+ }).catch(() => {
15670
+ });
15671
+ }
15672
+ const metadata = extractMetadataFromCallParams(params, event.self);
15673
+ const childTracing = prepareAISDKChildTracing(
15674
+ params,
15675
+ event.self,
15676
+ span,
15677
+ defaultDenyOutputPaths,
15678
+ event.aiSDK
15679
+ );
15680
+ event.modelWrapped = childTracing.modelWrapped;
15681
+ if (childTracing.cleanup) {
15682
+ event.__braintrust_ai_sdk_cleanup = childTracing.cleanup;
15683
+ }
15684
+ return {
15685
+ input,
15686
+ metadata
15687
+ };
15688
+ }
15689
+ function prepareAISDKEmbedInput(params, self) {
15690
+ return {
15691
+ input: { ...params },
15692
+ metadata: extractMetadataFromEmbedParams(params, self)
15693
+ };
15694
+ }
15695
+ function extractTopLevelAISDKMetrics(result, event, startTime) {
15696
+ const metrics = hasModelChildTracing(event) ? {} : extractTokenMetrics(result);
15697
+ if (startTime) {
15698
+ metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
15699
+ }
15700
+ return metrics;
15701
+ }
15702
+ function hasModelChildTracing(event) {
15703
+ return event?.modelWrapped === true || event?.__braintrust_ai_sdk_model_wrapped === true;
15704
+ }
15705
+ function createAISDKIntegrationMetadata() {
15706
+ return {
15707
+ braintrust: {
15708
+ integration_name: "ai-sdk",
15709
+ sdk_language: "typescript"
15710
+ }
15711
+ };
15712
+ }
15713
+ function resolveModelFromSelf(self) {
15714
+ 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;
15715
+ }
15716
+ function extractBaseMetadata(model, self) {
15717
+ const metadata = createAISDKIntegrationMetadata();
15718
+ const { model: modelId, provider } = serializeModelWithProvider(
15719
+ model ?? resolveModelFromSelf(self)
15720
+ );
15721
+ if (modelId) {
15722
+ metadata.model = modelId;
15723
+ }
15724
+ if (provider) {
15167
15725
  metadata.provider = provider;
15168
15726
  }
15727
+ return metadata;
15728
+ }
15729
+ function extractMetadataFromCallParams(params, self) {
15730
+ const metadata = extractBaseMetadata(params.model, self);
15169
15731
  const tools = serializeAISDKToolsForLogging(params.tools);
15170
15732
  if (tools) {
15171
15733
  metadata.tools = tools;
15172
15734
  }
15173
15735
  return metadata;
15174
15736
  }
15175
- function prepareAISDKChildTracing(params, self, parentSpan, denyOutputPaths) {
15737
+ function extractMetadataFromEmbedParams(params, self) {
15738
+ return extractBaseMetadata(params.model, self);
15739
+ }
15740
+ function prepareAISDKChildTracing(params, self, parentSpan, denyOutputPaths, aiSDK) {
15176
15741
  const cleanup = [];
15177
15742
  const patchedModels = /* @__PURE__ */ new WeakSet();
15178
15743
  const patchedTools = /* @__PURE__ */ new WeakSet();
15179
15744
  let modelWrapped = false;
15180
15745
  const patchModel = (model) => {
15181
- const resolvedModel = resolveAISDKModel(model);
15746
+ const resolvedModel = resolveAISDKModel(model, aiSDK);
15182
15747
  if (!resolvedModel || typeof resolvedModel !== "object" || typeof resolvedModel.doGenerate !== "function" || patchedModels.has(resolvedModel) || resolvedModel[AUTO_PATCHED_MODEL]) {
15183
- return;
15748
+ return resolvedModel;
15184
15749
  }
15185
15750
  patchedModels.add(resolvedModel);
15186
15751
  resolvedModel[AUTO_PATCHED_MODEL] = true;
@@ -15209,7 +15774,7 @@ function prepareAISDKChildTracing(params, self, parentSpan, denyOutputPaths) {
15209
15774
  type: "llm" /* LLM */
15210
15775
  },
15211
15776
  event: {
15212
- input: processAISDKInput(options),
15777
+ input: processAISDKCallInput(options).input,
15213
15778
  metadata: baseMetadata
15214
15779
  }
15215
15780
  }
@@ -15223,7 +15788,7 @@ function prepareAISDKChildTracing(params, self, parentSpan, denyOutputPaths) {
15223
15788
  type: "llm" /* LLM */
15224
15789
  },
15225
15790
  event: {
15226
- input: processAISDKInput(options),
15791
+ input: processAISDKCallInput(options).input,
15227
15792
  metadata: baseMetadata
15228
15793
  }
15229
15794
  });
@@ -15231,6 +15796,8 @@ function prepareAISDKChildTracing(params, self, parentSpan, denyOutputPaths) {
15231
15796
  span,
15232
15797
  () => Reflect.apply(originalDoStream, resolvedModel, [options])
15233
15798
  );
15799
+ const streamStartTime = getCurrentUnixTimestamp();
15800
+ let firstChunkTime;
15234
15801
  const output = {};
15235
15802
  let text = "";
15236
15803
  let reasoning = "";
@@ -15238,6 +15805,9 @@ function prepareAISDKChildTracing(params, self, parentSpan, denyOutputPaths) {
15238
15805
  let object = void 0;
15239
15806
  const transformStream = new TransformStream({
15240
15807
  transform(chunk, controller) {
15808
+ if (firstChunkTime === void 0) {
15809
+ firstChunkTime = getCurrentUnixTimestamp();
15810
+ }
15241
15811
  switch (chunk.type) {
15242
15812
  case "text-delta":
15243
15813
  text += extractTextDelta(chunk);
@@ -15278,12 +15848,19 @@ function prepareAISDKChildTracing(params, self, parentSpan, denyOutputPaths) {
15278
15848
  if (object !== void 0) {
15279
15849
  output.object = object;
15280
15850
  }
15851
+ const metrics = extractTokenMetrics(output);
15852
+ if (firstChunkTime !== void 0) {
15853
+ metrics.time_to_first_token = Math.max(
15854
+ firstChunkTime - streamStartTime,
15855
+ 1e-6
15856
+ );
15857
+ }
15281
15858
  span.log({
15282
15859
  output: processAISDKOutput(
15283
15860
  output,
15284
15861
  denyOutputPaths
15285
15862
  ),
15286
- metrics: extractTokenMetrics(output),
15863
+ metrics,
15287
15864
  ...buildResolvedMetadataPayload(output)
15288
15865
  });
15289
15866
  span.end();
@@ -15305,6 +15882,7 @@ function prepareAISDKChildTracing(params, self, parentSpan, denyOutputPaths) {
15305
15882
  }
15306
15883
  delete resolvedModel[AUTO_PATCHED_MODEL];
15307
15884
  });
15885
+ return resolvedModel;
15308
15886
  };
15309
15887
  const patchTool = (tool, name) => {
15310
15888
  if (tool == null || typeof tool !== "object" || !("execute" in tool) || typeof tool.execute !== "function" || patchedTools.has(tool) || tool[AUTO_PATCHED_TOOL]) {
@@ -15377,17 +15955,26 @@ function prepareAISDKChildTracing(params, self, parentSpan, denyOutputPaths) {
15377
15955
  }
15378
15956
  };
15379
15957
  if (params && typeof params === "object") {
15380
- patchModel(params.model);
15958
+ const patchedParamModel = patchModel(params.model);
15959
+ if (typeof params.model === "string" && patchedParamModel && typeof patchedParamModel === "object") {
15960
+ params.model = patchedParamModel;
15961
+ }
15381
15962
  patchTools(params.tools);
15382
15963
  }
15383
15964
  if (self && typeof self === "object") {
15384
15965
  const selfRecord = self;
15385
15966
  if (selfRecord.model !== void 0) {
15386
- patchModel(selfRecord.model);
15967
+ const patchedSelfModel = patchModel(selfRecord.model);
15968
+ if (typeof selfRecord.model === "string" && patchedSelfModel && typeof patchedSelfModel === "object") {
15969
+ selfRecord.model = patchedSelfModel;
15970
+ }
15387
15971
  }
15388
15972
  if (selfRecord.settings && typeof selfRecord.settings === "object") {
15389
15973
  if (selfRecord.settings.model !== void 0) {
15390
- patchModel(selfRecord.settings.model);
15974
+ const patchedSettingsModel = patchModel(selfRecord.settings.model);
15975
+ if (typeof selfRecord.settings.model === "string" && patchedSettingsModel && typeof patchedSettingsModel === "object") {
15976
+ selfRecord.settings.model = patchedSettingsModel;
15977
+ }
15391
15978
  }
15392
15979
  if (selfRecord.settings.tools !== void 0) {
15393
15980
  patchTools(selfRecord.settings.tools);
@@ -15411,63 +15998,178 @@ function finalizeAISDKChildTracing(event) {
15411
15998
  }
15412
15999
  }
15413
16000
  function patchAISDKStreamingResult(args) {
15414
- const { denyOutputPaths, endEvent, result, span, startTime } = args;
16001
+ const { defaultDenyOutputPaths, endEvent, result, span, startTime } = args;
15415
16002
  if (!result || typeof result !== "object") {
15416
16003
  return false;
15417
16004
  }
15418
16005
  const resultRecord = result;
15419
- if (!isReadableStreamLike(resultRecord.baseStream)) {
16006
+ attachKnownResultPromiseHandlers(resultRecord);
16007
+ if (isReadableStreamLike(resultRecord.baseStream)) {
16008
+ let firstChunkTime2;
16009
+ const wrappedBaseStream = resultRecord.baseStream.pipeThrough(
16010
+ new TransformStream({
16011
+ transform(chunk, controller) {
16012
+ if (firstChunkTime2 === void 0) {
16013
+ firstChunkTime2 = getCurrentUnixTimestamp();
16014
+ }
16015
+ controller.enqueue(chunk);
16016
+ },
16017
+ async flush() {
16018
+ const metrics = extractTopLevelAISDKMetrics(result, endEvent);
16019
+ if (metrics.time_to_first_token === void 0 && firstChunkTime2 !== void 0) {
16020
+ metrics.time_to_first_token = firstChunkTime2 - startTime;
16021
+ }
16022
+ const output = await processAISDKStreamingOutput(
16023
+ result,
16024
+ resolveDenyOutputPaths(endEvent, defaultDenyOutputPaths)
16025
+ );
16026
+ const metadata = buildResolvedMetadataPayload(result).metadata;
16027
+ span.log({
16028
+ output,
16029
+ ...metadata ? { metadata } : {},
16030
+ metrics
16031
+ });
16032
+ finalizeAISDKChildTracing(endEvent);
16033
+ span.end();
16034
+ }
16035
+ })
16036
+ );
16037
+ Object.defineProperty(resultRecord, "baseStream", {
16038
+ configurable: true,
16039
+ enumerable: true,
16040
+ value: wrappedBaseStream,
16041
+ writable: true
16042
+ });
16043
+ return true;
16044
+ }
16045
+ const streamField = findAsyncIterableField(resultRecord, [
16046
+ "partialObjectStream",
16047
+ "textStream",
16048
+ "fullStream",
16049
+ "stream"
16050
+ ]);
16051
+ if (!streamField) {
15420
16052
  return false;
15421
16053
  }
15422
16054
  let firstChunkTime;
15423
- const wrappedBaseStream = resultRecord.baseStream.pipeThrough(
15424
- new TransformStream({
15425
- transform(chunk, controller) {
15426
- if (firstChunkTime === void 0) {
15427
- firstChunkTime = getCurrentUnixTimestamp();
15428
- }
15429
- controller.enqueue(chunk);
15430
- },
15431
- async flush() {
15432
- const metrics = extractTopLevelAISDKMetrics(result, endEvent);
15433
- if (metrics.time_to_first_token === void 0 && firstChunkTime !== void 0) {
15434
- metrics.time_to_first_token = firstChunkTime - startTime;
15435
- }
15436
- const output = await processAISDKStreamingOutput(
15437
- result,
15438
- denyOutputPaths
15439
- );
15440
- const metadata = buildResolvedMetadataPayload(result).metadata;
15441
- span.log({
15442
- output,
15443
- ...metadata ? { metadata } : {},
15444
- metrics
15445
- });
15446
- finalizeAISDKChildTracing(endEvent);
15447
- span.end();
16055
+ const wrappedStream = createPatchedAsyncIterable(streamField.stream, {
16056
+ onChunk: () => {
16057
+ if (firstChunkTime === void 0) {
16058
+ firstChunkTime = getCurrentUnixTimestamp();
15448
16059
  }
15449
- })
15450
- );
15451
- Object.defineProperty(resultRecord, "baseStream", {
16060
+ },
16061
+ onComplete: async () => {
16062
+ const metrics = extractTopLevelAISDKMetrics(result, endEvent);
16063
+ if (metrics.time_to_first_token === void 0 && firstChunkTime !== void 0) {
16064
+ metrics.time_to_first_token = firstChunkTime - startTime;
16065
+ }
16066
+ const output = await processAISDKStreamingOutput(
16067
+ result,
16068
+ resolveDenyOutputPaths(endEvent, defaultDenyOutputPaths)
16069
+ );
16070
+ const metadata = buildResolvedMetadataPayload(result).metadata;
16071
+ span.log({
16072
+ output,
16073
+ ...metadata ? { metadata } : {},
16074
+ metrics
16075
+ });
16076
+ finalizeAISDKChildTracing(endEvent);
16077
+ span.end();
16078
+ },
16079
+ onError: (error2) => {
16080
+ span.log({
16081
+ error: error2.message
16082
+ });
16083
+ finalizeAISDKChildTracing(endEvent);
16084
+ span.end();
16085
+ }
16086
+ });
16087
+ Object.defineProperty(resultRecord, streamField.field, {
15452
16088
  configurable: true,
15453
16089
  enumerable: true,
15454
- value: wrappedBaseStream,
16090
+ value: wrappedStream,
15455
16091
  writable: true
15456
16092
  });
15457
16093
  return true;
15458
16094
  }
16095
+ function attachKnownResultPromiseHandlers(result) {
16096
+ const promiseLikeFields = [
16097
+ "content",
16098
+ "text",
16099
+ "object",
16100
+ "value",
16101
+ "values",
16102
+ "finishReason",
16103
+ "embedding",
16104
+ "embeddings",
16105
+ "usage",
16106
+ "totalUsage",
16107
+ "responses",
16108
+ "steps"
16109
+ ];
16110
+ for (const field of promiseLikeFields) {
16111
+ try {
16112
+ if (!(field in result)) {
16113
+ continue;
16114
+ }
16115
+ const value = result[field];
16116
+ if (isPromiseLike(value)) {
16117
+ void Promise.resolve(value).catch(() => {
16118
+ });
16119
+ }
16120
+ } catch {
16121
+ }
16122
+ }
16123
+ }
15459
16124
  function isReadableStreamLike(value) {
15460
16125
  return value != null && typeof value === "object" && typeof value.pipeThrough === "function";
15461
16126
  }
16127
+ function isAsyncIterableLike(value) {
16128
+ return value != null && typeof value === "object" && typeof value[Symbol.asyncIterator] === "function";
16129
+ }
16130
+ function findAsyncIterableField(result, candidateFields) {
16131
+ for (const field of candidateFields) {
16132
+ try {
16133
+ const stream = result[field];
16134
+ if (isAsyncIterableLike(stream)) {
16135
+ return { field, stream };
16136
+ }
16137
+ } catch {
16138
+ }
16139
+ }
16140
+ return null;
16141
+ }
16142
+ function createPatchedAsyncIterable(stream, hooks) {
16143
+ return {
16144
+ async *[Symbol.asyncIterator]() {
16145
+ try {
16146
+ for await (const chunk of stream) {
16147
+ hooks.onChunk(chunk);
16148
+ yield chunk;
16149
+ }
16150
+ await hooks.onComplete();
16151
+ } catch (error2) {
16152
+ hooks.onError(
16153
+ error2 instanceof Error ? error2 : new Error(String(error2))
16154
+ );
16155
+ throw error2;
16156
+ }
16157
+ }
16158
+ };
16159
+ }
15462
16160
  async function processAISDKStreamingOutput(result, denyOutputPaths) {
15463
16161
  const output = processAISDKOutput(result, denyOutputPaths);
15464
16162
  if (!output || typeof output !== "object") {
15465
16163
  return output;
15466
16164
  }
15467
16165
  const outputRecord = output;
16166
+ const isObjectStreamingResult = result != null && typeof result === "object" && "partialObjectStream" in result;
15468
16167
  try {
15469
- if ("text" in result && typeof result.text === "string") {
15470
- outputRecord.text = result.text;
16168
+ if (!isObjectStreamingResult && "text" in result) {
16169
+ const resolvedText = await Promise.resolve(result.text);
16170
+ if (typeof resolvedText === "string") {
16171
+ outputRecord.text = resolvedText;
16172
+ }
15471
16173
  }
15472
16174
  } catch {
15473
16175
  }
@@ -15480,6 +16182,15 @@ async function processAISDKStreamingOutput(result, denyOutputPaths) {
15480
16182
  }
15481
16183
  } catch {
15482
16184
  }
16185
+ try {
16186
+ if ("finishReason" in result) {
16187
+ const resolvedFinishReason = await Promise.resolve(result.finishReason);
16188
+ if (resolvedFinishReason !== void 0) {
16189
+ outputRecord.finishReason = resolvedFinishReason;
16190
+ }
16191
+ }
16192
+ } catch {
16193
+ }
15483
16194
  return outputRecord;
15484
16195
  }
15485
16196
  function buildAISDKChildMetadata(model) {
@@ -15502,16 +16213,25 @@ function buildResolvedMetadataPayload(result) {
15502
16213
  if (gatewayInfo?.model) {
15503
16214
  metadata.model = gatewayInfo.model;
15504
16215
  }
15505
- if (result.finishReason !== void 0) {
15506
- metadata.finish_reason = result.finishReason;
15507
- }
15508
- return Object.keys(metadata).length > 0 ? { metadata } : {};
16216
+ let finishReason;
16217
+ try {
16218
+ finishReason = result.finishReason;
16219
+ } catch {
16220
+ finishReason = void 0;
16221
+ }
16222
+ if (isPromiseLike(finishReason)) {
16223
+ void Promise.resolve(finishReason).catch(() => {
16224
+ });
16225
+ } else if (finishReason !== void 0) {
16226
+ metadata.finish_reason = finishReason;
16227
+ }
16228
+ return Object.keys(metadata).length > 0 ? { metadata } : {};
15509
16229
  }
15510
- function resolveAISDKModel(model) {
16230
+ function resolveAISDKModel(model, aiSDK) {
15511
16231
  if (typeof model !== "string") {
15512
16232
  return model;
15513
16233
  }
15514
- const provider = globalThis.AI_SDK_DEFAULT_PROVIDER ?? null;
16234
+ const provider = globalThis.AI_SDK_DEFAULT_PROVIDER ?? aiSDK?.gateway ?? null;
15515
16235
  if (provider && typeof provider.languageModel === "function") {
15516
16236
  return provider.languageModel(model);
15517
16237
  }
@@ -15532,17 +16252,49 @@ function processAISDKOutput(output, denyOutputPaths) {
15532
16252
  const merged = extractSerializableOutputFields(output);
15533
16253
  return normalizeAISDKLoggedOutput(omit(merged, denyOutputPaths));
15534
16254
  }
16255
+ function processAISDKEmbeddingOutput(output, denyOutputPaths) {
16256
+ if (!output || typeof output !== "object") {
16257
+ return output;
16258
+ }
16259
+ const summarized = {};
16260
+ const whitelistedFields = [
16261
+ "usage",
16262
+ "totalUsage",
16263
+ "warnings",
16264
+ "providerMetadata",
16265
+ "experimental_providerMetadata"
16266
+ ];
16267
+ for (const field of whitelistedFields) {
16268
+ const value = safeSerializableFieldRead(output, field);
16269
+ if (value !== void 0 && isSerializableOutputValue(value)) {
16270
+ summarized[field] = value;
16271
+ }
16272
+ }
16273
+ const embedding = safeSerializableFieldRead(output, "embedding");
16274
+ if (Array.isArray(embedding)) {
16275
+ summarized.embedding_length = embedding.length;
16276
+ }
16277
+ const embeddings = safeSerializableFieldRead(output, "embeddings");
16278
+ if (Array.isArray(embeddings)) {
16279
+ summarized.embedding_count = embeddings.length;
16280
+ const firstEmbedding = embeddings.find((item) => Array.isArray(item));
16281
+ if (Array.isArray(firstEmbedding)) {
16282
+ summarized.embedding_length = firstEmbedding.length;
16283
+ }
16284
+ }
16285
+ return normalizeAISDKLoggedOutput(omit(summarized, denyOutputPaths));
16286
+ }
15535
16287
  function extractTokenMetrics(result) {
15536
16288
  const metrics = {};
15537
- let usage = result?.totalUsage || result?.usage;
15538
- if (!usage && result) {
15539
- try {
15540
- if ("totalUsage" in result && typeof result.totalUsage !== "function") {
15541
- usage = result.totalUsage;
15542
- } else if ("usage" in result && typeof result.usage !== "function") {
15543
- usage = result.usage;
15544
- }
15545
- } catch {
16289
+ let usage;
16290
+ const totalUsageValue = safeResultFieldRead(result, "totalUsage");
16291
+ if (totalUsageValue !== void 0 && !isPromiseLike(totalUsageValue)) {
16292
+ usage = totalUsageValue;
16293
+ }
16294
+ if (!usage) {
16295
+ const usageValue = safeResultFieldRead(result, "usage");
16296
+ if (usageValue !== void 0 && !isPromiseLike(usageValue)) {
16297
+ usage = usageValue;
15546
16298
  }
15547
16299
  }
15548
16300
  if (!usage) {
@@ -15580,6 +16332,22 @@ function extractTokenMetrics(result) {
15580
16332
  }
15581
16333
  return metrics;
15582
16334
  }
16335
+ function safeResultFieldRead(result, field) {
16336
+ return safeSerializableFieldRead(result, field);
16337
+ }
16338
+ function safeSerializableFieldRead(obj, field) {
16339
+ try {
16340
+ const value = obj?.[field];
16341
+ if (isPromiseLike(value)) {
16342
+ void Promise.resolve(value).catch(() => {
16343
+ });
16344
+ return void 0;
16345
+ }
16346
+ return value;
16347
+ } catch {
16348
+ return void 0;
16349
+ }
16350
+ }
15583
16351
  function aggregateAISDKChunks(chunks, _result, endEvent) {
15584
16352
  const lastChunk = chunks[chunks.length - 1];
15585
16353
  const output = {};
@@ -15588,17 +16356,21 @@ function aggregateAISDKChunks(chunks, _result, endEvent) {
15588
16356
  if (lastChunk) {
15589
16357
  metrics = hasModelChildTracing(endEvent) ? {} : extractTokenMetrics(lastChunk);
15590
16358
  metadata = buildResolvedMetadataPayload(lastChunk).metadata;
15591
- if (lastChunk.text !== void 0) {
15592
- output.text = lastChunk.text;
16359
+ const text = safeSerializableFieldRead(lastChunk, "text");
16360
+ if (text !== void 0) {
16361
+ output.text = text;
15593
16362
  }
15594
- if (lastChunk.object !== void 0) {
15595
- output.object = lastChunk.object;
16363
+ const objectValue = safeSerializableFieldRead(lastChunk, "object");
16364
+ if (objectValue !== void 0) {
16365
+ output.object = objectValue;
15596
16366
  }
15597
- if (lastChunk.finishReason !== void 0) {
15598
- output.finishReason = lastChunk.finishReason;
16367
+ const finishReason = safeSerializableFieldRead(lastChunk, "finishReason");
16368
+ if (finishReason !== void 0) {
16369
+ output.finishReason = finishReason;
15599
16370
  }
15600
- if (lastChunk.toolCalls !== void 0) {
15601
- output.toolCalls = lastChunk.toolCalls;
16371
+ const toolCalls = safeSerializableFieldRead(lastChunk, "toolCalls");
16372
+ if (toolCalls !== void 0) {
16373
+ output.toolCalls = toolCalls;
15602
16374
  }
15603
16375
  }
15604
16376
  finalizeAISDKChildTracing(endEvent);
@@ -15607,14 +16379,20 @@ function aggregateAISDKChunks(chunks, _result, endEvent) {
15607
16379
  function extractGetterValues(obj) {
15608
16380
  const getterValues = {};
15609
16381
  const getterNames = [
16382
+ "content",
15610
16383
  "text",
15611
16384
  "object",
16385
+ "value",
16386
+ "values",
16387
+ "embedding",
16388
+ "embeddings",
15612
16389
  "finishReason",
15613
16390
  "usage",
15614
16391
  "totalUsage",
15615
16392
  "toolCalls",
15616
16393
  "toolResults",
15617
16394
  "warnings",
16395
+ "responses",
15618
16396
  "experimental_providerMetadata",
15619
16397
  "providerMetadata",
15620
16398
  "rawResponse",
@@ -15622,8 +16400,17 @@ function extractGetterValues(obj) {
15622
16400
  ];
15623
16401
  for (const name of getterNames) {
15624
16402
  try {
15625
- if (obj && name in obj && isSerializableOutputValue(obj[name])) {
15626
- getterValues[name] = obj[name];
16403
+ if (!obj || !(name in obj)) {
16404
+ continue;
16405
+ }
16406
+ const value = obj[name];
16407
+ if (isPromiseLike(value)) {
16408
+ void Promise.resolve(value).catch(() => {
16409
+ });
16410
+ continue;
16411
+ }
16412
+ if (isSerializableOutputValue(value)) {
16413
+ getterValues[name] = value;
15627
16414
  }
15628
16415
  } catch {
15629
16416
  }
@@ -15645,6 +16432,11 @@ function extractSerializableOutputFields(output) {
15645
16432
  for (const name of directFieldNames) {
15646
16433
  try {
15647
16434
  const value = output?.[name];
16435
+ if (isPromiseLike(value)) {
16436
+ void Promise.resolve(value).catch(() => {
16437
+ });
16438
+ continue;
16439
+ }
15648
16440
  if (isSerializableOutputValue(value)) {
15649
16441
  serialized[name] = value;
15650
16442
  }
@@ -15656,6 +16448,9 @@ function extractSerializableOutputFields(output) {
15656
16448
  ...extractGetterValues(output)
15657
16449
  };
15658
16450
  }
16451
+ function isPromiseLike(value) {
16452
+ return value != null && typeof value === "object" && typeof value.then === "function";
16453
+ }
15659
16454
  function isSerializableOutputValue(value) {
15660
16455
  if (typeof value === "function") {
15661
16456
  return false;
@@ -15697,8 +16492,9 @@ function parseGatewayModelString(modelString) {
15697
16492
  return { model: modelString };
15698
16493
  }
15699
16494
  function extractGatewayRoutingInfo(result) {
15700
- if (result?.steps && Array.isArray(result.steps) && result.steps.length > 0) {
15701
- const routing2 = result.steps[0]?.providerMetadata?.gateway?.routing;
16495
+ const steps = safeSerializableFieldRead(result, "steps");
16496
+ if (Array.isArray(steps) && steps.length > 0) {
16497
+ const routing2 = steps[0]?.providerMetadata?.gateway?.routing;
15702
16498
  if (routing2) {
15703
16499
  return {
15704
16500
  provider: routing2.resolvedProvider || routing2.finalProvider,
@@ -15706,7 +16502,11 @@ function extractGatewayRoutingInfo(result) {
15706
16502
  };
15707
16503
  }
15708
16504
  }
15709
- const routing = result?.providerMetadata?.gateway?.routing;
16505
+ const providerMetadata = safeSerializableFieldRead(
16506
+ result,
16507
+ "providerMetadata"
16508
+ );
16509
+ const routing = providerMetadata?.gateway?.routing;
15710
16510
  if (routing) {
15711
16511
  return {
15712
16512
  provider: routing.resolvedProvider || routing.finalProvider,
@@ -15716,10 +16516,11 @@ function extractGatewayRoutingInfo(result) {
15716
16516
  return null;
15717
16517
  }
15718
16518
  function extractCostFromResult(result) {
15719
- if (result?.steps && Array.isArray(result.steps) && result.steps.length > 0) {
16519
+ const steps = safeSerializableFieldRead(result, "steps");
16520
+ if (Array.isArray(steps) && steps.length > 0) {
15720
16521
  let totalCost = 0;
15721
16522
  let foundCost = false;
15722
- for (const step of result.steps) {
16523
+ for (const step of steps) {
15723
16524
  const gateway2 = step?.providerMetadata?.gateway;
15724
16525
  const stepCost = parseGatewayCost(gateway2?.cost) || parseGatewayCost(gateway2?.marketCost);
15725
16526
  if (stepCost !== void 0 && stepCost > 0) {
@@ -15731,7 +16532,11 @@ function extractCostFromResult(result) {
15731
16532
  return totalCost;
15732
16533
  }
15733
16534
  }
15734
- const gateway = result?.providerMetadata?.gateway;
16535
+ const providerMetadata = safeSerializableFieldRead(
16536
+ result,
16537
+ "providerMetadata"
16538
+ );
16539
+ const gateway = providerMetadata?.gateway;
15735
16540
  const directCost = parseGatewayCost(gateway?.cost) || parseGatewayCost(gateway?.marketCost);
15736
16541
  if (directCost !== void 0 && directCost > 0) {
15737
16542
  return directCost;
@@ -15848,7 +16653,307 @@ var claudeAgentSDKChannels = defineChannels(
15848
16653
  }
15849
16654
  );
15850
16655
 
16656
+ // src/instrumentation/plugins/claude-agent-sdk-instrumentation-constants.ts
16657
+ var CLAUDE_AGENT_SDK_SKIP_LOCAL_TOOL_HOOKS_OPTION = "__braintrust_skip_local_tool_hooks";
16658
+
16659
+ // src/instrumentation/plugins/claude-agent-sdk-local-tool-context.ts
16660
+ var LOCAL_TOOL_CONTEXT_ASYNC_ITERATOR_PATCHED = Symbol.for(
16661
+ "braintrust.claude_agent_sdk.local_tool_context_async_iterator_patched"
16662
+ );
16663
+ function createLocalToolContextStore() {
16664
+ const maybeIsoWithAsyncLocalStorage = isomorph_default;
16665
+ if (typeof maybeIsoWithAsyncLocalStorage.newAsyncLocalStorage === "function") {
16666
+ return maybeIsoWithAsyncLocalStorage.newAsyncLocalStorage();
16667
+ }
16668
+ let currentStore;
16669
+ return {
16670
+ enterWith(store) {
16671
+ currentStore = store;
16672
+ },
16673
+ getStore() {
16674
+ return currentStore;
16675
+ },
16676
+ run(store, callback) {
16677
+ const previousStore = currentStore;
16678
+ currentStore = store;
16679
+ try {
16680
+ return callback();
16681
+ } finally {
16682
+ currentStore = previousStore;
16683
+ }
16684
+ }
16685
+ };
16686
+ }
16687
+ var localToolContextStore = createLocalToolContextStore();
16688
+ var fallbackLocalToolParentResolver;
16689
+ function createClaudeLocalToolContext() {
16690
+ return {};
16691
+ }
16692
+ function runWithClaudeLocalToolContext(callback, context2) {
16693
+ return localToolContextStore.run(
16694
+ context2 ?? createClaudeLocalToolContext(),
16695
+ callback
16696
+ );
16697
+ }
16698
+ function ensureClaudeLocalToolContext() {
16699
+ const existing = localToolContextStore.getStore();
16700
+ if (existing) {
16701
+ return existing;
16702
+ }
16703
+ const created = {};
16704
+ localToolContextStore.enterWith(created);
16705
+ return created;
16706
+ }
16707
+ function setClaudeLocalToolParentResolver(resolver) {
16708
+ fallbackLocalToolParentResolver = resolver;
16709
+ const context2 = ensureClaudeLocalToolContext();
16710
+ if (!context2) {
16711
+ return;
16712
+ }
16713
+ context2.resolveLocalToolParent = resolver;
16714
+ }
16715
+ function getClaudeLocalToolParentResolver() {
16716
+ return localToolContextStore.getStore()?.resolveLocalToolParent ?? fallbackLocalToolParentResolver;
16717
+ }
16718
+ function isAsyncIterable4(value) {
16719
+ return value !== null && typeof value === "object" && Symbol.asyncIterator in value && typeof value[Symbol.asyncIterator] === "function";
16720
+ }
16721
+ function bindClaudeLocalToolContextToAsyncIterable(result, localToolContext) {
16722
+ if (!isAsyncIterable4(result) || Object.isFrozen(result) || Object.isSealed(result)) {
16723
+ return result;
16724
+ }
16725
+ const stream = result;
16726
+ const originalAsyncIterator = stream[Symbol.asyncIterator];
16727
+ if (originalAsyncIterator[LOCAL_TOOL_CONTEXT_ASYNC_ITERATOR_PATCHED]) {
16728
+ return result;
16729
+ }
16730
+ const patchedAsyncIterator = function() {
16731
+ return runWithClaudeLocalToolContext(() => {
16732
+ const iterator = Reflect.apply(originalAsyncIterator, this, []);
16733
+ if (!iterator || typeof iterator !== "object") {
16734
+ return iterator;
16735
+ }
16736
+ const patchMethod = (methodName) => {
16737
+ const originalMethod = Reflect.get(iterator, methodName);
16738
+ if (typeof originalMethod !== "function") {
16739
+ return;
16740
+ }
16741
+ Reflect.set(
16742
+ iterator,
16743
+ methodName,
16744
+ (...args) => runWithClaudeLocalToolContext(
16745
+ () => Reflect.apply(
16746
+ originalMethod,
16747
+ iterator,
16748
+ args
16749
+ ),
16750
+ localToolContext
16751
+ )
16752
+ );
16753
+ };
16754
+ patchMethod("next");
16755
+ patchMethod("return");
16756
+ patchMethod("throw");
16757
+ return iterator;
16758
+ }, localToolContext);
16759
+ };
16760
+ Object.defineProperty(
16761
+ patchedAsyncIterator,
16762
+ LOCAL_TOOL_CONTEXT_ASYNC_ITERATOR_PATCHED,
16763
+ {
16764
+ configurable: false,
16765
+ enumerable: false,
16766
+ value: true,
16767
+ writable: false
16768
+ }
16769
+ );
16770
+ Reflect.set(stream, Symbol.asyncIterator, patchedAsyncIterator);
16771
+ return result;
16772
+ }
16773
+
16774
+ // src/instrumentation/plugins/claude-agent-sdk-local-tool-spans.ts
16775
+ var LOCAL_TOOL_HANDLER_WRAPPED = Symbol.for(
16776
+ "braintrust.claude_agent_sdk.local_tool_handler_wrapped"
16777
+ );
16778
+ function toErrorMessage(error2) {
16779
+ return error2 instanceof Error ? error2.message : String(error2);
16780
+ }
16781
+ function isPromiseLike2(value) {
16782
+ return value !== null && typeof value === "object" && "then" in value && typeof value.then === "function";
16783
+ }
16784
+ function getToolUseIdFromExtra(extra) {
16785
+ if (!extra || typeof extra !== "object" || !("_meta" in extra)) {
16786
+ return void 0;
16787
+ }
16788
+ const meta = Reflect.get(extra, "_meta");
16789
+ if (!meta || typeof meta !== "object") {
16790
+ return void 0;
16791
+ }
16792
+ const toolUseId = Reflect.get(meta, "claudecode/toolUseId");
16793
+ return typeof toolUseId === "string" ? toolUseId : void 0;
16794
+ }
16795
+ function wrapLocalClaudeToolHandler(handler, getMetadata) {
16796
+ if (handler[LOCAL_TOOL_HANDLER_WRAPPED]) {
16797
+ return handler;
16798
+ }
16799
+ const wrappedHandler = function wrappedLocalToolHandler(...handlerArgs) {
16800
+ const metadata = getMetadata();
16801
+ const rawToolName = metadata.serverName ? `mcp__${metadata.serverName}__${metadata.toolName}` : metadata.toolName;
16802
+ const toolUseId = getToolUseIdFromExtra(handlerArgs[1]);
16803
+ const localToolParentResolver = getClaudeLocalToolParentResolver();
16804
+ const spanName = metadata.serverName ? `tool: ${metadata.serverName}/${metadata.toolName}` : `tool: ${metadata.toolName}`;
16805
+ const runWithResolvedParent = async () => {
16806
+ const parent = toolUseId && localToolParentResolver ? await localToolParentResolver(toolUseId).catch(() => void 0) : void 0;
16807
+ const span = startSpan({
16808
+ event: {
16809
+ input: handlerArgs[0],
16810
+ metadata: {
16811
+ "claude_agent_sdk.raw_tool_name": rawToolName,
16812
+ "gen_ai.tool.name": metadata.toolName,
16813
+ ...toolUseId && { "gen_ai.tool.call.id": toolUseId },
16814
+ ...metadata.serverName && {
16815
+ "mcp.server": metadata.serverName
16816
+ }
16817
+ }
16818
+ },
16819
+ name: spanName,
16820
+ ...parent && { parent },
16821
+ spanAttributes: { type: "tool" /* TOOL */ }
16822
+ });
16823
+ const runHandler = () => Reflect.apply(handler, this, handlerArgs);
16824
+ const finalizeSuccess = (result) => {
16825
+ span.log({ output: result });
16826
+ span.end();
16827
+ return result;
16828
+ };
16829
+ const finalizeError = (error2) => {
16830
+ span.log({ error: toErrorMessage(error2) });
16831
+ span.end();
16832
+ throw error2;
16833
+ };
16834
+ return withCurrent(span, () => {
16835
+ try {
16836
+ const result = runHandler();
16837
+ if (isPromiseLike2(result)) {
16838
+ return result.then(finalizeSuccess, finalizeError);
16839
+ }
16840
+ return finalizeSuccess(result);
16841
+ } catch (error2) {
16842
+ return finalizeError(error2);
16843
+ }
16844
+ });
16845
+ };
16846
+ return runWithResolvedParent();
16847
+ };
16848
+ Object.defineProperty(wrappedHandler, LOCAL_TOOL_HANDLER_WRAPPED, {
16849
+ configurable: false,
16850
+ enumerable: false,
16851
+ value: true,
16852
+ writable: false
16853
+ });
16854
+ return wrappedHandler;
16855
+ }
16856
+ function getRegisteredTools(instance) {
16857
+ if (!instance || typeof instance !== "object") {
16858
+ return void 0;
16859
+ }
16860
+ if (!("_registeredTools" in instance)) {
16861
+ return void 0;
16862
+ }
16863
+ const registeredTools = Reflect.get(instance, "_registeredTools");
16864
+ if (registeredTools instanceof Map) {
16865
+ return registeredTools;
16866
+ }
16867
+ if (registeredTools && typeof registeredTools === "object") {
16868
+ return registeredTools;
16869
+ }
16870
+ return void 0;
16871
+ }
16872
+ function wrapLocalMcpServerToolHandlers(serverName, serverConfig) {
16873
+ if (!serverConfig || typeof serverConfig !== "object") {
16874
+ return false;
16875
+ }
16876
+ if (!("instance" in serverConfig)) {
16877
+ return false;
16878
+ }
16879
+ const instance = Reflect.get(serverConfig, "instance");
16880
+ const registeredTools = getRegisteredTools(instance);
16881
+ if (!registeredTools) {
16882
+ return false;
16883
+ }
16884
+ let wrappedAny = false;
16885
+ const wrapHandler = (toolName, registration) => {
16886
+ if (!registration || typeof registration !== "object") {
16887
+ return;
16888
+ }
16889
+ const handler = Reflect.get(registration, "handler");
16890
+ if (typeof handler !== "function") {
16891
+ return;
16892
+ }
16893
+ const wrappedHandler = wrapLocalClaudeToolHandler(handler, () => ({
16894
+ serverName,
16895
+ toolName
16896
+ }));
16897
+ if (wrappedHandler !== handler) {
16898
+ Reflect.set(registration, "handler", wrappedHandler);
16899
+ wrappedAny = true;
16900
+ }
16901
+ };
16902
+ if (registeredTools instanceof Map) {
16903
+ for (const [toolName, registration] of registeredTools.entries()) {
16904
+ wrapHandler(toolName, registration);
16905
+ }
16906
+ return wrappedAny;
16907
+ }
16908
+ for (const [toolName, registration] of Object.entries(registeredTools)) {
16909
+ wrapHandler(toolName, registration);
16910
+ }
16911
+ return wrappedAny;
16912
+ }
16913
+ function collectLocalMcpServerToolHookNames(serverName, serverConfig) {
16914
+ const toolNames = /* @__PURE__ */ new Set();
16915
+ if (!serverConfig || typeof serverConfig !== "object") {
16916
+ return toolNames;
16917
+ }
16918
+ if ("instance" in serverConfig) {
16919
+ const instance = Reflect.get(serverConfig, "instance");
16920
+ const registeredTools = getRegisteredTools(instance);
16921
+ if (registeredTools instanceof Map) {
16922
+ for (const toolName of registeredTools.keys()) {
16923
+ toolNames.add(toolName);
16924
+ toolNames.add(`mcp__${serverName}__${toolName}`);
16925
+ }
16926
+ } else if (registeredTools) {
16927
+ for (const toolName of Object.keys(registeredTools)) {
16928
+ toolNames.add(toolName);
16929
+ toolNames.add(`mcp__${serverName}__${toolName}`);
16930
+ }
16931
+ }
16932
+ }
16933
+ if ("tools" in serverConfig) {
16934
+ const rawTools = Reflect.get(serverConfig, "tools");
16935
+ if (Array.isArray(rawTools)) {
16936
+ for (const tool of rawTools) {
16937
+ if (!tool || typeof tool !== "object") {
16938
+ continue;
16939
+ }
16940
+ const toolName = Reflect.get(tool, "name");
16941
+ if (typeof toolName !== "string") {
16942
+ continue;
16943
+ }
16944
+ toolNames.add(toolName);
16945
+ toolNames.add(`mcp__${serverName}__${toolName}`);
16946
+ }
16947
+ }
16948
+ }
16949
+ return toolNames;
16950
+ }
16951
+
15851
16952
  // src/instrumentation/plugins/claude-agent-sdk-plugin.ts
16953
+ var ROOT_LLM_PARENT_KEY = "__root__";
16954
+ function llmParentKey(parentToolUseId) {
16955
+ return parentToolUseId ?? ROOT_LLM_PARENT_KEY;
16956
+ }
15852
16957
  function isSubAgentToolName(toolName) {
15853
16958
  return toolName === "Agent" || toolName === "Task";
15854
16959
  }
@@ -15934,7 +17039,7 @@ function buildLLMInput(prompt, conversationHistory, capturedPromptMessages) {
15934
17039
  function formatCapturedMessages(messages) {
15935
17040
  return messages.length > 0 ? messages : [];
15936
17041
  }
15937
- async function createLLMSpanForMessages(messages, prompt, conversationHistory, options, startTime, capturedPromptMessages, parentSpan) {
17042
+ async function createLLMSpanForMessages(messages, prompt, conversationHistory, options, startTime, capturedPromptMessages, parentSpan, existingSpan) {
15938
17043
  if (messages.length === 0) {
15939
17044
  return void 0;
15940
17045
  }
@@ -15954,7 +17059,7 @@ async function createLLMSpanForMessages(messages, prompt, conversationHistory, o
15954
17059
  ).filter(
15955
17060
  (c) => c !== void 0
15956
17061
  );
15957
- const span = startSpan({
17062
+ const span = existingSpan ?? startSpan({
15958
17063
  name: "anthropic.messages.create",
15959
17064
  parent: parentSpan,
15960
17065
  spanAttributes: {
@@ -15968,8 +17073,13 @@ async function createLLMSpanForMessages(messages, prompt, conversationHistory, o
15968
17073
  metrics: usage,
15969
17074
  output: outputs
15970
17075
  });
17076
+ const spanExport = await span.export();
15971
17077
  await span.end();
15972
- return lastMessage.message?.content && lastMessage.message?.role ? { content: lastMessage.message.content, role: lastMessage.message.role } : void 0;
17078
+ const finalMessage = lastMessage.message?.content && lastMessage.message?.role ? { content: lastMessage.message.content, role: lastMessage.message.role } : void 0;
17079
+ return {
17080
+ finalMessage,
17081
+ spanExport
17082
+ };
15973
17083
  }
15974
17084
  function getMcpServerMetadata(serverName, mcpServers) {
15975
17085
  if (!serverName || !mcpServers) {
@@ -16013,11 +17123,51 @@ function parseToolName(rawToolName) {
16013
17123
  toolName: rawToolName
16014
17124
  };
16015
17125
  }
16016
- function createToolTracingHooks(resolveParentSpan, activeToolSpans, mcpServers, subAgentSpans, endedSubAgentSpans) {
17126
+ function isLocalToolUse(rawToolName, mcpServers) {
17127
+ const parsed = parseToolName(rawToolName);
17128
+ if (!parsed.mcpServer || !mcpServers) {
17129
+ return false;
17130
+ }
17131
+ const serverConfig = mcpServers[parsed.mcpServer];
17132
+ if (!serverConfig || typeof serverConfig !== "object") {
17133
+ return false;
17134
+ }
17135
+ return serverConfig.type === "sdk" || "transport" in serverConfig;
17136
+ }
17137
+ function prepareLocalToolHandlersInMcpServers(mcpServers) {
17138
+ const localToolHookNames = /* @__PURE__ */ new Set();
17139
+ if (!mcpServers) {
17140
+ return {
17141
+ hasLocalToolHandlers: false,
17142
+ localToolHookNames
17143
+ };
17144
+ }
17145
+ let hasLocalToolHandlers = false;
17146
+ for (const [serverName, serverConfig] of Object.entries(mcpServers)) {
17147
+ const toolNames = collectLocalMcpServerToolHookNames(
17148
+ serverName,
17149
+ serverConfig
17150
+ );
17151
+ for (const toolName of toolNames) {
17152
+ localToolHookNames.add(toolName);
17153
+ }
17154
+ if (toolNames.size > 0) {
17155
+ hasLocalToolHandlers = true;
17156
+ }
17157
+ if (wrapLocalMcpServerToolHandlers(serverName, serverConfig)) {
17158
+ hasLocalToolHandlers = true;
17159
+ }
17160
+ }
17161
+ return { hasLocalToolHandlers, localToolHookNames };
17162
+ }
17163
+ function createToolTracingHooks(resolveParentSpan, activeToolSpans, mcpServers, localToolHookNames, skipLocalToolHooks, subAgentSpans, endedSubAgentSpans) {
16017
17164
  const preToolUse = async (input, toolUseID) => {
16018
17165
  if (input.hook_event_name !== "PreToolUse" || !toolUseID) {
16019
17166
  return {};
16020
17167
  }
17168
+ if (skipLocalToolHooks && (isLocalToolUse(input.tool_name, mcpServers) || localToolHookNames.has(input.tool_name))) {
17169
+ return {};
17170
+ }
16021
17171
  if (isSubAgentToolName(input.tool_name)) {
16022
17172
  return {};
16023
17173
  }
@@ -16046,6 +17196,9 @@ function createToolTracingHooks(resolveParentSpan, activeToolSpans, mcpServers,
16046
17196
  if (input.hook_event_name !== "PostToolUse" || !toolUseID) {
16047
17197
  return {};
16048
17198
  }
17199
+ if (skipLocalToolHooks && (isLocalToolUse(input.tool_name, mcpServers) || localToolHookNames.has(input.tool_name))) {
17200
+ return {};
17201
+ }
16049
17202
  const subAgentSpan = subAgentSpans.get(toolUseID);
16050
17203
  if (subAgentSpan) {
16051
17204
  try {
@@ -16086,6 +17239,9 @@ function createToolTracingHooks(resolveParentSpan, activeToolSpans, mcpServers,
16086
17239
  if (input.hook_event_name !== "PostToolUseFailure" || !toolUseID) {
16087
17240
  return {};
16088
17241
  }
17242
+ if (skipLocalToolHooks && (isLocalToolUse(input.tool_name, mcpServers) || localToolHookNames.has(input.tool_name))) {
17243
+ return {};
17244
+ }
16089
17245
  const subAgentSpan = subAgentSpans.get(toolUseID);
16090
17246
  if (subAgentSpan) {
16091
17247
  try {
@@ -16120,11 +17276,13 @@ function createToolTracingHooks(resolveParentSpan, activeToolSpans, mcpServers,
16120
17276
  };
16121
17277
  return { postToolUse, postToolUseFailure, preToolUse };
16122
17278
  }
16123
- function injectTracingHooks(options, resolveParentSpan, activeToolSpans, subAgentSpans, endedSubAgentSpans) {
17279
+ function injectTracingHooks(options, resolveParentSpan, activeToolSpans, localToolHookNames, skipLocalToolHooks, subAgentSpans, endedSubAgentSpans) {
16124
17280
  const { preToolUse, postToolUse, postToolUseFailure } = createToolTracingHooks(
16125
17281
  resolveParentSpan,
16126
17282
  activeToolSpans,
16127
17283
  options.mcpServers,
17284
+ localToolHookNames,
17285
+ skipLocalToolHooks,
16128
17286
  subAgentSpans,
16129
17287
  endedSubAgentSpans
16130
17288
  );
@@ -16155,6 +17313,7 @@ async function finalizeCurrentMessageGroup(state) {
16155
17313
  return;
16156
17314
  }
16157
17315
  const parentToolUseId = state.currentMessages[0]?.parent_tool_use_id ?? null;
17316
+ const parentKey = llmParentKey(parentToolUseId);
16158
17317
  let parentSpan = await state.span.export();
16159
17318
  if (parentToolUseId) {
16160
17319
  const subAgentSpan = state.subAgentSpans.get(parentToolUseId);
@@ -16162,17 +17321,30 @@ async function finalizeCurrentMessageGroup(state) {
16162
17321
  parentSpan = await subAgentSpan.export();
16163
17322
  }
16164
17323
  }
16165
- const finalMessage = await createLLMSpanForMessages(
17324
+ const existingLlmSpan = state.activeLlmSpansByParentToolUse.get(parentKey);
17325
+ const llmSpanResult = await createLLMSpanForMessages(
16166
17326
  state.currentMessages,
16167
17327
  state.originalPrompt,
16168
17328
  state.finalResults,
16169
17329
  state.options,
16170
17330
  state.currentMessageStartTime,
16171
17331
  state.capturedPromptMessages,
16172
- parentSpan
17332
+ parentSpan,
17333
+ existingLlmSpan
16173
17334
  );
16174
- if (finalMessage) {
16175
- state.finalResults.push(finalMessage);
17335
+ state.activeLlmSpansByParentToolUse.delete(parentKey);
17336
+ if (llmSpanResult) {
17337
+ if (parentToolUseId) {
17338
+ state.latestLlmParentBySubAgentToolUse.set(
17339
+ parentToolUseId,
17340
+ llmSpanResult.spanExport
17341
+ );
17342
+ } else {
17343
+ state.latestRootLlmParentRef.value = llmSpanResult.spanExport;
17344
+ }
17345
+ if (llmSpanResult.finalMessage) {
17346
+ state.finalResults.push(llmSpanResult.finalMessage);
17347
+ }
16176
17348
  }
16177
17349
  const lastMessage = state.currentMessages[state.currentMessages.length - 1];
16178
17350
  if (lastMessage?.message?.usage) {
@@ -16240,6 +17412,29 @@ async function handleStreamMessage(state, message) {
16240
17412
  state.currentMessageStartTime = getCurrentUnixTimestamp();
16241
17413
  }
16242
17414
  if (message.type === "assistant" && message.message?.usage) {
17415
+ const parentToolUseId = message.parent_tool_use_id ?? null;
17416
+ const parentKey = llmParentKey(parentToolUseId);
17417
+ if (!state.activeLlmSpansByParentToolUse.has(parentKey)) {
17418
+ let llmParentSpan = await state.span.export();
17419
+ if (parentToolUseId) {
17420
+ const subAgentSpan = await ensureSubAgentSpan(
17421
+ state.pendingSubAgentNames,
17422
+ state.span,
17423
+ state.subAgentSpans,
17424
+ parentToolUseId
17425
+ );
17426
+ llmParentSpan = await subAgentSpan.export();
17427
+ }
17428
+ const llmSpan = startSpan({
17429
+ name: "anthropic.messages.create",
17430
+ parent: llmParentSpan,
17431
+ spanAttributes: {
17432
+ type: "llm" /* LLM */
17433
+ },
17434
+ startTime: state.currentMessageStartTime
17435
+ });
17436
+ state.activeLlmSpansByParentToolUse.set(parentKey, llmSpan);
17437
+ }
16243
17438
  state.currentMessages.push(message);
16244
17439
  }
16245
17440
  if (message.type !== "result" || !message.usage) {
@@ -16300,6 +17495,10 @@ async function finalizeQuerySpan(state) {
16300
17495
  }
16301
17496
  }
16302
17497
  } finally {
17498
+ for (const llmSpan of state.activeLlmSpansByParentToolUse.values()) {
17499
+ llmSpan.end();
17500
+ }
17501
+ state.activeLlmSpansByParentToolUse.clear();
16303
17502
  for (const [id, subAgentSpan] of state.subAgentSpans) {
16304
17503
  if (!state.endedSubAgentSpans.has(id)) {
16305
17504
  subAgentSpan.end();
@@ -16365,26 +17564,51 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
16365
17564
  console.error("Error extracting input for Claude Agent SDK:", error2);
16366
17565
  }
16367
17566
  const activeToolSpans = /* @__PURE__ */ new Map();
17567
+ const activeLlmSpansByParentToolUse = /* @__PURE__ */ new Map();
16368
17568
  const subAgentSpans = /* @__PURE__ */ new Map();
16369
17569
  const endedSubAgentSpans = /* @__PURE__ */ new Set();
16370
17570
  const toolUseToParent = /* @__PURE__ */ new Map();
17571
+ const latestLlmParentBySubAgentToolUse = /* @__PURE__ */ new Map();
17572
+ const latestRootLlmParentRef = {
17573
+ value: void 0
17574
+ };
16371
17575
  const pendingSubAgentNames = /* @__PURE__ */ new Map();
17576
+ const localToolContext = createClaudeLocalToolContext();
17577
+ const { hasLocalToolHandlers, localToolHookNames } = prepareLocalToolHandlersInMcpServers(options.mcpServers);
17578
+ const skipLocalToolHooks = options[CLAUDE_AGENT_SDK_SKIP_LOCAL_TOOL_HOOKS_OPTION] === true || hasLocalToolHandlers;
17579
+ const resolveToolUseParentSpan = async (toolUseID) => {
17580
+ const parentToolUseId = toolUseToParent.get(toolUseID) ?? null;
17581
+ const parentKey = llmParentKey(parentToolUseId);
17582
+ const activeLlmSpan = activeLlmSpansByParentToolUse.get(parentKey);
17583
+ if (activeLlmSpan) {
17584
+ return activeLlmSpan.export();
17585
+ }
17586
+ if (parentToolUseId) {
17587
+ const parentLlm = latestLlmParentBySubAgentToolUse.get(parentToolUseId);
17588
+ if (parentLlm) {
17589
+ return parentLlm;
17590
+ }
17591
+ const subAgentSpan = await ensureSubAgentSpan(
17592
+ pendingSubAgentNames,
17593
+ span,
17594
+ subAgentSpans,
17595
+ parentToolUseId
17596
+ );
17597
+ return subAgentSpan.export();
17598
+ }
17599
+ if (latestRootLlmParentRef.value) {
17600
+ return latestRootLlmParentRef.value;
17601
+ }
17602
+ return span.export();
17603
+ };
17604
+ localToolContext.resolveLocalToolParent = resolveToolUseParentSpan;
17605
+ setClaudeLocalToolParentResolver(resolveToolUseParentSpan);
16372
17606
  const optionsWithHooks = injectTracingHooks(
16373
17607
  options,
16374
- async (toolUseID) => {
16375
- const parentToolUseId = toolUseToParent.get(toolUseID);
16376
- if (parentToolUseId) {
16377
- const subAgentSpan = await ensureSubAgentSpan(
16378
- pendingSubAgentNames,
16379
- span,
16380
- subAgentSpans,
16381
- parentToolUseId
16382
- );
16383
- return subAgentSpan.export();
16384
- }
16385
- return span.export();
16386
- },
17608
+ resolveToolUseParentSpan,
16387
17609
  activeToolSpans,
17610
+ localToolHookNames,
17611
+ skipLocalToolHooks,
16388
17612
  subAgentSpans,
16389
17613
  endedSubAgentSpans
16390
17614
  );
@@ -16392,6 +17616,7 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
16392
17616
  event.arguments[0] = params;
16393
17617
  spans.set(event, {
16394
17618
  accumulatedOutputTokens: 0,
17619
+ activeLlmSpansByParentToolUse,
16395
17620
  activeToolSpans,
16396
17621
  capturedPromptMessages,
16397
17622
  currentMessageId: void 0,
@@ -16407,7 +17632,10 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
16407
17632
  promptStarted: () => promptStarted,
16408
17633
  span,
16409
17634
  subAgentSpans,
16410
- toolUseToParent
17635
+ latestLlmParentBySubAgentToolUse,
17636
+ latestRootLlmParentRef,
17637
+ toolUseToParent,
17638
+ localToolContext
16411
17639
  });
16412
17640
  },
16413
17641
  end: (event) => {
@@ -16415,7 +17643,10 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
16415
17643
  if (!state) {
16416
17644
  return;
16417
17645
  }
16418
- const eventResult = event.result;
17646
+ const eventResult = bindClaudeLocalToolContextToAsyncIterable(
17647
+ event.result,
17648
+ state.localToolContext
17649
+ );
16419
17650
  if (eventResult === void 0) {
16420
17651
  state.span.end();
16421
17652
  spans.delete(event);
@@ -16432,20 +17663,16 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
16432
17663
  );
16433
17664
  });
16434
17665
  },
16435
- onComplete: () => {
16436
- void state.processing.then(() => finalizeQuerySpan(state)).finally(() => {
16437
- spans.delete(event);
16438
- });
16439
- },
16440
- onError: (error2) => {
16441
- void state.processing.then(() => {
16442
- state.span.log({
16443
- error: error2.message
16444
- });
16445
- }).then(() => finalizeQuerySpan(state)).finally(() => {
16446
- spans.delete(event);
17666
+ onComplete: () => state.processing.then(() => finalizeQuerySpan(state)).finally(() => {
17667
+ spans.delete(event);
17668
+ }),
17669
+ onError: (error2) => state.processing.then(() => {
17670
+ state.span.log({
17671
+ error: error2.message
16447
17672
  });
16448
- }
17673
+ }).then(() => finalizeQuerySpan(state)).finally(() => {
17674
+ spans.delete(event);
17675
+ })
16449
17676
  });
16450
17677
  return;
16451
17678
  }
@@ -16593,12 +17820,14 @@ var GoogleGenAIPlugin = class extends BasePlugin {
16593
17820
  const params = event.arguments[0];
16594
17821
  streamEvent.googleGenAIInput = serializeInput(params);
16595
17822
  streamEvent.googleGenAIMetadata = extractMetadata(params);
17823
+ streamEvent.googleGenAIStartTime = getCurrentUnixTimestamp();
16596
17824
  },
16597
17825
  asyncEnd: (event) => {
16598
17826
  const streamEvent = event;
16599
17827
  patchGoogleGenAIStreamingResult({
16600
17828
  input: streamEvent.googleGenAIInput,
16601
17829
  metadata: streamEvent.googleGenAIMetadata,
17830
+ startTime: streamEvent.googleGenAIStartTime,
16602
17831
  result: streamEvent.result
16603
17832
  });
16604
17833
  },
@@ -16622,19 +17851,20 @@ function ensureSpanState(states, event, create) {
16622
17851
  }
16623
17852
  function bindCurrentSpanStoreToStart2(tracingChannel2, states, create) {
16624
17853
  const state = _internalGetGlobalState();
17854
+ const contextManager = state?.contextManager;
16625
17855
  const startChannel = tracingChannel2.start;
16626
- const currentSpanStore = state?.contextManager ? state.contextManager[BRAINTRUST_CURRENT_SPAN_STORE] : void 0;
17856
+ const currentSpanStore = contextManager ? contextManager[BRAINTRUST_CURRENT_SPAN_STORE] : void 0;
16627
17857
  if (!startChannel?.bindStore || !currentSpanStore) {
16628
17858
  return void 0;
16629
17859
  }
16630
- startChannel.bindStore(
16631
- currentSpanStore,
16632
- (event) => ensureSpanState(
17860
+ startChannel.bindStore(currentSpanStore, (event) => {
17861
+ const span = ensureSpanState(
16633
17862
  states,
16634
17863
  event,
16635
17864
  () => create(event)
16636
- ).span
16637
- );
17865
+ ).span;
17866
+ return contextManager.wrapSpanForStore(span);
17867
+ });
16638
17868
  return () => {
16639
17869
  startChannel.unbindStore?.(currentSpanStore);
16640
17870
  };
@@ -16651,7 +17881,7 @@ function logErrorAndEndSpan(states, event) {
16651
17881
  states.delete(event);
16652
17882
  }
16653
17883
  function patchGoogleGenAIStreamingResult(args) {
16654
- const { input, metadata, result } = args;
17884
+ const { input, metadata, result, startTime } = args;
16655
17885
  if (!input || !metadata || !result || typeof result !== "object" || typeof result.next !== "function") {
16656
17886
  return false;
16657
17887
  }
@@ -16659,7 +17889,7 @@ function patchGoogleGenAIStreamingResult(args) {
16659
17889
  let firstTokenTime = null;
16660
17890
  let finalized = false;
16661
17891
  let span = null;
16662
- let startTime = null;
17892
+ const requestStartTime = startTime ?? getCurrentUnixTimestamp();
16663
17893
  const ensureSpan = () => {
16664
17894
  if (!span) {
16665
17895
  span = startSpan({
@@ -16672,7 +17902,6 @@ function patchGoogleGenAIStreamingResult(args) {
16672
17902
  metadata
16673
17903
  }
16674
17904
  });
16675
- startTime = getCurrentUnixTimestamp();
16676
17905
  }
16677
17906
  return span;
16678
17907
  };
@@ -16726,11 +17955,11 @@ function patchGoogleGenAIStreamingResult(args) {
16726
17955
  }
16727
17956
  chunks.push(nextResult.value);
16728
17957
  }
16729
- if (nextResult.done && startTime !== null) {
17958
+ if (nextResult.done) {
16730
17959
  finalize({
16731
17960
  result: aggregateGenerateContentChunks(
16732
17961
  chunks,
16733
- startTime,
17962
+ requestStartTime,
16734
17963
  firstTokenTime
16735
17964
  )
16736
17965
  });
@@ -16750,13 +17979,13 @@ function patchGoogleGenAIStreamingResult(args) {
16750
17979
  ...returnArgs
16751
17980
  );
16752
17981
  } finally {
16753
- if (startTime !== null) {
17982
+ if (chunks.length > 0) {
16754
17983
  finalize({
16755
- result: chunks.length > 0 ? aggregateGenerateContentChunks(
17984
+ result: aggregateGenerateContentChunks(
16756
17985
  chunks,
16757
- startTime,
17986
+ requestStartTime,
16758
17987
  firstTokenTime
16759
- ) : void 0
17988
+ )
16760
17989
  });
16761
17990
  } else {
16762
17991
  finalize({});
@@ -17030,41 +18259,156 @@ function tryToDict(obj) {
17030
18259
  return null;
17031
18260
  }
17032
18261
 
17033
- // src/instrumentation/plugins/openrouter-channels.ts
17034
- var openRouterChannels = defineChannels("@openrouter/sdk", {
17035
- chatSend: channel({
17036
- channelName: "chat.send",
17037
- kind: "async"
17038
- }),
17039
- embeddingsGenerate: channel({
17040
- channelName: "embeddings.generate",
17041
- kind: "async"
17042
- }),
17043
- betaResponsesSend: channel({
17044
- channelName: "beta.responses.send",
17045
- kind: "async"
17046
- }),
18262
+ // src/instrumentation/plugins/openrouter-agent-channels.ts
18263
+ var openRouterAgentChannels = defineChannels("@openrouter/agent", {
17047
18264
  callModel: channel({
17048
18265
  channelName: "callModel",
17049
18266
  kind: "sync-stream"
17050
18267
  }),
18268
+ callModelTurn: channel({
18269
+ channelName: "callModel.turn",
18270
+ kind: "async"
18271
+ }),
17051
18272
  toolExecute: channel({
17052
18273
  channelName: "tool.execute",
17053
18274
  kind: "async"
17054
18275
  })
17055
18276
  });
17056
18277
 
17057
- // src/openrouter-utils.ts
17058
- var TOKEN_NAME_MAP2 = {
17059
- promptTokens: "prompt_tokens",
17060
- inputTokens: "prompt_tokens",
17061
- completionTokens: "completion_tokens",
17062
- outputTokens: "completion_tokens",
17063
- totalTokens: "tokens",
17064
- prompt_tokens: "prompt_tokens",
17065
- input_tokens: "prompt_tokens",
17066
- completion_tokens: "completion_tokens",
17067
- output_tokens: "completion_tokens",
18278
+ // src/instrumentation/plugins/openrouter-agent-plugin.ts
18279
+ var OpenRouterAgentPlugin = class extends BasePlugin {
18280
+ onEnable() {
18281
+ this.subscribeToOpenRouterAgentChannels();
18282
+ }
18283
+ onDisable() {
18284
+ this.unsubscribers = unsubscribeAll(this.unsubscribers);
18285
+ }
18286
+ subscribeToOpenRouterAgentChannels() {
18287
+ this.unsubscribers.push(
18288
+ traceSyncStreamChannel(openRouterAgentChannels.callModel, {
18289
+ name: "openrouter.callModel",
18290
+ type: "llm" /* LLM */,
18291
+ extractInput: (args) => {
18292
+ const request = getOpenRouterCallModelRequestArg(args);
18293
+ return {
18294
+ input: request ? extractOpenRouterCallModelInput(request) : void 0,
18295
+ metadata: request ? extractOpenRouterCallModelMetadata(request) : { provider: "openrouter" }
18296
+ };
18297
+ },
18298
+ patchResult: ({ endEvent, result, span }) => {
18299
+ return patchOpenRouterCallModelResult({
18300
+ request: getOpenRouterCallModelRequestArg(endEvent.arguments),
18301
+ result,
18302
+ span
18303
+ });
18304
+ }
18305
+ })
18306
+ );
18307
+ this.unsubscribers.push(
18308
+ traceAsyncChannel(openRouterAgentChannels.callModelTurn, {
18309
+ name: "openrouter.beta.responses.send",
18310
+ type: "llm" /* LLM */,
18311
+ extractInput: (args, event) => {
18312
+ const request = getOpenRouterCallModelRequestArg(args);
18313
+ const metadata = request ? extractOpenRouterCallModelMetadata(request) : { provider: "openrouter" };
18314
+ if (isObject(metadata) && "tools" in metadata) {
18315
+ delete metadata.tools;
18316
+ }
18317
+ return {
18318
+ input: request ? extractOpenRouterCallModelInput(request) : void 0,
18319
+ metadata: {
18320
+ ...metadata,
18321
+ step: event.step,
18322
+ step_type: event.stepType
18323
+ }
18324
+ };
18325
+ },
18326
+ extractOutput: (result) => extractOpenRouterResponseOutput(result),
18327
+ extractMetadata: (result, event) => {
18328
+ if (!isObject(result)) {
18329
+ return {
18330
+ step: event?.step,
18331
+ step_type: event?.stepType
18332
+ };
18333
+ }
18334
+ return {
18335
+ ...extractOpenRouterResponseMetadata(result) || {},
18336
+ ...event?.step !== void 0 ? { step: event.step } : {},
18337
+ ...event?.stepType ? { step_type: event.stepType } : {}
18338
+ };
18339
+ },
18340
+ extractMetrics: (result) => isObject(result) ? parseOpenRouterMetricsFromUsage(result.usage) : {}
18341
+ })
18342
+ );
18343
+ this.unsubscribers.push(
18344
+ traceStreamingChannel(openRouterAgentChannels.toolExecute, {
18345
+ name: "openrouter.tool",
18346
+ type: "tool" /* TOOL */,
18347
+ extractInput: (args, event) => ({
18348
+ input: args[0],
18349
+ metadata: {
18350
+ provider: "openrouter",
18351
+ tool_name: event.toolName,
18352
+ ...event.toolCallId ? { tool_call_id: event.toolCallId } : {}
18353
+ }
18354
+ }),
18355
+ extractOutput: (result) => result,
18356
+ extractMetrics: () => ({}),
18357
+ aggregateChunks: (chunks) => ({
18358
+ output: chunks.length > 0 ? chunks[chunks.length - 1] : void 0,
18359
+ metrics: {}
18360
+ })
18361
+ })
18362
+ );
18363
+ const callModelChannel = openRouterAgentChannels.callModel.tracingChannel();
18364
+ const callModelHandlers = {
18365
+ start: (event) => {
18366
+ const request = getOpenRouterCallModelRequestArg(event.arguments);
18367
+ if (!request) {
18368
+ return;
18369
+ }
18370
+ patchOpenRouterCallModelRequestTools(request);
18371
+ }
18372
+ };
18373
+ callModelChannel.subscribe(callModelHandlers);
18374
+ this.unsubscribers.push(() => {
18375
+ callModelChannel.unsubscribe(callModelHandlers);
18376
+ });
18377
+ }
18378
+ };
18379
+ function normalizeArgs(args) {
18380
+ if (Array.isArray(args)) {
18381
+ return args;
18382
+ }
18383
+ if (isArrayLike2(args)) {
18384
+ return Array.from(args);
18385
+ }
18386
+ return [args];
18387
+ }
18388
+ function isArrayLike2(value) {
18389
+ return isObject(value) && "length" in value && typeof value.length === "number" && Number.isInteger(value.length) && value.length >= 0;
18390
+ }
18391
+ function getOpenRouterCallModelRequestArg(args) {
18392
+ const normalizedArgs = normalizeArgs(args);
18393
+ const keyedRequestArg = normalizedArgs.find(
18394
+ (arg) => isObject(arg) && ("input" in arg || "model" in arg || "tools" in arg)
18395
+ );
18396
+ if (isObject(keyedRequestArg)) {
18397
+ return keyedRequestArg;
18398
+ }
18399
+ const firstObjectArg = normalizedArgs.find((arg) => isObject(arg));
18400
+ return isObject(firstObjectArg) ? firstObjectArg : void 0;
18401
+ }
18402
+ var TOKEN_NAME_MAP2 = {
18403
+ promptTokens: "prompt_tokens",
18404
+ inputTokens: "prompt_tokens",
18405
+ completionTokens: "completion_tokens",
18406
+ outputTokens: "completion_tokens",
18407
+ totalTokens: "tokens",
18408
+ prompt_tokens: "prompt_tokens",
18409
+ input_tokens: "prompt_tokens",
18410
+ completion_tokens: "completion_tokens",
18411
+ output_tokens: "completion_tokens",
17068
18412
  total_tokens: "tokens"
17069
18413
  };
17070
18414
  var TOKEN_DETAIL_PREFIX_MAP = {
@@ -17120,8 +18464,6 @@ function extractOpenRouterUsageMetadata(usage) {
17120
18464
  }
17121
18465
  return Object.keys(metadata).length > 0 ? metadata : void 0;
17122
18466
  }
17123
-
17124
- // src/openrouter-logging.ts
17125
18467
  var OMITTED_OPENROUTER_KEYS = /* @__PURE__ */ new Set([
17126
18468
  "execute",
17127
18469
  "render",
@@ -17141,10 +18483,10 @@ function parseOpenRouterModelString(model) {
17141
18483
  }
17142
18484
  return { model };
17143
18485
  }
17144
- function isZodSchema2(value) {
18486
+ function isZodSchema3(value) {
17145
18487
  return value != null && typeof value === "object" && "_def" in value && typeof value._def === "object";
17146
18488
  }
17147
- function serializeZodSchema2(schema) {
18489
+ function serializeZodSchema3(schema) {
17148
18490
  try {
17149
18491
  return zodToJsonSchema(schema);
17150
18492
  } catch {
@@ -17178,8 +18520,8 @@ function serializeOpenRouterToolsForLogging(tools) {
17178
18520
  return tools.map((tool) => serializeOpenRouterTool(tool));
17179
18521
  }
17180
18522
  function sanitizeOpenRouterLoggedValue(value) {
17181
- if (isZodSchema2(value)) {
17182
- return serializeZodSchema2(value);
18523
+ if (isZodSchema3(value)) {
18524
+ return serializeZodSchema3(value);
17183
18525
  }
17184
18526
  if (typeof value === "function") {
17185
18527
  return "[Function]";
@@ -17203,7 +18545,7 @@ function sanitizeOpenRouterLoggedValue(value) {
17203
18545
  }
17204
18546
  return sanitized;
17205
18547
  }
17206
- function buildOpenRouterMetadata(metadata, httpReferer, xTitle) {
18548
+ function buildOpenRouterMetadata(metadata, httpReferer, appTitle, appCategories, xTitle) {
17207
18549
  const sanitized = sanitizeOpenRouterLoggedValue(metadata);
17208
18550
  const metadataRecord = isObject(sanitized) ? sanitized : {};
17209
18551
  const { model, provider: providerRouting, ...rest } = metadataRecord;
@@ -17213,17 +18555,12 @@ function buildOpenRouterMetadata(metadata, httpReferer, xTitle) {
17213
18555
  ...normalizedModel.model !== void 0 ? { model: normalizedModel.model } : {},
17214
18556
  ...providerRouting !== void 0 ? { providerRouting } : {},
17215
18557
  ...httpReferer !== void 0 ? { httpReferer } : {},
18558
+ ...appTitle !== void 0 ? { appTitle } : {},
18559
+ ...appCategories !== void 0 ? { appCategories } : {},
17216
18560
  ...xTitle !== void 0 ? { xTitle } : {},
17217
18561
  provider: normalizedModel.provider || "openrouter"
17218
18562
  };
17219
18563
  }
17220
- function buildOpenRouterEmbeddingMetadata(metadata, httpReferer, xTitle) {
17221
- const normalized = buildOpenRouterMetadata(metadata, httpReferer, xTitle);
17222
- return typeof normalized.model === "string" ? {
17223
- ...normalized,
17224
- embedding_model: normalized.model
17225
- } : normalized;
17226
- }
17227
18564
  function extractOpenRouterCallModelInput(request) {
17228
18565
  return isObject(request) && "input" in request ? sanitizeOpenRouterLoggedValue(request.input) : void 0;
17229
18566
  }
@@ -17232,7 +18569,13 @@ function extractOpenRouterCallModelMetadata(request) {
17232
18569
  return { provider: "openrouter" };
17233
18570
  }
17234
18571
  const { input: _input, ...metadata } = request;
17235
- return buildOpenRouterMetadata(metadata, void 0, void 0);
18572
+ return buildOpenRouterMetadata(
18573
+ metadata,
18574
+ void 0,
18575
+ void 0,
18576
+ void 0,
18577
+ void 0
18578
+ );
17236
18579
  }
17237
18580
  function extractOpenRouterResponseMetadata(result) {
17238
18581
  if (!isObject(result)) {
@@ -17262,9 +18605,101 @@ function extractOpenRouterResponseOutput(response, fallbackOutput) {
17262
18605
  }
17263
18606
  return void 0;
17264
18607
  }
17265
-
17266
- // src/openrouter-tool-wrapping.ts
17267
18608
  var OPENROUTER_WRAPPED_TOOL = Symbol("braintrust.openrouter.wrappedTool");
18609
+ function patchOpenRouterCallModelRequestTools(request) {
18610
+ if (!Array.isArray(request.tools) || request.tools.length === 0) {
18611
+ return void 0;
18612
+ }
18613
+ const originalTools = request.tools;
18614
+ const wrappedTools = originalTools.map((tool) => wrapOpenRouterTool(tool));
18615
+ const didPatch = wrappedTools.some(
18616
+ (tool, index) => tool !== originalTools[index]
18617
+ );
18618
+ if (!didPatch) {
18619
+ return void 0;
18620
+ }
18621
+ request.tools = wrappedTools;
18622
+ return () => {
18623
+ request.tools = originalTools;
18624
+ };
18625
+ }
18626
+ function wrapOpenRouterTool(tool) {
18627
+ if (isWrappedTool(tool) || !tool.function || typeof tool.function !== "object" || typeof tool.function.execute !== "function") {
18628
+ return tool;
18629
+ }
18630
+ const toolName = tool.function.name || "tool";
18631
+ const originalExecute = tool.function.execute;
18632
+ const wrappedTool = {
18633
+ ...tool,
18634
+ function: {
18635
+ ...tool.function,
18636
+ execute(...args) {
18637
+ return traceToolExecution({
18638
+ args,
18639
+ execute: () => Reflect.apply(originalExecute, this, args),
18640
+ toolCallId: getToolCallId(args[1]),
18641
+ toolName
18642
+ });
18643
+ }
18644
+ }
18645
+ };
18646
+ Object.defineProperty(wrappedTool, OPENROUTER_WRAPPED_TOOL, {
18647
+ value: true,
18648
+ enumerable: false,
18649
+ configurable: false
18650
+ });
18651
+ return wrappedTool;
18652
+ }
18653
+ function isWrappedTool(tool) {
18654
+ return Boolean(tool[OPENROUTER_WRAPPED_TOOL]);
18655
+ }
18656
+ function traceToolExecution(args) {
18657
+ const tracingChannel2 = openRouterAgentChannels.toolExecute.tracingChannel();
18658
+ const input = args.args.length > 0 ? args.args[0] : void 0;
18659
+ const event = {
18660
+ arguments: [input],
18661
+ span_info: {
18662
+ name: args.toolName
18663
+ },
18664
+ toolCallId: args.toolCallId,
18665
+ toolName: args.toolName
18666
+ };
18667
+ tracingChannel2.start.publish(event);
18668
+ try {
18669
+ const result = args.execute();
18670
+ return publishToolResult(tracingChannel2, event, result);
18671
+ } catch (error2) {
18672
+ event.error = normalizeError(error2);
18673
+ tracingChannel2.error.publish(event);
18674
+ throw error2;
18675
+ }
18676
+ }
18677
+ function publishToolResult(tracingChannel2, event, result) {
18678
+ if (isPromiseLike3(result)) {
18679
+ return result.then(
18680
+ (resolved) => {
18681
+ event.result = resolved;
18682
+ tracingChannel2.asyncEnd.publish(event);
18683
+ return resolved;
18684
+ },
18685
+ (error2) => {
18686
+ event.error = normalizeError(error2);
18687
+ tracingChannel2.error.publish(event);
18688
+ throw error2;
18689
+ }
18690
+ );
18691
+ }
18692
+ event.result = result;
18693
+ tracingChannel2.asyncEnd.publish(event);
18694
+ return result;
18695
+ }
18696
+ function getToolCallId(context2) {
18697
+ const toolContext = context2;
18698
+ return typeof toolContext?.toolCall?.id === "string" ? toolContext.toolCall.id : void 0;
18699
+ }
18700
+ function isPromiseLike3(value) {
18701
+ return !!value && (typeof value === "object" || typeof value === "function") && "then" in value && typeof value.then === "function";
18702
+ }
17268
18703
  var OPENROUTER_WRAPPED_CALL_MODEL_RESULT = Symbol(
17269
18704
  "braintrust.openrouter.wrappedCallModelResult"
17270
18705
  );
@@ -17284,24 +18719,8 @@ var OPENROUTER_CALL_MODEL_CONTEXT_METHODS = [
17284
18719
  "getToolCalls",
17285
18720
  "requiresApproval"
17286
18721
  ];
17287
- function patchOpenRouterCallModelRequestTools(request) {
17288
- if (!Array.isArray(request.tools) || request.tools.length === 0) {
17289
- return void 0;
17290
- }
17291
- const originalTools = request.tools;
17292
- const wrappedTools = originalTools.map((tool) => wrapOpenRouterTool(tool));
17293
- const didPatch = wrappedTools.some(
17294
- (tool, index) => tool !== originalTools[index]
17295
- );
17296
- if (!didPatch) {
17297
- return void 0;
17298
- }
17299
- request.tools = wrappedTools;
17300
- return () => {
17301
- request.tools = originalTools;
17302
- };
17303
- }
17304
- function patchOpenRouterCallModelResult(span, result, request) {
18722
+ function patchOpenRouterCallModelResult(args) {
18723
+ const { request, result, span } = args;
17305
18724
  if (!isObject(result) || isWrappedCallModelResult(result)) {
17306
18725
  return false;
17307
18726
  }
@@ -17374,10 +18793,10 @@ function patchOpenRouterCallModelResult(span, result, request) {
17374
18793
  }
17375
18794
  };
17376
18795
  if (originalGetResponse) {
17377
- resultLike.getResponse = async (...args) => {
18796
+ resultLike.getResponse = async (...args2) => {
17378
18797
  return await withCurrent(span, async () => {
17379
18798
  try {
17380
- const response = await originalGetResponse(...args);
18799
+ const response = await originalGetResponse(...args2);
17381
18800
  await endSpanWithResult(response);
17382
18801
  return response;
17383
18802
  } catch (error2) {
@@ -17389,10 +18808,10 @@ function patchOpenRouterCallModelResult(span, result, request) {
17389
18808
  }
17390
18809
  if (typeof resultLike.getText === "function") {
17391
18810
  const originalGetText = resultLike.getText.bind(resultLike);
17392
- resultLike.getText = async (...args) => {
18811
+ resultLike.getText = async (...args2) => {
17393
18812
  return await withCurrent(span, async () => {
17394
18813
  try {
17395
- const text = await originalGetText(...args);
18814
+ const text = await originalGetText(...args2);
17396
18815
  await finalizeFromResponse(text);
17397
18816
  return text;
17398
18817
  } catch (error2) {
@@ -17407,9 +18826,9 @@ function patchOpenRouterCallModelResult(span, result, request) {
17407
18826
  continue;
17408
18827
  }
17409
18828
  const originalMethod = resultLike[methodName];
17410
- resultLike[methodName] = async (...args) => {
18829
+ resultLike[methodName] = async (...args2) => {
17411
18830
  return await withCurrent(span, async () => {
17412
- return await originalMethod.apply(resultLike, args);
18831
+ return await originalMethod.apply(resultLike, args2);
17413
18832
  });
17414
18833
  };
17415
18834
  }
@@ -17418,12 +18837,12 @@ function patchOpenRouterCallModelResult(span, result, request) {
17418
18837
  continue;
17419
18838
  }
17420
18839
  const originalMethod = resultLike[methodName];
17421
- resultLike[methodName] = (...args) => {
18840
+ resultLike[methodName] = (...args2) => {
17422
18841
  const stream = withCurrent(
17423
18842
  span,
17424
- () => originalMethod.apply(resultLike, args)
18843
+ () => originalMethod.apply(resultLike, args2)
17425
18844
  );
17426
- if (!isAsyncIterable4(stream)) {
18845
+ if (!isAsyncIterable5(stream)) {
17427
18846
  return stream;
17428
18847
  }
17429
18848
  return wrapAsyncIterableWithSpan({
@@ -17436,157 +18855,70 @@ function patchOpenRouterCallModelResult(span, result, request) {
17436
18855
  }
17437
18856
  if (originalGetInitialResponse) {
17438
18857
  let initialTurnTraced = false;
17439
- resultLike.getInitialResponse = async (...args) => {
18858
+ resultLike.getInitialResponse = async (...args2) => {
17440
18859
  if (initialTurnTraced) {
17441
18860
  return await withCurrent(span, async () => {
17442
- return await originalGetInitialResponse(...args);
18861
+ return await originalGetInitialResponse(...args2);
17443
18862
  });
17444
18863
  }
17445
18864
  initialTurnTraced = true;
17446
- const resolvedRequest = getOpenRouterResolvedRequest(resultLike, request);
17447
- const childSpan = startOpenRouterCallModelTurnSpan({
17448
- request: resolvedRequest,
17449
- step: tracedTurnCount + 1,
17450
- stepType: tracedTurnCount === 0 ? "initial" : "continue"
17451
- });
17452
- return await withCurrent(childSpan, async () => {
17453
- try {
17454
- const response = await originalGetInitialResponse(...args);
18865
+ const step = tracedTurnCount + 1;
18866
+ const stepType = tracedTurnCount === 0 ? "initial" : "continue";
18867
+ const response = await traceOpenRouterCallModelTurn({
18868
+ fn: async () => {
18869
+ const nextResponse = await originalGetInitialResponse(...args2);
17455
18870
  tracedTurnCount++;
17456
- finishOpenRouterCallModelTurnSpan({
17457
- response,
17458
- step: tracedTurnCount,
17459
- stepType: tracedTurnCount === 1 ? "initial" : "continue",
17460
- span: childSpan
17461
- });
17462
- return response;
17463
- } catch (error2) {
17464
- childSpan.log({
17465
- error: normalizeError(error2).message
17466
- });
17467
- childSpan.end();
17468
- throw error2;
17469
- }
18871
+ return nextResponse;
18872
+ },
18873
+ parentSpan: span,
18874
+ request: getOpenRouterResolvedRequest(resultLike, request),
18875
+ step,
18876
+ stepType
17470
18877
  });
18878
+ return response;
17471
18879
  };
17472
18880
  }
17473
18881
  if (originalMakeFollowupRequest) {
17474
- resultLike.makeFollowupRequest = async (...args) => {
17475
- const currentResponse = args[0];
17476
- const toolResults = Array.isArray(args[1]) ? args[1] : [];
17477
- const resolvedRequest = getOpenRouterResolvedRequest(resultLike, request);
17478
- const followupRequest = buildOpenRouterFollowupRequest(
17479
- resolvedRequest,
17480
- currentResponse,
17481
- toolResults
17482
- );
17483
- const childSpan = startOpenRouterCallModelTurnSpan({
17484
- request: followupRequest,
17485
- step: tracedTurnCount + 1,
17486
- stepType: "continue"
17487
- });
17488
- return await withCurrent(childSpan, async () => {
17489
- try {
17490
- const response = await originalMakeFollowupRequest(...args);
18882
+ resultLike.makeFollowupRequest = async (...args2) => {
18883
+ const currentResponse = args2[0];
18884
+ const toolResults = Array.isArray(args2[1]) ? args2[1] : [];
18885
+ const step = tracedTurnCount + 1;
18886
+ const response = await traceOpenRouterCallModelTurn({
18887
+ fn: async () => {
18888
+ const nextResponse = await originalMakeFollowupRequest(...args2);
17491
18889
  tracedTurnCount++;
17492
- finishOpenRouterCallModelTurnSpan({
17493
- response,
17494
- step: tracedTurnCount,
17495
- stepType: "continue",
17496
- span: childSpan
17497
- });
17498
- return response;
17499
- } catch (error2) {
17500
- childSpan.log({
17501
- error: normalizeError(error2).message
17502
- });
17503
- childSpan.end();
17504
- throw error2;
17505
- }
18890
+ return nextResponse;
18891
+ },
18892
+ parentSpan: span,
18893
+ request: buildOpenRouterFollowupRequest(
18894
+ getOpenRouterResolvedRequest(resultLike, request),
18895
+ currentResponse,
18896
+ toolResults
18897
+ ),
18898
+ step,
18899
+ stepType: "continue"
17506
18900
  });
18901
+ return response;
17507
18902
  };
17508
18903
  }
17509
18904
  return true;
17510
18905
  }
17511
- function wrapOpenRouterTool(tool) {
17512
- if (isWrappedTool(tool) || !tool.function || typeof tool.function !== "object" || typeof tool.function.execute !== "function") {
17513
- return tool;
17514
- }
17515
- const toolName = tool.function.name || "tool";
17516
- const originalExecute = tool.function.execute;
17517
- const wrappedTool = {
17518
- ...tool,
17519
- function: {
17520
- ...tool.function,
17521
- execute(...args) {
17522
- return traceToolExecution({
17523
- args,
17524
- execute: () => Reflect.apply(originalExecute, this, args),
17525
- toolCallId: getToolCallId(args[1]),
17526
- toolName
17527
- });
17528
- }
17529
- }
18906
+ async function traceOpenRouterCallModelTurn(args) {
18907
+ const context2 = {
18908
+ arguments: [args.request],
18909
+ step: args.step,
18910
+ stepType: args.stepType
17530
18911
  };
17531
- Object.defineProperty(wrappedTool, OPENROUTER_WRAPPED_TOOL, {
17532
- value: true,
17533
- enumerable: false,
17534
- configurable: false
17535
- });
17536
- return wrappedTool;
17537
- }
17538
- function isWrappedTool(tool) {
17539
- return Boolean(tool[OPENROUTER_WRAPPED_TOOL]);
18912
+ return await withCurrent(
18913
+ args.parentSpan,
18914
+ () => openRouterAgentChannels.callModelTurn.tracePromise(args.fn, context2)
18915
+ );
17540
18916
  }
17541
18917
  function isWrappedCallModelResult(value) {
17542
18918
  return Boolean(
17543
18919
  isObject(value) && value[OPENROUTER_WRAPPED_CALL_MODEL_RESULT]
17544
18920
  );
17545
18921
  }
17546
- function traceToolExecution(args) {
17547
- const tracingChannel2 = openRouterChannels.toolExecute.tracingChannel();
17548
- const input = args.args.length > 0 ? args.args[0] : void 0;
17549
- const event = {
17550
- arguments: [input],
17551
- span_info: {
17552
- name: args.toolName
17553
- },
17554
- toolCallId: args.toolCallId,
17555
- toolName: args.toolName
17556
- };
17557
- tracingChannel2.start.publish(event);
17558
- try {
17559
- const result = args.execute();
17560
- return publishToolResult(tracingChannel2, event, result);
17561
- } catch (error2) {
17562
- event.error = normalizeError(error2);
17563
- tracingChannel2.error.publish(event);
17564
- throw error2;
17565
- }
17566
- }
17567
- function publishToolResult(tracingChannel2, event, result) {
17568
- if (isPromiseLike(result)) {
17569
- return result.then(
17570
- (resolved) => {
17571
- event.result = resolved;
17572
- tracingChannel2.asyncEnd.publish(event);
17573
- return resolved;
17574
- },
17575
- (error2) => {
17576
- event.error = normalizeError(error2);
17577
- tracingChannel2.error.publish(event);
17578
- throw error2;
17579
- }
17580
- );
17581
- }
17582
- event.result = result;
17583
- tracingChannel2.asyncEnd.publish(event);
17584
- return result;
17585
- }
17586
- function getToolCallId(context2) {
17587
- const toolContext = context2;
17588
- return typeof toolContext?.toolCall?.id === "string" ? toolContext.toolCall.id : void 0;
17589
- }
17590
18922
  function extractOpenRouterCallModelResultMetadata(response, turnCount) {
17591
18923
  const combined = {
17592
18924
  ...extractOpenRouterResponseMetadata(response) || {},
@@ -17631,45 +18963,6 @@ function buildNextOpenRouterCallModelInput(currentInput, response, toolResults)
17631
18963
  (entry) => sanitizeOpenRouterLoggedValue(entry)
17632
18964
  );
17633
18965
  }
17634
- function startOpenRouterCallModelTurnSpan(args) {
17635
- const requestRecord = isObject(args.request) ? args.request : void 0;
17636
- const metadata = requestRecord ? extractOpenRouterCallModelMetadata(requestRecord) : { provider: "openrouter" };
17637
- if (isObject(metadata) && "tools" in metadata) {
17638
- delete metadata.tools;
17639
- }
17640
- return startSpan({
17641
- name: "openrouter.beta.responses.send",
17642
- spanAttributes: {
17643
- type: "llm" /* LLM */
17644
- },
17645
- event: {
17646
- input: requestRecord ? extractOpenRouterCallModelInput(requestRecord) : void 0,
17647
- metadata: {
17648
- ...metadata,
17649
- step: args.step,
17650
- step_type: args.stepType
17651
- }
17652
- }
17653
- });
17654
- }
17655
- function finishOpenRouterCallModelTurnSpan(args) {
17656
- if (!isObject(args.response)) {
17657
- args.span.end();
17658
- return;
17659
- }
17660
- args.span.log({
17661
- output: extractOpenRouterResponseOutput(args.response),
17662
- ...extractOpenRouterResponseMetadata(args.response) ? {
17663
- metadata: {
17664
- ...extractOpenRouterResponseMetadata(args.response),
17665
- ...args.step !== void 0 ? { step: args.step } : {},
17666
- ...args.stepType ? { step_type: args.stepType } : {}
17667
- }
17668
- } : {},
17669
- metrics: parseOpenRouterMetricsFromUsage(args.response.usage)
17670
- });
17671
- args.span.end();
17672
- }
17673
18966
  function getOpenRouterResolvedRequest(result, request) {
17674
18967
  if (isObject(result.resolvedRequest)) {
17675
18968
  return result.resolvedRequest;
@@ -17744,16 +19037,41 @@ function wrapAsyncIterableWithSpan(args) {
17744
19037
  }
17745
19038
  };
17746
19039
  }
17747
- function isAsyncIterable4(value) {
19040
+ function isAsyncIterable5(value) {
17748
19041
  return !!value && (typeof value === "object" || typeof value === "function") && Symbol.asyncIterator in value && typeof value[Symbol.asyncIterator] === "function";
17749
19042
  }
17750
- function isPromiseLike(value) {
17751
- return !!value && (typeof value === "object" || typeof value === "function") && "then" in value && typeof value.then === "function";
17752
- }
17753
19043
  function normalizeError(error2) {
17754
19044
  return error2 instanceof Error ? error2 : new Error(String(error2));
17755
19045
  }
17756
19046
 
19047
+ // src/instrumentation/plugins/openrouter-channels.ts
19048
+ var openRouterChannels = defineChannels("@openrouter/sdk", {
19049
+ chatSend: channel({
19050
+ channelName: "chat.send",
19051
+ kind: "async"
19052
+ }),
19053
+ embeddingsGenerate: channel({
19054
+ channelName: "embeddings.generate",
19055
+ kind: "async"
19056
+ }),
19057
+ betaResponsesSend: channel({
19058
+ channelName: "beta.responses.send",
19059
+ kind: "async"
19060
+ }),
19061
+ callModel: channel({
19062
+ channelName: "callModel",
19063
+ kind: "sync-stream"
19064
+ }),
19065
+ callModelTurn: channel({
19066
+ channelName: "callModel.turn",
19067
+ kind: "async"
19068
+ }),
19069
+ toolExecute: channel({
19070
+ channelName: "tool.execute",
19071
+ kind: "async"
19072
+ })
19073
+ });
19074
+
17757
19075
  // src/instrumentation/plugins/openrouter-plugin.ts
17758
19076
  var OpenRouterPlugin = class extends BasePlugin {
17759
19077
  onEnable() {
@@ -17775,14 +19093,14 @@ var OpenRouterPlugin = class extends BasePlugin {
17775
19093
  const { messages, ...metadata } = chatGenerationParams;
17776
19094
  return {
17777
19095
  input: messages,
17778
- metadata: buildOpenRouterMetadata(metadata, httpReferer, xTitle)
19096
+ metadata: buildOpenRouterMetadata2(metadata, httpReferer, xTitle)
17779
19097
  };
17780
19098
  },
17781
19099
  extractOutput: (result) => {
17782
19100
  return isObject(result) ? result.choices : void 0;
17783
19101
  },
17784
19102
  extractMetrics: (result, startTime) => {
17785
- const metrics = parseOpenRouterMetricsFromUsage(result?.usage);
19103
+ const metrics = parseOpenRouterMetricsFromUsage2(result?.usage);
17786
19104
  if (startTime) {
17787
19105
  metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
17788
19106
  }
@@ -17821,10 +19139,10 @@ var OpenRouterPlugin = class extends BasePlugin {
17821
19139
  if (!isObject(result)) {
17822
19140
  return void 0;
17823
19141
  }
17824
- return extractOpenRouterResponseMetadata(result);
19142
+ return extractOpenRouterResponseMetadata2(result);
17825
19143
  },
17826
19144
  extractMetrics: (result) => {
17827
- return isObject(result) ? parseOpenRouterMetricsFromUsage(result.usage) : {};
19145
+ return isObject(result) ? parseOpenRouterMetricsFromUsage2(result.usage) : {};
17828
19146
  }
17829
19147
  })
17830
19148
  );
@@ -17840,13 +19158,13 @@ var OpenRouterPlugin = class extends BasePlugin {
17840
19158
  const { input, ...metadata } = openResponsesRequest;
17841
19159
  return {
17842
19160
  input,
17843
- metadata: buildOpenRouterMetadata(metadata, httpReferer, xTitle)
19161
+ metadata: buildOpenRouterMetadata2(metadata, httpReferer, xTitle)
17844
19162
  };
17845
19163
  },
17846
- extractOutput: (result) => extractOpenRouterResponseOutput(result),
17847
- extractMetadata: (result) => extractOpenRouterResponseMetadata(result),
19164
+ extractOutput: (result) => extractOpenRouterResponseOutput2(result),
19165
+ extractMetadata: (result) => extractOpenRouterResponseMetadata2(result),
17848
19166
  extractMetrics: (result, startTime) => {
17849
- const metrics = parseOpenRouterMetricsFromUsage(result?.usage);
19167
+ const metrics = parseOpenRouterMetricsFromUsage2(result?.usage);
17850
19168
  if (startTime) {
17851
19169
  metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
17852
19170
  }
@@ -17860,21 +19178,57 @@ var OpenRouterPlugin = class extends BasePlugin {
17860
19178
  name: "openrouter.callModel",
17861
19179
  type: "llm" /* LLM */,
17862
19180
  extractInput: (args) => {
17863
- const request = getOpenRouterCallModelRequestArg(args);
19181
+ const request = getOpenRouterCallModelRequestArg2(args);
17864
19182
  return {
17865
- input: request ? extractOpenRouterCallModelInput(request) : void 0,
17866
- metadata: request ? extractOpenRouterCallModelMetadata(request) : { provider: "openrouter" }
19183
+ input: request ? extractOpenRouterCallModelInput2(request) : void 0,
19184
+ metadata: request ? extractOpenRouterCallModelMetadata2(request) : { provider: "openrouter" }
17867
19185
  };
17868
19186
  },
17869
19187
  patchResult: ({ endEvent, result, span }) => {
17870
- return patchOpenRouterCallModelResult(
17871
- span,
19188
+ return patchOpenRouterCallModelResult2({
19189
+ request: getOpenRouterCallModelRequestArg2(endEvent.arguments),
17872
19190
  result,
17873
- getOpenRouterCallModelRequestArg(endEvent.arguments)
17874
- );
19191
+ span
19192
+ });
17875
19193
  }
17876
19194
  })
17877
19195
  );
19196
+ this.unsubscribers.push(
19197
+ traceAsyncChannel(openRouterChannels.callModelTurn, {
19198
+ name: "openrouter.beta.responses.send",
19199
+ type: "llm" /* LLM */,
19200
+ extractInput: (args, event) => {
19201
+ const request = getOpenRouterCallModelRequestArg2(args);
19202
+ const metadata = request ? extractOpenRouterCallModelMetadata2(request) : { provider: "openrouter" };
19203
+ if (isObject(metadata) && "tools" in metadata) {
19204
+ delete metadata.tools;
19205
+ }
19206
+ return {
19207
+ input: request ? extractOpenRouterCallModelInput2(request) : void 0,
19208
+ metadata: {
19209
+ ...metadata,
19210
+ step: event.step,
19211
+ step_type: event.stepType
19212
+ }
19213
+ };
19214
+ },
19215
+ extractOutput: (result) => extractOpenRouterResponseOutput2(result),
19216
+ extractMetadata: (result, event) => {
19217
+ if (!isObject(result)) {
19218
+ return {
19219
+ step: event?.step,
19220
+ step_type: event?.stepType
19221
+ };
19222
+ }
19223
+ return {
19224
+ ...extractOpenRouterResponseMetadata2(result) || {},
19225
+ ...event?.step !== void 0 ? { step: event.step } : {},
19226
+ ...event?.stepType ? { step_type: event.stepType } : {}
19227
+ };
19228
+ },
19229
+ extractMetrics: (result) => isObject(result) ? parseOpenRouterMetricsFromUsage2(result.usage) : {}
19230
+ })
19231
+ );
17878
19232
  this.unsubscribers.push(
17879
19233
  traceStreamingChannel(openRouterChannels.toolExecute, {
17880
19234
  name: "openrouter.tool",
@@ -17895,155 +19249,1303 @@ var OpenRouterPlugin = class extends BasePlugin {
17895
19249
  })
17896
19250
  })
17897
19251
  );
17898
- const callModelChannel = openRouterChannels.callModel.tracingChannel();
17899
- const callModelHandlers = {
17900
- start: (event) => {
17901
- const request = getOpenRouterCallModelRequestArg(event.arguments);
17902
- if (!request) {
17903
- return;
17904
- }
17905
- patchOpenRouterCallModelRequestTools(request);
17906
- }
17907
- };
17908
- callModelChannel.subscribe(callModelHandlers);
17909
- this.unsubscribers.push(() => {
17910
- callModelChannel.unsubscribe(callModelHandlers);
17911
- });
19252
+ const callModelChannel = openRouterChannels.callModel.tracingChannel();
19253
+ const callModelHandlers = {
19254
+ start: (event) => {
19255
+ const request = getOpenRouterCallModelRequestArg2(event.arguments);
19256
+ if (!request) {
19257
+ return;
19258
+ }
19259
+ patchOpenRouterCallModelRequestTools2(request);
19260
+ }
19261
+ };
19262
+ callModelChannel.subscribe(callModelHandlers);
19263
+ this.unsubscribers.push(() => {
19264
+ callModelChannel.unsubscribe(callModelHandlers);
19265
+ });
19266
+ }
19267
+ };
19268
+ function normalizeArgs2(args) {
19269
+ if (Array.isArray(args)) {
19270
+ return args;
19271
+ }
19272
+ if (isArrayLike3(args)) {
19273
+ return Array.from(args);
19274
+ }
19275
+ return [args];
19276
+ }
19277
+ function isArrayLike3(value) {
19278
+ return isObject(value) && "length" in value && typeof value.length === "number" && Number.isInteger(value.length) && value.length >= 0;
19279
+ }
19280
+ function getOpenRouterRequestArg(args) {
19281
+ const normalizedArgs = normalizeArgs2(args);
19282
+ const keyedCandidate = normalizedArgs.find(
19283
+ (arg) => isObject(arg) && ("chatGenerationParams" in arg || "requestBody" in arg || "openResponsesRequest" in arg)
19284
+ );
19285
+ if (isObject(keyedCandidate)) {
19286
+ return keyedCandidate;
19287
+ }
19288
+ const firstObjectArg = normalizedArgs.find((arg) => isObject(arg));
19289
+ return isObject(firstObjectArg) ? firstObjectArg : void 0;
19290
+ }
19291
+ function getOpenRouterCallModelRequestArg2(args) {
19292
+ const firstObjectArg = normalizeArgs2(args).find((arg) => isObject(arg));
19293
+ return isObject(firstObjectArg) ? firstObjectArg : void 0;
19294
+ }
19295
+ var TOKEN_NAME_MAP3 = {
19296
+ promptTokens: "prompt_tokens",
19297
+ inputTokens: "prompt_tokens",
19298
+ completionTokens: "completion_tokens",
19299
+ outputTokens: "completion_tokens",
19300
+ totalTokens: "tokens",
19301
+ prompt_tokens: "prompt_tokens",
19302
+ input_tokens: "prompt_tokens",
19303
+ completion_tokens: "completion_tokens",
19304
+ output_tokens: "completion_tokens",
19305
+ total_tokens: "tokens"
19306
+ };
19307
+ var TOKEN_DETAIL_PREFIX_MAP2 = {
19308
+ promptTokensDetails: "prompt",
19309
+ inputTokensDetails: "prompt",
19310
+ completionTokensDetails: "completion",
19311
+ outputTokensDetails: "completion",
19312
+ costDetails: "cost",
19313
+ prompt_tokens_details: "prompt",
19314
+ input_tokens_details: "prompt",
19315
+ completion_tokens_details: "completion",
19316
+ output_tokens_details: "completion",
19317
+ cost_details: "cost"
19318
+ };
19319
+ function camelToSnake2(value) {
19320
+ return value.replace(/[A-Z]/g, (match) => `_${match.toLowerCase()}`);
19321
+ }
19322
+ function parseOpenRouterMetricsFromUsage2(usage) {
19323
+ if (!isObject(usage)) {
19324
+ return {};
19325
+ }
19326
+ const metrics = {};
19327
+ for (const [name, value] of Object.entries(usage)) {
19328
+ if (typeof value === "number") {
19329
+ metrics[TOKEN_NAME_MAP3[name] || camelToSnake2(name)] = value;
19330
+ continue;
19331
+ }
19332
+ if (!isObject(value)) {
19333
+ continue;
19334
+ }
19335
+ const prefix = TOKEN_DETAIL_PREFIX_MAP2[name];
19336
+ if (!prefix) {
19337
+ continue;
19338
+ }
19339
+ for (const [nestedName, nestedValue] of Object.entries(value)) {
19340
+ if (typeof nestedValue !== "number") {
19341
+ continue;
19342
+ }
19343
+ metrics[`${prefix}_${camelToSnake2(nestedName)}`] = nestedValue;
19344
+ }
19345
+ }
19346
+ return metrics;
19347
+ }
19348
+ function extractOpenRouterUsageMetadata2(usage) {
19349
+ if (!isObject(usage)) {
19350
+ return void 0;
19351
+ }
19352
+ const metadata = {};
19353
+ if (typeof usage.isByok === "boolean") {
19354
+ metadata.is_byok = usage.isByok;
19355
+ } else if (typeof usage.is_byok === "boolean") {
19356
+ metadata.is_byok = usage.is_byok;
19357
+ }
19358
+ return Object.keys(metadata).length > 0 ? metadata : void 0;
19359
+ }
19360
+ var OMITTED_OPENROUTER_KEYS2 = /* @__PURE__ */ new Set([
19361
+ "execute",
19362
+ "render",
19363
+ "nextTurnParams",
19364
+ "requireApproval"
19365
+ ]);
19366
+ function parseOpenRouterModelString2(model) {
19367
+ if (typeof model !== "string") {
19368
+ return { model };
19369
+ }
19370
+ const slashIndex = model.indexOf("/");
19371
+ if (slashIndex > 0 && slashIndex < model.length - 1) {
19372
+ return {
19373
+ provider: model.substring(0, slashIndex),
19374
+ model: model.substring(slashIndex + 1)
19375
+ };
19376
+ }
19377
+ return { model };
19378
+ }
19379
+ function isZodSchema4(value) {
19380
+ return value != null && typeof value === "object" && "_def" in value && typeof value._def === "object";
19381
+ }
19382
+ function serializeZodSchema4(schema) {
19383
+ try {
19384
+ return zodToJsonSchema(schema);
19385
+ } catch {
19386
+ return {
19387
+ type: "object",
19388
+ description: "Zod schema (conversion failed)"
19389
+ };
19390
+ }
19391
+ }
19392
+ function serializeOpenRouterTool2(tool) {
19393
+ if (!isObject(tool)) {
19394
+ return tool;
19395
+ }
19396
+ const serialized = {};
19397
+ for (const [key, value] of Object.entries(tool)) {
19398
+ if (OMITTED_OPENROUTER_KEYS2.has(key)) {
19399
+ continue;
19400
+ }
19401
+ if (key === "function" && isObject(value)) {
19402
+ serialized.function = sanitizeOpenRouterLoggedValue2(value);
19403
+ continue;
19404
+ }
19405
+ serialized[key] = sanitizeOpenRouterLoggedValue2(value);
19406
+ }
19407
+ return serialized;
19408
+ }
19409
+ function serializeOpenRouterToolsForLogging2(tools) {
19410
+ if (!Array.isArray(tools)) {
19411
+ return void 0;
19412
+ }
19413
+ return tools.map((tool) => serializeOpenRouterTool2(tool));
19414
+ }
19415
+ function sanitizeOpenRouterLoggedValue2(value) {
19416
+ if (isZodSchema4(value)) {
19417
+ return serializeZodSchema4(value);
19418
+ }
19419
+ if (typeof value === "function") {
19420
+ return "[Function]";
19421
+ }
19422
+ if (Array.isArray(value)) {
19423
+ return value.map((entry) => sanitizeOpenRouterLoggedValue2(entry));
19424
+ }
19425
+ if (!isObject(value)) {
19426
+ return value;
19427
+ }
19428
+ const sanitized = {};
19429
+ for (const [key, entry] of Object.entries(value)) {
19430
+ if (OMITTED_OPENROUTER_KEYS2.has(key)) {
19431
+ continue;
19432
+ }
19433
+ if (key === "tools" && Array.isArray(entry)) {
19434
+ sanitized.tools = serializeOpenRouterToolsForLogging2(entry);
19435
+ continue;
19436
+ }
19437
+ sanitized[key] = sanitizeOpenRouterLoggedValue2(entry);
19438
+ }
19439
+ return sanitized;
19440
+ }
19441
+ function buildOpenRouterMetadata2(metadata, httpReferer, xTitle) {
19442
+ const sanitized = sanitizeOpenRouterLoggedValue2(metadata);
19443
+ const metadataRecord = isObject(sanitized) ? sanitized : {};
19444
+ const { model, provider: providerRouting, ...rest } = metadataRecord;
19445
+ const normalizedModel = parseOpenRouterModelString2(model);
19446
+ return {
19447
+ ...rest,
19448
+ ...normalizedModel.model !== void 0 ? { model: normalizedModel.model } : {},
19449
+ ...providerRouting !== void 0 ? { providerRouting } : {},
19450
+ ...httpReferer !== void 0 ? { httpReferer } : {},
19451
+ ...xTitle !== void 0 ? { xTitle } : {},
19452
+ provider: normalizedModel.provider || "openrouter"
19453
+ };
19454
+ }
19455
+ function buildOpenRouterEmbeddingMetadata(metadata, httpReferer, xTitle) {
19456
+ const normalized = buildOpenRouterMetadata2(metadata, httpReferer, xTitle);
19457
+ return typeof normalized.model === "string" ? {
19458
+ ...normalized,
19459
+ embedding_model: normalized.model
19460
+ } : normalized;
19461
+ }
19462
+ function extractOpenRouterCallModelInput2(request) {
19463
+ return isObject(request) && "input" in request ? sanitizeOpenRouterLoggedValue2(request.input) : void 0;
19464
+ }
19465
+ function extractOpenRouterCallModelMetadata2(request) {
19466
+ if (!isObject(request)) {
19467
+ return { provider: "openrouter" };
19468
+ }
19469
+ const { input: _input, ...metadata } = request;
19470
+ return buildOpenRouterMetadata2(metadata, void 0, void 0);
19471
+ }
19472
+ function extractOpenRouterResponseMetadata2(result) {
19473
+ if (!isObject(result)) {
19474
+ return void 0;
19475
+ }
19476
+ const { output: _output, data: _data, usage, ...metadata } = result;
19477
+ const sanitized = sanitizeOpenRouterLoggedValue2(metadata);
19478
+ const metadataRecord = isObject(sanitized) ? sanitized : {};
19479
+ const { model, provider, ...rest } = metadataRecord;
19480
+ const normalizedModel = parseOpenRouterModelString2(model);
19481
+ const normalizedProvider = (typeof provider === "string" ? provider : void 0) || normalizedModel.provider;
19482
+ const usageMetadata = extractOpenRouterUsageMetadata2(usage);
19483
+ const combined = {
19484
+ ...rest,
19485
+ ...normalizedModel.model !== void 0 ? { model: normalizedModel.model } : {},
19486
+ ...usageMetadata || {},
19487
+ ...normalizedProvider !== void 0 ? { provider: normalizedProvider } : {}
19488
+ };
19489
+ return Object.keys(combined).length > 0 ? combined : void 0;
19490
+ }
19491
+ function extractOpenRouterResponseOutput2(response, fallbackOutput) {
19492
+ if (isObject(response) && "output" in response && response.output !== void 0) {
19493
+ return sanitizeOpenRouterLoggedValue2(response.output);
19494
+ }
19495
+ if (fallbackOutput !== void 0) {
19496
+ return sanitizeOpenRouterLoggedValue2(fallbackOutput);
19497
+ }
19498
+ return void 0;
19499
+ }
19500
+ var OPENROUTER_WRAPPED_TOOL2 = Symbol("braintrust.openrouter.wrappedTool");
19501
+ function patchOpenRouterCallModelRequestTools2(request) {
19502
+ if (!Array.isArray(request.tools) || request.tools.length === 0) {
19503
+ return void 0;
19504
+ }
19505
+ const originalTools = request.tools;
19506
+ const wrappedTools = originalTools.map((tool) => wrapOpenRouterTool2(tool));
19507
+ const didPatch = wrappedTools.some(
19508
+ (tool, index) => tool !== originalTools[index]
19509
+ );
19510
+ if (!didPatch) {
19511
+ return void 0;
19512
+ }
19513
+ request.tools = wrappedTools;
19514
+ return () => {
19515
+ request.tools = originalTools;
19516
+ };
19517
+ }
19518
+ function wrapOpenRouterTool2(tool) {
19519
+ if (isWrappedTool2(tool) || !tool.function || typeof tool.function !== "object" || typeof tool.function.execute !== "function") {
19520
+ return tool;
19521
+ }
19522
+ const toolName = tool.function.name || "tool";
19523
+ const originalExecute = tool.function.execute;
19524
+ const wrappedTool = {
19525
+ ...tool,
19526
+ function: {
19527
+ ...tool.function,
19528
+ execute(...args) {
19529
+ return traceToolExecution2({
19530
+ args,
19531
+ execute: () => Reflect.apply(originalExecute, this, args),
19532
+ toolCallId: getToolCallId2(args[1]),
19533
+ toolName
19534
+ });
19535
+ }
19536
+ }
19537
+ };
19538
+ Object.defineProperty(wrappedTool, OPENROUTER_WRAPPED_TOOL2, {
19539
+ value: true,
19540
+ enumerable: false,
19541
+ configurable: false
19542
+ });
19543
+ return wrappedTool;
19544
+ }
19545
+ function isWrappedTool2(tool) {
19546
+ return Boolean(tool[OPENROUTER_WRAPPED_TOOL2]);
19547
+ }
19548
+ function traceToolExecution2(args) {
19549
+ const tracingChannel2 = openRouterChannels.toolExecute.tracingChannel();
19550
+ const input = args.args.length > 0 ? args.args[0] : void 0;
19551
+ const event = {
19552
+ arguments: [input],
19553
+ span_info: {
19554
+ name: args.toolName
19555
+ },
19556
+ toolCallId: args.toolCallId,
19557
+ toolName: args.toolName
19558
+ };
19559
+ tracingChannel2.start.publish(event);
19560
+ try {
19561
+ const result = args.execute();
19562
+ return publishToolResult2(tracingChannel2, event, result);
19563
+ } catch (error2) {
19564
+ event.error = normalizeError2(error2);
19565
+ tracingChannel2.error.publish(event);
19566
+ throw error2;
19567
+ }
19568
+ }
19569
+ function publishToolResult2(tracingChannel2, event, result) {
19570
+ if (isPromiseLike4(result)) {
19571
+ return result.then(
19572
+ (resolved) => {
19573
+ event.result = resolved;
19574
+ tracingChannel2.asyncEnd.publish(event);
19575
+ return resolved;
19576
+ },
19577
+ (error2) => {
19578
+ event.error = normalizeError2(error2);
19579
+ tracingChannel2.error.publish(event);
19580
+ throw error2;
19581
+ }
19582
+ );
19583
+ }
19584
+ event.result = result;
19585
+ tracingChannel2.asyncEnd.publish(event);
19586
+ return result;
19587
+ }
19588
+ function getToolCallId2(context2) {
19589
+ const toolContext = context2;
19590
+ return typeof toolContext?.toolCall?.id === "string" ? toolContext.toolCall.id : void 0;
19591
+ }
19592
+ function isPromiseLike4(value) {
19593
+ return !!value && (typeof value === "object" || typeof value === "function") && "then" in value && typeof value.then === "function";
19594
+ }
19595
+ function aggregateOpenRouterChatChunks(chunks) {
19596
+ let role;
19597
+ let content = "";
19598
+ let toolCalls;
19599
+ let finishReason;
19600
+ let metrics = {};
19601
+ for (const chunk of chunks) {
19602
+ metrics = {
19603
+ ...metrics,
19604
+ ...parseOpenRouterMetricsFromUsage2(chunk?.usage)
19605
+ };
19606
+ const choice = chunk?.choices?.[0];
19607
+ const delta = choice?.delta;
19608
+ if (!delta) {
19609
+ if (choice?.finish_reason !== void 0) {
19610
+ finishReason = choice.finish_reason;
19611
+ }
19612
+ continue;
19613
+ }
19614
+ if (!role && delta.role) {
19615
+ role = delta.role;
19616
+ }
19617
+ if (typeof delta.content === "string") {
19618
+ content += delta.content;
19619
+ }
19620
+ const choiceFinishReason = choice?.finishReason ?? choice?.finish_reason ?? void 0;
19621
+ const deltaFinishReason = delta.finishReason ?? delta.finish_reason ?? void 0;
19622
+ if (choiceFinishReason !== void 0) {
19623
+ finishReason = choiceFinishReason;
19624
+ } else if (deltaFinishReason !== void 0) {
19625
+ finishReason = deltaFinishReason;
19626
+ }
19627
+ const toolCallDeltas = Array.isArray(delta.toolCalls) ? delta.toolCalls : Array.isArray(delta.tool_calls) ? delta.tool_calls : void 0;
19628
+ if (!toolCallDeltas) {
19629
+ continue;
19630
+ }
19631
+ for (const toolDelta of toolCallDeltas) {
19632
+ if (!toolDelta?.function) {
19633
+ continue;
19634
+ }
19635
+ const toolIndex = toolDelta.index ?? 0;
19636
+ const existingToolCall = toolCalls?.[toolIndex];
19637
+ if (!existingToolCall || toolDelta.id && existingToolCall.id !== void 0 && existingToolCall.id !== toolDelta.id) {
19638
+ const nextToolCalls = [...toolCalls || []];
19639
+ nextToolCalls[toolIndex] = {
19640
+ index: toolIndex,
19641
+ id: toolDelta.id,
19642
+ type: toolDelta.type,
19643
+ function: {
19644
+ name: toolDelta.function.name,
19645
+ arguments: toolDelta.function.arguments || ""
19646
+ }
19647
+ };
19648
+ toolCalls = nextToolCalls;
19649
+ continue;
19650
+ }
19651
+ const current = existingToolCall;
19652
+ if (toolDelta.id && !current.id) {
19653
+ current.id = toolDelta.id;
19654
+ }
19655
+ if (toolDelta.type && !current.type) {
19656
+ current.type = toolDelta.type;
19657
+ }
19658
+ if (toolDelta.function.name && !current.function.name) {
19659
+ current.function.name = toolDelta.function.name;
19660
+ }
19661
+ current.function.arguments += toolDelta.function.arguments || "";
19662
+ }
19663
+ }
19664
+ return {
19665
+ output: [
19666
+ {
19667
+ index: 0,
19668
+ message: {
19669
+ role,
19670
+ content: content || void 0,
19671
+ ...toolCalls ? { tool_calls: toolCalls } : {}
19672
+ },
19673
+ logprobs: null,
19674
+ finish_reason: finishReason
19675
+ }
19676
+ ],
19677
+ metrics
19678
+ };
19679
+ }
19680
+ function aggregateOpenRouterResponseStreamEvents(chunks) {
19681
+ let finalResponse;
19682
+ for (const chunk of chunks) {
19683
+ const response = chunk?.response;
19684
+ if (!response) {
19685
+ continue;
19686
+ }
19687
+ if (chunk.type === "response.completed" || chunk.type === "response.incomplete" || chunk.type === "response.failed") {
19688
+ finalResponse = response;
19689
+ }
19690
+ }
19691
+ if (!finalResponse) {
19692
+ return {
19693
+ output: void 0,
19694
+ metrics: {}
19695
+ };
19696
+ }
19697
+ return {
19698
+ output: extractOpenRouterResponseOutput2(finalResponse),
19699
+ metrics: parseOpenRouterMetricsFromUsage2(finalResponse.usage),
19700
+ ...extractOpenRouterResponseMetadata2(finalResponse) ? { metadata: extractOpenRouterResponseMetadata2(finalResponse) } : {}
19701
+ };
19702
+ }
19703
+ var OPENROUTER_WRAPPED_CALL_MODEL_RESULT2 = Symbol(
19704
+ "braintrust.openrouter.wrappedCallModelResult"
19705
+ );
19706
+ var OPENROUTER_CALL_MODEL_STREAM_METHODS2 = [
19707
+ "getFullResponsesStream",
19708
+ "getItemsStream",
19709
+ "getNewMessagesStream",
19710
+ "getReasoningStream",
19711
+ "getTextStream",
19712
+ "getToolCallsStream",
19713
+ "getToolStream"
19714
+ ];
19715
+ var OPENROUTER_CALL_MODEL_CONTEXT_METHODS2 = [
19716
+ "cancel",
19717
+ "getPendingToolCalls",
19718
+ "getState",
19719
+ "getToolCalls",
19720
+ "requiresApproval"
19721
+ ];
19722
+ function patchOpenRouterCallModelResult2(args) {
19723
+ const { request, result, span } = args;
19724
+ if (!isObject(result) || isWrappedCallModelResult2(result)) {
19725
+ return false;
19726
+ }
19727
+ const resultLike = result;
19728
+ const hasInstrumentableMethod = typeof resultLike.getResponse === "function" || typeof resultLike.getText === "function" || OPENROUTER_CALL_MODEL_STREAM_METHODS2.some(
19729
+ (methodName) => typeof resultLike[methodName] === "function"
19730
+ );
19731
+ if (!hasInstrumentableMethod) {
19732
+ return false;
19733
+ }
19734
+ Object.defineProperty(resultLike, OPENROUTER_WRAPPED_CALL_MODEL_RESULT2, {
19735
+ value: true,
19736
+ enumerable: false,
19737
+ configurable: false
19738
+ });
19739
+ const originalGetResponse = typeof resultLike.getResponse === "function" ? resultLike.getResponse.bind(resultLike) : void 0;
19740
+ const originalGetInitialResponse = typeof resultLike.getInitialResponse === "function" ? resultLike.getInitialResponse.bind(resultLike) : void 0;
19741
+ const originalMakeFollowupRequest = typeof resultLike.makeFollowupRequest === "function" ? resultLike.makeFollowupRequest.bind(resultLike) : void 0;
19742
+ let ended = false;
19743
+ let tracedTurnCount = 0;
19744
+ const endSpanWithResult = async (response, fallbackOutput) => {
19745
+ if (ended) {
19746
+ return;
19747
+ }
19748
+ ended = true;
19749
+ const finalResponse = getFinalOpenRouterCallModelResponse2(
19750
+ resultLike,
19751
+ response
19752
+ );
19753
+ if (finalResponse) {
19754
+ const rounds = getOpenRouterCallModelRounds2(resultLike);
19755
+ const metadata = extractOpenRouterCallModelResultMetadata2(
19756
+ finalResponse,
19757
+ rounds.length + 1
19758
+ );
19759
+ span.log({
19760
+ output: extractOpenRouterResponseOutput2(finalResponse, fallbackOutput),
19761
+ ...metadata ? { metadata } : {},
19762
+ metrics: aggregateOpenRouterCallModelMetrics2(rounds, finalResponse)
19763
+ });
19764
+ span.end();
19765
+ return;
19766
+ }
19767
+ if (fallbackOutput !== void 0) {
19768
+ span.log({
19769
+ output: fallbackOutput
19770
+ });
19771
+ }
19772
+ span.end();
19773
+ };
19774
+ const endSpanWithError = (error2) => {
19775
+ if (ended) {
19776
+ return;
19777
+ }
19778
+ ended = true;
19779
+ span.log({
19780
+ error: normalizeError2(error2).message
19781
+ });
19782
+ span.end();
19783
+ };
19784
+ const finalizeFromResponse = async (fallbackOutput) => {
19785
+ if (!originalGetResponse) {
19786
+ await endSpanWithResult(void 0, fallbackOutput);
19787
+ return;
19788
+ }
19789
+ try {
19790
+ await endSpanWithResult(await originalGetResponse(), fallbackOutput);
19791
+ } catch {
19792
+ await endSpanWithResult(void 0, fallbackOutput);
19793
+ }
19794
+ };
19795
+ if (originalGetResponse) {
19796
+ resultLike.getResponse = async (...args2) => {
19797
+ return await withCurrent(span, async () => {
19798
+ try {
19799
+ const response = await originalGetResponse(...args2);
19800
+ await endSpanWithResult(response);
19801
+ return response;
19802
+ } catch (error2) {
19803
+ endSpanWithError(error2);
19804
+ throw error2;
19805
+ }
19806
+ });
19807
+ };
19808
+ }
19809
+ if (typeof resultLike.getText === "function") {
19810
+ const originalGetText = resultLike.getText.bind(resultLike);
19811
+ resultLike.getText = async (...args2) => {
19812
+ return await withCurrent(span, async () => {
19813
+ try {
19814
+ const text = await originalGetText(...args2);
19815
+ await finalizeFromResponse(text);
19816
+ return text;
19817
+ } catch (error2) {
19818
+ endSpanWithError(error2);
19819
+ throw error2;
19820
+ }
19821
+ });
19822
+ };
19823
+ }
19824
+ for (const methodName of OPENROUTER_CALL_MODEL_CONTEXT_METHODS2) {
19825
+ if (typeof resultLike[methodName] !== "function") {
19826
+ continue;
19827
+ }
19828
+ const originalMethod = resultLike[methodName];
19829
+ resultLike[methodName] = async (...args2) => {
19830
+ return await withCurrent(span, async () => {
19831
+ return await originalMethod.apply(resultLike, args2);
19832
+ });
19833
+ };
19834
+ }
19835
+ for (const methodName of OPENROUTER_CALL_MODEL_STREAM_METHODS2) {
19836
+ if (typeof resultLike[methodName] !== "function") {
19837
+ continue;
19838
+ }
19839
+ const originalMethod = resultLike[methodName];
19840
+ resultLike[methodName] = (...args2) => {
19841
+ const stream = withCurrent(
19842
+ span,
19843
+ () => originalMethod.apply(resultLike, args2)
19844
+ );
19845
+ if (!isAsyncIterable6(stream)) {
19846
+ return stream;
19847
+ }
19848
+ return wrapAsyncIterableWithSpan2({
19849
+ finalize: finalizeFromResponse,
19850
+ iteratorFactory: () => stream[Symbol.asyncIterator](),
19851
+ onError: endSpanWithError,
19852
+ span
19853
+ });
19854
+ };
19855
+ }
19856
+ if (originalGetInitialResponse) {
19857
+ let initialTurnTraced = false;
19858
+ resultLike.getInitialResponse = async (...args2) => {
19859
+ if (initialTurnTraced) {
19860
+ return await withCurrent(span, async () => {
19861
+ return await originalGetInitialResponse(...args2);
19862
+ });
19863
+ }
19864
+ initialTurnTraced = true;
19865
+ const step = tracedTurnCount + 1;
19866
+ const stepType = tracedTurnCount === 0 ? "initial" : "continue";
19867
+ const response = await traceOpenRouterCallModelTurn2({
19868
+ fn: async () => {
19869
+ const nextResponse = await originalGetInitialResponse(...args2);
19870
+ tracedTurnCount++;
19871
+ return nextResponse;
19872
+ },
19873
+ parentSpan: span,
19874
+ request: getOpenRouterResolvedRequest2(resultLike, request),
19875
+ step,
19876
+ stepType
19877
+ });
19878
+ return response;
19879
+ };
19880
+ }
19881
+ if (originalMakeFollowupRequest) {
19882
+ resultLike.makeFollowupRequest = async (...args2) => {
19883
+ const currentResponse = args2[0];
19884
+ const toolResults = Array.isArray(args2[1]) ? args2[1] : [];
19885
+ const step = tracedTurnCount + 1;
19886
+ const response = await traceOpenRouterCallModelTurn2({
19887
+ fn: async () => {
19888
+ const nextResponse = await originalMakeFollowupRequest(...args2);
19889
+ tracedTurnCount++;
19890
+ return nextResponse;
19891
+ },
19892
+ parentSpan: span,
19893
+ request: buildOpenRouterFollowupRequest2(
19894
+ getOpenRouterResolvedRequest2(resultLike, request),
19895
+ currentResponse,
19896
+ toolResults
19897
+ ),
19898
+ step,
19899
+ stepType: "continue"
19900
+ });
19901
+ return response;
19902
+ };
19903
+ }
19904
+ return true;
19905
+ }
19906
+ async function traceOpenRouterCallModelTurn2(args) {
19907
+ const context2 = {
19908
+ arguments: [args.request],
19909
+ step: args.step,
19910
+ stepType: args.stepType
19911
+ };
19912
+ return await withCurrent(
19913
+ args.parentSpan,
19914
+ () => openRouterChannels.callModelTurn.tracePromise(args.fn, context2)
19915
+ );
19916
+ }
19917
+ function isWrappedCallModelResult2(value) {
19918
+ return Boolean(
19919
+ isObject(value) && value[OPENROUTER_WRAPPED_CALL_MODEL_RESULT2]
19920
+ );
19921
+ }
19922
+ function extractOpenRouterCallModelResultMetadata2(response, turnCount) {
19923
+ const combined = {
19924
+ ...extractOpenRouterResponseMetadata2(response) || {},
19925
+ ...turnCount !== void 0 ? { turn_count: turnCount } : {}
19926
+ };
19927
+ return Object.keys(combined).length > 0 ? combined : void 0;
19928
+ }
19929
+ function getFinalOpenRouterCallModelResponse2(result, response) {
19930
+ if (isObject(response)) {
19931
+ return response;
19932
+ }
19933
+ return isObject(result.finalResponse) ? result.finalResponse : void 0;
19934
+ }
19935
+ function getOpenRouterCallModelRounds2(result) {
19936
+ if (!Array.isArray(result.allToolExecutionRounds)) {
19937
+ return [];
19938
+ }
19939
+ return result.allToolExecutionRounds.filter((round) => isObject(round)).map((round) => ({
19940
+ response: isObject(round.response) ? round.response : void 0,
19941
+ round: typeof round.round === "number" ? round.round : void 0,
19942
+ toolResults: Array.isArray(round.toolResults) ? round.toolResults : []
19943
+ })).filter((round) => round.response !== void 0);
19944
+ }
19945
+ function aggregateOpenRouterCallModelMetrics2(rounds, finalResponse) {
19946
+ const metrics = {};
19947
+ const responses = [
19948
+ ...rounds.map((round) => round.response).filter(isObject),
19949
+ finalResponse
19950
+ ];
19951
+ for (const response of responses) {
19952
+ const responseMetrics = parseOpenRouterMetricsFromUsage2(response.usage);
19953
+ for (const [name, value] of Object.entries(responseMetrics)) {
19954
+ metrics[name] = (metrics[name] || 0) + value;
19955
+ }
19956
+ }
19957
+ return metrics;
19958
+ }
19959
+ function buildNextOpenRouterCallModelInput2(currentInput, response, toolResults) {
19960
+ const normalizedInput = Array.isArray(currentInput) ? [...currentInput] : currentInput === void 0 ? [] : [currentInput];
19961
+ const responseOutput = Array.isArray(response.output) ? response.output : response.output === void 0 ? [] : [response.output];
19962
+ return [...normalizedInput, ...responseOutput, ...toolResults].map(
19963
+ (entry) => sanitizeOpenRouterLoggedValue2(entry)
19964
+ );
19965
+ }
19966
+ function getOpenRouterResolvedRequest2(result, request) {
19967
+ if (isObject(result.resolvedRequest)) {
19968
+ return result.resolvedRequest;
19969
+ }
19970
+ return request;
19971
+ }
19972
+ function buildOpenRouterFollowupRequest2(request, currentResponse, toolResults) {
19973
+ if (!request) {
19974
+ return void 0;
19975
+ }
19976
+ return {
19977
+ ...request,
19978
+ input: buildNextOpenRouterCallModelInput2(
19979
+ extractOpenRouterCallModelInput2(request),
19980
+ isObject(currentResponse) ? currentResponse : {},
19981
+ toolResults
19982
+ ),
19983
+ stream: false
19984
+ };
19985
+ }
19986
+ function wrapAsyncIterableWithSpan2(args) {
19987
+ return {
19988
+ [Symbol.asyncIterator]() {
19989
+ const iterator = args.iteratorFactory();
19990
+ return {
19991
+ next(value) {
19992
+ return withCurrent(
19993
+ args.span,
19994
+ () => value === void 0 ? iterator.next() : iterator.next(value)
19995
+ ).then(
19996
+ async (result) => {
19997
+ if (result.done) {
19998
+ await args.finalize();
19999
+ }
20000
+ return result;
20001
+ },
20002
+ (error2) => {
20003
+ args.onError(error2);
20004
+ throw error2;
20005
+ }
20006
+ );
20007
+ },
20008
+ return(value) {
20009
+ if (typeof iterator.return !== "function") {
20010
+ return args.finalize().then(() => ({
20011
+ done: true,
20012
+ value
20013
+ }));
20014
+ }
20015
+ return withCurrent(args.span, () => iterator.return(value)).then(
20016
+ async (result) => {
20017
+ await args.finalize();
20018
+ return result;
20019
+ },
20020
+ (error2) => {
20021
+ args.onError(error2);
20022
+ throw error2;
20023
+ }
20024
+ );
20025
+ },
20026
+ throw(error2) {
20027
+ args.onError(error2);
20028
+ if (typeof iterator.throw !== "function") {
20029
+ return Promise.reject(error2);
20030
+ }
20031
+ return withCurrent(args.span, () => iterator.throw(error2));
20032
+ },
20033
+ [Symbol.asyncIterator]() {
20034
+ return this;
20035
+ }
20036
+ };
20037
+ }
20038
+ };
20039
+ }
20040
+ function isAsyncIterable6(value) {
20041
+ return !!value && (typeof value === "object" || typeof value === "function") && Symbol.asyncIterator in value && typeof value[Symbol.asyncIterator] === "function";
20042
+ }
20043
+ function normalizeError2(error2) {
20044
+ return error2 instanceof Error ? error2 : new Error(String(error2));
20045
+ }
20046
+
20047
+ // src/instrumentation/plugins/mistral-channels.ts
20048
+ var mistralChannels = defineChannels("@mistralai/mistralai", {
20049
+ chatComplete: channel({
20050
+ channelName: "chat.complete",
20051
+ kind: "async"
20052
+ }),
20053
+ chatStream: channel({
20054
+ channelName: "chat.stream",
20055
+ kind: "async"
20056
+ }),
20057
+ embeddingsCreate: channel({
20058
+ channelName: "embeddings.create",
20059
+ kind: "async"
20060
+ }),
20061
+ fimComplete: channel({
20062
+ channelName: "fim.complete",
20063
+ kind: "async"
20064
+ }),
20065
+ fimStream: channel({
20066
+ channelName: "fim.stream",
20067
+ kind: "async"
20068
+ }),
20069
+ agentsComplete: channel({
20070
+ channelName: "agents.complete",
20071
+ kind: "async"
20072
+ }),
20073
+ agentsStream: channel({
20074
+ channelName: "agents.stream",
20075
+ kind: "async"
20076
+ })
20077
+ });
20078
+
20079
+ // src/instrumentation/plugins/mistral-plugin.ts
20080
+ var MistralPlugin = class extends BasePlugin {
20081
+ onEnable() {
20082
+ this.subscribeToMistralChannels();
20083
+ }
20084
+ onDisable() {
20085
+ this.unsubscribers = unsubscribeAll(this.unsubscribers);
20086
+ }
20087
+ subscribeToMistralChannels() {
20088
+ this.unsubscribers.push(
20089
+ traceStreamingChannel(mistralChannels.chatComplete, {
20090
+ name: "mistral.chat.complete",
20091
+ type: "llm" /* LLM */,
20092
+ extractInput: extractMessagesInputWithMetadata,
20093
+ extractOutput: (result) => {
20094
+ return result?.choices;
20095
+ },
20096
+ extractMetadata: (result) => extractMistralResponseMetadata(result),
20097
+ extractMetrics: (result, startTime) => extractMistralMetrics(result?.usage, startTime)
20098
+ })
20099
+ );
20100
+ this.unsubscribers.push(
20101
+ traceStreamingChannel(mistralChannels.chatStream, {
20102
+ name: "mistral.chat.stream",
20103
+ type: "llm" /* LLM */,
20104
+ extractInput: extractMessagesInputWithMetadata,
20105
+ extractOutput: extractMistralStreamOutput,
20106
+ extractMetadata: (result) => extractMistralResponseMetadata(result),
20107
+ extractMetrics: (result, startTime) => extractMistralStreamingMetrics(result, startTime),
20108
+ aggregateChunks: aggregateMistralStreamChunks
20109
+ })
20110
+ );
20111
+ this.unsubscribers.push(
20112
+ traceAsyncChannel(mistralChannels.embeddingsCreate, {
20113
+ name: "mistral.embeddings.create",
20114
+ type: "llm" /* LLM */,
20115
+ extractInput: extractEmbeddingInputWithMetadata,
20116
+ extractOutput: (result) => {
20117
+ const embedding = result?.data?.[0]?.embedding;
20118
+ return Array.isArray(embedding) ? { embedding_length: embedding.length } : void 0;
20119
+ },
20120
+ extractMetadata: (result) => extractMistralResponseMetadata(result),
20121
+ extractMetrics: (result) => parseMistralMetricsFromUsage(result?.usage)
20122
+ })
20123
+ );
20124
+ this.unsubscribers.push(
20125
+ traceStreamingChannel(mistralChannels.fimComplete, {
20126
+ name: "mistral.fim.complete",
20127
+ type: "llm" /* LLM */,
20128
+ extractInput: extractPromptInputWithMetadata,
20129
+ extractOutput: (result) => {
20130
+ return result?.choices;
20131
+ },
20132
+ extractMetadata: (result) => extractMistralResponseMetadata(result),
20133
+ extractMetrics: (result, startTime) => extractMistralMetrics(result?.usage, startTime)
20134
+ })
20135
+ );
20136
+ this.unsubscribers.push(
20137
+ traceStreamingChannel(mistralChannels.fimStream, {
20138
+ name: "mistral.fim.stream",
20139
+ type: "llm" /* LLM */,
20140
+ extractInput: extractPromptInputWithMetadata,
20141
+ extractOutput: extractMistralStreamOutput,
20142
+ extractMetadata: (result) => extractMistralResponseMetadata(result),
20143
+ extractMetrics: (result, startTime) => extractMistralStreamingMetrics(result, startTime),
20144
+ aggregateChunks: aggregateMistralStreamChunks
20145
+ })
20146
+ );
20147
+ this.unsubscribers.push(
20148
+ traceStreamingChannel(mistralChannels.agentsComplete, {
20149
+ name: "mistral.agents.complete",
20150
+ type: "llm" /* LLM */,
20151
+ extractInput: extractMessagesInputWithMetadata,
20152
+ extractOutput: (result) => {
20153
+ return result?.choices;
20154
+ },
20155
+ extractMetadata: (result) => extractMistralResponseMetadata(result),
20156
+ extractMetrics: (result, startTime) => extractMistralMetrics(result?.usage, startTime)
20157
+ })
20158
+ );
20159
+ this.unsubscribers.push(
20160
+ traceStreamingChannel(mistralChannels.agentsStream, {
20161
+ name: "mistral.agents.stream",
20162
+ type: "llm" /* LLM */,
20163
+ extractInput: extractMessagesInputWithMetadata,
20164
+ extractOutput: extractMistralStreamOutput,
20165
+ extractMetadata: (result) => extractMistralResponseMetadata(result),
20166
+ extractMetrics: (result, startTime) => extractMistralStreamingMetrics(result, startTime),
20167
+ aggregateChunks: aggregateMistralStreamChunks
20168
+ })
20169
+ );
17912
20170
  }
17913
20171
  };
17914
- function normalizeArgs(args) {
20172
+ var TOKEN_NAME_MAP4 = {
20173
+ promptTokens: "prompt_tokens",
20174
+ inputTokens: "prompt_tokens",
20175
+ completionTokens: "completion_tokens",
20176
+ outputTokens: "completion_tokens",
20177
+ totalTokens: "tokens",
20178
+ prompt_tokens: "prompt_tokens",
20179
+ input_tokens: "prompt_tokens",
20180
+ completion_tokens: "completion_tokens",
20181
+ output_tokens: "completion_tokens",
20182
+ total_tokens: "tokens",
20183
+ promptAudioSeconds: "prompt_audio_seconds",
20184
+ prompt_audio_seconds: "prompt_audio_seconds"
20185
+ };
20186
+ var TOKEN_DETAIL_PREFIX_MAP3 = {
20187
+ promptTokensDetails: "prompt",
20188
+ inputTokensDetails: "prompt",
20189
+ completionTokensDetails: "completion",
20190
+ outputTokensDetails: "completion",
20191
+ prompt_tokens_details: "prompt",
20192
+ input_tokens_details: "prompt",
20193
+ completion_tokens_details: "completion",
20194
+ output_tokens_details: "completion"
20195
+ };
20196
+ var MISTRAL_REQUEST_METADATA_ALLOWLIST = /* @__PURE__ */ new Set([
20197
+ "agentId",
20198
+ "agent_id",
20199
+ "encodingFormat",
20200
+ "encoding_format",
20201
+ "frequencyPenalty",
20202
+ "frequency_penalty",
20203
+ "maxTokens",
20204
+ "max_tokens",
20205
+ "model",
20206
+ "n",
20207
+ "presencePenalty",
20208
+ "presence_penalty",
20209
+ "randomSeed",
20210
+ "random_seed",
20211
+ "responseFormat",
20212
+ "response_format",
20213
+ "safePrompt",
20214
+ "safe_prompt",
20215
+ "stream",
20216
+ "stop",
20217
+ "temperature",
20218
+ "toolChoice",
20219
+ "tool_choice",
20220
+ "topP",
20221
+ "top_p"
20222
+ ]);
20223
+ var MISTRAL_RESPONSE_METADATA_ALLOWLIST = /* @__PURE__ */ new Set([
20224
+ "agentId",
20225
+ "agent_id",
20226
+ "created",
20227
+ "id",
20228
+ "model",
20229
+ "object"
20230
+ ]);
20231
+ function camelToSnake3(value) {
20232
+ return value.replace(/[A-Z]/g, (match) => `_${match.toLowerCase()}`);
20233
+ }
20234
+ function normalizeArgs3(args) {
17915
20235
  if (Array.isArray(args)) {
17916
20236
  return args;
17917
20237
  }
17918
- if (isArrayLike2(args)) {
20238
+ if (isArrayLike4(args)) {
17919
20239
  return Array.from(args);
17920
20240
  }
17921
20241
  return [args];
17922
20242
  }
17923
- function isArrayLike2(value) {
20243
+ function isArrayLike4(value) {
17924
20244
  return isObject(value) && "length" in value && typeof value.length === "number" && Number.isInteger(value.length) && value.length >= 0;
17925
20245
  }
17926
- function getOpenRouterRequestArg(args) {
17927
- const normalizedArgs = normalizeArgs(args);
17928
- const keyedCandidate = normalizedArgs.find(
17929
- (arg) => isObject(arg) && ("chatGenerationParams" in arg || "requestBody" in arg || "openResponsesRequest" in arg)
20246
+ function getMistralRequestArg(args) {
20247
+ const firstObjectArg = normalizeArgs3(args).find((arg) => isObject(arg));
20248
+ return isObject(firstObjectArg) ? firstObjectArg : void 0;
20249
+ }
20250
+ function addMistralProviderMetadata(metadata) {
20251
+ return {
20252
+ ...metadata,
20253
+ provider: "mistral"
20254
+ };
20255
+ }
20256
+ function pickAllowedMetadata(metadata, allowlist) {
20257
+ if (!metadata) {
20258
+ return {};
20259
+ }
20260
+ const picked = {};
20261
+ for (const key of allowlist) {
20262
+ const value = metadata[key];
20263
+ if (value !== void 0) {
20264
+ picked[key] = value;
20265
+ }
20266
+ }
20267
+ return picked;
20268
+ }
20269
+ function extractMistralRequestMetadata(metadata) {
20270
+ return pickAllowedMetadata(metadata, MISTRAL_REQUEST_METADATA_ALLOWLIST);
20271
+ }
20272
+ function isMistralChatCompletionChunk(value) {
20273
+ return isObject(value);
20274
+ }
20275
+ function isMistralChunkChoice(value) {
20276
+ return isObject(value);
20277
+ }
20278
+ function extractMessagesInputWithMetadata(args) {
20279
+ const params = getMistralRequestArg(args);
20280
+ const { messages, ...rawMetadata } = params || {};
20281
+ return {
20282
+ input: processInputAttachments(messages),
20283
+ metadata: addMistralProviderMetadata(
20284
+ extractMistralRequestMetadata(rawMetadata)
20285
+ )
20286
+ };
20287
+ }
20288
+ function extractEmbeddingInputWithMetadata(args) {
20289
+ const params = getMistralRequestArg(args);
20290
+ const { inputs, ...rawMetadata } = params || {};
20291
+ return {
20292
+ input: inputs,
20293
+ metadata: addMistralProviderMetadata(
20294
+ extractMistralRequestMetadata(rawMetadata)
20295
+ )
20296
+ };
20297
+ }
20298
+ function extractPromptInputWithMetadata(args) {
20299
+ const params = getMistralRequestArg(args);
20300
+ const { prompt, ...rawMetadata } = params || {};
20301
+ return {
20302
+ input: prompt,
20303
+ metadata: addMistralProviderMetadata(
20304
+ extractMistralRequestMetadata(rawMetadata)
20305
+ )
20306
+ };
20307
+ }
20308
+ function extractMistralResponseMetadata(result) {
20309
+ if (!isObject(result)) {
20310
+ return void 0;
20311
+ }
20312
+ const { choices: _choices, usage: _usage, data: _data, ...metadata } = result;
20313
+ const picked = pickAllowedMetadata(
20314
+ metadata,
20315
+ MISTRAL_RESPONSE_METADATA_ALLOWLIST
17930
20316
  );
17931
- if (isObject(keyedCandidate)) {
17932
- return keyedCandidate;
20317
+ return Object.keys(picked).length > 0 ? picked : void 0;
20318
+ }
20319
+ function extractMistralMetrics(usage, startTime) {
20320
+ const metrics = parseMistralMetricsFromUsage(usage);
20321
+ if (startTime) {
20322
+ metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
17933
20323
  }
17934
- const firstObjectArg = normalizedArgs.find((arg) => isObject(arg));
17935
- return isObject(firstObjectArg) ? firstObjectArg : void 0;
20324
+ return metrics;
17936
20325
  }
17937
- function getOpenRouterCallModelRequestArg(args) {
17938
- const firstObjectArg = normalizeArgs(args).find((arg) => isObject(arg));
17939
- return isObject(firstObjectArg) ? firstObjectArg : void 0;
20326
+ function extractMistralStreamOutput(result) {
20327
+ return isObject(result) ? result.choices : void 0;
17940
20328
  }
17941
- function aggregateOpenRouterChatChunks(chunks) {
17942
- let role;
17943
- let content = "";
17944
- let toolCalls;
17945
- let finishReason;
17946
- let metrics = {};
17947
- for (const chunk of chunks) {
17948
- metrics = {
17949
- ...metrics,
17950
- ...parseOpenRouterMetricsFromUsage(chunk?.usage)
17951
- };
17952
- const choice = chunk?.choices?.[0];
17953
- const delta = choice?.delta;
17954
- if (!delta) {
17955
- if (choice?.finish_reason !== void 0) {
17956
- finishReason = choice.finish_reason;
20329
+ function extractMistralStreamingMetrics(result, startTime) {
20330
+ const metrics = isObject(result) ? parseMistralMetricsFromUsage(result.usage) : {};
20331
+ if (startTime) {
20332
+ metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
20333
+ }
20334
+ return metrics;
20335
+ }
20336
+ function extractDeltaText(content) {
20337
+ if (typeof content === "string") {
20338
+ return content;
20339
+ }
20340
+ if (!Array.isArray(content)) {
20341
+ return void 0;
20342
+ }
20343
+ const textParts = content.map((part) => {
20344
+ if (!isObject(part) || part.type !== "text") {
20345
+ return "";
20346
+ }
20347
+ return typeof part.text === "string" ? part.text : "";
20348
+ }).filter((part) => part.length > 0);
20349
+ return textParts.length > 0 ? textParts.join("") : void 0;
20350
+ }
20351
+ function getDeltaToolCalls(delta) {
20352
+ const toolCalls = Array.isArray(delta.toolCalls) && delta.toolCalls || Array.isArray(delta.tool_calls) && delta.tool_calls || [];
20353
+ return toolCalls.filter((toolCall) => isObject(toolCall));
20354
+ }
20355
+ function getToolCallIndex(toolCall) {
20356
+ return typeof toolCall.index === "number" && toolCall.index >= 0 ? toolCall.index : void 0;
20357
+ }
20358
+ function createMergedToolCallDelta(delta) {
20359
+ return {
20360
+ ...delta,
20361
+ function: {
20362
+ ...delta.function,
20363
+ arguments: typeof delta.function?.arguments === "string" ? delta.function.arguments : ""
20364
+ }
20365
+ };
20366
+ }
20367
+ function mergeToolCallDeltaPair(current, delta) {
20368
+ const currentArguments = typeof current.function?.arguments === "string" ? current.function.arguments : "";
20369
+ const deltaArguments = typeof delta.function?.arguments === "string" ? delta.function.arguments : "";
20370
+ return {
20371
+ ...current,
20372
+ ...delta,
20373
+ function: {
20374
+ ...current.function || {},
20375
+ ...delta.function || {},
20376
+ arguments: `${currentArguments}${deltaArguments}`
20377
+ }
20378
+ };
20379
+ }
20380
+ function mergeToolCallDeltas(toolCalls, deltas) {
20381
+ if (deltas.length === 0) {
20382
+ return toolCalls;
20383
+ }
20384
+ const merged = toolCalls ? [...toolCalls] : [];
20385
+ const indexToPosition = /* @__PURE__ */ new Map();
20386
+ const idToPosition = /* @__PURE__ */ new Map();
20387
+ for (const [position, toolCall] of merged.entries()) {
20388
+ const index = getToolCallIndex(toolCall);
20389
+ if (index !== void 0 && !indexToPosition.has(index)) {
20390
+ indexToPosition.set(index, position);
20391
+ }
20392
+ if (typeof toolCall.id === "string" && !idToPosition.has(toolCall.id)) {
20393
+ idToPosition.set(toolCall.id, position);
20394
+ }
20395
+ }
20396
+ for (const delta of deltas) {
20397
+ const deltaIndex = getToolCallIndex(delta);
20398
+ const existingByIndex = deltaIndex !== void 0 ? indexToPosition.get(deltaIndex) : void 0;
20399
+ const existingById = typeof delta.id === "string" ? idToPosition.get(delta.id) : void 0;
20400
+ const existingPosition = existingByIndex ?? existingById;
20401
+ if (existingPosition === void 0) {
20402
+ const newToolCall = createMergedToolCallDelta(delta);
20403
+ merged.push(newToolCall);
20404
+ const newPosition = merged.length - 1;
20405
+ const newIndex = getToolCallIndex(newToolCall);
20406
+ if (newIndex !== void 0 && !indexToPosition.has(newIndex)) {
20407
+ indexToPosition.set(newIndex, newPosition);
20408
+ }
20409
+ if (typeof newToolCall.id === "string" && !idToPosition.has(newToolCall.id)) {
20410
+ idToPosition.set(newToolCall.id, newPosition);
17957
20411
  }
17958
20412
  continue;
17959
20413
  }
17960
- if (!role && delta.role) {
17961
- role = delta.role;
20414
+ const mergedToolCall = mergeToolCallDeltaPair(
20415
+ merged[existingPosition],
20416
+ delta
20417
+ );
20418
+ merged[existingPosition] = mergedToolCall;
20419
+ const mergedIndex = getToolCallIndex(mergedToolCall);
20420
+ if (mergedIndex !== void 0 && !indexToPosition.has(mergedIndex)) {
20421
+ indexToPosition.set(mergedIndex, existingPosition);
17962
20422
  }
17963
- if (typeof delta.content === "string") {
17964
- content += delta.content;
20423
+ if (typeof mergedToolCall.id === "string" && !idToPosition.has(mergedToolCall.id)) {
20424
+ idToPosition.set(mergedToolCall.id, existingPosition);
17965
20425
  }
17966
- const choiceFinishReason = choice?.finishReason ?? choice?.finish_reason ?? void 0;
17967
- const deltaFinishReason = delta.finishReason ?? delta.finish_reason ?? void 0;
17968
- if (choiceFinishReason !== void 0) {
17969
- finishReason = choiceFinishReason;
17970
- } else if (deltaFinishReason !== void 0) {
17971
- finishReason = deltaFinishReason;
20426
+ }
20427
+ return merged.length > 0 ? merged : void 0;
20428
+ }
20429
+ function getChoiceFinishReason(choice) {
20430
+ if (typeof choice.finishReason === "string" || choice.finishReason === null) {
20431
+ return choice.finishReason;
20432
+ }
20433
+ if (typeof choice.finish_reason === "string" || choice.finish_reason === null) {
20434
+ return choice.finish_reason;
20435
+ }
20436
+ return void 0;
20437
+ }
20438
+ function parseMistralMetricsFromUsage(usage) {
20439
+ if (!isObject(usage)) {
20440
+ return {};
20441
+ }
20442
+ const metrics = {};
20443
+ for (const [name, value] of Object.entries(usage)) {
20444
+ if (typeof value === "number") {
20445
+ metrics[TOKEN_NAME_MAP4[name] || camelToSnake3(name)] = value;
20446
+ continue;
17972
20447
  }
17973
- const toolCallDeltas = Array.isArray(delta.toolCalls) ? delta.toolCalls : Array.isArray(delta.tool_calls) ? delta.tool_calls : void 0;
17974
- if (!toolCallDeltas) {
20448
+ if (!isObject(value)) {
17975
20449
  continue;
17976
20450
  }
17977
- for (const toolDelta of toolCallDeltas) {
17978
- if (!toolDelta?.function) {
20451
+ const prefix = TOKEN_DETAIL_PREFIX_MAP3[name];
20452
+ if (!prefix) {
20453
+ continue;
20454
+ }
20455
+ for (const [nestedName, nestedValue] of Object.entries(value)) {
20456
+ if (typeof nestedValue !== "number") {
17979
20457
  continue;
17980
20458
  }
17981
- const toolIndex = toolDelta.index ?? 0;
17982
- const existingToolCall = toolCalls?.[toolIndex];
17983
- if (!existingToolCall || toolDelta.id && existingToolCall.id !== void 0 && existingToolCall.id !== toolDelta.id) {
17984
- const nextToolCalls = [...toolCalls || []];
17985
- nextToolCalls[toolIndex] = {
17986
- index: toolIndex,
17987
- id: toolDelta.id,
17988
- type: toolDelta.type,
17989
- function: {
17990
- name: toolDelta.function.name,
17991
- arguments: toolDelta.function.arguments || ""
17992
- }
17993
- };
17994
- toolCalls = nextToolCalls;
20459
+ metrics[`${prefix}_${camelToSnake3(nestedName)}`] = nestedValue;
20460
+ }
20461
+ }
20462
+ return metrics;
20463
+ }
20464
+ function aggregateMistralStreamChunks(chunks) {
20465
+ const choiceAccumulators = /* @__PURE__ */ new Map();
20466
+ const indexToAccumulatorKey = /* @__PURE__ */ new Map();
20467
+ const positionToAccumulatorKey = /* @__PURE__ */ new Map();
20468
+ let nextAccumulatorOrder = 0;
20469
+ let metrics = {};
20470
+ let metadata;
20471
+ for (const event of chunks) {
20472
+ const chunk = isMistralChatCompletionChunk(event?.data) ? event.data : void 0;
20473
+ if (!chunk) {
20474
+ continue;
20475
+ }
20476
+ if (isObject(chunk.usage)) {
20477
+ metrics = {
20478
+ ...metrics,
20479
+ ...parseMistralMetricsFromUsage(chunk.usage)
20480
+ };
20481
+ }
20482
+ const chunkMetadata = extractMistralResponseMetadata(chunk);
20483
+ if (chunkMetadata) {
20484
+ metadata = { ...metadata || {}, ...chunkMetadata };
20485
+ }
20486
+ for (const [choicePosition, rawChoice] of (chunk.choices || []).entries()) {
20487
+ if (!isMistralChunkChoice(rawChoice)) {
17995
20488
  continue;
17996
20489
  }
17997
- const current = existingToolCall;
17998
- if (toolDelta.id && !current.id) {
17999
- current.id = toolDelta.id;
20490
+ const choice = rawChoice;
20491
+ const choiceIndex = typeof choice.index === "number" && choice.index >= 0 ? choice.index : void 0;
20492
+ let accumulatorKey = choiceIndex !== void 0 ? indexToAccumulatorKey.get(choiceIndex) : void 0;
20493
+ if (!accumulatorKey) {
20494
+ accumulatorKey = positionToAccumulatorKey.get(choicePosition);
20495
+ }
20496
+ if (!accumulatorKey) {
20497
+ const initialIndex = choiceIndex ?? choicePosition;
20498
+ const keyPrefix = choiceIndex !== void 0 ? "index" : "position";
20499
+ accumulatorKey = `${keyPrefix}:${initialIndex}`;
20500
+ choiceAccumulators.set(accumulatorKey, {
20501
+ index: initialIndex,
20502
+ order: nextAccumulatorOrder++
20503
+ });
18000
20504
  }
18001
- if (toolDelta.type && !current.type) {
18002
- current.type = toolDelta.type;
20505
+ const accumulator = choiceAccumulators.get(accumulatorKey);
20506
+ if (!accumulator) {
20507
+ continue;
18003
20508
  }
18004
- if (toolDelta.function.name && !current.function.name) {
18005
- current.function.name = toolDelta.function.name;
20509
+ if (choiceIndex !== void 0) {
20510
+ accumulator.index = choiceIndex;
20511
+ indexToAccumulatorKey.set(choiceIndex, accumulatorKey);
18006
20512
  }
18007
- current.function.arguments += toolDelta.function.arguments || "";
18008
- }
18009
- }
18010
- return {
18011
- output: [
18012
- {
18013
- index: 0,
18014
- message: {
18015
- role,
18016
- content: content || void 0,
18017
- ...toolCalls ? { tool_calls: toolCalls } : {}
18018
- },
18019
- logprobs: null,
18020
- finish_reason: finishReason
20513
+ positionToAccumulatorKey.set(choicePosition, accumulatorKey);
20514
+ const delta = isObject(choice.delta) ? choice.delta : void 0;
20515
+ if (delta) {
20516
+ if (!accumulator.role && typeof delta.role === "string") {
20517
+ accumulator.role = delta.role;
20518
+ }
20519
+ const deltaText = extractDeltaText(delta.content);
20520
+ if (deltaText) {
20521
+ accumulator.content = `${accumulator.content || ""}${deltaText}`;
20522
+ }
20523
+ accumulator.toolCalls = mergeToolCallDeltas(
20524
+ accumulator.toolCalls,
20525
+ getDeltaToolCalls(delta)
20526
+ );
20527
+ }
20528
+ const choiceFinishReason = getChoiceFinishReason(choice);
20529
+ if (choiceFinishReason !== void 0) {
20530
+ accumulator.finishReason = choiceFinishReason;
18021
20531
  }
18022
- ],
18023
- metrics
18024
- };
18025
- }
18026
- function aggregateOpenRouterResponseStreamEvents(chunks) {
18027
- let finalResponse;
18028
- for (const chunk of chunks) {
18029
- const response = chunk?.response;
18030
- if (!response) {
18031
- continue;
18032
- }
18033
- if (chunk.type === "response.completed" || chunk.type === "response.incomplete" || chunk.type === "response.failed") {
18034
- finalResponse = response;
18035
20532
  }
18036
20533
  }
18037
- if (!finalResponse) {
18038
- return {
18039
- output: void 0,
18040
- metrics: {}
18041
- };
18042
- }
20534
+ const output = Array.from(choiceAccumulators.values()).sort(
20535
+ (left, right) => left.index === right.index ? left.order - right.order : left.index - right.index
20536
+ ).map((choice) => ({
20537
+ index: choice.index,
20538
+ message: {
20539
+ ...choice.role ? { role: choice.role } : {},
20540
+ content: choice.content ?? null,
20541
+ ...choice.toolCalls ? { toolCalls: choice.toolCalls } : {}
20542
+ },
20543
+ ...choice.finishReason !== void 0 ? { finishReason: choice.finishReason } : {}
20544
+ }));
18043
20545
  return {
18044
- output: extractOpenRouterResponseOutput(finalResponse),
18045
- metrics: parseOpenRouterMetricsFromUsage(finalResponse.usage),
18046
- ...extractOpenRouterResponseMetadata(finalResponse) ? { metadata: extractOpenRouterResponseMetadata(finalResponse) } : {}
20546
+ output,
20547
+ metrics,
20548
+ ...metadata ? { metadata } : {}
18047
20549
  };
18048
20550
  }
18049
20551
 
@@ -18056,6 +20558,8 @@ var BraintrustPlugin = class extends BasePlugin {
18056
20558
  claudeAgentSDKPlugin = null;
18057
20559
  googleGenAIPlugin = null;
18058
20560
  openRouterPlugin = null;
20561
+ openRouterAgentPlugin = null;
20562
+ mistralPlugin = null;
18059
20563
  constructor(config3 = {}) {
18060
20564
  super();
18061
20565
  this.config = config3;
@@ -18086,6 +20590,14 @@ var BraintrustPlugin = class extends BasePlugin {
18086
20590
  this.openRouterPlugin = new OpenRouterPlugin();
18087
20591
  this.openRouterPlugin.enable();
18088
20592
  }
20593
+ if (integrations.openrouterAgent !== false) {
20594
+ this.openRouterAgentPlugin = new OpenRouterAgentPlugin();
20595
+ this.openRouterAgentPlugin.enable();
20596
+ }
20597
+ if (integrations.mistral !== false) {
20598
+ this.mistralPlugin = new MistralPlugin();
20599
+ this.mistralPlugin.enable();
20600
+ }
18089
20601
  }
18090
20602
  onDisable() {
18091
20603
  if (this.openaiPlugin) {
@@ -18112,6 +20624,14 @@ var BraintrustPlugin = class extends BasePlugin {
18112
20624
  this.openRouterPlugin.disable();
18113
20625
  this.openRouterPlugin = null;
18114
20626
  }
20627
+ if (this.openRouterAgentPlugin) {
20628
+ this.openRouterAgentPlugin.disable();
20629
+ this.openRouterAgentPlugin = null;
20630
+ }
20631
+ if (this.mistralPlugin) {
20632
+ this.mistralPlugin.disable();
20633
+ this.mistralPlugin = null;
20634
+ }
18115
20635
  }
18116
20636
  };
18117
20637
 
@@ -18184,7 +20704,9 @@ var PluginRegistry = class {
18184
20704
  aisdk: true,
18185
20705
  google: true,
18186
20706
  claudeAgentSDK: true,
18187
- openrouter: true
20707
+ openrouter: true,
20708
+ openrouterAgent: true,
20709
+ mistral: true
18188
20710
  };
18189
20711
  }
18190
20712
  /**
@@ -18654,7 +21176,8 @@ var ScorerBuilder = class {
18654
21176
  type: "llm_classifier",
18655
21177
  use_cot: opts.useCot,
18656
21178
  choice_scores: opts.choiceScores
18657
- }
21179
+ },
21180
+ ...opts.templateFormat ? { template_format: opts.templateFormat } : {}
18658
21181
  };
18659
21182
  const codePrompt = new CodePrompt(
18660
21183
  this.project,
@@ -19967,7 +22490,7 @@ var parametersContainerSchema = import_v315.z.object({
19967
22490
  var staticParametersContainerSchema = import_v315.z.object({
19968
22491
  type: import_v315.z.literal("braintrust.staticParameters"),
19969
22492
  schema: staticParametersSchema,
19970
- source: import_v315.z.null()
22493
+ source: import_v315.z.null().nullish()
19971
22494
  });
19972
22495
  var serializedParametersContainerSchema = import_v315.z.union([
19973
22496
  parametersContainerSchema,