braintrust 3.8.0 → 3.9.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 (48) hide show
  1. package/dev/dist/index.d.mts +84 -3
  2. package/dev/dist/index.d.ts +84 -3
  3. package/dev/dist/index.js +3687 -691
  4. package/dev/dist/index.mjs +3399 -403
  5. package/dist/auto-instrumentations/bundler/esbuild.cjs +575 -2
  6. package/dist/auto-instrumentations/bundler/esbuild.mjs +2 -2
  7. package/dist/auto-instrumentations/bundler/rollup.cjs +575 -2
  8. package/dist/auto-instrumentations/bundler/rollup.mjs +2 -2
  9. package/dist/auto-instrumentations/bundler/vite.cjs +575 -2
  10. package/dist/auto-instrumentations/bundler/vite.mjs +2 -2
  11. package/dist/auto-instrumentations/bundler/webpack-loader.cjs +575 -2
  12. package/dist/auto-instrumentations/bundler/webpack.cjs +575 -2
  13. package/dist/auto-instrumentations/bundler/webpack.mjs +2 -2
  14. package/dist/auto-instrumentations/{chunk-MD7W27YH.mjs → chunk-G7F6HZGE.mjs} +5 -1
  15. package/dist/auto-instrumentations/{chunk-OLBMPZXE.mjs → chunk-KIMMUFAK.mjs} +578 -3
  16. package/dist/auto-instrumentations/hook.mjs +757 -10
  17. package/dist/auto-instrumentations/index.cjs +739 -2
  18. package/dist/auto-instrumentations/index.d.mts +18 -1
  19. package/dist/auto-instrumentations/index.d.ts +18 -1
  20. package/dist/auto-instrumentations/index.mjs +168 -1
  21. package/dist/auto-instrumentations/loader/esm-hook.mjs +2 -1
  22. package/dist/browser.d.mts +312 -6
  23. package/dist/browser.d.ts +312 -6
  24. package/dist/browser.js +5335 -1892
  25. package/dist/browser.mjs +5335 -1892
  26. package/dist/cli.js +3514 -489
  27. package/dist/edge-light.d.mts +1 -1
  28. package/dist/edge-light.d.ts +1 -1
  29. package/dist/edge-light.js +5335 -1892
  30. package/dist/edge-light.mjs +5335 -1892
  31. package/dist/index.d.mts +312 -6
  32. package/dist/index.d.ts +312 -6
  33. package/dist/index.js +4244 -801
  34. package/dist/index.mjs +5335 -1892
  35. package/dist/instrumentation/index.d.mts +10 -0
  36. package/dist/instrumentation/index.d.ts +10 -0
  37. package/dist/instrumentation/index.js +3160 -286
  38. package/dist/instrumentation/index.mjs +3160 -286
  39. package/dist/workerd.d.mts +1 -1
  40. package/dist/workerd.d.ts +1 -1
  41. package/dist/workerd.js +5335 -1892
  42. package/dist/workerd.mjs +5335 -1892
  43. package/package.json +52 -47
  44. package/util/dist/index.d.mts +42 -1
  45. package/util/dist/index.d.ts +42 -1
  46. package/util/dist/index.js +5 -1
  47. package/util/dist/index.mjs +4 -0
  48. package/LICENSE +0 -201
@@ -1218,6 +1218,9 @@ function isArray(value) {
1218
1218
  function isObjectOrArray(value) {
1219
1219
  return value instanceof Object;
1220
1220
  }
1221
+ function isPromiseLike(value) {
1222
+ return value != null && (typeof value === "object" || typeof value === "function") && "then" in value && typeof value.then === "function";
1223
+ }
1221
1224
 
1222
1225
  // util/object_util.ts
1223
1226
  var SET_UNION_FIELDS = /* @__PURE__ */ new Set(["tags"]);
@@ -2317,7 +2320,11 @@ var CodeBundle = z6.object({
2317
2320
  eval_name: z6.string(),
2318
2321
  position: z6.union([
2319
2322
  z6.object({ type: z6.literal("task") }),
2320
- z6.object({ type: z6.literal("scorer"), index: z6.number().int().gte(0) })
2323
+ z6.object({ type: z6.literal("scorer"), index: z6.number().int().gte(0) }),
2324
+ z6.object({
2325
+ type: z6.literal("classifier"),
2326
+ index: z6.number().int().gte(0)
2327
+ })
2321
2328
  ])
2322
2329
  }),
2323
2330
  z6.object({ type: z6.literal("function"), index: z6.number().int().gte(0) }),
@@ -3439,11 +3446,15 @@ var RunEval = z6.object({
3439
3446
  data: z6.union([
3440
3447
  z6.object({
3441
3448
  dataset_id: z6.string(),
3449
+ dataset_version: z6.union([z6.string(), z6.null()]).optional(),
3450
+ dataset_environment: z6.union([z6.string(), z6.null()]).optional(),
3442
3451
  _internal_btql: z6.union([z6.object({}).partial().passthrough(), z6.null()]).optional()
3443
3452
  }),
3444
3453
  z6.object({
3445
3454
  project_name: z6.string(),
3446
3455
  dataset_name: z6.string(),
3456
+ dataset_version: z6.union([z6.string(), z6.null()]).optional(),
3457
+ dataset_environment: z6.union([z6.string(), z6.null()]).optional(),
3447
3458
  _internal_btql: z6.union([z6.object({}).partial().passthrough(), z6.null()]).optional()
3448
3459
  }),
3449
3460
  z6.object({ data: z6.array(z6.unknown()) })
@@ -3571,6 +3582,7 @@ var ViewOptions = z6.union([
3571
3582
  rowHeight: z6.union([z6.string(), z6.null()]),
3572
3583
  tallGroupRows: z6.union([z6.boolean(), z6.null()]),
3573
3584
  layout: z6.union([z6.string(), z6.null()]),
3585
+ topicMapReportKey: z6.union([z6.string(), z6.null()]),
3574
3586
  chartHeight: z6.union([z6.number(), z6.null()]),
3575
3587
  excludedMeasures: z6.union([
3576
3588
  z6.array(
@@ -3613,6 +3625,7 @@ var ViewOptions = z6.union([
3613
3625
  z6.null()
3614
3626
  ]),
3615
3627
  queryShape: z6.union([z6.enum(["traces", "spans"]), z6.null()]),
3628
+ cluster: z6.union([z6.string(), z6.null()]),
3616
3629
  freezeColumns: z6.union([z6.boolean(), z6.null()])
3617
3630
  }).partial(),
3618
3631
  z6.null()
@@ -7252,8 +7265,9 @@ function validateAndSanitizeExperimentLogPartialArgs(event) {
7252
7265
  }
7253
7266
  function deepCopyEvent(event) {
7254
7267
  const attachments = [];
7255
- const IDENTIFIER = "_bt_internal_saved_attachment";
7256
- const savedAttachmentSchema = z8.strictObject({ [IDENTIFIER]: z8.number() });
7268
+ const ATTACHMENT_INDEX_KEY = "_bt_internal_saved_attachment_idx";
7269
+ const ATTACHMENT_MARKER_KEY = "_bt_internal_saved_attachment_marker";
7270
+ const attachmentMarker = ++deepCopyEventMarkerCounter;
7257
7271
  const serialized = JSON.stringify(event, (_k, v) => {
7258
7272
  if (v instanceof SpanImpl || v instanceof NoopSpan) {
7259
7273
  return `<span>`;
@@ -7265,21 +7279,39 @@ function deepCopyEvent(event) {
7265
7279
  return `<logger>`;
7266
7280
  } else if (v instanceof BaseAttachment) {
7267
7281
  const idx = attachments.push(v);
7268
- return { [IDENTIFIER]: idx - 1 };
7282
+ return {
7283
+ [ATTACHMENT_INDEX_KEY]: idx - 1,
7284
+ [ATTACHMENT_MARKER_KEY]: attachmentMarker
7285
+ };
7269
7286
  } else if (v instanceof ReadonlyAttachment) {
7270
7287
  return v.reference;
7271
7288
  }
7272
7289
  return v;
7273
7290
  });
7274
7291
  const x = JSON.parse(serialized, (_k, v) => {
7275
- const parsedAttachment = savedAttachmentSchema.safeParse(v);
7276
- if (parsedAttachment.success) {
7277
- return attachments[parsedAttachment.data[IDENTIFIER]];
7292
+ if (isDeepCopyAttachmentPlaceholder(v, attachmentMarker)) {
7293
+ return attachments[v[ATTACHMENT_INDEX_KEY]];
7278
7294
  }
7279
7295
  return v;
7280
7296
  });
7281
7297
  return x;
7282
7298
  }
7299
+ var deepCopyEventMarkerCounter = 0;
7300
+ function isDeepCopyAttachmentPlaceholder(value, attachmentMarker) {
7301
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
7302
+ return false;
7303
+ }
7304
+ const record = value;
7305
+ if (!Object.hasOwn(record, "_bt_internal_saved_attachment_idx") || !Object.hasOwn(record, "_bt_internal_saved_attachment_marker")) {
7306
+ return false;
7307
+ }
7308
+ if (Object.keys(record).length !== 2) {
7309
+ return false;
7310
+ }
7311
+ const attachmentIndex = record._bt_internal_saved_attachment_idx;
7312
+ const marker = record._bt_internal_saved_attachment_marker;
7313
+ return Number.isInteger(attachmentIndex) && attachmentIndex >= 0 && marker === attachmentMarker;
7314
+ }
7283
7315
  function extractAttachments(event, attachments) {
7284
7316
  for (const [key, value] of Object.entries(event)) {
7285
7317
  if (!value) {
@@ -8889,6 +8921,16 @@ var TEST_API_KEY = "___TEST_API_KEY__THIS_IS_NOT_REAL___";
8889
8921
  function isAsyncIterable(value) {
8890
8922
  return value !== null && typeof value === "object" && Symbol.asyncIterator in value && typeof value[Symbol.asyncIterator] === "function";
8891
8923
  }
8924
+ function hasAsyncIteratorMethods(value) {
8925
+ return value !== null && typeof value === "object" && "next" in value && typeof value.next === "function";
8926
+ }
8927
+ function isSelfAsyncIterator(value) {
8928
+ try {
8929
+ return value[Symbol.asyncIterator]() === value;
8930
+ } catch {
8931
+ return false;
8932
+ }
8933
+ }
8892
8934
  function patchStreamIfNeeded(stream, options) {
8893
8935
  if (!isAsyncIterable(stream)) {
8894
8936
  return stream;
@@ -8899,6 +8941,98 @@ function patchStreamIfNeeded(stream, options) {
8899
8941
  );
8900
8942
  return stream;
8901
8943
  }
8944
+ if (hasAsyncIteratorMethods(stream) && isSelfAsyncIterator(stream)) {
8945
+ if ("__braintrust_patched_iterator_methods" in stream) {
8946
+ return stream;
8947
+ }
8948
+ try {
8949
+ const originalNext = stream.next.bind(stream);
8950
+ const originalReturn = typeof stream.return === "function" ? stream.return.bind(stream) : null;
8951
+ const originalThrow = typeof stream.throw === "function" ? stream.throw.bind(stream) : null;
8952
+ const chunks = [];
8953
+ let completed = false;
8954
+ stream.next = async (...args) => {
8955
+ try {
8956
+ const result = await originalNext(...args);
8957
+ if (result.done) {
8958
+ if (!completed) {
8959
+ completed = true;
8960
+ try {
8961
+ await options.onComplete(chunks);
8962
+ } catch (error) {
8963
+ console.error("Error in stream onComplete handler:", error);
8964
+ }
8965
+ }
8966
+ } else {
8967
+ const chunk = result.value;
8968
+ const shouldCollect = options.shouldCollect ? options.shouldCollect(chunk) : true;
8969
+ if (shouldCollect) {
8970
+ chunks.push(chunk);
8971
+ if (options.onChunk) {
8972
+ try {
8973
+ await options.onChunk(chunk);
8974
+ } catch (error) {
8975
+ console.error("Error in stream onChunk handler:", error);
8976
+ }
8977
+ }
8978
+ }
8979
+ }
8980
+ return result;
8981
+ } catch (error) {
8982
+ if (!completed) {
8983
+ completed = true;
8984
+ if (options.onError) {
8985
+ try {
8986
+ await options.onError(
8987
+ error instanceof Error ? error : new Error(String(error)),
8988
+ chunks
8989
+ );
8990
+ } catch (handlerError) {
8991
+ console.error("Error in stream onError handler:", handlerError);
8992
+ }
8993
+ }
8994
+ }
8995
+ throw error;
8996
+ }
8997
+ };
8998
+ if (originalReturn) {
8999
+ stream.return = async (...args) => {
9000
+ if (!completed) {
9001
+ completed = true;
9002
+ try {
9003
+ await options.onComplete(chunks);
9004
+ } catch (error) {
9005
+ console.error("Error in stream onComplete handler:", error);
9006
+ }
9007
+ }
9008
+ return originalReturn(...args);
9009
+ };
9010
+ }
9011
+ if (originalThrow) {
9012
+ stream.throw = async (...args) => {
9013
+ if (!completed) {
9014
+ completed = true;
9015
+ const rawError = args[0];
9016
+ const error = rawError instanceof Error ? rawError : new Error(String(rawError));
9017
+ if (options.onError) {
9018
+ try {
9019
+ await options.onError(error, chunks);
9020
+ } catch (handlerError) {
9021
+ console.error("Error in stream onError handler:", handlerError);
9022
+ }
9023
+ }
9024
+ }
9025
+ return originalThrow(...args);
9026
+ };
9027
+ }
9028
+ Object.defineProperty(stream, "__braintrust_patched_iterator_methods", {
9029
+ value: true
9030
+ });
9031
+ return stream;
9032
+ } catch (error) {
9033
+ console.warn("Failed to patch stream iterator methods:", error);
9034
+ }
9035
+ }
8902
9036
  const originalIteratorFn = stream[Symbol.asyncIterator];
8903
9037
  if ("__braintrust_patched" in originalIteratorFn && originalIteratorFn["__braintrust_patched"]) {
8904
9038
  return stream;
@@ -10455,10 +10589,42 @@ function processImagesInOutput(output) {
10455
10589
  }
10456
10590
  return output;
10457
10591
  }
10592
+ function mergeLogprobTokens(existing, incoming) {
10593
+ if (incoming === void 0) {
10594
+ return existing;
10595
+ }
10596
+ if (incoming === null) {
10597
+ return existing ?? null;
10598
+ }
10599
+ if (Array.isArray(existing)) {
10600
+ return [...existing, ...incoming];
10601
+ }
10602
+ return [...incoming];
10603
+ }
10604
+ function aggregateChatLogprobs(existing, incoming) {
10605
+ if (incoming === void 0) {
10606
+ return existing;
10607
+ }
10608
+ if (incoming === null) {
10609
+ return existing ?? null;
10610
+ }
10611
+ const aggregated = existing && existing !== null ? { ...existing, ...incoming } : { ...incoming };
10612
+ const content = mergeLogprobTokens(existing?.content, incoming.content);
10613
+ if (content !== void 0) {
10614
+ aggregated.content = content;
10615
+ }
10616
+ const refusal = mergeLogprobTokens(existing?.refusal, incoming.refusal);
10617
+ if (refusal !== void 0) {
10618
+ aggregated.refusal = refusal;
10619
+ }
10620
+ return aggregated;
10621
+ }
10458
10622
  function aggregateChatCompletionChunks(chunks, streamResult, endEvent) {
10459
10623
  let role = void 0;
10460
10624
  let content = void 0;
10625
+ let refusal = void 0;
10461
10626
  let tool_calls = void 0;
10627
+ let logprobs = void 0;
10462
10628
  let finish_reason = void 0;
10463
10629
  let metrics = {};
10464
10630
  for (const chunk of chunks) {
@@ -10468,19 +10634,30 @@ function aggregateChatCompletionChunks(chunks, streamResult, endEvent) {
10468
10634
  ...parseMetricsFromUsage(chunk.usage)
10469
10635
  };
10470
10636
  }
10471
- const delta = chunk.choices?.[0]?.delta;
10472
- if (!delta) {
10637
+ const choice = chunk.choices?.[0];
10638
+ if (!choice) {
10473
10639
  continue;
10474
10640
  }
10475
- if (!role && delta.role) {
10476
- role = delta.role;
10641
+ if (choice.finish_reason) {
10642
+ finish_reason = choice.finish_reason;
10643
+ }
10644
+ logprobs = aggregateChatLogprobs(logprobs, choice.logprobs);
10645
+ const delta = choice.delta;
10646
+ if (!delta) {
10647
+ continue;
10477
10648
  }
10478
10649
  if (delta.finish_reason) {
10479
10650
  finish_reason = delta.finish_reason;
10480
10651
  }
10652
+ if (!role && delta.role) {
10653
+ role = delta.role;
10654
+ }
10481
10655
  if (delta.content) {
10482
10656
  content = (content || "") + delta.content;
10483
10657
  }
10658
+ if (delta.refusal) {
10659
+ refusal = (refusal || "") + delta.refusal;
10660
+ }
10484
10661
  if (delta.tool_calls) {
10485
10662
  const toolDelta = delta.tool_calls[0];
10486
10663
  if (!tool_calls || toolDelta.id && tool_calls[tool_calls.length - 1].id !== toolDelta.id) {
@@ -10506,9 +10683,10 @@ function aggregateChatCompletionChunks(chunks, streamResult, endEvent) {
10506
10683
  message: {
10507
10684
  role,
10508
10685
  content,
10686
+ ...refusal !== void 0 ? { refusal } : {},
10509
10687
  tool_calls
10510
10688
  },
10511
- logprobs: null,
10689
+ logprobs: logprobs ?? null,
10512
10690
  finish_reason
10513
10691
  }
10514
10692
  ]
@@ -10571,13 +10749,21 @@ var anthropicChannels = defineChannels("@anthropic-ai/sdk", {
10571
10749
  betaMessagesCreate: channel({
10572
10750
  channelName: "beta.messages.create",
10573
10751
  kind: "async"
10752
+ }),
10753
+ betaMessagesToolRunner: channel({
10754
+ channelName: "beta.messages.toolRunner",
10755
+ kind: "sync-stream"
10574
10756
  })
10575
10757
  });
10576
10758
 
10577
10759
  // src/instrumentation/plugins/anthropic-plugin.ts
10760
+ var ANTHROPIC_TOOL_RUNNER_TOOL_WRAPPED = Symbol.for(
10761
+ "braintrust.anthropic_tool_runner_tool_wrapped"
10762
+ );
10578
10763
  var AnthropicPlugin = class extends BasePlugin {
10579
10764
  onEnable() {
10580
10765
  this.subscribeToAnthropicChannels();
10766
+ this.subscribeToAnthropicToolRunner();
10581
10767
  }
10582
10768
  onDisable() {
10583
10769
  this.unsubscribers = unsubscribeAll(this.unsubscribers);
@@ -10632,6 +10818,61 @@ var AnthropicPlugin = class extends BasePlugin {
10632
10818
  })
10633
10819
  );
10634
10820
  }
10821
+ subscribeToAnthropicToolRunner() {
10822
+ const tracingChannel2 = anthropicChannels.betaMessagesToolRunner.tracingChannel();
10823
+ const states = /* @__PURE__ */ new WeakMap();
10824
+ const handlers = {
10825
+ start: (event) => {
10826
+ const params = event.arguments[0] ?? {};
10827
+ const span = startSpan({
10828
+ name: "anthropic.beta.messages.toolRunner",
10829
+ spanAttributes: {
10830
+ type: "task" /* TASK */
10831
+ }
10832
+ });
10833
+ span.log({
10834
+ input: processAttachmentsInInput(
10835
+ coalesceInput(params.messages ?? [], params.system)
10836
+ ),
10837
+ metadata: {
10838
+ ...extractAnthropicToolRunnerMetadata(params),
10839
+ provider: "anthropic"
10840
+ }
10841
+ });
10842
+ const state = {
10843
+ aggregatedMetrics: {},
10844
+ finalized: false,
10845
+ iterationCount: 0,
10846
+ seenMessages: /* @__PURE__ */ new WeakSet(),
10847
+ span,
10848
+ startTime: getCurrentUnixTimestamp()
10849
+ };
10850
+ states.set(event, state);
10851
+ },
10852
+ end: (event) => {
10853
+ const state = states.get(event);
10854
+ if (!state) {
10855
+ return;
10856
+ }
10857
+ patchAnthropicToolRunner({
10858
+ runner: event.result,
10859
+ state
10860
+ });
10861
+ },
10862
+ error: (event) => {
10863
+ const state = states.get(event);
10864
+ if (!state || !event.error) {
10865
+ return;
10866
+ }
10867
+ finalizeAnthropicToolRunnerError(state, event.error);
10868
+ states.delete(event);
10869
+ }
10870
+ };
10871
+ tracingChannel2.subscribe(handlers);
10872
+ this.unsubscribers.push(() => {
10873
+ tracingChannel2.unsubscribe(handlers);
10874
+ });
10875
+ }
10635
10876
  };
10636
10877
  function parseMetricsFromUsage2(usage) {
10637
10878
  if (!usage) {
@@ -10648,71 +10889,410 @@ function parseMetricsFromUsage2(usage) {
10648
10889
  saveIfExistsTo("output_tokens", "completion_tokens");
10649
10890
  saveIfExistsTo("cache_read_input_tokens", "prompt_cached_tokens");
10650
10891
  saveIfExistsTo("cache_creation_input_tokens", "prompt_cache_creation_tokens");
10892
+ if (isObject(usage.server_tool_use)) {
10893
+ for (const [name, value] of Object.entries(usage.server_tool_use)) {
10894
+ if (typeof value === "number") {
10895
+ metrics[`server_tool_use_${name}`] = value;
10896
+ }
10897
+ }
10898
+ }
10651
10899
  return metrics;
10652
10900
  }
10653
- function aggregateAnthropicStreamChunks(chunks) {
10654
- const fallbackTextDeltas = [];
10655
- const contentBlocks = {};
10656
- const contentBlockDeltas = {};
10657
- let metrics = {};
10658
- let metadata = {};
10659
- let role;
10660
- for (const event of chunks) {
10661
- switch (event?.type) {
10662
- case "message_start":
10663
- if (event.message?.usage) {
10664
- const initialMetrics = parseMetricsFromUsage2(event.message.usage);
10665
- metrics = { ...metrics, ...initialMetrics };
10666
- }
10667
- if (typeof event.message?.role === "string") {
10668
- role = event.message.role;
10669
- }
10670
- break;
10671
- case "content_block_start":
10672
- if (event.content_block) {
10673
- contentBlocks[event.index] = event.content_block;
10674
- contentBlockDeltas[event.index] = { textDeltas: [], citations: [] };
10675
- }
10676
- break;
10677
- case "content_block_delta": {
10678
- const acc = contentBlockDeltas[event.index];
10679
- const delta = event.delta;
10680
- if (!delta) break;
10681
- if (delta.type === "text_delta" && "text" in delta) {
10682
- const text = delta.text;
10683
- if (text) {
10684
- if (acc !== void 0) {
10685
- acc.textDeltas.push(text);
10686
- } else {
10687
- fallbackTextDeltas.push(text);
10901
+ function extractAnthropicToolRunnerMetadata(params) {
10902
+ const metadata = filterFrom(params, ["messages", "system", "tools"]);
10903
+ const toolNames = extractAnthropicToolNames(params.tools);
10904
+ return {
10905
+ ...metadata,
10906
+ operation: "toolRunner",
10907
+ ...toolNames.length > 0 ? { tool_names: toolNames } : {}
10908
+ };
10909
+ }
10910
+ function extractAnthropicToolNames(tools) {
10911
+ const toolNames = [];
10912
+ for (const tool of tools) {
10913
+ if (!tool || typeof tool !== "object") {
10914
+ continue;
10915
+ }
10916
+ const toolRecord = tool;
10917
+ if (typeof toolRecord.name === "string") {
10918
+ toolNames.push(toolRecord.name);
10919
+ continue;
10920
+ }
10921
+ if (typeof toolRecord.mcp_server_name === "string") {
10922
+ toolNames.push(toolRecord.mcp_server_name);
10923
+ }
10924
+ }
10925
+ return toolNames;
10926
+ }
10927
+ function toErrorMessage(error) {
10928
+ return error instanceof Error ? error.message : String(error);
10929
+ }
10930
+ function getAnthropicToolRunnerInput(args) {
10931
+ return args.length > 0 ? args[0] : void 0;
10932
+ }
10933
+ function wrapAnthropicToolRunnerTools(params, state) {
10934
+ if (!Array.isArray(params.tools)) {
10935
+ return;
10936
+ }
10937
+ params.tools = params.tools.map(
10938
+ (tool, index) => wrapAnthropicToolRunnerTool(tool, index, state)
10939
+ );
10940
+ }
10941
+ function wrapAnthropicToolRunnerTool(tool, index, state) {
10942
+ if (!tool || typeof tool !== "object" || typeof tool.run !== "function" || tool[ANTHROPIC_TOOL_RUNNER_TOOL_WRAPPED]) {
10943
+ return tool;
10944
+ }
10945
+ const toolName = typeof tool.name === "string" ? tool.name : `tool[${index}]`;
10946
+ const originalRun = tool.run;
10947
+ const runDescriptor = Object.getOwnPropertyDescriptor(tool, "run");
10948
+ const wrappedTool = Object.create(
10949
+ Object.getPrototypeOf(tool),
10950
+ Object.getOwnPropertyDescriptors(tool)
10951
+ );
10952
+ Object.defineProperty(wrappedTool, "run", {
10953
+ configurable: runDescriptor?.configurable ?? true,
10954
+ enumerable: runDescriptor?.enumerable ?? true,
10955
+ value: function braintrustAnthropicToolRunnerRun(...args) {
10956
+ return state.span.traced(
10957
+ (span) => {
10958
+ const finalizeSuccess = (result) => {
10959
+ span.log({ output: result });
10960
+ return result;
10961
+ };
10962
+ const finalizeError = (error) => {
10963
+ span.log({ error: toErrorMessage(error) });
10964
+ throw error;
10965
+ };
10966
+ try {
10967
+ const result = Reflect.apply(originalRun, this, args);
10968
+ if (isPromiseLike(result)) {
10969
+ return result.then(finalizeSuccess, finalizeError);
10688
10970
  }
10971
+ return finalizeSuccess(result);
10972
+ } catch (error) {
10973
+ return finalizeError(error);
10689
10974
  }
10690
- } else if (delta.type === "input_json_delta" && "partial_json" in delta) {
10691
- const partialJson = delta.partial_json;
10692
- if (partialJson && acc !== void 0) {
10693
- acc.textDeltas.push(partialJson);
10694
- }
10695
- } else if (delta.type === "thinking_delta" && "thinking" in delta) {
10696
- const thinking = delta.thinking;
10697
- if (thinking && acc !== void 0) {
10698
- acc.textDeltas.push(thinking);
10699
- }
10700
- } else if (delta.type === "citations_delta" && "citation" in delta) {
10701
- const citation = delta.citation;
10702
- if (citation && acc !== void 0) {
10703
- acc.citations.push(citation);
10975
+ },
10976
+ {
10977
+ event: {
10978
+ input: getAnthropicToolRunnerInput(args),
10979
+ metadata: {
10980
+ "gen_ai.tool.name": toolName,
10981
+ provider: "anthropic"
10982
+ }
10983
+ },
10984
+ name: `tool: ${toolName}`,
10985
+ spanAttributes: {
10986
+ type: "tool" /* TOOL */
10704
10987
  }
10705
10988
  }
10706
- break;
10707
- }
10708
- case "content_block_stop":
10709
- finalizeContentBlock(
10710
- event.index,
10711
- contentBlocks,
10712
- contentBlockDeltas,
10713
- fallbackTextDeltas
10714
- );
10715
- break;
10989
+ );
10990
+ },
10991
+ writable: runDescriptor?.writable ?? true
10992
+ });
10993
+ Object.defineProperty(wrappedTool, ANTHROPIC_TOOL_RUNNER_TOOL_WRAPPED, {
10994
+ configurable: false,
10995
+ enumerable: false,
10996
+ value: true,
10997
+ writable: false
10998
+ });
10999
+ return wrappedTool;
11000
+ }
11001
+ function getAnthropicToolRunnerParams(runnerRecord) {
11002
+ const params = Reflect.get(runnerRecord, "params");
11003
+ return params && typeof params === "object" ? params : void 0;
11004
+ }
11005
+ function ensureAnthropicToolRunnerToolsWrapped(runnerRecord, state) {
11006
+ const params = getAnthropicToolRunnerParams(runnerRecord);
11007
+ if (params) {
11008
+ wrapAnthropicToolRunnerTools(params, state);
11009
+ }
11010
+ }
11011
+ function wrapAnthropicToolRunnerSetMessagesParams(runnerRecord, state) {
11012
+ const setMessagesParams = Reflect.get(runnerRecord, "setMessagesParams");
11013
+ if (typeof setMessagesParams !== "function") {
11014
+ return;
11015
+ }
11016
+ Reflect.set(
11017
+ runnerRecord,
11018
+ "setMessagesParams",
11019
+ function patchedSetMessagesParams(...args) {
11020
+ const result = Reflect.apply(setMessagesParams, this, args);
11021
+ const nextParams = getAnthropicToolRunnerParams(runnerRecord);
11022
+ if (nextParams) {
11023
+ wrapAnthropicToolRunnerTools(nextParams, state);
11024
+ }
11025
+ return result;
11026
+ }
11027
+ );
11028
+ }
11029
+ function isAnthropicMessage(value) {
11030
+ return !!value && typeof value === "object" && typeof value.role === "string" && Array.isArray(value.content);
11031
+ }
11032
+ function isAnthropicMessageStream(value) {
11033
+ return !!value && typeof value === "object" && isAsyncIterable(value) && "finalMessage" in value && typeof value.finalMessage === "function";
11034
+ }
11035
+ function recordAnthropicToolRunnerMessage(state, message) {
11036
+ if (typeof message !== "object" || message === null) {
11037
+ return;
11038
+ }
11039
+ if (state.seenMessages.has(message)) {
11040
+ state.lastMessage = message;
11041
+ return;
11042
+ }
11043
+ state.seenMessages.add(message);
11044
+ state.lastMessage = message;
11045
+ const parsedMetrics = parseMetricsFromUsage2(message.usage);
11046
+ for (const [key, value] of Object.entries(parsedMetrics)) {
11047
+ if (typeof value === "number") {
11048
+ state.aggregatedMetrics[key] = (state.aggregatedMetrics[key] ?? 0) + value;
11049
+ }
11050
+ }
11051
+ }
11052
+ function instrumentAnthropicMessageStream(stream, state) {
11053
+ if ("__braintrust_tool_runner_stream_patched" in stream) {
11054
+ return;
11055
+ }
11056
+ if (!Object.isFrozen(stream) && !Object.isSealed(stream)) {
11057
+ patchStreamIfNeeded(stream, {
11058
+ onChunk: () => {
11059
+ if (state.firstTokenTime === void 0) {
11060
+ state.firstTokenTime = getCurrentUnixTimestamp();
11061
+ }
11062
+ },
11063
+ onComplete: () => void 0
11064
+ });
11065
+ }
11066
+ if (typeof stream.finalMessage === "function") {
11067
+ const originalFinalMessage = stream.finalMessage.bind(stream);
11068
+ stream.finalMessage = async () => {
11069
+ const message = await originalFinalMessage();
11070
+ recordAnthropicToolRunnerMessage(state, message);
11071
+ return message;
11072
+ };
11073
+ }
11074
+ Object.defineProperty(stream, "__braintrust_tool_runner_stream_patched", {
11075
+ value: true
11076
+ });
11077
+ }
11078
+ async function finalizeAnthropicToolRunner(state, finalMessage) {
11079
+ if (state.finalized) {
11080
+ return;
11081
+ }
11082
+ state.finalized = true;
11083
+ const message = finalMessage ?? state.lastMessage;
11084
+ if (message) {
11085
+ recordAnthropicToolRunnerMessage(state, message);
11086
+ }
11087
+ const metrics = finalizeAnthropicTokens({
11088
+ ...state.aggregatedMetrics
11089
+ });
11090
+ if (state.firstTokenTime !== void 0) {
11091
+ metrics.time_to_first_token = state.firstTokenTime - state.startTime;
11092
+ }
11093
+ const metadata = {
11094
+ anthropic_tool_runner_iterations: state.iterationCount
11095
+ };
11096
+ if (message?.stop_reason !== void 0) {
11097
+ metadata.stop_reason = message.stop_reason;
11098
+ }
11099
+ if (message?.stop_sequence !== void 0) {
11100
+ metadata.stop_sequence = message.stop_sequence;
11101
+ }
11102
+ state.span.log({
11103
+ ...message ? { output: { role: message.role, content: message.content } } : {},
11104
+ metadata,
11105
+ metrics: Object.fromEntries(
11106
+ Object.entries(metrics).filter(
11107
+ (entry) => entry[1] !== void 0
11108
+ )
11109
+ )
11110
+ });
11111
+ state.span.end();
11112
+ }
11113
+ function finalizeAnthropicToolRunnerError(state, error) {
11114
+ if (state.finalized) {
11115
+ return;
11116
+ }
11117
+ state.finalized = true;
11118
+ state.span.log({
11119
+ error: error instanceof Error ? error.message : String(error)
11120
+ });
11121
+ state.span.end();
11122
+ }
11123
+ async function resolveAnthropicToolRunnerFinalMessage(runner) {
11124
+ if (typeof runner.done === "function") {
11125
+ return await runner.done();
11126
+ }
11127
+ if (typeof runner.runUntilDone === "function") {
11128
+ return await runner.runUntilDone();
11129
+ }
11130
+ return void 0;
11131
+ }
11132
+ function wrapAnthropicToolRunnerPromiseMethod(runnerRecord, methodName, state) {
11133
+ const method = runnerRecord[methodName];
11134
+ if (typeof method !== "function") {
11135
+ return;
11136
+ }
11137
+ runnerRecord[methodName] = async (...args) => {
11138
+ ensureAnthropicToolRunnerToolsWrapped(runnerRecord, state);
11139
+ return await withCurrent(state.span, async () => {
11140
+ try {
11141
+ const message = await method.apply(runnerRecord, args);
11142
+ recordAnthropicToolRunnerMessage(state, message);
11143
+ await finalizeAnthropicToolRunner(state, message);
11144
+ return message;
11145
+ } catch (error) {
11146
+ finalizeAnthropicToolRunnerError(state, error);
11147
+ throw error;
11148
+ }
11149
+ });
11150
+ };
11151
+ }
11152
+ function patchAnthropicToolRunner(args) {
11153
+ const { runner, state } = args;
11154
+ if (!runner || typeof runner !== "object") {
11155
+ void finalizeAnthropicToolRunner(state);
11156
+ return;
11157
+ }
11158
+ const runnerRecord = runner;
11159
+ if ("__braintrust_tool_runner_patched" in runnerRecord) {
11160
+ return;
11161
+ }
11162
+ ensureAnthropicToolRunnerToolsWrapped(runnerRecord, state);
11163
+ wrapAnthropicToolRunnerSetMessagesParams(runnerRecord, state);
11164
+ wrapAnthropicToolRunnerPromiseMethod(runnerRecord, "done", state);
11165
+ wrapAnthropicToolRunnerPromiseMethod(runnerRecord, "runUntilDone", state);
11166
+ if (!isAsyncIterable(runnerRecord)) {
11167
+ Object.defineProperty(runnerRecord, "__braintrust_tool_runner_patched", {
11168
+ value: true
11169
+ });
11170
+ return;
11171
+ }
11172
+ const originalIterator = runnerRecord[Symbol.asyncIterator].bind(runnerRecord);
11173
+ runnerRecord[Symbol.asyncIterator] = function() {
11174
+ const iterator = originalIterator();
11175
+ return {
11176
+ async next(value) {
11177
+ try {
11178
+ ensureAnthropicToolRunnerToolsWrapped(runnerRecord, state);
11179
+ const result = await withCurrent(
11180
+ state.span,
11181
+ () => value === void 0 ? iterator.next() : iterator.next(value)
11182
+ );
11183
+ if (result.done) {
11184
+ const finalMessage = await resolveAnthropicToolRunnerFinalMessage(runner);
11185
+ await finalizeAnthropicToolRunner(state, finalMessage);
11186
+ return result;
11187
+ }
11188
+ state.iterationCount += 1;
11189
+ if (isAnthropicMessage(result.value)) {
11190
+ if (state.firstTokenTime === void 0) {
11191
+ state.firstTokenTime = getCurrentUnixTimestamp();
11192
+ }
11193
+ recordAnthropicToolRunnerMessage(state, result.value);
11194
+ } else if (isAnthropicMessageStream(result.value)) {
11195
+ instrumentAnthropicMessageStream(result.value, state);
11196
+ }
11197
+ return result;
11198
+ } catch (error) {
11199
+ finalizeAnthropicToolRunnerError(state, error);
11200
+ throw error;
11201
+ }
11202
+ },
11203
+ async return(value) {
11204
+ try {
11205
+ ensureAnthropicToolRunnerToolsWrapped(runnerRecord, state);
11206
+ const result = typeof iterator.return === "function" ? await withCurrent(state.span, () => iterator.return(value)) : { done: true, value };
11207
+ const finalMessage = await resolveAnthropicToolRunnerFinalMessage(
11208
+ runner
11209
+ ).catch(() => void 0);
11210
+ await finalizeAnthropicToolRunner(state, finalMessage);
11211
+ return result;
11212
+ } catch (error) {
11213
+ finalizeAnthropicToolRunnerError(state, error);
11214
+ throw error;
11215
+ }
11216
+ },
11217
+ async throw(error) {
11218
+ finalizeAnthropicToolRunnerError(state, error);
11219
+ if (typeof iterator.throw === "function") {
11220
+ return await withCurrent(state.span, () => iterator.throw(error));
11221
+ }
11222
+ throw error;
11223
+ },
11224
+ [Symbol.asyncIterator]() {
11225
+ return this;
11226
+ }
11227
+ };
11228
+ };
11229
+ Object.defineProperty(runnerRecord, "__braintrust_tool_runner_patched", {
11230
+ value: true
11231
+ });
11232
+ }
11233
+ function aggregateAnthropicStreamChunks(chunks) {
11234
+ const fallbackTextDeltas = [];
11235
+ const contentBlocks = {};
11236
+ const contentBlockDeltas = {};
11237
+ let metrics = {};
11238
+ let metadata = {};
11239
+ let role;
11240
+ for (const event of chunks) {
11241
+ switch (event?.type) {
11242
+ case "message_start":
11243
+ if (event.message?.usage) {
11244
+ const initialMetrics = parseMetricsFromUsage2(event.message.usage);
11245
+ metrics = { ...metrics, ...initialMetrics };
11246
+ }
11247
+ if (typeof event.message?.role === "string") {
11248
+ role = event.message.role;
11249
+ }
11250
+ break;
11251
+ case "content_block_start":
11252
+ if (event.content_block) {
11253
+ contentBlocks[event.index] = event.content_block;
11254
+ contentBlockDeltas[event.index] = { textDeltas: [], citations: [] };
11255
+ }
11256
+ break;
11257
+ case "content_block_delta": {
11258
+ const acc = contentBlockDeltas[event.index];
11259
+ const delta = event.delta;
11260
+ if (!delta) break;
11261
+ if (delta.type === "text_delta" && "text" in delta) {
11262
+ const text = delta.text;
11263
+ if (text) {
11264
+ if (acc !== void 0) {
11265
+ acc.textDeltas.push(text);
11266
+ } else {
11267
+ fallbackTextDeltas.push(text);
11268
+ }
11269
+ }
11270
+ } else if (delta.type === "input_json_delta" && "partial_json" in delta) {
11271
+ const partialJson = delta.partial_json;
11272
+ if (partialJson && acc !== void 0) {
11273
+ acc.textDeltas.push(partialJson);
11274
+ }
11275
+ } else if (delta.type === "thinking_delta" && "thinking" in delta) {
11276
+ const thinking = delta.thinking;
11277
+ if (thinking && acc !== void 0) {
11278
+ acc.textDeltas.push(thinking);
11279
+ }
11280
+ } else if (delta.type === "citations_delta" && "citation" in delta) {
11281
+ const citation = delta.citation;
11282
+ if (citation && acc !== void 0) {
11283
+ acc.citations.push(citation);
11284
+ }
11285
+ }
11286
+ break;
11287
+ }
11288
+ case "content_block_stop":
11289
+ finalizeContentBlock(
11290
+ event.index,
11291
+ contentBlocks,
11292
+ contentBlockDeltas,
11293
+ fallbackTextDeltas
11294
+ );
11295
+ break;
10716
11296
  case "message_delta":
10717
11297
  if (event.usage) {
10718
11298
  const finalMetrics = parseMetricsFromUsage2(event.usage);
@@ -10758,15 +11338,24 @@ function finalizeContentBlock(index, contentBlocks, contentBlockDeltas, fallback
10758
11338
  }
10759
11339
  const acc = contentBlockDeltas[index];
10760
11340
  const text = acc?.textDeltas.join("") ?? "";
10761
- if (isToolUseContentBlock(contentBlock)) {
11341
+ if (isToolUseLikeContentBlock(contentBlock)) {
10762
11342
  if (!text) {
10763
11343
  return;
10764
11344
  }
10765
11345
  try {
10766
- contentBlocks[index] = {
10767
- ...contentBlock,
10768
- input: JSON.parse(text)
11346
+ const parsedInput = JSON.parse(text);
11347
+ if (!isObject(parsedInput)) {
11348
+ fallbackTextDeltas.push(text);
11349
+ delete contentBlocks[index];
11350
+ return;
11351
+ }
11352
+ const parsedToolUseBlock = {
11353
+ type: contentBlock.type,
11354
+ id: contentBlock.id,
11355
+ name: contentBlock.name,
11356
+ input: parsedInput
10769
11357
  };
11358
+ contentBlocks[index] = parsedToolUseBlock;
10770
11359
  } catch {
10771
11360
  fallbackTextDeltas.push(text);
10772
11361
  delete contentBlocks[index];
@@ -10800,8 +11389,8 @@ function finalizeContentBlock(index, contentBlocks, contentBlockDeltas, fallback
10800
11389
  function isTextContentBlock(contentBlock) {
10801
11390
  return contentBlock.type === "text";
10802
11391
  }
10803
- function isToolUseContentBlock(contentBlock) {
10804
- return contentBlock.type === "tool_use";
11392
+ function isToolUseLikeContentBlock(contentBlock) {
11393
+ return (contentBlock.type === "tool_use" || contentBlock.type === "server_tool_use") && typeof contentBlock.id === "string" && typeof contentBlock.name === "string" && isObject(contentBlock.input);
10805
11394
  }
10806
11395
  function isThinkingContentBlock(contentBlock) {
10807
11396
  return contentBlock.type === "thinking";
@@ -10999,6 +11588,10 @@ var aiSDKChannels = defineChannels("ai", {
10999
11588
  channelName: "embedMany",
11000
11589
  kind: "async"
11001
11590
  }),
11591
+ rerank: channel({
11592
+ channelName: "rerank",
11593
+ kind: "async"
11594
+ }),
11002
11595
  agentGenerate: channel({
11003
11596
  channelName: "Agent.generate",
11004
11597
  kind: "async"
@@ -11058,7 +11651,7 @@ var AISDKPlugin = class extends BasePlugin {
11058
11651
  this.unsubscribers.push(
11059
11652
  traceStreamingChannel(aiSDKChannels.generateText, {
11060
11653
  name: "generateText",
11061
- type: "llm" /* LLM */,
11654
+ type: "function" /* FUNCTION */,
11062
11655
  extractInput: ([params], event, span) => prepareAISDKCallInput(params, event, span, denyOutputPaths),
11063
11656
  extractOutput: (result, endEvent) => {
11064
11657
  finalizeAISDKChildTracing(endEvent);
@@ -11074,7 +11667,7 @@ var AISDKPlugin = class extends BasePlugin {
11074
11667
  this.unsubscribers.push(
11075
11668
  traceStreamingChannel(aiSDKChannels.streamText, {
11076
11669
  name: "streamText",
11077
- type: "llm" /* LLM */,
11670
+ type: "function" /* FUNCTION */,
11078
11671
  extractInput: ([params], event, span) => prepareAISDKCallInput(params, event, span, denyOutputPaths),
11079
11672
  extractOutput: (result, endEvent) => processAISDKOutput(
11080
11673
  result,
@@ -11094,7 +11687,7 @@ var AISDKPlugin = class extends BasePlugin {
11094
11687
  this.unsubscribers.push(
11095
11688
  traceSyncStreamChannel(aiSDKChannels.streamTextSync, {
11096
11689
  name: "streamText",
11097
- type: "llm" /* LLM */,
11690
+ type: "function" /* FUNCTION */,
11098
11691
  extractInput: ([params], event, span) => prepareAISDKCallInput(params, event, span, denyOutputPaths),
11099
11692
  patchResult: ({ endEvent, result, span, startTime }) => patchAISDKStreamingResult({
11100
11693
  defaultDenyOutputPaths: denyOutputPaths,
@@ -11108,7 +11701,7 @@ var AISDKPlugin = class extends BasePlugin {
11108
11701
  this.unsubscribers.push(
11109
11702
  traceStreamingChannel(aiSDKChannels.generateObject, {
11110
11703
  name: "generateObject",
11111
- type: "llm" /* LLM */,
11704
+ type: "function" /* FUNCTION */,
11112
11705
  extractInput: ([params], event, span) => prepareAISDKCallInput(params, event, span, denyOutputPaths),
11113
11706
  extractOutput: (result, endEvent) => {
11114
11707
  finalizeAISDKChildTracing(endEvent);
@@ -11124,7 +11717,7 @@ var AISDKPlugin = class extends BasePlugin {
11124
11717
  this.unsubscribers.push(
11125
11718
  traceStreamingChannel(aiSDKChannels.streamObject, {
11126
11719
  name: "streamObject",
11127
- type: "llm" /* LLM */,
11720
+ type: "function" /* FUNCTION */,
11128
11721
  extractInput: ([params], event, span) => prepareAISDKCallInput(params, event, span, denyOutputPaths),
11129
11722
  extractOutput: (result, endEvent) => processAISDKOutput(
11130
11723
  result,
@@ -11144,7 +11737,7 @@ var AISDKPlugin = class extends BasePlugin {
11144
11737
  this.unsubscribers.push(
11145
11738
  traceSyncStreamChannel(aiSDKChannels.streamObjectSync, {
11146
11739
  name: "streamObject",
11147
- type: "llm" /* LLM */,
11740
+ type: "function" /* FUNCTION */,
11148
11741
  extractInput: ([params], event, span) => prepareAISDKCallInput(params, event, span, denyOutputPaths),
11149
11742
  patchResult: ({ endEvent, result, span, startTime }) => patchAISDKStreamingResult({
11150
11743
  defaultDenyOutputPaths: denyOutputPaths,
@@ -11158,7 +11751,7 @@ var AISDKPlugin = class extends BasePlugin {
11158
11751
  this.unsubscribers.push(
11159
11752
  traceAsyncChannel(aiSDKChannels.embed, {
11160
11753
  name: "embed",
11161
- type: "llm" /* LLM */,
11754
+ type: "function" /* FUNCTION */,
11162
11755
  extractInput: ([params], event) => prepareAISDKEmbedInput(params, event.self),
11163
11756
  extractOutput: (result, endEvent) => processAISDKEmbeddingOutput(
11164
11757
  result,
@@ -11170,7 +11763,7 @@ var AISDKPlugin = class extends BasePlugin {
11170
11763
  this.unsubscribers.push(
11171
11764
  traceAsyncChannel(aiSDKChannels.embedMany, {
11172
11765
  name: "embedMany",
11173
- type: "llm" /* LLM */,
11766
+ type: "function" /* FUNCTION */,
11174
11767
  extractInput: ([params], event) => prepareAISDKEmbedInput(params, event.self),
11175
11768
  extractOutput: (result, endEvent) => processAISDKEmbeddingOutput(
11176
11769
  result,
@@ -11179,10 +11772,22 @@ var AISDKPlugin = class extends BasePlugin {
11179
11772
  extractMetrics: (result, _startTime, endEvent) => extractTopLevelAISDKMetrics(result, endEvent)
11180
11773
  })
11181
11774
  );
11775
+ this.unsubscribers.push(
11776
+ traceAsyncChannel(aiSDKChannels.rerank, {
11777
+ name: "rerank",
11778
+ type: "function" /* FUNCTION */,
11779
+ extractInput: ([params], event) => prepareAISDKRerankInput(params, event.self),
11780
+ extractOutput: (result, endEvent) => processAISDKRerankOutput(
11781
+ result,
11782
+ resolveDenyOutputPaths(endEvent, denyOutputPaths)
11783
+ ),
11784
+ extractMetrics: (result, _startTime, endEvent) => extractTopLevelAISDKMetrics(result, endEvent)
11785
+ })
11786
+ );
11182
11787
  this.unsubscribers.push(
11183
11788
  traceStreamingChannel(aiSDKChannels.agentGenerate, {
11184
11789
  name: "Agent.generate",
11185
- type: "llm" /* LLM */,
11790
+ type: "function" /* FUNCTION */,
11186
11791
  extractInput: ([params], event, span) => prepareAISDKCallInput(params, event, span, denyOutputPaths),
11187
11792
  extractOutput: (result, endEvent) => {
11188
11793
  finalizeAISDKChildTracing(endEvent);
@@ -11198,7 +11803,7 @@ var AISDKPlugin = class extends BasePlugin {
11198
11803
  this.unsubscribers.push(
11199
11804
  traceStreamingChannel(aiSDKChannels.agentStream, {
11200
11805
  name: "Agent.stream",
11201
- type: "llm" /* LLM */,
11806
+ type: "function" /* FUNCTION */,
11202
11807
  extractInput: ([params], event, span) => prepareAISDKCallInput(params, event, span, denyOutputPaths),
11203
11808
  extractOutput: (result, endEvent) => processAISDKOutput(
11204
11809
  result,
@@ -11218,7 +11823,7 @@ var AISDKPlugin = class extends BasePlugin {
11218
11823
  this.unsubscribers.push(
11219
11824
  traceSyncStreamChannel(aiSDKChannels.agentStreamSync, {
11220
11825
  name: "Agent.stream",
11221
- type: "llm" /* LLM */,
11826
+ type: "function" /* FUNCTION */,
11222
11827
  extractInput: ([params], event, span) => prepareAISDKCallInput(params, event, span, denyOutputPaths),
11223
11828
  patchResult: ({ endEvent, result, span, startTime }) => patchAISDKStreamingResult({
11224
11829
  defaultDenyOutputPaths: denyOutputPaths,
@@ -11232,7 +11837,7 @@ var AISDKPlugin = class extends BasePlugin {
11232
11837
  this.unsubscribers.push(
11233
11838
  traceStreamingChannel(aiSDKChannels.toolLoopAgentGenerate, {
11234
11839
  name: "ToolLoopAgent.generate",
11235
- type: "llm" /* LLM */,
11840
+ type: "function" /* FUNCTION */,
11236
11841
  extractInput: ([params], event, span) => prepareAISDKCallInput(params, event, span, denyOutputPaths),
11237
11842
  extractOutput: (result, endEvent) => {
11238
11843
  finalizeAISDKChildTracing(endEvent);
@@ -11248,7 +11853,7 @@ var AISDKPlugin = class extends BasePlugin {
11248
11853
  this.unsubscribers.push(
11249
11854
  traceStreamingChannel(aiSDKChannels.toolLoopAgentStream, {
11250
11855
  name: "ToolLoopAgent.stream",
11251
- type: "llm" /* LLM */,
11856
+ type: "function" /* FUNCTION */,
11252
11857
  extractInput: ([params], event, span) => prepareAISDKCallInput(params, event, span, denyOutputPaths),
11253
11858
  extractOutput: (result, endEvent) => processAISDKOutput(
11254
11859
  result,
@@ -11598,6 +12203,16 @@ function prepareAISDKEmbedInput(params, self) {
11598
12203
  metadata: extractMetadataFromEmbedParams(params, self)
11599
12204
  };
11600
12205
  }
12206
+ function prepareAISDKRerankInput(params, self) {
12207
+ const { documents, query } = params;
12208
+ return {
12209
+ input: {
12210
+ documents,
12211
+ query
12212
+ },
12213
+ metadata: extractMetadataFromRerankParams(params, self)
12214
+ };
12215
+ }
11601
12216
  function extractTopLevelAISDKMetrics(result, event, startTime) {
11602
12217
  const metrics = hasModelChildTracing(event) ? {} : extractTokenMetrics(result);
11603
12218
  if (startTime) {
@@ -11643,6 +12258,16 @@ function extractMetadataFromCallParams(params, self) {
11643
12258
  function extractMetadataFromEmbedParams(params, self) {
11644
12259
  return extractBaseMetadata(params.model, self);
11645
12260
  }
12261
+ function extractMetadataFromRerankParams(params, self) {
12262
+ const metadata = extractBaseMetadata(params.model, self);
12263
+ if (typeof params.topN === "number") {
12264
+ metadata.topN = params.topN;
12265
+ }
12266
+ if (Array.isArray(params.documents)) {
12267
+ metadata.document_count = params.documents.length;
12268
+ }
12269
+ return metadata;
12270
+ }
11646
12271
  function prepareAISDKChildTracing(params, self, parentSpan, denyOutputPaths, aiSDK) {
11647
12272
  const cleanup = [];
11648
12273
  const patchedModels = /* @__PURE__ */ new WeakSet();
@@ -12190,6 +12815,22 @@ function processAISDKEmbeddingOutput(output, denyOutputPaths) {
12190
12815
  }
12191
12816
  return normalizeAISDKLoggedOutput(omit(summarized, denyOutputPaths));
12192
12817
  }
12818
+ function processAISDKRerankOutput(output, _denyOutputPaths) {
12819
+ if (!output || typeof output !== "object") {
12820
+ return output;
12821
+ }
12822
+ const ranking = safeSerializableFieldRead(output, "ranking");
12823
+ if (Array.isArray(ranking)) {
12824
+ return ranking.slice(0, 100).map((item) => {
12825
+ const entry = item && typeof item === "object" ? item : void 0;
12826
+ return {
12827
+ index: typeof entry?.originalIndex === "number" ? entry.originalIndex : void 0,
12828
+ relevance_score: typeof entry?.score === "number" ? entry.score : void 0
12829
+ };
12830
+ });
12831
+ }
12832
+ return void 0;
12833
+ }
12193
12834
  function extractTokenMetrics(result) {
12194
12835
  const metrics = {};
12195
12836
  let usage;
@@ -12232,12 +12873,80 @@ function extractTokenMetrics(result) {
12232
12873
  if (totalTokens !== void 0) {
12233
12874
  metrics.tokens = totalTokens;
12234
12875
  }
12876
+ const promptCachedTokens = firstNumber(
12877
+ usage.inputTokens?.cacheRead,
12878
+ usage.inputTokenDetails?.cacheReadTokens,
12879
+ usage.cachedInputTokens,
12880
+ usage.promptCachedTokens,
12881
+ usage.prompt_cached_tokens
12882
+ );
12883
+ if (promptCachedTokens !== void 0) {
12884
+ metrics.prompt_cached_tokens = promptCachedTokens;
12885
+ }
12886
+ const promptCacheCreationTokens = firstNumber(
12887
+ usage.inputTokens?.cacheWrite,
12888
+ usage.inputTokenDetails?.cacheWriteTokens,
12889
+ usage.promptCacheCreationTokens,
12890
+ usage.prompt_cache_creation_tokens,
12891
+ extractAnthropicCacheCreationTokens(result)
12892
+ );
12893
+ if (promptCacheCreationTokens !== void 0) {
12894
+ metrics.prompt_cache_creation_tokens = promptCacheCreationTokens;
12895
+ }
12896
+ const promptReasoningTokens = firstNumber(
12897
+ usage.promptReasoningTokens,
12898
+ usage.prompt_reasoning_tokens
12899
+ );
12900
+ if (promptReasoningTokens !== void 0) {
12901
+ metrics.prompt_reasoning_tokens = promptReasoningTokens;
12902
+ }
12903
+ const completionCachedTokens = firstNumber(
12904
+ usage.completionCachedTokens,
12905
+ usage.completion_cached_tokens
12906
+ );
12907
+ if (completionCachedTokens !== void 0) {
12908
+ metrics.completion_cached_tokens = completionCachedTokens;
12909
+ }
12910
+ const reasoningTokenCount = firstNumber(
12911
+ usage.outputTokens?.reasoning,
12912
+ usage.reasoningTokens,
12913
+ usage.completionReasoningTokens,
12914
+ usage.completion_reasoning_tokens,
12915
+ usage.reasoning_tokens,
12916
+ usage.thinkingTokens,
12917
+ usage.thinking_tokens
12918
+ );
12919
+ if (reasoningTokenCount !== void 0) {
12920
+ metrics.completion_reasoning_tokens = reasoningTokenCount;
12921
+ metrics.reasoning_tokens = reasoningTokenCount;
12922
+ }
12923
+ const completionAudioTokens = firstNumber(
12924
+ usage.completionAudioTokens,
12925
+ usage.completion_audio_tokens
12926
+ );
12927
+ if (completionAudioTokens !== void 0) {
12928
+ metrics.completion_audio_tokens = completionAudioTokens;
12929
+ }
12235
12930
  const cost = extractCostFromResult(result);
12236
12931
  if (cost !== void 0) {
12237
12932
  metrics.estimated_cost = cost;
12238
12933
  }
12239
12934
  return metrics;
12240
12935
  }
12936
+ function extractAnthropicCacheCreationTokens(result) {
12937
+ const providerMetadata = safeSerializableFieldRead(
12938
+ result,
12939
+ "providerMetadata"
12940
+ );
12941
+ const anthropicMetadata = providerMetadata?.anthropic;
12942
+ if (!anthropicMetadata) {
12943
+ return void 0;
12944
+ }
12945
+ return firstNumber(
12946
+ anthropicMetadata.cacheCreationInputTokens,
12947
+ anthropicMetadata.usage?.cache_creation_input_tokens
12948
+ );
12949
+ }
12241
12950
  function safeResultFieldRead(result, field) {
12242
12951
  return safeSerializableFieldRead(result, field);
12243
12952
  }
@@ -12354,14 +13063,11 @@ function extractSerializableOutputFields(output) {
12354
13063
  ...extractGetterValues(output)
12355
13064
  };
12356
13065
  }
12357
- function isPromiseLike(value) {
12358
- return value != null && typeof value === "object" && typeof value.then === "function";
12359
- }
12360
13066
  function isSerializableOutputValue(value) {
12361
13067
  if (typeof value === "function") {
12362
13068
  return false;
12363
13069
  }
12364
- if (value && typeof value === "object" && typeof value.then === "function") {
13070
+ if (isPromiseLike(value)) {
12365
13071
  return false;
12366
13072
  }
12367
13073
  if (value && typeof value === "object" && typeof value.getReader === "function") {
@@ -12681,12 +13387,9 @@ function bindClaudeLocalToolContextToAsyncIterable(result, localToolContext) {
12681
13387
  var LOCAL_TOOL_HANDLER_WRAPPED = Symbol.for(
12682
13388
  "braintrust.claude_agent_sdk.local_tool_handler_wrapped"
12683
13389
  );
12684
- function toErrorMessage(error) {
13390
+ function toErrorMessage2(error) {
12685
13391
  return error instanceof Error ? error.message : String(error);
12686
13392
  }
12687
- function isPromiseLike2(value) {
12688
- return value !== null && typeof value === "object" && "then" in value && typeof value.then === "function";
12689
- }
12690
13393
  function getToolUseIdFromExtra(extra) {
12691
13394
  if (!extra || typeof extra !== "object" || !("_meta" in extra)) {
12692
13395
  return void 0;
@@ -12733,14 +13436,14 @@ function wrapLocalClaudeToolHandler(handler, getMetadata) {
12733
13436
  return result;
12734
13437
  };
12735
13438
  const finalizeError = (error) => {
12736
- span.log({ error: toErrorMessage(error) });
13439
+ span.log({ error: toErrorMessage2(error) });
12737
13440
  span.end();
12738
13441
  throw error;
12739
13442
  };
12740
13443
  return withCurrent(span, () => {
12741
13444
  try {
12742
13445
  const result = runHandler();
12743
- if (isPromiseLike2(result)) {
13446
+ if (isPromiseLike(result)) {
12744
13447
  return result.then(finalizeSuccess, finalizeError);
12745
13448
  }
12746
13449
  return finalizeSuccess(result);
@@ -12860,7 +13563,7 @@ var ROOT_LLM_PARENT_KEY = "__root__";
12860
13563
  function llmParentKey(parentToolUseId) {
12861
13564
  return parentToolUseId ?? ROOT_LLM_PARENT_KEY;
12862
13565
  }
12863
- function isSubAgentToolName(toolName) {
13566
+ function isSubAgentDelegationToolName(toolName) {
12864
13567
  return toolName === "Agent" || toolName === "Task";
12865
13568
  }
12866
13569
  function filterSerializableOptions(options) {
@@ -12894,24 +13597,92 @@ function getNumberProperty(obj, key) {
12894
13597
  const value = Reflect.get(obj, key);
12895
13598
  return typeof value === "number" ? value : void 0;
12896
13599
  }
12897
- function extractUsageFromMessage(message) {
12898
- const metrics = {};
12899
- let usage;
12900
- if (message.type === "assistant") {
12901
- usage = message.message?.usage;
12902
- } else if (message.type === "result") {
12903
- usage = message.usage;
13600
+ function getStringProperty(obj, key) {
13601
+ if (!obj || typeof obj !== "object" || !(key in obj)) {
13602
+ return void 0;
12904
13603
  }
12905
- if (!usage || typeof usage !== "object") {
12906
- return metrics;
13604
+ const value = Reflect.get(obj, key);
13605
+ return typeof value === "string" ? value : void 0;
13606
+ }
13607
+ function upsertSubAgentDetails(detailsByToolUseId, toolUseId, update) {
13608
+ const existing = detailsByToolUseId.get(toolUseId) ?? {};
13609
+ const merged = {
13610
+ ...existing,
13611
+ ...Object.fromEntries(
13612
+ Object.entries(update).filter(([, value]) => value !== void 0)
13613
+ )
13614
+ };
13615
+ detailsByToolUseId.set(toolUseId, merged);
13616
+ return merged;
13617
+ }
13618
+ function formatSubAgentSpanName(details) {
13619
+ if (details?.description) {
13620
+ return `Agent: ${details.description}`;
12907
13621
  }
12908
- const inputTokens = getNumberProperty(usage, "input_tokens");
12909
- if (inputTokens !== void 0) {
12910
- metrics.prompt_tokens = inputTokens;
13622
+ if (details?.agentType) {
13623
+ return `Agent: ${details.agentType}`;
12911
13624
  }
12912
- const outputTokens = getNumberProperty(usage, "output_tokens");
12913
- if (outputTokens !== void 0) {
12914
- metrics.completion_tokens = outputTokens;
13625
+ return "Agent: sub-agent";
13626
+ }
13627
+ function subAgentDetailsToMetadata(details) {
13628
+ if (!details) {
13629
+ return {};
13630
+ }
13631
+ const metadata = {};
13632
+ if (details.agentId) {
13633
+ metadata["claude_agent_sdk.agent_id"] = details.agentId;
13634
+ }
13635
+ if (details.agentType) {
13636
+ metadata["claude_agent_sdk.agent_type"] = details.agentType;
13637
+ }
13638
+ if (details.description) {
13639
+ metadata["claude_agent_sdk.description"] = details.description;
13640
+ }
13641
+ if (details.taskId) {
13642
+ metadata["claude_agent_sdk.task_id"] = details.taskId;
13643
+ }
13644
+ if (details.taskType) {
13645
+ metadata["claude_agent_sdk.task_type"] = details.taskType;
13646
+ }
13647
+ if (details.toolUseId) {
13648
+ metadata["claude_agent_sdk.tool_use_id"] = details.toolUseId;
13649
+ }
13650
+ if (details.workflowName) {
13651
+ metadata["claude_agent_sdk.workflow_name"] = details.workflowName;
13652
+ }
13653
+ return metadata;
13654
+ }
13655
+ function resolveTaskToolUseId(taskIdToToolUseId, message) {
13656
+ const messageToolUseId = typeof message.tool_use_id === "string" ? message.tool_use_id : void 0;
13657
+ if (messageToolUseId && typeof message.task_id === "string") {
13658
+ taskIdToToolUseId.set(message.task_id, messageToolUseId);
13659
+ }
13660
+ if (messageToolUseId) {
13661
+ return messageToolUseId;
13662
+ }
13663
+ if (typeof message.task_id === "string") {
13664
+ return taskIdToToolUseId.get(message.task_id);
13665
+ }
13666
+ return void 0;
13667
+ }
13668
+ function extractUsageFromMessage(message) {
13669
+ const metrics = {};
13670
+ let usage;
13671
+ if (message.type === "assistant") {
13672
+ usage = message.message?.usage;
13673
+ } else if (message.type === "result") {
13674
+ usage = message.usage;
13675
+ }
13676
+ if (!usage || typeof usage !== "object") {
13677
+ return metrics;
13678
+ }
13679
+ const inputTokens = getNumberProperty(usage, "input_tokens");
13680
+ if (inputTokens !== void 0) {
13681
+ metrics.prompt_tokens = inputTokens;
13682
+ }
13683
+ const outputTokens = getNumberProperty(usage, "output_tokens");
13684
+ if (outputTokens !== void 0) {
13685
+ metrics.completion_tokens = outputTokens;
12915
13686
  }
12916
13687
  const cacheReadTokens = getNumberProperty(usage, "cache_read_input_tokens") || 0;
12917
13688
  const cacheCreationTokens = getNumberProperty(usage, "cache_creation_input_tokens") || 0;
@@ -13066,7 +13837,7 @@ function prepareLocalToolHandlersInMcpServers(mcpServers) {
13066
13837
  }
13067
13838
  return { hasLocalToolHandlers, localToolHookNames };
13068
13839
  }
13069
- function createToolTracingHooks(resolveParentSpan, activeToolSpans, mcpServers, localToolHookNames, skipLocalToolHooks, subAgentSpans, endedSubAgentSpans) {
13840
+ function createToolTracingHooks(resolveParentSpan, activeToolSpans, mcpServers, localToolHookNames, skipLocalToolHooks, subAgentDetailsByToolUseId, subAgentSpans, endedSubAgentSpans) {
13070
13841
  const preToolUse = async (input, toolUseID) => {
13071
13842
  if (input.hook_event_name !== "PreToolUse" || !toolUseID) {
13072
13843
  return {};
@@ -13074,9 +13845,6 @@ function createToolTracingHooks(resolveParentSpan, activeToolSpans, mcpServers,
13074
13845
  if (skipLocalToolHooks && (isLocalToolUse(input.tool_name, mcpServers) || localToolHookNames.has(input.tool_name))) {
13075
13846
  return {};
13076
13847
  }
13077
- if (isSubAgentToolName(input.tool_name)) {
13078
- return {};
13079
- }
13080
13848
  const parsed = parseToolName(input.tool_name);
13081
13849
  const toolSpan = startSpan({
13082
13850
  event: {
@@ -13106,10 +13874,18 @@ function createToolTracingHooks(resolveParentSpan, activeToolSpans, mcpServers,
13106
13874
  return {};
13107
13875
  }
13108
13876
  const subAgentSpan = subAgentSpans.get(toolUseID);
13877
+ const toolSpan = activeToolSpans.get(toolUseID);
13109
13878
  if (subAgentSpan) {
13879
+ if (endedSubAgentSpans.has(toolUseID)) {
13880
+ return {};
13881
+ }
13110
13882
  try {
13111
13883
  const response = input.tool_response;
13112
- const metadata = {};
13884
+ const metadata = {
13885
+ ...subAgentDetailsToMetadata(
13886
+ subAgentDetailsByToolUseId.get(toolUseID)
13887
+ )
13888
+ };
13113
13889
  if (response?.status) {
13114
13890
  metadata["claude_agent_sdk.status"] = response.status;
13115
13891
  }
@@ -13127,9 +13903,16 @@ function createToolTracingHooks(resolveParentSpan, activeToolSpans, mcpServers,
13127
13903
  subAgentSpan.end();
13128
13904
  endedSubAgentSpans.add(toolUseID);
13129
13905
  }
13906
+ if (toolSpan) {
13907
+ try {
13908
+ toolSpan.log({ output: input.tool_response });
13909
+ } finally {
13910
+ toolSpan.end();
13911
+ activeToolSpans.delete(toolUseID);
13912
+ }
13913
+ }
13130
13914
  return {};
13131
13915
  }
13132
- const toolSpan = activeToolSpans.get(toolUseID);
13133
13916
  if (!toolSpan) {
13134
13917
  return {};
13135
13918
  }
@@ -13149,16 +13932,43 @@ function createToolTracingHooks(resolveParentSpan, activeToolSpans, mcpServers,
13149
13932
  return {};
13150
13933
  }
13151
13934
  const subAgentSpan = subAgentSpans.get(toolUseID);
13935
+ const toolSpan = activeToolSpans.get(toolUseID);
13152
13936
  if (subAgentSpan) {
13937
+ if (endedSubAgentSpans.has(toolUseID)) {
13938
+ return {};
13939
+ }
13153
13940
  try {
13154
- subAgentSpan.log({ error: input.error });
13941
+ subAgentSpan.log({
13942
+ error: input.error,
13943
+ metadata: subAgentDetailsToMetadata(
13944
+ subAgentDetailsByToolUseId.get(toolUseID)
13945
+ )
13946
+ });
13155
13947
  } finally {
13156
13948
  subAgentSpan.end();
13157
13949
  endedSubAgentSpans.add(toolUseID);
13158
13950
  }
13951
+ if (toolSpan) {
13952
+ const parsed2 = parseToolName(input.tool_name);
13953
+ try {
13954
+ toolSpan.log({
13955
+ error: input.error,
13956
+ metadata: {
13957
+ "claude_agent_sdk.is_interrupt": input.is_interrupt,
13958
+ "claude_agent_sdk.session_id": input.session_id,
13959
+ "claude_agent_sdk.raw_tool_name": parsed2.rawToolName,
13960
+ "gen_ai.tool.call.id": toolUseID,
13961
+ "gen_ai.tool.name": parsed2.toolName,
13962
+ ...parsed2.mcpServer && { "mcp.server": parsed2.mcpServer }
13963
+ }
13964
+ });
13965
+ } finally {
13966
+ toolSpan.end();
13967
+ activeToolSpans.delete(toolUseID);
13968
+ }
13969
+ }
13159
13970
  return {};
13160
13971
  }
13161
- const toolSpan = activeToolSpans.get(toolUseID);
13162
13972
  if (!toolSpan) {
13163
13973
  return {};
13164
13974
  }
@@ -13180,15 +13990,84 @@ function createToolTracingHooks(resolveParentSpan, activeToolSpans, mcpServers,
13180
13990
  }
13181
13991
  return {};
13182
13992
  };
13183
- return { postToolUse, postToolUseFailure, preToolUse };
13993
+ const subagentStart = async (input, toolUseID) => {
13994
+ if (input.hook_event_name !== "SubagentStart" || !toolUseID) {
13995
+ return {};
13996
+ }
13997
+ const details = upsertSubAgentDetails(
13998
+ subAgentDetailsByToolUseId,
13999
+ toolUseID,
14000
+ {
14001
+ agentId: input.agent_id,
14002
+ agentType: input.agent_type,
14003
+ toolUseId: toolUseID
14004
+ }
14005
+ );
14006
+ const subAgentSpan = subAgentSpans.get(toolUseID);
14007
+ if (subAgentSpan && !endedSubAgentSpans.has(toolUseID)) {
14008
+ subAgentSpan.log({
14009
+ metadata: subAgentDetailsToMetadata(details)
14010
+ });
14011
+ }
14012
+ return {};
14013
+ };
14014
+ const subagentStop = async (input, toolUseID) => {
14015
+ if (input.hook_event_name !== "SubagentStop" || !toolUseID) {
14016
+ return {};
14017
+ }
14018
+ const details = upsertSubAgentDetails(
14019
+ subAgentDetailsByToolUseId,
14020
+ toolUseID,
14021
+ {
14022
+ agentId: input.agent_id,
14023
+ agentType: input.agent_type,
14024
+ toolUseId: toolUseID
14025
+ }
14026
+ );
14027
+ const subAgentSpan = subAgentSpans.get(toolUseID);
14028
+ if (!subAgentSpan || endedSubAgentSpans.has(toolUseID)) {
14029
+ return {};
14030
+ }
14031
+ const metadata = {
14032
+ ...subAgentDetailsToMetadata(details),
14033
+ ...input.agent_transcript_path && {
14034
+ "claude_agent_sdk.agent_transcript_path": input.agent_transcript_path
14035
+ },
14036
+ "claude_agent_sdk.stop_hook_active": input.stop_hook_active
14037
+ };
14038
+ try {
14039
+ subAgentSpan.log({
14040
+ metadata,
14041
+ output: input.last_assistant_message
14042
+ });
14043
+ } finally {
14044
+ subAgentSpan.end();
14045
+ endedSubAgentSpans.add(toolUseID);
14046
+ }
14047
+ return {};
14048
+ };
14049
+ return {
14050
+ postToolUse,
14051
+ postToolUseFailure,
14052
+ preToolUse,
14053
+ subagentStart,
14054
+ subagentStop
14055
+ };
13184
14056
  }
13185
- function injectTracingHooks(options, resolveParentSpan, activeToolSpans, localToolHookNames, skipLocalToolHooks, subAgentSpans, endedSubAgentSpans) {
13186
- const { preToolUse, postToolUse, postToolUseFailure } = createToolTracingHooks(
14057
+ function injectTracingHooks(options, resolveParentSpan, activeToolSpans, localToolHookNames, skipLocalToolHooks, subAgentDetailsByToolUseId, subAgentSpans, endedSubAgentSpans) {
14058
+ const {
14059
+ preToolUse,
14060
+ postToolUse,
14061
+ postToolUseFailure,
14062
+ subagentStart,
14063
+ subagentStop
14064
+ } = createToolTracingHooks(
13187
14065
  resolveParentSpan,
13188
14066
  activeToolSpans,
13189
14067
  options.mcpServers,
13190
14068
  localToolHookNames,
13191
14069
  skipLocalToolHooks,
14070
+ subAgentDetailsByToolUseId,
13192
14071
  subAgentSpans,
13193
14072
  endedSubAgentSpans
13194
14073
  );
@@ -13210,6 +14089,18 @@ function injectTracingHooks(options, resolveParentSpan, activeToolSpans, localTo
13210
14089
  PreToolUse: [
13211
14090
  ...existingHooks.PreToolUse ?? [],
13212
14091
  { hooks: [preToolUse] }
14092
+ ],
14093
+ SubagentStart: [
14094
+ ...existingHooks.SubagentStart ?? [],
14095
+ {
14096
+ hooks: [subagentStart]
14097
+ }
14098
+ ],
14099
+ SubagentStop: [
14100
+ ...existingHooks.SubagentStop ?? [],
14101
+ {
14102
+ hooks: [subagentStop]
14103
+ }
13213
14104
  ]
13214
14105
  }
13215
14106
  };
@@ -13238,7 +14129,6 @@ async function finalizeCurrentMessageGroup(state) {
13238
14129
  parentSpan,
13239
14130
  existingLlmSpan
13240
14131
  );
13241
- state.activeLlmSpansByParentToolUse.delete(parentKey);
13242
14132
  if (llmSpanResult) {
13243
14133
  if (parentToolUseId) {
13244
14134
  state.latestLlmParentBySubAgentToolUse.set(
@@ -13252,6 +14142,7 @@ async function finalizeCurrentMessageGroup(state) {
13252
14142
  state.finalResults.push(llmSpanResult.finalMessage);
13253
14143
  }
13254
14144
  }
14145
+ state.activeLlmSpansByParentToolUse.delete(parentKey);
13255
14146
  const lastMessage = state.currentMessages[state.currentMessages.length - 1];
13256
14147
  if (lastMessage?.message?.usage) {
13257
14148
  state.accumulatedOutputTokens += getNumberProperty(lastMessage.message.usage, "output_tokens") || 0;
@@ -13268,8 +14159,12 @@ function maybeTrackToolUseContext(state, message) {
13268
14159
  continue;
13269
14160
  }
13270
14161
  state.toolUseToParent.set(block.id, parentToolUseId);
13271
- if (block.name === "Task" && typeof block.input === "object" && block.input !== null && "subagent_type" in block.input && typeof block.input.subagent_type === "string") {
13272
- state.pendingSubAgentNames.set(block.id, block.input.subagent_type);
14162
+ if (typeof block.name === "string" && isSubAgentDelegationToolName(block.name) && typeof block.input === "object" && block.input !== null) {
14163
+ upsertSubAgentDetails(state.subAgentDetailsByToolUseId, block.id, {
14164
+ agentType: getStringProperty(block.input, "subagent_type"),
14165
+ description: getStringProperty(block.input, "description"),
14166
+ toolUseId: block.id
14167
+ });
13273
14168
  }
13274
14169
  }
13275
14170
  }
@@ -13282,34 +14177,133 @@ async function maybeStartSubAgentSpan(state, message) {
13282
14177
  return;
13283
14178
  }
13284
14179
  await ensureSubAgentSpan(
13285
- state.pendingSubAgentNames,
14180
+ state.subAgentDetailsByToolUseId,
13286
14181
  state.span,
14182
+ state.activeToolSpans,
13287
14183
  state.subAgentSpans,
13288
14184
  parentToolUseId
13289
14185
  );
13290
14186
  }
13291
- async function ensureSubAgentSpan(pendingSubAgentNames, rootSpan, subAgentSpans, parentToolUseId) {
14187
+ async function ensureSubAgentSpan(subAgentDetailsByToolUseId, rootSpan, activeToolSpans, subAgentSpans, parentToolUseId) {
13292
14188
  const existingSpan = subAgentSpans.get(parentToolUseId);
13293
14189
  if (existingSpan) {
13294
14190
  return existingSpan;
13295
14191
  }
13296
- const agentName = pendingSubAgentNames.get(parentToolUseId);
13297
- const spanName = agentName ? `Agent: ${agentName}` : "Agent: sub-agent";
14192
+ const details = subAgentDetailsByToolUseId.get(parentToolUseId);
14193
+ const spanName = formatSubAgentSpanName(details);
14194
+ const parentToolSpan = activeToolSpans.get(parentToolUseId);
14195
+ const parentSpan = parentToolSpan ? await parentToolSpan.export() : await rootSpan.export();
13298
14196
  const subAgentSpan = startSpan({
13299
14197
  event: {
13300
- metadata: {
13301
- ...agentName && { "claude_agent_sdk.agent_type": agentName }
13302
- }
14198
+ metadata: subAgentDetailsToMetadata(details)
13303
14199
  },
13304
14200
  name: spanName,
13305
- parent: await rootSpan.export(),
14201
+ parent: parentSpan,
13306
14202
  spanAttributes: { type: "task" /* TASK */ }
13307
14203
  });
13308
14204
  subAgentSpans.set(parentToolUseId, subAgentSpan);
13309
14205
  return subAgentSpan;
13310
14206
  }
14207
+ async function maybeHandleTaskLifecycleMessage(state, message) {
14208
+ if (message.type !== "system") {
14209
+ return false;
14210
+ }
14211
+ if (message.subtype !== "task_started" && message.subtype !== "task_progress" && message.subtype !== "task_notification") {
14212
+ return false;
14213
+ }
14214
+ const toolUseId = resolveTaskToolUseId(state.taskIdToToolUseId, message);
14215
+ if (!toolUseId) {
14216
+ return true;
14217
+ }
14218
+ const details = upsertSubAgentDetails(
14219
+ state.subAgentDetailsByToolUseId,
14220
+ toolUseId,
14221
+ {
14222
+ description: getStringProperty(message, "description"),
14223
+ taskId: getStringProperty(message, "task_id"),
14224
+ taskType: getStringProperty(message, "task_type"),
14225
+ toolUseId,
14226
+ workflowName: getStringProperty(message, "workflow_name")
14227
+ }
14228
+ );
14229
+ const subAgentSpan = await ensureSubAgentSpan(
14230
+ state.subAgentDetailsByToolUseId,
14231
+ state.span,
14232
+ state.activeToolSpans,
14233
+ state.subAgentSpans,
14234
+ toolUseId
14235
+ );
14236
+ if (state.endedSubAgentSpans.has(toolUseId)) {
14237
+ return true;
14238
+ }
14239
+ const usage = message.usage;
14240
+ const usageTotalTokens = getNumberProperty(usage, "total_tokens");
14241
+ const usageToolUses = getNumberProperty(usage, "tool_uses");
14242
+ const usageDurationMs = getNumberProperty(usage, "duration_ms");
14243
+ const metadata = {
14244
+ ...subAgentDetailsToMetadata(details),
14245
+ "claude_agent_sdk.tool_use_id": toolUseId,
14246
+ ...usageTotalTokens !== void 0 && {
14247
+ "claude_agent_sdk.total_tokens": usageTotalTokens
14248
+ },
14249
+ ...usageToolUses !== void 0 && {
14250
+ "claude_agent_sdk.tool_use_count": usageToolUses
14251
+ },
14252
+ ...usageDurationMs !== void 0 && {
14253
+ "claude_agent_sdk.duration_ms": usageDurationMs
14254
+ }
14255
+ };
14256
+ if (message.subtype === "task_started") {
14257
+ const prompt = getStringProperty(message, "prompt");
14258
+ subAgentSpan.log({
14259
+ input: prompt,
14260
+ metadata
14261
+ });
14262
+ return true;
14263
+ }
14264
+ const summary = getStringProperty(message, "summary");
14265
+ if (summary) {
14266
+ metadata["claude_agent_sdk.summary"] = summary;
14267
+ }
14268
+ if (message.subtype === "task_progress") {
14269
+ const lastToolName = getStringProperty(message, "last_tool_name");
14270
+ if (lastToolName) {
14271
+ metadata["claude_agent_sdk.last_tool_name"] = lastToolName;
14272
+ }
14273
+ subAgentSpan.log({
14274
+ metadata,
14275
+ output: summary
14276
+ });
14277
+ return true;
14278
+ }
14279
+ const status = getStringProperty(message, "status");
14280
+ const outputFile = getStringProperty(message, "output_file");
14281
+ if (status) {
14282
+ metadata["claude_agent_sdk.task_status"] = status;
14283
+ }
14284
+ if (outputFile) {
14285
+ metadata["claude_agent_sdk.output_file"] = outputFile;
14286
+ }
14287
+ const output = summary || outputFile ? {
14288
+ ...summary && { summary },
14289
+ ...outputFile && { output_file: outputFile }
14290
+ } : void 0;
14291
+ try {
14292
+ subAgentSpan.log({
14293
+ metadata,
14294
+ output
14295
+ });
14296
+ } finally {
14297
+ subAgentSpan.end();
14298
+ state.endedSubAgentSpans.add(toolUseId);
14299
+ }
14300
+ return true;
14301
+ }
13311
14302
  async function handleStreamMessage(state, message) {
13312
14303
  maybeTrackToolUseContext(state, message);
14304
+ if (await maybeHandleTaskLifecycleMessage(state, message)) {
14305
+ return;
14306
+ }
13313
14307
  await maybeStartSubAgentSpan(state, message);
13314
14308
  const messageId = message.message?.id;
13315
14309
  if (messageId && messageId !== state.currentMessageId) {
@@ -13324,8 +14318,9 @@ async function handleStreamMessage(state, message) {
13324
14318
  let llmParentSpan = await state.span.export();
13325
14319
  if (parentToolUseId) {
13326
14320
  const subAgentSpan = await ensureSubAgentSpan(
13327
- state.pendingSubAgentNames,
14321
+ state.subAgentDetailsByToolUseId,
13328
14322
  state.span,
14323
+ state.activeToolSpans,
13329
14324
  state.subAgentSpans,
13330
14325
  parentToolUseId
13331
14326
  );
@@ -13405,6 +14400,10 @@ async function finalizeQuerySpan(state) {
13405
14400
  llmSpan.end();
13406
14401
  }
13407
14402
  state.activeLlmSpansByParentToolUse.clear();
14403
+ for (const toolSpan of state.activeToolSpans.values()) {
14404
+ toolSpan.end();
14405
+ }
14406
+ state.activeToolSpans.clear();
13408
14407
  for (const [id, subAgentSpan] of state.subAgentSpans) {
13409
14408
  if (!state.endedSubAgentSpans.has(id)) {
13410
14409
  subAgentSpan.end();
@@ -13478,7 +14477,8 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
13478
14477
  const latestRootLlmParentRef = {
13479
14478
  value: void 0
13480
14479
  };
13481
- const pendingSubAgentNames = /* @__PURE__ */ new Map();
14480
+ const subAgentDetailsByToolUseId = /* @__PURE__ */ new Map();
14481
+ const taskIdToToolUseId = /* @__PURE__ */ new Map();
13482
14482
  const localToolContext = createClaudeLocalToolContext();
13483
14483
  const { hasLocalToolHandlers, localToolHookNames } = prepareLocalToolHandlersInMcpServers(options.mcpServers);
13484
14484
  const skipLocalToolHooks = options[CLAUDE_AGENT_SDK_SKIP_LOCAL_TOOL_HOOKS_OPTION] === true || hasLocalToolHandlers;
@@ -13495,8 +14495,9 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
13495
14495
  return parentLlm;
13496
14496
  }
13497
14497
  const subAgentSpan = await ensureSubAgentSpan(
13498
- pendingSubAgentNames,
14498
+ subAgentDetailsByToolUseId,
13499
14499
  span,
14500
+ activeToolSpans,
13500
14501
  subAgentSpans,
13501
14502
  parentToolUseId
13502
14503
  );
@@ -13515,6 +14516,7 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
13515
14516
  activeToolSpans,
13516
14517
  localToolHookNames,
13517
14518
  skipLocalToolHooks,
14519
+ subAgentDetailsByToolUseId,
13518
14520
  subAgentSpans,
13519
14521
  endedSubAgentSpans
13520
14522
  );
@@ -13532,12 +14534,13 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
13532
14534
  finalResults: [],
13533
14535
  options: optionsWithHooks,
13534
14536
  originalPrompt,
13535
- pendingSubAgentNames,
13536
14537
  processing: Promise.resolve(),
13537
14538
  promptDone,
13538
14539
  promptStarted: () => promptStarted,
13539
14540
  span,
14541
+ subAgentDetailsByToolUseId,
13540
14542
  subAgentSpans,
14543
+ taskIdToToolUseId,
13541
14544
  latestLlmParentBySubAgentToolUse,
13542
14545
  latestRootLlmParentRef,
13543
14546
  toolUseToParent,
@@ -13619,6 +14622,10 @@ var googleGenAIChannels = defineChannels("@google/genai", {
13619
14622
  generateContentStream: channel({
13620
14623
  channelName: "models.generateContentStream",
13621
14624
  kind: "async"
14625
+ }),
14626
+ embedContent: channel({
14627
+ channelName: "models.embedContent",
14628
+ kind: "async"
13622
14629
  })
13623
14630
  });
13624
14631
 
@@ -13645,6 +14652,7 @@ var GoogleGenAIPlugin = class extends BasePlugin {
13645
14652
  subscribeToGoogleGenAIChannels() {
13646
14653
  this.subscribeToGenerateContentChannel();
13647
14654
  this.subscribeToGenerateContentStreamChannel();
14655
+ this.subscribeToEmbedContentChannel();
13648
14656
  }
13649
14657
  subscribeToGenerateContentChannel() {
13650
14658
  const tracingChannel2 = googleGenAIChannels.generateContent.tracingChannel();
@@ -13654,8 +14662,8 @@ var GoogleGenAIPlugin = class extends BasePlugin {
13654
14662
  states,
13655
14663
  (event) => {
13656
14664
  const params = event.arguments[0];
13657
- const input = serializeInput(params);
13658
- const metadata = extractMetadata(params);
14665
+ const input = serializeGenerateContentInput(params);
14666
+ const metadata = extractGenerateContentMetadata(params);
13659
14667
  const span = startSpan({
13660
14668
  name: "generate_content",
13661
14669
  spanAttributes: {
@@ -13673,8 +14681,8 @@ var GoogleGenAIPlugin = class extends BasePlugin {
13673
14681
  start: (event) => {
13674
14682
  ensureSpanState(states, event, () => {
13675
14683
  const params = event.arguments[0];
13676
- const input = serializeInput(params);
13677
- const metadata = extractMetadata(params);
14684
+ const input = serializeGenerateContentInput(params);
14685
+ const metadata = extractGenerateContentMetadata(params);
13678
14686
  const span = startSpan({
13679
14687
  name: "generate_content",
13680
14688
  spanAttributes: {
@@ -13694,7 +14702,9 @@ var GoogleGenAIPlugin = class extends BasePlugin {
13694
14702
  return;
13695
14703
  }
13696
14704
  try {
14705
+ const responseMetadata = extractResponseMetadata(event.result);
13697
14706
  spanState.span.log({
14707
+ ...responseMetadata ? { metadata: responseMetadata } : {},
13698
14708
  metrics: cleanMetrics(
13699
14709
  extractGenerateContentMetrics(
13700
14710
  event.result,
@@ -13724,8 +14734,8 @@ var GoogleGenAIPlugin = class extends BasePlugin {
13724
14734
  start: (event) => {
13725
14735
  const streamEvent = event;
13726
14736
  const params = event.arguments[0];
13727
- streamEvent.googleGenAIInput = serializeInput(params);
13728
- streamEvent.googleGenAIMetadata = extractMetadata(params);
14737
+ streamEvent.googleGenAIInput = serializeGenerateContentInput(params);
14738
+ streamEvent.googleGenAIMetadata = extractGenerateContentMetadata(params);
13729
14739
  streamEvent.googleGenAIStartTime = getCurrentUnixTimestamp();
13730
14740
  },
13731
14741
  asyncEnd: (event) => {
@@ -13745,6 +14755,76 @@ var GoogleGenAIPlugin = class extends BasePlugin {
13745
14755
  tracingChannel2.unsubscribe(handlers);
13746
14756
  });
13747
14757
  }
14758
+ subscribeToEmbedContentChannel() {
14759
+ const tracingChannel2 = googleGenAIChannels.embedContent.tracingChannel();
14760
+ const states = /* @__PURE__ */ new WeakMap();
14761
+ const unbindCurrentSpanStore = bindCurrentSpanStoreToStart2(
14762
+ tracingChannel2,
14763
+ states,
14764
+ (event) => {
14765
+ const params = event.arguments[0];
14766
+ const input = serializeEmbedContentInput(params);
14767
+ const metadata = extractEmbedContentMetadata(params);
14768
+ const span = startSpan({
14769
+ name: "embed_content",
14770
+ spanAttributes: {
14771
+ type: "llm" /* LLM */
14772
+ },
14773
+ event: createWrapperParityEvent({ input, metadata })
14774
+ });
14775
+ return {
14776
+ span,
14777
+ startTime: getCurrentUnixTimestamp()
14778
+ };
14779
+ }
14780
+ );
14781
+ const handlers = {
14782
+ start: (event) => {
14783
+ ensureSpanState(states, event, () => {
14784
+ const params = event.arguments[0];
14785
+ const input = serializeEmbedContentInput(params);
14786
+ const metadata = extractEmbedContentMetadata(params);
14787
+ const span = startSpan({
14788
+ name: "embed_content",
14789
+ spanAttributes: {
14790
+ type: "llm" /* LLM */
14791
+ },
14792
+ event: createWrapperParityEvent({ input, metadata })
14793
+ });
14794
+ return {
14795
+ span,
14796
+ startTime: getCurrentUnixTimestamp()
14797
+ };
14798
+ });
14799
+ },
14800
+ asyncEnd: (event) => {
14801
+ const spanState = states.get(event);
14802
+ if (!spanState) {
14803
+ return;
14804
+ }
14805
+ try {
14806
+ const output = summarizeEmbedContentOutput(event.result);
14807
+ spanState.span.log({
14808
+ ...output ? { output } : {},
14809
+ metrics: cleanMetrics(
14810
+ extractEmbedContentMetrics(event.result, spanState.startTime)
14811
+ )
14812
+ });
14813
+ } finally {
14814
+ spanState.span.end();
14815
+ states.delete(event);
14816
+ }
14817
+ },
14818
+ error: (event) => {
14819
+ logErrorAndEndSpan(states, event);
14820
+ }
14821
+ };
14822
+ tracingChannel2.subscribe(handlers);
14823
+ this.unsubscribers.push(() => {
14824
+ unbindCurrentSpanStore?.();
14825
+ tracingChannel2.unsubscribe(handlers);
14826
+ });
14827
+ }
13748
14828
  };
13749
14829
  function ensureSpanState(states, event, create) {
13750
14830
  const existing = states.get(event);
@@ -13818,7 +14898,11 @@ function patchGoogleGenAIStreamingResult(args) {
13818
14898
  finalized = true;
13819
14899
  if (options.result) {
13820
14900
  const { end, ...metricsWithoutEnd } = options.result.metrics;
14901
+ const responseMetadata = extractResponseMetadata(
14902
+ options.result.aggregated
14903
+ );
13821
14904
  span.log({
14905
+ ...responseMetadata ? { metadata: responseMetadata } : {},
13822
14906
  metrics: cleanMetrics(metricsWithoutEnd),
13823
14907
  output: options.result.aggregated
13824
14908
  });
@@ -13921,26 +15005,35 @@ function patchGoogleGenAIStreamingResult(args) {
13921
15005
  patchIterator(result);
13922
15006
  return true;
13923
15007
  }
13924
- function serializeInput(params) {
15008
+ function serializeGenerateContentInput(params) {
13925
15009
  const input = {
13926
15010
  model: params.model,
13927
- contents: serializeContents(params.contents)
15011
+ contents: serializeContentCollection(params.contents)
13928
15012
  };
13929
- if (params.config) {
13930
- const config = tryToDict(params.config);
13931
- if (config) {
13932
- const filteredConfig = {};
13933
- Object.keys(config).forEach((key) => {
13934
- if (key !== "tools") {
13935
- filteredConfig[key] = config[key];
13936
- }
13937
- });
13938
- input.config = filteredConfig;
13939
- }
15013
+ const config = params.config ? tryToDict(params.config) : null;
15014
+ if (config) {
15015
+ const filteredConfig = {};
15016
+ Object.keys(config).forEach((key) => {
15017
+ if (key !== "tools") {
15018
+ filteredConfig[key] = config[key];
15019
+ }
15020
+ });
15021
+ input.config = filteredConfig;
15022
+ }
15023
+ return input;
15024
+ }
15025
+ function serializeEmbedContentInput(params) {
15026
+ const input = {
15027
+ model: params.model,
15028
+ contents: serializeContentCollection(params.contents)
15029
+ };
15030
+ const config = params.config ? tryToDict(params.config) : null;
15031
+ if (config) {
15032
+ input.config = config;
13940
15033
  }
13941
15034
  return input;
13942
15035
  }
13943
- function serializeContents(contents) {
15036
+ function serializeContentCollection(contents) {
13944
15037
  if (contents === null || contents === void 0) {
13945
15038
  return null;
13946
15039
  }
@@ -13992,22 +15085,26 @@ function serializePart(part) {
13992
15085
  }
13993
15086
  return part;
13994
15087
  }
13995
- function serializeTools(params) {
13996
- if (!params.config?.tools) {
15088
+ function serializeGenerateContentTools(params) {
15089
+ const config = params.config ? tryToDict(params.config) : null;
15090
+ const tools = config?.tools;
15091
+ if (!Array.isArray(tools)) {
13997
15092
  return null;
13998
15093
  }
13999
15094
  try {
14000
- return params.config.tools.map((tool) => {
14001
- if (typeof tool === "object" && tool.functionDeclarations) {
14002
- return tool;
15095
+ const serializedTools = [];
15096
+ for (const tool of tools) {
15097
+ const toolDict = tryToDict(tool);
15098
+ if (toolDict) {
15099
+ serializedTools.push(toolDict);
14003
15100
  }
14004
- return tool;
14005
- });
15101
+ }
15102
+ return serializedTools.length > 0 ? serializedTools : null;
14006
15103
  } catch {
14007
15104
  return null;
14008
15105
  }
14009
15106
  }
14010
- function extractMetadata(params) {
15107
+ function extractGenerateContentMetadata(params) {
14011
15108
  const metadata = {};
14012
15109
  if (params.model) {
14013
15110
  metadata.model = params.model;
@@ -14022,12 +15119,25 @@ function extractMetadata(params) {
14022
15119
  });
14023
15120
  }
14024
15121
  }
14025
- const tools = serializeTools(params);
15122
+ const tools = serializeGenerateContentTools(params);
14026
15123
  if (tools) {
14027
15124
  metadata.tools = tools;
14028
15125
  }
14029
15126
  return metadata;
14030
15127
  }
15128
+ function extractEmbedContentMetadata(params) {
15129
+ const metadata = {};
15130
+ if (params.model) {
15131
+ metadata.model = params.model;
15132
+ }
15133
+ const config = params.config ? tryToDict(params.config) : null;
15134
+ if (config) {
15135
+ Object.keys(config).forEach((key) => {
15136
+ metadata[key] = config[key];
15137
+ });
15138
+ }
15139
+ return metadata;
15140
+ }
14031
15141
  function extractGenerateContentMetrics(response, startTime) {
14032
15142
  const metrics = {};
14033
15143
  if (startTime !== void 0) {
@@ -14041,24 +15151,87 @@ function extractGenerateContentMetrics(response, startTime) {
14041
15151
  }
14042
15152
  return metrics;
14043
15153
  }
14044
- function populateUsageMetrics(metrics, usage) {
14045
- if (usage.promptTokenCount !== void 0) {
14046
- metrics.prompt_tokens = usage.promptTokenCount;
15154
+ function extractEmbedContentMetrics(response, startTime) {
15155
+ const metrics = {};
15156
+ if (startTime !== void 0) {
15157
+ const end = getCurrentUnixTimestamp();
15158
+ metrics.start = startTime;
15159
+ metrics.end = end;
15160
+ metrics.duration = end - startTime;
14047
15161
  }
14048
- if (usage.candidatesTokenCount !== void 0) {
14049
- metrics.completion_tokens = usage.candidatesTokenCount;
15162
+ if (response?.usageMetadata) {
15163
+ populateUsageMetrics(metrics, response.usageMetadata);
14050
15164
  }
14051
- if (usage.totalTokenCount !== void 0) {
14052
- metrics.tokens = usage.totalTokenCount;
15165
+ const embeddingTokenCount = extractEmbedPromptTokenCount(response);
15166
+ if (embeddingTokenCount !== void 0) {
15167
+ metrics.prompt_tokens = embeddingTokenCount;
15168
+ metrics.tokens = embeddingTokenCount;
14053
15169
  }
14054
- if (usage.cachedContentTokenCount !== void 0) {
14055
- metrics.prompt_cached_tokens = usage.cachedContentTokenCount;
15170
+ return metrics;
15171
+ }
15172
+ function extractEmbedPromptTokenCount(response) {
15173
+ if (!response) {
15174
+ return void 0;
14056
15175
  }
14057
- if (usage.thoughtsTokenCount !== void 0) {
14058
- metrics.completion_reasoning_tokens = usage.thoughtsTokenCount;
15176
+ const usagePromptTokens = response.usageMetadata?.promptTokenCount;
15177
+ if (typeof usagePromptTokens === "number" && Number.isFinite(usagePromptTokens)) {
15178
+ return usagePromptTokens;
15179
+ }
15180
+ const usageTotalTokens = response.usageMetadata?.totalTokenCount;
15181
+ if (typeof usageTotalTokens === "number" && Number.isFinite(usageTotalTokens)) {
15182
+ return usageTotalTokens;
15183
+ }
15184
+ const embeddings = Array.isArray(response.embeddings) ? response.embeddings : response.embedding ? [response.embedding] : [];
15185
+ if (embeddings.length === 0) {
15186
+ return void 0;
15187
+ }
15188
+ let total = 0;
15189
+ let sawAny = false;
15190
+ for (const embedding of embeddings) {
15191
+ const embeddingStats = tryToDict(tryToDict(embedding)?.statistics);
15192
+ const tokenCount = embeddingStats?.tokenCount;
15193
+ if (typeof tokenCount === "number" && Number.isFinite(tokenCount)) {
15194
+ total += tokenCount;
15195
+ sawAny = true;
15196
+ }
14059
15197
  }
15198
+ return sawAny ? total : void 0;
14060
15199
  }
14061
- function aggregateGenerateContentChunks(chunks, startTime, firstTokenTime) {
15200
+ function summarizeEmbedContentOutput(response) {
15201
+ if (!response) {
15202
+ return void 0;
15203
+ }
15204
+ const embeddings = Array.isArray(response.embeddings) ? response.embeddings : response.embedding ? [response.embedding] : [];
15205
+ if (embeddings.length === 0) {
15206
+ return void 0;
15207
+ }
15208
+ const firstValues = embeddings[0]?.values;
15209
+ if (!Array.isArray(firstValues)) {
15210
+ return void 0;
15211
+ }
15212
+ return {
15213
+ embedding_count: embeddings.length,
15214
+ embedding_length: firstValues.length
15215
+ };
15216
+ }
15217
+ function populateUsageMetrics(metrics, usage) {
15218
+ if (usage.promptTokenCount !== void 0) {
15219
+ metrics.prompt_tokens = usage.promptTokenCount;
15220
+ }
15221
+ if (usage.candidatesTokenCount !== void 0) {
15222
+ metrics.completion_tokens = usage.candidatesTokenCount;
15223
+ }
15224
+ if (usage.totalTokenCount !== void 0) {
15225
+ metrics.tokens = usage.totalTokenCount;
15226
+ }
15227
+ if (usage.cachedContentTokenCount !== void 0) {
15228
+ metrics.prompt_cached_tokens = usage.cachedContentTokenCount;
15229
+ }
15230
+ if (usage.thoughtsTokenCount !== void 0) {
15231
+ metrics.completion_reasoning_tokens = usage.thoughtsTokenCount;
15232
+ }
15233
+ }
15234
+ function aggregateGenerateContentChunks(chunks, startTime, firstTokenTime) {
14062
15235
  const end = getCurrentUnixTimestamp();
14063
15236
  const metrics = {
14064
15237
  start: startTime,
@@ -14074,6 +15247,7 @@ function aggregateGenerateContentChunks(chunks, startTime, firstTokenTime) {
14074
15247
  let text = "";
14075
15248
  let thoughtText = "";
14076
15249
  const otherParts = [];
15250
+ let groundingMetadata = void 0;
14077
15251
  let usageMetadata = null;
14078
15252
  let lastResponse = null;
14079
15253
  for (const chunk of chunks) {
@@ -14081,6 +15255,9 @@ function aggregateGenerateContentChunks(chunks, startTime, firstTokenTime) {
14081
15255
  if (chunk.usageMetadata) {
14082
15256
  usageMetadata = chunk.usageMetadata;
14083
15257
  }
15258
+ if (chunk.groundingMetadata !== void 0) {
15259
+ groundingMetadata = chunk.groundingMetadata;
15260
+ }
14084
15261
  if (chunk.candidates && Array.isArray(chunk.candidates)) {
14085
15262
  for (const candidate of chunk.candidates) {
14086
15263
  if (candidate.content?.parts) {
@@ -14126,6 +15303,12 @@ function aggregateGenerateContentChunks(chunks, startTime, firstTokenTime) {
14126
15303
  if (candidate.finishReason !== void 0) {
14127
15304
  candidateDict.finishReason = candidate.finishReason;
14128
15305
  }
15306
+ if (candidate.groundingMetadata !== void 0) {
15307
+ candidateDict.groundingMetadata = candidate.groundingMetadata;
15308
+ if (groundingMetadata === void 0) {
15309
+ groundingMetadata = candidate.groundingMetadata;
15310
+ }
15311
+ }
14129
15312
  if (candidate.safetyRatings) {
14130
15313
  candidateDict.safetyRatings = candidate.safetyRatings;
14131
15314
  }
@@ -14137,6 +15320,9 @@ function aggregateGenerateContentChunks(chunks, startTime, firstTokenTime) {
14137
15320
  aggregated.usageMetadata = usageMetadata;
14138
15321
  populateUsageMetrics(metrics, usageMetadata);
14139
15322
  }
15323
+ if (groundingMetadata !== void 0) {
15324
+ aggregated.groundingMetadata = groundingMetadata;
15325
+ }
14140
15326
  if (text) {
14141
15327
  aggregated.text = text;
14142
15328
  }
@@ -14151,6 +15337,31 @@ function cleanMetrics(metrics) {
14151
15337
  }
14152
15338
  return cleaned;
14153
15339
  }
15340
+ function extractResponseMetadata(response) {
15341
+ const responseDict = tryToDict(response);
15342
+ if (!responseDict) {
15343
+ return void 0;
15344
+ }
15345
+ const metadata = {};
15346
+ const responseGroundingMetadata = responseDict.groundingMetadata;
15347
+ const candidateGroundingMetadata = [];
15348
+ if (Array.isArray(responseDict.candidates)) {
15349
+ for (const candidate of responseDict.candidates) {
15350
+ const candidateDict = tryToDict(candidate);
15351
+ if (candidateDict?.groundingMetadata !== void 0) {
15352
+ candidateGroundingMetadata.push(candidateDict.groundingMetadata);
15353
+ }
15354
+ }
15355
+ }
15356
+ if (responseGroundingMetadata !== void 0) {
15357
+ metadata.groundingMetadata = responseGroundingMetadata;
15358
+ } else if (candidateGroundingMetadata.length === 1) {
15359
+ [metadata.groundingMetadata] = candidateGroundingMetadata;
15360
+ } else if (candidateGroundingMetadata.length > 1) {
15361
+ metadata.groundingMetadata = candidateGroundingMetadata;
15362
+ }
15363
+ return Object.keys(metadata).length > 0 ? metadata : void 0;
15364
+ }
14154
15365
  function tryToDict(obj) {
14155
15366
  if (obj === null || obj === void 0) {
14156
15367
  return null;
@@ -14165,6 +15376,385 @@ function tryToDict(obj) {
14165
15376
  return null;
14166
15377
  }
14167
15378
 
15379
+ // src/instrumentation/plugins/huggingface-channels.ts
15380
+ var huggingFaceChannels = defineChannels("@huggingface/inference", {
15381
+ chatCompletion: channel({
15382
+ channelName: "chatCompletion",
15383
+ kind: "async"
15384
+ }),
15385
+ chatCompletionStream: channel({
15386
+ channelName: "chatCompletionStream",
15387
+ kind: "sync-stream"
15388
+ }),
15389
+ textGeneration: channel({
15390
+ channelName: "textGeneration",
15391
+ kind: "async"
15392
+ }),
15393
+ textGenerationStream: channel({
15394
+ channelName: "textGenerationStream",
15395
+ kind: "sync-stream"
15396
+ }),
15397
+ featureExtraction: channel({
15398
+ channelName: "featureExtraction",
15399
+ kind: "async"
15400
+ })
15401
+ });
15402
+
15403
+ // src/instrumentation/plugins/huggingface-plugin.ts
15404
+ var REQUEST_METADATA_ALLOWLIST = /* @__PURE__ */ new Set([
15405
+ "dimensions",
15406
+ "encoding_format",
15407
+ "endpointUrl",
15408
+ "max_tokens",
15409
+ "model",
15410
+ "provider",
15411
+ "seed",
15412
+ "stop",
15413
+ "stream",
15414
+ "temperature",
15415
+ "top_p"
15416
+ ]);
15417
+ var RESPONSE_METADATA_ALLOWLIST = /* @__PURE__ */ new Set([
15418
+ "created",
15419
+ "id",
15420
+ "model",
15421
+ "object"
15422
+ ]);
15423
+ var HuggingFacePlugin = class extends BasePlugin {
15424
+ onEnable() {
15425
+ this.unsubscribers.push(
15426
+ traceAsyncChannel(huggingFaceChannels.chatCompletion, {
15427
+ name: "huggingface.chat_completion",
15428
+ type: "llm" /* LLM */,
15429
+ extractInput: extractChatInputWithMetadata,
15430
+ extractOutput: (result) => result?.choices,
15431
+ extractMetadata: (result) => extractResponseMetadata2(result),
15432
+ extractMetrics: (result) => parseMetricsFromUsage(result?.usage)
15433
+ }),
15434
+ traceSyncStreamChannel(huggingFaceChannels.chatCompletionStream, {
15435
+ name: "huggingface.chat_completion_stream",
15436
+ type: "llm" /* LLM */,
15437
+ extractInput: extractChatInputWithMetadata,
15438
+ patchResult: ({ result, span, startTime }) => patchChatCompletionStream({
15439
+ result,
15440
+ span,
15441
+ startTime
15442
+ })
15443
+ }),
15444
+ traceAsyncChannel(huggingFaceChannels.textGeneration, {
15445
+ name: "huggingface.text_generation",
15446
+ type: "llm" /* LLM */,
15447
+ extractInput: extractTextGenerationInputWithMetadata,
15448
+ extractOutput: (result) => isObject(result) ? { generated_text: result.generated_text } : result,
15449
+ extractMetadata: extractTextGenerationMetadata,
15450
+ extractMetrics: (result) => extractTextGenerationMetrics(result?.details ?? null)
15451
+ }),
15452
+ traceSyncStreamChannel(huggingFaceChannels.textGenerationStream, {
15453
+ name: "huggingface.text_generation_stream",
15454
+ type: "llm" /* LLM */,
15455
+ extractInput: extractTextGenerationInputWithMetadata,
15456
+ patchResult: ({ result, span, startTime }) => patchTextGenerationStream({
15457
+ result,
15458
+ span,
15459
+ startTime
15460
+ })
15461
+ }),
15462
+ traceAsyncChannel(huggingFaceChannels.featureExtraction, {
15463
+ name: "huggingface.feature_extraction",
15464
+ type: "llm" /* LLM */,
15465
+ extractInput: extractFeatureExtractionInputWithMetadata,
15466
+ extractOutput: summarizeFeatureExtractionOutput,
15467
+ extractMetrics: () => ({})
15468
+ })
15469
+ );
15470
+ }
15471
+ onDisable() {
15472
+ this.unsubscribers = unsubscribeAll(this.unsubscribers);
15473
+ }
15474
+ };
15475
+ function addProviderMetadata(metadata) {
15476
+ return {
15477
+ ...metadata,
15478
+ provider: metadata.provider ?? "huggingface"
15479
+ };
15480
+ }
15481
+ function normalizeArgs(args) {
15482
+ if (Array.isArray(args)) {
15483
+ return args;
15484
+ }
15485
+ if (isArrayLike(args)) {
15486
+ return Array.from(args);
15487
+ }
15488
+ return [args];
15489
+ }
15490
+ function isArrayLike(value) {
15491
+ return isObject(value) && "length" in value && typeof value.length === "number" && Number.isInteger(value.length) && value.length >= 0;
15492
+ }
15493
+ function getFirstObjectArg(args) {
15494
+ const firstObjectArg = normalizeArgs(args).find((arg) => isObject(arg));
15495
+ return isObject(firstObjectArg) ? firstObjectArg : void 0;
15496
+ }
15497
+ function pickRequestMetadata(params) {
15498
+ if (!params) {
15499
+ return addProviderMetadata({});
15500
+ }
15501
+ const metadata = {};
15502
+ for (const key of REQUEST_METADATA_ALLOWLIST) {
15503
+ const value = params[key];
15504
+ if (value !== void 0) {
15505
+ metadata[key] = value;
15506
+ }
15507
+ }
15508
+ if (isObject(params.parameters)) {
15509
+ metadata.parameters = params.parameters;
15510
+ }
15511
+ return addProviderMetadata(metadata);
15512
+ }
15513
+ function extractChatInputWithMetadata(args) {
15514
+ const params = getFirstObjectArg(args);
15515
+ const { messages, ...rawMetadata } = params ?? {};
15516
+ return {
15517
+ input: messages,
15518
+ metadata: pickRequestMetadata(rawMetadata)
15519
+ };
15520
+ }
15521
+ function extractTextGenerationInputWithMetadata(args) {
15522
+ const params = getFirstObjectArg(args);
15523
+ const { inputs, ...rawMetadata } = params ?? {};
15524
+ return {
15525
+ input: inputs,
15526
+ metadata: pickRequestMetadata(rawMetadata)
15527
+ };
15528
+ }
15529
+ function extractFeatureExtractionInputWithMetadata(args) {
15530
+ const params = getFirstObjectArg(args);
15531
+ const { inputs, ...rawMetadata } = params ?? {};
15532
+ return {
15533
+ input: inputs,
15534
+ metadata: pickRequestMetadata(rawMetadata)
15535
+ };
15536
+ }
15537
+ function extractResponseMetadata2(result) {
15538
+ if (!isObject(result)) {
15539
+ return void 0;
15540
+ }
15541
+ const metadata = {};
15542
+ for (const key of RESPONSE_METADATA_ALLOWLIST) {
15543
+ const value = result[key];
15544
+ if (value !== void 0) {
15545
+ metadata[key] = value;
15546
+ }
15547
+ }
15548
+ return Object.keys(metadata).length > 0 ? metadata : void 0;
15549
+ }
15550
+ function extractTextGenerationMetrics(details) {
15551
+ if (!isObject(details)) {
15552
+ return {};
15553
+ }
15554
+ const promptTokens = Array.isArray(details.prefill) ? details.prefill.length : void 0;
15555
+ const completionTokens = typeof details.generated_tokens === "number" ? details.generated_tokens : Array.isArray(details.tokens) ? details.tokens.length : void 0;
15556
+ const metrics = {};
15557
+ if (promptTokens !== void 0) {
15558
+ metrics.prompt_tokens = promptTokens;
15559
+ }
15560
+ if (completionTokens !== void 0) {
15561
+ metrics.completion_tokens = completionTokens;
15562
+ }
15563
+ if (promptTokens !== void 0 || completionTokens !== void 0) {
15564
+ metrics.tokens = (promptTokens ?? 0) + (completionTokens ?? 0);
15565
+ }
15566
+ return metrics;
15567
+ }
15568
+ function extractTextGenerationMetadata(result) {
15569
+ if (!isObject(result?.details)) {
15570
+ return void 0;
15571
+ }
15572
+ return typeof result.details.finish_reason === "string" ? {
15573
+ finish_reason: result.details.finish_reason
15574
+ } : void 0;
15575
+ }
15576
+ function summarizeFeatureExtractionOutput(result) {
15577
+ if (!Array.isArray(result)) {
15578
+ return void 0;
15579
+ }
15580
+ const first = result[0];
15581
+ if (typeof first === "number") {
15582
+ return { embedding_length: result.length };
15583
+ }
15584
+ if (Array.isArray(first) && first.every((value) => typeof value === "number")) {
15585
+ return {
15586
+ embedding_count: result.length,
15587
+ embedding_length: first.length
15588
+ };
15589
+ }
15590
+ if (Array.isArray(first) && first.length > 0 && Array.isArray(first[0]) && first[0].every((value) => typeof value === "number")) {
15591
+ return {
15592
+ embedding_batch_count: result.length,
15593
+ embedding_count: first.length,
15594
+ embedding_length: first[0].length
15595
+ };
15596
+ }
15597
+ return void 0;
15598
+ }
15599
+ function patchChatCompletionStream(args) {
15600
+ const { result, span, startTime } = args;
15601
+ if (!result || !isAsyncIterable(result)) {
15602
+ return false;
15603
+ }
15604
+ let firstChunkTime;
15605
+ patchStreamIfNeeded(result, {
15606
+ onChunk: () => {
15607
+ if (firstChunkTime === void 0) {
15608
+ firstChunkTime = getCurrentUnixTimestamp();
15609
+ }
15610
+ },
15611
+ onComplete: (chunks) => {
15612
+ const lastChunk = chunks.at(-1);
15613
+ const responseMetadata = extractResponseMetadata2(lastChunk);
15614
+ const metrics = {
15615
+ ...parseMetricsFromUsage(lastChunk?.usage),
15616
+ ...firstChunkTime !== void 0 ? { time_to_first_token: firstChunkTime - startTime } : {}
15617
+ };
15618
+ span.log({
15619
+ output: aggregateChatCompletionChunks2(chunks),
15620
+ ...responseMetadata ? { metadata: responseMetadata } : {},
15621
+ metrics
15622
+ });
15623
+ span.end();
15624
+ },
15625
+ onError: (error) => {
15626
+ span.log({
15627
+ error: error.message
15628
+ });
15629
+ span.end();
15630
+ }
15631
+ });
15632
+ return true;
15633
+ }
15634
+ function patchTextGenerationStream(args) {
15635
+ const { result, span, startTime } = args;
15636
+ if (!result || !isAsyncIterable(result)) {
15637
+ return false;
15638
+ }
15639
+ let firstChunkTime;
15640
+ patchStreamIfNeeded(result, {
15641
+ onChunk: () => {
15642
+ if (firstChunkTime === void 0) {
15643
+ firstChunkTime = getCurrentUnixTimestamp();
15644
+ }
15645
+ },
15646
+ onComplete: (chunks) => {
15647
+ const lastChunk = chunks.at(-1);
15648
+ const streamMetadata = extractTextGenerationStreamMetadata(chunks);
15649
+ span.log({
15650
+ output: aggregateTextGenerationStreamChunks(chunks),
15651
+ ...streamMetadata ? { metadata: streamMetadata } : {},
15652
+ metrics: {
15653
+ ...extractTextGenerationMetrics(lastChunk?.details ?? null),
15654
+ ...parseMetricsFromUsage(lastChunk?.usage),
15655
+ ...firstChunkTime !== void 0 ? { time_to_first_token: firstChunkTime - startTime } : {}
15656
+ }
15657
+ });
15658
+ span.end();
15659
+ },
15660
+ onError: (error) => {
15661
+ span.log({
15662
+ error: error.message
15663
+ });
15664
+ span.end();
15665
+ }
15666
+ });
15667
+ return true;
15668
+ }
15669
+ function aggregateChatCompletionChunks2(chunks) {
15670
+ if (chunks.length === 0) {
15671
+ return void 0;
15672
+ }
15673
+ const aggregatedChoices = /* @__PURE__ */ new Map();
15674
+ for (const chunk of chunks) {
15675
+ for (const choice of chunk.choices ?? []) {
15676
+ const index = typeof choice.index === "number" ? choice.index : 0;
15677
+ const existing = aggregatedChoices.get(index) ?? { content: "" };
15678
+ const delta = isObject(choice.delta) ? choice.delta : void 0;
15679
+ const message = isObject(choice.message) ? choice.message : void 0;
15680
+ if (typeof delta?.content === "string") {
15681
+ existing.content += delta.content;
15682
+ } else if (typeof message?.content === "string") {
15683
+ existing.content = message.content;
15684
+ }
15685
+ if (typeof delta?.role === "string") {
15686
+ existing.role = delta.role;
15687
+ } else if (typeof message?.role === "string") {
15688
+ existing.role = message.role;
15689
+ }
15690
+ if (choice.finish_reason !== void 0) {
15691
+ existing.finish_reason = choice.finish_reason;
15692
+ }
15693
+ aggregatedChoices.set(index, existing);
15694
+ }
15695
+ }
15696
+ return {
15697
+ choices: [...aggregatedChoices.entries()].map(([index, choice]) => ({
15698
+ index,
15699
+ message: {
15700
+ content: choice.content,
15701
+ role: choice.role ?? "assistant"
15702
+ },
15703
+ ...choice.finish_reason !== void 0 ? { finish_reason: choice.finish_reason } : {}
15704
+ }))
15705
+ };
15706
+ }
15707
+ function aggregateTextGenerationStreamChunks(chunks) {
15708
+ if (chunks.length === 0) {
15709
+ return void 0;
15710
+ }
15711
+ let generatedText = "";
15712
+ let finishReason;
15713
+ for (const chunk of chunks) {
15714
+ if (typeof chunk.generated_text === "string") {
15715
+ generatedText = chunk.generated_text;
15716
+ } else if (typeof chunk.token?.text === "string" && !chunk.token.special) {
15717
+ generatedText += chunk.token.text;
15718
+ } else if (Array.isArray(chunk.choices)) {
15719
+ for (const choice of chunk.choices) {
15720
+ if (typeof choice.text === "string") {
15721
+ generatedText += choice.text;
15722
+ }
15723
+ if (choice.finish_reason !== void 0) {
15724
+ finishReason = choice.finish_reason;
15725
+ }
15726
+ }
15727
+ }
15728
+ if (isObject(chunk.details) && typeof chunk.details.finish_reason === "string") {
15729
+ finishReason = chunk.details.finish_reason;
15730
+ }
15731
+ }
15732
+ return {
15733
+ generated_text: generatedText,
15734
+ ...finishReason !== void 0 ? { finish_reason: finishReason } : {}
15735
+ };
15736
+ }
15737
+ function extractTextGenerationStreamMetadata(chunks) {
15738
+ for (let index = chunks.length - 1; index >= 0; index--) {
15739
+ const chunk = chunks[index];
15740
+ if (isObject(chunk?.details) && typeof chunk.details.finish_reason === "string") {
15741
+ return {
15742
+ finish_reason: chunk.details.finish_reason
15743
+ };
15744
+ }
15745
+ if (!Array.isArray(chunk?.choices)) {
15746
+ continue;
15747
+ }
15748
+ for (let choiceIndex = chunk.choices.length - 1; choiceIndex >= 0; choiceIndex--) {
15749
+ const choice = chunk.choices[choiceIndex];
15750
+ if (choice?.finish_reason !== void 0) {
15751
+ return { finish_reason: choice.finish_reason };
15752
+ }
15753
+ }
15754
+ }
15755
+ return void 0;
15756
+ }
15757
+
14168
15758
  // src/instrumentation/plugins/openrouter-agent-channels.ts
14169
15759
  var openRouterAgentChannels = defineChannels("@openrouter/agent", {
14170
15760
  callModel: channel({
@@ -14282,20 +15872,20 @@ var OpenRouterAgentPlugin = class extends BasePlugin {
14282
15872
  });
14283
15873
  }
14284
15874
  };
14285
- function normalizeArgs(args) {
15875
+ function normalizeArgs2(args) {
14286
15876
  if (Array.isArray(args)) {
14287
15877
  return args;
14288
15878
  }
14289
- if (isArrayLike(args)) {
15879
+ if (isArrayLike2(args)) {
14290
15880
  return Array.from(args);
14291
15881
  }
14292
15882
  return [args];
14293
15883
  }
14294
- function isArrayLike(value) {
15884
+ function isArrayLike2(value) {
14295
15885
  return isObject(value) && "length" in value && typeof value.length === "number" && Number.isInteger(value.length) && value.length >= 0;
14296
15886
  }
14297
15887
  function getOpenRouterCallModelRequestArg(args) {
14298
- const normalizedArgs = normalizeArgs(args);
15888
+ const normalizedArgs = normalizeArgs2(args);
14299
15889
  const keyedRequestArg = normalizedArgs.find(
14300
15890
  (arg) => isObject(arg) && ("input" in arg || "model" in arg || "tools" in arg)
14301
15891
  );
@@ -14581,7 +16171,7 @@ function traceToolExecution(args) {
14581
16171
  }
14582
16172
  }
14583
16173
  function publishToolResult(tracingChannel2, event, result) {
14584
- if (isPromiseLike3(result)) {
16174
+ if (isPromiseLike(result)) {
14585
16175
  return result.then(
14586
16176
  (resolved) => {
14587
16177
  event.result = resolved;
@@ -14603,9 +16193,6 @@ function getToolCallId(context) {
14603
16193
  const toolContext = context;
14604
16194
  return typeof toolContext?.toolCall?.id === "string" ? toolContext.toolCall.id : void 0;
14605
16195
  }
14606
- function isPromiseLike3(value) {
14607
- return !!value && (typeof value === "object" || typeof value === "function") && "then" in value && typeof value.then === "function";
14608
- }
14609
16196
  var OPENROUTER_WRAPPED_CALL_MODEL_RESULT = Symbol(
14610
16197
  "braintrust.openrouter.wrappedCallModelResult"
14611
16198
  );
@@ -14960,7 +16547,13 @@ var openRouterChannels = defineChannels("@openrouter/sdk", {
14960
16547
  channelName: "embeddings.generate",
14961
16548
  kind: "async"
14962
16549
  }),
14963
- betaResponsesSend: channel({
16550
+ rerankRerank: channel(
16551
+ {
16552
+ channelName: "rerank.rerank",
16553
+ kind: "async"
16554
+ }
16555
+ ),
16556
+ betaResponsesSend: channel({
14964
16557
  channelName: "beta.responses.send",
14965
16558
  kind: "async"
14966
16559
  }),
@@ -15052,6 +16645,34 @@ var OpenRouterPlugin = class extends BasePlugin {
15052
16645
  }
15053
16646
  })
15054
16647
  );
16648
+ this.unsubscribers.push(
16649
+ traceAsyncChannel(openRouterChannels.rerankRerank, {
16650
+ name: "openrouter.rerank.rerank",
16651
+ type: "llm" /* LLM */,
16652
+ extractInput: (args) => {
16653
+ const request = getOpenRouterRequestArg(args);
16654
+ const requestBody = isObject(request?.requestBody) ? request.requestBody : {};
16655
+ const httpReferer = request?.httpReferer;
16656
+ const xTitle = request?.xTitle ?? request?.appTitle;
16657
+ const { documents, query, ...metadata } = requestBody;
16658
+ return {
16659
+ input: {
16660
+ documents,
16661
+ query
16662
+ },
16663
+ metadata: buildOpenRouterRerankMetadata(
16664
+ metadata,
16665
+ documents,
16666
+ httpReferer,
16667
+ xTitle
16668
+ )
16669
+ };
16670
+ },
16671
+ extractOutput: (result) => extractOpenRouterRerankOutput(result),
16672
+ extractMetadata: (result) => extractOpenRouterResponseMetadata2(result),
16673
+ extractMetrics: (result) => isObject(result) ? parseOpenRouterMetricsFromUsage2(result.usage) : {}
16674
+ })
16675
+ );
15055
16676
  this.unsubscribers.push(
15056
16677
  traceStreamingChannel(openRouterChannels.betaResponsesSend, {
15057
16678
  name: "openrouter.beta.responses.send",
@@ -15171,20 +16792,20 @@ var OpenRouterPlugin = class extends BasePlugin {
15171
16792
  });
15172
16793
  }
15173
16794
  };
15174
- function normalizeArgs2(args) {
16795
+ function normalizeArgs3(args) {
15175
16796
  if (Array.isArray(args)) {
15176
16797
  return args;
15177
16798
  }
15178
- if (isArrayLike2(args)) {
16799
+ if (isArrayLike3(args)) {
15179
16800
  return Array.from(args);
15180
16801
  }
15181
16802
  return [args];
15182
16803
  }
15183
- function isArrayLike2(value) {
16804
+ function isArrayLike3(value) {
15184
16805
  return isObject(value) && "length" in value && typeof value.length === "number" && Number.isInteger(value.length) && value.length >= 0;
15185
16806
  }
15186
16807
  function getOpenRouterRequestArg(args) {
15187
- const normalizedArgs = normalizeArgs2(args);
16808
+ const normalizedArgs = normalizeArgs3(args);
15188
16809
  const keyedCandidate = normalizedArgs.find(
15189
16810
  (arg) => isObject(arg) && ("chatGenerationParams" in arg || "requestBody" in arg || "openResponsesRequest" in arg)
15190
16811
  );
@@ -15195,7 +16816,7 @@ function getOpenRouterRequestArg(args) {
15195
16816
  return isObject(firstObjectArg) ? firstObjectArg : void 0;
15196
16817
  }
15197
16818
  function getOpenRouterCallModelRequestArg2(args) {
15198
- const firstObjectArg = normalizeArgs2(args).find((arg) => isObject(arg));
16819
+ const firstObjectArg = normalizeArgs3(args).find((arg) => isObject(arg));
15199
16820
  return isObject(firstObjectArg) ? firstObjectArg : void 0;
15200
16821
  }
15201
16822
  var TOKEN_NAME_MAP3 = {
@@ -15365,6 +16986,13 @@ function buildOpenRouterEmbeddingMetadata(metadata, httpReferer, xTitle) {
15365
16986
  embedding_model: normalized.model
15366
16987
  } : normalized;
15367
16988
  }
16989
+ function buildOpenRouterRerankMetadata(metadata, documents, httpReferer, xTitle) {
16990
+ const normalized = buildOpenRouterMetadata2(metadata, httpReferer, xTitle);
16991
+ return {
16992
+ ...normalized,
16993
+ ...Array.isArray(documents) ? { document_count: documents.length } : {}
16994
+ };
16995
+ }
15368
16996
  function extractOpenRouterCallModelInput2(request) {
15369
16997
  return isObject(request) && "input" in request ? sanitizeOpenRouterLoggedValue2(request.input) : void 0;
15370
16998
  }
@@ -15384,7 +17012,7 @@ function extractOpenRouterResponseMetadata2(result) {
15384
17012
  const metadataRecord = isObject(sanitized) ? sanitized : {};
15385
17013
  const { model, provider, ...rest } = metadataRecord;
15386
17014
  const normalizedModel = parseOpenRouterModelString2(model);
15387
- const normalizedProvider = (typeof provider === "string" ? provider : void 0) || normalizedModel.provider;
17015
+ const normalizedProvider = (typeof provider === "string" ? provider.toLowerCase() : void 0) || normalizedModel.provider;
15388
17016
  const usageMetadata = extractOpenRouterUsageMetadata2(usage);
15389
17017
  const combined = {
15390
17018
  ...rest,
@@ -15403,6 +17031,15 @@ function extractOpenRouterResponseOutput2(response, fallbackOutput) {
15403
17031
  }
15404
17032
  return void 0;
15405
17033
  }
17034
+ function extractOpenRouterRerankOutput(result) {
17035
+ if (!isObject(result) || !Array.isArray(result.results)) {
17036
+ return void 0;
17037
+ }
17038
+ return result.results.slice(0, 100).map((item) => ({
17039
+ index: isObject(item) && typeof item.index === "number" ? item.index : void 0,
17040
+ relevance_score: isObject(item) && typeof item.relevanceScore === "number" ? item.relevanceScore : isObject(item) && typeof item.relevance_score === "number" ? item.relevance_score : void 0
17041
+ }));
17042
+ }
15406
17043
  var OPENROUTER_WRAPPED_TOOL2 = Symbol("braintrust.openrouter.wrappedTool");
15407
17044
  function patchOpenRouterCallModelRequestTools2(request) {
15408
17045
  if (!Array.isArray(request.tools) || request.tools.length === 0) {
@@ -15473,7 +17110,7 @@ function traceToolExecution2(args) {
15473
17110
  }
15474
17111
  }
15475
17112
  function publishToolResult2(tracingChannel2, event, result) {
15476
- if (isPromiseLike4(result)) {
17113
+ if (isPromiseLike(result)) {
15477
17114
  return result.then(
15478
17115
  (resolved) => {
15479
17116
  event.result = resolved;
@@ -15495,9 +17132,6 @@ function getToolCallId2(context) {
15495
17132
  const toolContext = context;
15496
17133
  return typeof toolContext?.toolCall?.id === "string" ? toolContext.toolCall.id : void 0;
15497
17134
  }
15498
- function isPromiseLike4(value) {
15499
- return !!value && (typeof value === "object" || typeof value === "function") && "then" in value && typeof value.then === "function";
15500
- }
15501
17135
  function aggregateOpenRouterChatChunks(chunks) {
15502
17136
  let role;
15503
17137
  let content = "";
@@ -16137,20 +17771,20 @@ var MISTRAL_RESPONSE_METADATA_ALLOWLIST = /* @__PURE__ */ new Set([
16137
17771
  function camelToSnake3(value) {
16138
17772
  return value.replace(/[A-Z]/g, (match) => `_${match.toLowerCase()}`);
16139
17773
  }
16140
- function normalizeArgs3(args) {
17774
+ function normalizeArgs4(args) {
16141
17775
  if (Array.isArray(args)) {
16142
17776
  return args;
16143
17777
  }
16144
- if (isArrayLike3(args)) {
17778
+ if (isArrayLike4(args)) {
16145
17779
  return Array.from(args);
16146
17780
  }
16147
17781
  return [args];
16148
17782
  }
16149
- function isArrayLike3(value) {
17783
+ function isArrayLike4(value) {
16150
17784
  return isObject(value) && "length" in value && typeof value.length === "number" && Number.isInteger(value.length) && value.length >= 0;
16151
17785
  }
16152
17786
  function getMistralRequestArg(args) {
16153
- const firstObjectArg = normalizeArgs3(args).find((arg) => isObject(arg));
17787
+ const firstObjectArg = normalizeArgs4(args).find((arg) => isObject(arg));
16154
17788
  return isObject(firstObjectArg) ? firstObjectArg : void 0;
16155
17789
  }
16156
17790
  function addMistralProviderMetadata(metadata) {
@@ -16330,128 +17964,1339 @@ function mergeToolCallDeltas(toolCalls, deltas) {
16330
17964
  idToPosition.set(mergedToolCall.id, existingPosition);
16331
17965
  }
16332
17966
  }
16333
- return merged.length > 0 ? merged : void 0;
17967
+ return merged.length > 0 ? merged : void 0;
17968
+ }
17969
+ function getChoiceFinishReason(choice) {
17970
+ if (typeof choice.finishReason === "string" || choice.finishReason === null) {
17971
+ return choice.finishReason;
17972
+ }
17973
+ if (typeof choice.finish_reason === "string" || choice.finish_reason === null) {
17974
+ return choice.finish_reason;
17975
+ }
17976
+ return void 0;
17977
+ }
17978
+ function parseMistralMetricsFromUsage(usage) {
17979
+ if (!isObject(usage)) {
17980
+ return {};
17981
+ }
17982
+ const metrics = {};
17983
+ for (const [name, value] of Object.entries(usage)) {
17984
+ if (typeof value === "number") {
17985
+ metrics[TOKEN_NAME_MAP4[name] || camelToSnake3(name)] = value;
17986
+ continue;
17987
+ }
17988
+ if (!isObject(value)) {
17989
+ continue;
17990
+ }
17991
+ const prefix = TOKEN_DETAIL_PREFIX_MAP3[name];
17992
+ if (!prefix) {
17993
+ continue;
17994
+ }
17995
+ for (const [nestedName, nestedValue] of Object.entries(value)) {
17996
+ if (typeof nestedValue !== "number") {
17997
+ continue;
17998
+ }
17999
+ metrics[`${prefix}_${camelToSnake3(nestedName)}`] = nestedValue;
18000
+ }
18001
+ }
18002
+ return metrics;
18003
+ }
18004
+ function aggregateMistralStreamChunks(chunks) {
18005
+ const choiceAccumulators = /* @__PURE__ */ new Map();
18006
+ const indexToAccumulatorKey = /* @__PURE__ */ new Map();
18007
+ const positionToAccumulatorKey = /* @__PURE__ */ new Map();
18008
+ let nextAccumulatorOrder = 0;
18009
+ let metrics = {};
18010
+ let metadata;
18011
+ for (const event of chunks) {
18012
+ const chunk = isMistralChatCompletionChunk(event?.data) ? event.data : void 0;
18013
+ if (!chunk) {
18014
+ continue;
18015
+ }
18016
+ if (isObject(chunk.usage)) {
18017
+ metrics = {
18018
+ ...metrics,
18019
+ ...parseMistralMetricsFromUsage(chunk.usage)
18020
+ };
18021
+ }
18022
+ const chunkMetadata = extractMistralResponseMetadata(chunk);
18023
+ if (chunkMetadata) {
18024
+ metadata = { ...metadata || {}, ...chunkMetadata };
18025
+ }
18026
+ for (const [choicePosition, rawChoice] of (chunk.choices || []).entries()) {
18027
+ if (!isMistralChunkChoice(rawChoice)) {
18028
+ continue;
18029
+ }
18030
+ const choice = rawChoice;
18031
+ const choiceIndex = typeof choice.index === "number" && choice.index >= 0 ? choice.index : void 0;
18032
+ let accumulatorKey = choiceIndex !== void 0 ? indexToAccumulatorKey.get(choiceIndex) : void 0;
18033
+ if (!accumulatorKey) {
18034
+ accumulatorKey = positionToAccumulatorKey.get(choicePosition);
18035
+ }
18036
+ if (!accumulatorKey) {
18037
+ const initialIndex = choiceIndex ?? choicePosition;
18038
+ const keyPrefix = choiceIndex !== void 0 ? "index" : "position";
18039
+ accumulatorKey = `${keyPrefix}:${initialIndex}`;
18040
+ choiceAccumulators.set(accumulatorKey, {
18041
+ index: initialIndex,
18042
+ order: nextAccumulatorOrder++
18043
+ });
18044
+ }
18045
+ const accumulator = choiceAccumulators.get(accumulatorKey);
18046
+ if (!accumulator) {
18047
+ continue;
18048
+ }
18049
+ if (choiceIndex !== void 0) {
18050
+ accumulator.index = choiceIndex;
18051
+ indexToAccumulatorKey.set(choiceIndex, accumulatorKey);
18052
+ }
18053
+ positionToAccumulatorKey.set(choicePosition, accumulatorKey);
18054
+ const delta = isObject(choice.delta) ? choice.delta : void 0;
18055
+ if (delta) {
18056
+ if (!accumulator.role && typeof delta.role === "string") {
18057
+ accumulator.role = delta.role;
18058
+ }
18059
+ const deltaText = extractDeltaText(delta.content);
18060
+ if (deltaText) {
18061
+ accumulator.content = `${accumulator.content || ""}${deltaText}`;
18062
+ }
18063
+ accumulator.toolCalls = mergeToolCallDeltas(
18064
+ accumulator.toolCalls,
18065
+ getDeltaToolCalls(delta)
18066
+ );
18067
+ }
18068
+ const choiceFinishReason = getChoiceFinishReason(choice);
18069
+ if (choiceFinishReason !== void 0) {
18070
+ accumulator.finishReason = choiceFinishReason;
18071
+ }
18072
+ }
18073
+ }
18074
+ const output = Array.from(choiceAccumulators.values()).sort(
18075
+ (left, right) => left.index === right.index ? left.order - right.order : left.index - right.index
18076
+ ).map((choice) => ({
18077
+ index: choice.index,
18078
+ message: {
18079
+ ...choice.role ? { role: choice.role } : {},
18080
+ content: choice.content ?? null,
18081
+ ...choice.toolCalls ? { toolCalls: choice.toolCalls } : {}
18082
+ },
18083
+ ...choice.finishReason !== void 0 ? { finishReason: choice.finishReason } : {}
18084
+ }));
18085
+ return {
18086
+ output,
18087
+ metrics,
18088
+ ...metadata ? { metadata } : {}
18089
+ };
18090
+ }
18091
+
18092
+ // src/instrumentation/plugins/google-adk-channels.ts
18093
+ var googleADKChannels = defineChannels("@google/adk", {
18094
+ runnerRunAsync: channel({
18095
+ channelName: "runner.runAsync",
18096
+ kind: "sync-stream"
18097
+ }),
18098
+ agentRunAsync: channel({
18099
+ channelName: "agent.runAsync",
18100
+ kind: "sync-stream"
18101
+ }),
18102
+ toolRunAsync: channel({
18103
+ channelName: "tool.runAsync",
18104
+ kind: "async"
18105
+ })
18106
+ });
18107
+
18108
+ // src/instrumentation/plugins/google-adk-plugin.ts
18109
+ var GoogleADKPlugin = class extends BasePlugin {
18110
+ activeRunnerSpans = /* @__PURE__ */ new Map();
18111
+ activeAgentSpans = /* @__PURE__ */ new Map();
18112
+ onEnable() {
18113
+ this.subscribeToRunnerRunAsync();
18114
+ this.subscribeToAgentRunAsync();
18115
+ this.subscribeToToolRunAsync();
18116
+ }
18117
+ onDisable() {
18118
+ for (const unsubscribe of this.unsubscribers) {
18119
+ unsubscribe();
18120
+ }
18121
+ this.unsubscribers = [];
18122
+ this.activeRunnerSpans.clear();
18123
+ this.activeAgentSpans.clear();
18124
+ }
18125
+ subscribeToRunnerRunAsync() {
18126
+ const tracingChannel2 = googleADKChannels.runnerRunAsync.tracingChannel();
18127
+ const states = /* @__PURE__ */ new WeakMap();
18128
+ const createState = (event) => {
18129
+ const params = event.arguments[0] ?? {};
18130
+ const contextKey = extractRunnerContextKey(params);
18131
+ const span = startSpan({
18132
+ name: "Google ADK Runner",
18133
+ spanAttributes: {
18134
+ type: "task" /* TASK */
18135
+ }
18136
+ });
18137
+ const startTime = getCurrentUnixTimestamp();
18138
+ try {
18139
+ const metadata = extractRunnerMetadata(params);
18140
+ span.log({
18141
+ input: extractRunnerInput(params),
18142
+ metadata
18143
+ });
18144
+ } catch {
18145
+ }
18146
+ if (contextKey) {
18147
+ this.activeRunnerSpans.set(contextKey, span);
18148
+ }
18149
+ return { span, startTime, events: [], contextKey };
18150
+ };
18151
+ const unbindCurrentSpanStore = bindCurrentSpanStoreToStart3(
18152
+ tracingChannel2,
18153
+ states,
18154
+ createState
18155
+ );
18156
+ const handlers = {
18157
+ start: (event) => {
18158
+ ensureState(states, event, () => createState(event));
18159
+ },
18160
+ end: (event) => {
18161
+ const state = states.get(event);
18162
+ if (!state) {
18163
+ return;
18164
+ }
18165
+ const result = event.result;
18166
+ if (isAsyncIterable(result)) {
18167
+ bindAsyncIterableToCurrentSpan(result, state.span);
18168
+ patchStreamIfNeeded(result, {
18169
+ onChunk: (adkEvent) => {
18170
+ state.events.push(adkEvent);
18171
+ },
18172
+ onComplete: () => {
18173
+ finalizeRunnerSpan(state, this.activeRunnerSpans);
18174
+ states.delete(event);
18175
+ },
18176
+ onError: (error) => {
18177
+ cleanupActiveRunnerSpan(state, this.activeRunnerSpans);
18178
+ state.span.log({ error: error.message });
18179
+ state.span.end();
18180
+ states.delete(event);
18181
+ }
18182
+ });
18183
+ return;
18184
+ }
18185
+ try {
18186
+ state.span.log({ output: result });
18187
+ } finally {
18188
+ cleanupActiveRunnerSpan(state, this.activeRunnerSpans);
18189
+ state.span.end();
18190
+ states.delete(event);
18191
+ }
18192
+ },
18193
+ error: (event) => {
18194
+ const state = states.get(event);
18195
+ if (!state || !event.error) {
18196
+ return;
18197
+ }
18198
+ cleanupActiveRunnerSpan(state, this.activeRunnerSpans);
18199
+ state.span.log({ error: event.error.message });
18200
+ state.span.end();
18201
+ states.delete(event);
18202
+ }
18203
+ };
18204
+ tracingChannel2.subscribe(handlers);
18205
+ this.unsubscribers.push(() => {
18206
+ unbindCurrentSpanStore?.();
18207
+ tracingChannel2.unsubscribe(handlers);
18208
+ });
18209
+ }
18210
+ subscribeToAgentRunAsync() {
18211
+ const tracingChannel2 = googleADKChannels.agentRunAsync.tracingChannel();
18212
+ const states = /* @__PURE__ */ new WeakMap();
18213
+ const createState = (event) => {
18214
+ const parentContext = event.arguments[0];
18215
+ const agentName = extractAgentName(parentContext);
18216
+ const runnerParentSpan = findRunnerParentSpan(
18217
+ parentContext,
18218
+ this.activeRunnerSpans
18219
+ );
18220
+ const contextKey = extractInvocationContextKey(parentContext);
18221
+ const span = startSpan({
18222
+ name: agentName ? `Agent: ${agentName}` : "Google ADK Agent",
18223
+ spanAttributes: {
18224
+ type: "task" /* TASK */
18225
+ },
18226
+ ...runnerParentSpan ? {
18227
+ parentSpanIds: {
18228
+ spanId: runnerParentSpan.spanId,
18229
+ rootSpanId: runnerParentSpan.rootSpanId
18230
+ }
18231
+ } : {}
18232
+ });
18233
+ const startTime = getCurrentUnixTimestamp();
18234
+ try {
18235
+ const metadata = {
18236
+ provider: "google-adk"
18237
+ };
18238
+ if (agentName) {
18239
+ metadata["google_adk.agent_name"] = agentName;
18240
+ }
18241
+ const modelName = extractModelName(parentContext);
18242
+ if (modelName) {
18243
+ metadata.model = modelName;
18244
+ }
18245
+ span.log({ metadata });
18246
+ } catch {
18247
+ }
18248
+ if (contextKey && agentName) {
18249
+ this.activeAgentSpans.set(agentContextKey(contextKey, agentName), span);
18250
+ }
18251
+ return { span, startTime, events: [], contextKey, name: agentName };
18252
+ };
18253
+ const unbindCurrentSpanStore = bindCurrentSpanStoreToStart3(
18254
+ tracingChannel2,
18255
+ states,
18256
+ createState
18257
+ );
18258
+ const handlers = {
18259
+ start: (event) => {
18260
+ ensureState(states, event, () => createState(event));
18261
+ },
18262
+ end: (event) => {
18263
+ const state = states.get(event);
18264
+ if (!state) {
18265
+ return;
18266
+ }
18267
+ const result = event.result;
18268
+ if (isAsyncIterable(result)) {
18269
+ bindAsyncIterableToCurrentSpan(result, state.span);
18270
+ patchStreamIfNeeded(result, {
18271
+ onChunk: (adkEvent) => {
18272
+ state.events.push(adkEvent);
18273
+ },
18274
+ onComplete: () => {
18275
+ finalizeAgentSpan(state, this.activeAgentSpans);
18276
+ states.delete(event);
18277
+ },
18278
+ onError: (error) => {
18279
+ cleanupActiveAgentSpan(state, this.activeAgentSpans);
18280
+ state.span.log({ error: error.message });
18281
+ state.span.end();
18282
+ states.delete(event);
18283
+ }
18284
+ });
18285
+ return;
18286
+ }
18287
+ try {
18288
+ state.span.log({ output: result });
18289
+ } finally {
18290
+ cleanupActiveAgentSpan(state, this.activeAgentSpans);
18291
+ state.span.end();
18292
+ states.delete(event);
18293
+ }
18294
+ },
18295
+ error: (event) => {
18296
+ const state = states.get(event);
18297
+ if (!state || !event.error) {
18298
+ return;
18299
+ }
18300
+ cleanupActiveAgentSpan(state, this.activeAgentSpans);
18301
+ state.span.log({ error: event.error.message });
18302
+ state.span.end();
18303
+ states.delete(event);
18304
+ }
18305
+ };
18306
+ tracingChannel2.subscribe(handlers);
18307
+ this.unsubscribers.push(() => {
18308
+ unbindCurrentSpanStore?.();
18309
+ tracingChannel2.unsubscribe(handlers);
18310
+ });
18311
+ }
18312
+ subscribeToToolRunAsync() {
18313
+ const tracingChannel2 = googleADKChannels.toolRunAsync.tracingChannel();
18314
+ const states = /* @__PURE__ */ new WeakMap();
18315
+ const handlers = {
18316
+ start: (event) => {
18317
+ const req = event.arguments[0] ?? {};
18318
+ const tool = event.self;
18319
+ const toolName = extractToolName(req, tool);
18320
+ const parentSpan = findToolParentSpan(
18321
+ req,
18322
+ this.activeAgentSpans,
18323
+ this.activeRunnerSpans
18324
+ );
18325
+ const createSpan = () => startSpan({
18326
+ name: toolName ? `tool: ${toolName}` : "Google ADK Tool",
18327
+ spanAttributes: {
18328
+ type: "tool" /* TOOL */
18329
+ },
18330
+ event: {
18331
+ input: req.args,
18332
+ metadata: {
18333
+ provider: "google-adk",
18334
+ ...toolName && { "google_adk.tool_name": toolName },
18335
+ ...extractToolCallId(req) && {
18336
+ "google_adk.tool_call_id": extractToolCallId(req)
18337
+ }
18338
+ }
18339
+ }
18340
+ });
18341
+ const span = parentSpan ? withCurrent(parentSpan, () => createSpan()) : createSpan();
18342
+ const startTime = getCurrentUnixTimestamp();
18343
+ states.set(event, { span, startTime });
18344
+ },
18345
+ asyncEnd: (event) => {
18346
+ const state = states.get(event);
18347
+ if (!state) {
18348
+ return;
18349
+ }
18350
+ try {
18351
+ const metrics = {};
18352
+ const end = getCurrentUnixTimestamp();
18353
+ metrics.start = state.startTime;
18354
+ metrics.end = end;
18355
+ metrics.duration = end - state.startTime;
18356
+ state.span.log({
18357
+ output: event.result,
18358
+ metrics: cleanMetrics2(metrics)
18359
+ });
18360
+ } finally {
18361
+ state.span.end();
18362
+ states.delete(event);
18363
+ }
18364
+ },
18365
+ error: (event) => {
18366
+ const state = states.get(event);
18367
+ if (!state || !event.error) {
18368
+ return;
18369
+ }
18370
+ state.span.log({ error: event.error.message });
18371
+ state.span.end();
18372
+ states.delete(event);
18373
+ }
18374
+ };
18375
+ tracingChannel2.subscribe(handlers);
18376
+ this.unsubscribers.push(() => {
18377
+ tracingChannel2.unsubscribe(handlers);
18378
+ });
18379
+ }
18380
+ };
18381
+ function ensureState(states, event, create) {
18382
+ const existing = states.get(event);
18383
+ if (existing) {
18384
+ return existing;
18385
+ }
18386
+ const created = create();
18387
+ states.set(event, created);
18388
+ return created;
18389
+ }
18390
+ function bindAsyncIterableToCurrentSpan(stream, span) {
18391
+ if (!isAsyncIterable(stream)) {
18392
+ return stream;
18393
+ }
18394
+ if (Object.isFrozen(stream) || Object.isSealed(stream)) {
18395
+ return stream;
18396
+ }
18397
+ if ("next" in stream && typeof stream.next === "function") {
18398
+ if ("__braintrust_current_span_bound" in stream) {
18399
+ return stream;
18400
+ }
18401
+ try {
18402
+ const iterator = stream;
18403
+ const originalNext = iterator.next.bind(iterator);
18404
+ iterator.next = (...args) => withCurrent(span, () => originalNext(...args));
18405
+ if (typeof iterator.return === "function") {
18406
+ const originalReturn = iterator.return.bind(iterator);
18407
+ iterator.return = (...args) => withCurrent(span, () => originalReturn(...args));
18408
+ }
18409
+ if (typeof iterator.throw === "function") {
18410
+ const originalThrow = iterator.throw.bind(iterator);
18411
+ iterator.throw = (...args) => withCurrent(span, () => originalThrow(...args));
18412
+ }
18413
+ Object.defineProperty(stream, "__braintrust_current_span_bound", {
18414
+ value: true
18415
+ });
18416
+ return stream;
18417
+ } catch {
18418
+ return stream;
18419
+ }
18420
+ }
18421
+ const originalIteratorFn = stream[Symbol.asyncIterator];
18422
+ if ("__braintrust_current_span_bound" in originalIteratorFn && originalIteratorFn.__braintrust_current_span_bound) {
18423
+ return stream;
18424
+ }
18425
+ try {
18426
+ const patchedIteratorFn = function() {
18427
+ const iterator = originalIteratorFn.call(this);
18428
+ const originalNext = iterator.next.bind(iterator);
18429
+ iterator.next = (...args) => withCurrent(span, () => originalNext(...args));
18430
+ if (typeof iterator.return === "function") {
18431
+ const originalReturn = iterator.return.bind(iterator);
18432
+ iterator.return = (...args) => withCurrent(span, () => originalReturn(...args));
18433
+ }
18434
+ if (typeof iterator.throw === "function") {
18435
+ const originalThrow = iterator.throw.bind(iterator);
18436
+ iterator.throw = (...args) => withCurrent(span, () => originalThrow(...args));
18437
+ }
18438
+ return iterator;
18439
+ };
18440
+ Object.defineProperty(
18441
+ patchedIteratorFn,
18442
+ "__braintrust_current_span_bound",
18443
+ {
18444
+ value: true
18445
+ }
18446
+ );
18447
+ stream[Symbol.asyncIterator] = patchedIteratorFn;
18448
+ } catch {
18449
+ return stream;
18450
+ }
18451
+ return stream;
18452
+ }
18453
+ function bindCurrentSpanStoreToStart3(tracingChannel2, states, create) {
18454
+ const state = _internalGetGlobalState();
18455
+ const contextManager = state?.contextManager;
18456
+ const startChannel = tracingChannel2.start;
18457
+ const currentSpanStore = contextManager ? contextManager[BRAINTRUST_CURRENT_SPAN_STORE] : void 0;
18458
+ if (!startChannel?.bindStore || !currentSpanStore) {
18459
+ return void 0;
18460
+ }
18461
+ startChannel.bindStore(currentSpanStore, (event) => {
18462
+ const span = ensureState(
18463
+ states,
18464
+ event,
18465
+ () => create(event)
18466
+ ).span;
18467
+ return contextManager.wrapSpanForStore(span);
18468
+ });
18469
+ return () => {
18470
+ startChannel.unbindStore?.(currentSpanStore);
18471
+ };
18472
+ }
18473
+ function extractRunnerContextKey(paramsOrContext) {
18474
+ const directUserId = "userId" in paramsOrContext ? paramsOrContext.userId : void 0;
18475
+ const directSessionId = "sessionId" in paramsOrContext ? paramsOrContext.sessionId : void 0;
18476
+ if (typeof directUserId === "string" && typeof directSessionId === "string") {
18477
+ return `${directUserId}:${directSessionId}`;
18478
+ }
18479
+ const invocationContext = paramsOrContext;
18480
+ return extractInvocationContextKey(invocationContext);
18481
+ }
18482
+ function extractInvocationContextKey(parentContext) {
18483
+ const session = parentContext?.session;
18484
+ const userId = session?.userId;
18485
+ const sessionId = session?.id;
18486
+ if (typeof userId !== "string" || typeof sessionId !== "string") {
18487
+ return void 0;
18488
+ }
18489
+ return `${userId}:${sessionId}`;
18490
+ }
18491
+ function findRunnerParentSpan(parentContext, activeRunnerSpans) {
18492
+ const contextKey = extractInvocationContextKey(parentContext);
18493
+ return contextKey ? activeRunnerSpans.get(contextKey) : void 0;
18494
+ }
18495
+ function cleanupActiveRunnerSpan(state, activeRunnerSpans) {
18496
+ if (state.contextKey) {
18497
+ activeRunnerSpans.delete(state.contextKey);
18498
+ }
18499
+ }
18500
+ function agentContextKey(contextKey, agentName) {
18501
+ return `${contextKey}:${agentName}`;
18502
+ }
18503
+ function cleanupActiveAgentSpan(state, activeAgentSpans) {
18504
+ if (state.contextKey && state.name) {
18505
+ activeAgentSpans.delete(agentContextKey(state.contextKey, state.name));
18506
+ }
18507
+ }
18508
+ function extractRunnerInput(paramsOrContext) {
18509
+ const content = "newMessage" in paramsOrContext ? paramsOrContext.newMessage : paramsOrContext.userContent;
18510
+ if (!content || typeof content !== "object") {
18511
+ return void 0;
18512
+ }
18513
+ const normalizedContent = content;
18514
+ if (normalizedContent.parts && Array.isArray(normalizedContent.parts)) {
18515
+ const textParts = normalizedContent.parts.filter((p) => p.text !== void 0).map((p) => p.text);
18516
+ if (textParts.length > 0) {
18517
+ return {
18518
+ messages: [
18519
+ {
18520
+ role: normalizedContent.role ?? "user",
18521
+ content: textParts.join("")
18522
+ }
18523
+ ]
18524
+ };
18525
+ }
18526
+ }
18527
+ return { messages: [normalizedContent] };
18528
+ }
18529
+ function extractRunnerMetadata(paramsOrContext) {
18530
+ const metadata = {
18531
+ provider: "google-adk"
18532
+ };
18533
+ const directUserId = "userId" in paramsOrContext ? paramsOrContext.userId : void 0;
18534
+ const directSessionId = "sessionId" in paramsOrContext ? paramsOrContext.sessionId : void 0;
18535
+ if (typeof directUserId === "string") {
18536
+ metadata["google_adk.user_id"] = directUserId;
18537
+ }
18538
+ if (typeof directSessionId === "string") {
18539
+ metadata["google_adk.session_id"] = directSessionId;
18540
+ }
18541
+ const session = "session" in paramsOrContext ? paramsOrContext.session : void 0;
18542
+ if (metadata["google_adk.user_id"] === void 0 && typeof session?.userId === "string") {
18543
+ metadata["google_adk.user_id"] = session.userId;
18544
+ }
18545
+ if (metadata["google_adk.session_id"] === void 0 && typeof session?.id === "string") {
18546
+ metadata["google_adk.session_id"] = session.id;
18547
+ }
18548
+ return metadata;
18549
+ }
18550
+ function extractAgentName(parentContext) {
18551
+ if (!parentContext) {
18552
+ return void 0;
18553
+ }
18554
+ const agent = parentContext.agent;
18555
+ return agent?.name;
18556
+ }
18557
+ function extractModelName(parentContext) {
18558
+ if (!parentContext) {
18559
+ return void 0;
18560
+ }
18561
+ const agent = parentContext.agent;
18562
+ if (!agent?.model) {
18563
+ return void 0;
18564
+ }
18565
+ if (typeof agent.model === "string") {
18566
+ return agent.model;
18567
+ }
18568
+ if (typeof agent.model === "object" && "model" in agent.model) {
18569
+ return agent.model.model;
18570
+ }
18571
+ return void 0;
18572
+ }
18573
+ function extractToolCallId(req) {
18574
+ const toolContext = req.toolContext;
18575
+ return toolContext?.functionCallId;
18576
+ }
18577
+ function extractToolName(req, tool) {
18578
+ if (typeof tool?.name === "string" && tool.name.length > 0) {
18579
+ return tool.name;
18580
+ }
18581
+ const toolContext = req.toolContext;
18582
+ const invocationContext = toolContext?.invocationContext;
18583
+ const invocationTool = invocationContext?.tool;
18584
+ const toolName = invocationTool?.name;
18585
+ return typeof toolName === "string" && toolName.length > 0 ? toolName : void 0;
18586
+ }
18587
+ function extractToolAgentName(req) {
18588
+ const toolContext = req.toolContext;
18589
+ const directName = toolContext?.agentName;
18590
+ if (typeof directName === "string" && directName.length > 0) {
18591
+ return directName;
18592
+ }
18593
+ const invocationContext = toolContext?.invocationContext;
18594
+ return extractAgentName(invocationContext);
18595
+ }
18596
+ function findToolParentSpan(req, activeAgentSpans, activeRunnerSpans) {
18597
+ const toolContext = req.toolContext;
18598
+ const invocationContext = toolContext?.invocationContext;
18599
+ const contextKey = extractInvocationContextKey(invocationContext);
18600
+ const agentName = extractToolAgentName(req);
18601
+ if (contextKey && agentName) {
18602
+ const agentSpan = activeAgentSpans.get(
18603
+ agentContextKey(contextKey, agentName)
18604
+ );
18605
+ if (agentSpan) {
18606
+ return agentSpan;
18607
+ }
18608
+ }
18609
+ return contextKey ? activeRunnerSpans.get(contextKey) : void 0;
18610
+ }
18611
+ function finalizeRunnerSpan(state, activeRunnerSpans) {
18612
+ try {
18613
+ const lastEvent = getLastNonPartialEvent(state.events);
18614
+ const metrics = {};
18615
+ const end = getCurrentUnixTimestamp();
18616
+ metrics.start = state.startTime;
18617
+ metrics.end = end;
18618
+ metrics.duration = end - state.startTime;
18619
+ const usage = aggregateUsageFromEvents(state.events);
18620
+ if (usage) {
18621
+ populateUsageMetrics2(metrics, usage);
18622
+ }
18623
+ state.span.log({
18624
+ output: lastEvent ? extractEventOutput(lastEvent) : void 0,
18625
+ metrics: cleanMetrics2(metrics)
18626
+ });
18627
+ } finally {
18628
+ cleanupActiveRunnerSpan(state, activeRunnerSpans);
18629
+ state.span.end();
18630
+ }
18631
+ }
18632
+ function finalizeAgentSpan(state, activeAgentSpans) {
18633
+ try {
18634
+ const lastEvent = getLastNonPartialEvent(state.events);
18635
+ const metrics = {};
18636
+ const end = getCurrentUnixTimestamp();
18637
+ metrics.start = state.startTime;
18638
+ metrics.end = end;
18639
+ metrics.duration = end - state.startTime;
18640
+ state.span.log({
18641
+ output: lastEvent ? extractEventOutput(lastEvent) : void 0,
18642
+ metrics: cleanMetrics2(metrics)
18643
+ });
18644
+ } finally {
18645
+ cleanupActiveAgentSpan(state, activeAgentSpans);
18646
+ state.span.end();
18647
+ }
18648
+ }
18649
+ function getLastNonPartialEvent(events) {
18650
+ for (let i = events.length - 1; i >= 0; i--) {
18651
+ if (!events[i].partial) {
18652
+ return events[i];
18653
+ }
18654
+ }
18655
+ return events.length > 0 ? events[events.length - 1] : void 0;
18656
+ }
18657
+ function extractEventOutput(event) {
18658
+ if (!event.content) {
18659
+ return void 0;
18660
+ }
18661
+ const output = {};
18662
+ if (event.content.role) {
18663
+ output.role = event.content.role;
18664
+ }
18665
+ if (event.content.parts && Array.isArray(event.content.parts)) {
18666
+ const textParts = event.content.parts.filter((p) => p.text !== void 0 && !p.thought).map((p) => p.text);
18667
+ const thoughtParts = event.content.parts.filter((p) => p.text !== void 0 && p.thought).map((p) => p.text);
18668
+ const functionCalls = event.content.parts.filter((p) => p.functionCall).map((p) => p.functionCall);
18669
+ if (textParts.length > 0) {
18670
+ output.content = textParts.join("");
18671
+ }
18672
+ if (thoughtParts.length > 0) {
18673
+ output.thought = thoughtParts.join("");
18674
+ }
18675
+ if (functionCalls.length > 0) {
18676
+ output.functionCalls = functionCalls;
18677
+ }
18678
+ }
18679
+ if (event.author) {
18680
+ output.author = event.author;
18681
+ }
18682
+ return Object.keys(output).length > 0 ? output : void 0;
18683
+ }
18684
+ function aggregateUsageFromEvents(events) {
18685
+ let hasUsage = false;
18686
+ const aggregated = {};
18687
+ for (const event of events) {
18688
+ if (!event.usageMetadata) {
18689
+ continue;
18690
+ }
18691
+ hasUsage = true;
18692
+ const usage = event.usageMetadata;
18693
+ if (usage.promptTokenCount !== void 0) {
18694
+ aggregated.promptTokenCount = (aggregated.promptTokenCount ?? 0) + usage.promptTokenCount;
18695
+ }
18696
+ if (usage.candidatesTokenCount !== void 0) {
18697
+ aggregated.candidatesTokenCount = (aggregated.candidatesTokenCount ?? 0) + usage.candidatesTokenCount;
18698
+ }
18699
+ if (usage.totalTokenCount !== void 0) {
18700
+ aggregated.totalTokenCount = (aggregated.totalTokenCount ?? 0) + usage.totalTokenCount;
18701
+ }
18702
+ if (usage.cachedContentTokenCount !== void 0) {
18703
+ aggregated.cachedContentTokenCount = (aggregated.cachedContentTokenCount ?? 0) + usage.cachedContentTokenCount;
18704
+ }
18705
+ if (usage.thoughtsTokenCount !== void 0) {
18706
+ aggregated.thoughtsTokenCount = (aggregated.thoughtsTokenCount ?? 0) + usage.thoughtsTokenCount;
18707
+ }
18708
+ }
18709
+ return hasUsage ? aggregated : void 0;
18710
+ }
18711
+ function populateUsageMetrics2(metrics, usage) {
18712
+ if (usage.promptTokenCount !== void 0) {
18713
+ metrics.prompt_tokens = usage.promptTokenCount;
18714
+ }
18715
+ if (usage.candidatesTokenCount !== void 0) {
18716
+ metrics.completion_tokens = usage.candidatesTokenCount;
18717
+ }
18718
+ if (usage.totalTokenCount !== void 0) {
18719
+ metrics.tokens = usage.totalTokenCount;
18720
+ }
18721
+ if (usage.cachedContentTokenCount !== void 0) {
18722
+ metrics.prompt_cached_tokens = usage.cachedContentTokenCount;
18723
+ }
18724
+ if (usage.thoughtsTokenCount !== void 0) {
18725
+ metrics.completion_reasoning_tokens = usage.thoughtsTokenCount;
18726
+ }
18727
+ }
18728
+ function cleanMetrics2(metrics) {
18729
+ const cleaned = {};
18730
+ for (const [key, value] of Object.entries(metrics)) {
18731
+ if (value !== null && value !== void 0) {
18732
+ cleaned[key] = value;
18733
+ }
18734
+ }
18735
+ return cleaned;
18736
+ }
18737
+
18738
+ // src/instrumentation/plugins/cohere-channels.ts
18739
+ var cohereChannels = defineChannels("cohere-ai", {
18740
+ chat: channel({
18741
+ channelName: "chat",
18742
+ kind: "async"
18743
+ }),
18744
+ chatStream: channel({
18745
+ channelName: "chatStream",
18746
+ kind: "async"
18747
+ }),
18748
+ embed: channel({
18749
+ channelName: "embed",
18750
+ kind: "async"
18751
+ }),
18752
+ rerank: channel({
18753
+ channelName: "rerank",
18754
+ kind: "async"
18755
+ })
18756
+ });
18757
+
18758
+ // src/instrumentation/plugins/cohere-plugin.ts
18759
+ var CoherePlugin = class extends BasePlugin {
18760
+ onEnable() {
18761
+ this.subscribeToCohereChannels();
18762
+ }
18763
+ onDisable() {
18764
+ this.unsubscribers = unsubscribeAll(this.unsubscribers);
18765
+ }
18766
+ subscribeToCohereChannels() {
18767
+ this.unsubscribers.push(
18768
+ traceStreamingChannel(cohereChannels.chat, {
18769
+ name: "cohere.chat",
18770
+ type: "llm" /* LLM */,
18771
+ extractInput: extractChatInputWithMetadata2,
18772
+ extractOutput: (result) => extractCohereChatOutput(result),
18773
+ extractMetadata: (result) => extractCohereResponseMetadata(result),
18774
+ extractMetrics: (result, startTime) => {
18775
+ const metrics = parseCohereMetricsFromUsage(result);
18776
+ if (startTime) {
18777
+ metrics.time_to_first_token = getCurrentUnixTimestamp() - startTime;
18778
+ }
18779
+ return metrics;
18780
+ }
18781
+ })
18782
+ );
18783
+ this.unsubscribers.push(
18784
+ traceStreamingChannel(cohereChannels.chatStream, {
18785
+ name: "cohere.chatStream",
18786
+ type: "llm" /* LLM */,
18787
+ extractInput: extractChatInputWithMetadata2,
18788
+ extractOutput: () => void 0,
18789
+ extractMetadata: () => void 0,
18790
+ extractMetrics: () => ({}),
18791
+ aggregateChunks: aggregateCohereChatStreamChunks
18792
+ })
18793
+ );
18794
+ this.unsubscribers.push(
18795
+ traceAsyncChannel(cohereChannels.embed, {
18796
+ name: "cohere.embed",
18797
+ type: "llm" /* LLM */,
18798
+ extractInput: extractEmbedInputWithMetadata,
18799
+ extractOutput: extractCohereEmbeddingOutput,
18800
+ extractMetadata: (result) => extractCohereResponseMetadata(result),
18801
+ extractMetrics: (result) => parseCohereMetricsFromUsage(result)
18802
+ })
18803
+ );
18804
+ this.unsubscribers.push(
18805
+ traceAsyncChannel(cohereChannels.rerank, {
18806
+ name: "cohere.rerank",
18807
+ type: "llm" /* LLM */,
18808
+ extractInput: extractRerankInputWithMetadata,
18809
+ extractOutput: (result) => {
18810
+ if (!isObject(result) || !Array.isArray(result.results)) {
18811
+ return void 0;
18812
+ }
18813
+ return result.results.slice(0, 100).map((item) => ({
18814
+ index: isObject(item) ? item.index : void 0,
18815
+ relevance_score: isObject(item) ? (typeof item.relevanceScore === "number" ? item.relevanceScore : item.relevance_score) ?? null : null
18816
+ }));
18817
+ },
18818
+ extractMetadata: (result) => extractCohereResponseMetadata(result),
18819
+ extractMetrics: (result) => parseCohereMetricsFromUsage(result)
18820
+ })
18821
+ );
18822
+ }
18823
+ };
18824
+ var CHAT_REQUEST_METADATA_ALLOWLIST = /* @__PURE__ */ new Set([
18825
+ "conversationId",
18826
+ "conversation_id",
18827
+ "frequencyPenalty",
18828
+ "frequency_penalty",
18829
+ "k",
18830
+ "maxInputTokens",
18831
+ "max_input_tokens",
18832
+ "maxTokens",
18833
+ "max_tokens",
18834
+ "model",
18835
+ "p",
18836
+ "preamble",
18837
+ "presencePenalty",
18838
+ "presence_penalty",
18839
+ "priority",
18840
+ "promptTruncation",
18841
+ "prompt_truncation",
18842
+ "rawPrompting",
18843
+ "raw_prompting",
18844
+ "responseFormat",
18845
+ "response_format",
18846
+ "safetyMode",
18847
+ "safety_mode",
18848
+ "searchQueriesOnly",
18849
+ "search_queries_only",
18850
+ "seed",
18851
+ "stopSequences",
18852
+ "stop_sequences",
18853
+ "strictTools",
18854
+ "strict_tools",
18855
+ "temperature",
18856
+ "toolChoice",
18857
+ "tool_choice"
18858
+ ]);
18859
+ var EMBED_REQUEST_METADATA_ALLOWLIST = /* @__PURE__ */ new Set([
18860
+ "embeddingTypes",
18861
+ "embedding_types",
18862
+ "inputType",
18863
+ "input_type",
18864
+ "maxTokens",
18865
+ "max_tokens",
18866
+ "model",
18867
+ "outputDimension",
18868
+ "output_dimension",
18869
+ "priority",
18870
+ "truncate"
18871
+ ]);
18872
+ var RERANK_REQUEST_METADATA_ALLOWLIST = /* @__PURE__ */ new Set([
18873
+ "maxChunksPerDoc",
18874
+ "max_chunks_per_doc",
18875
+ "maxTokensPerDoc",
18876
+ "max_tokens_per_doc",
18877
+ "model",
18878
+ "priority",
18879
+ "rankFields",
18880
+ "rank_fields",
18881
+ "returnDocuments",
18882
+ "return_documents",
18883
+ "topN",
18884
+ "top_n"
18885
+ ]);
18886
+ var RESPONSE_METADATA_ALLOWLIST2 = /* @__PURE__ */ new Set([
18887
+ "finishReason",
18888
+ "finish_reason",
18889
+ "generationId",
18890
+ "generation_id",
18891
+ "id",
18892
+ "responseId",
18893
+ "responseType",
18894
+ "response_id",
18895
+ "response_type"
18896
+ ]);
18897
+ function normalizeArgs5(args) {
18898
+ if (Array.isArray(args)) {
18899
+ return args;
18900
+ }
18901
+ if (isArrayLike5(args)) {
18902
+ return Array.from(args);
18903
+ }
18904
+ return [args];
18905
+ }
18906
+ function isArrayLike5(value) {
18907
+ return isObject(value) && "length" in value && typeof value.length === "number" && Number.isInteger(value.length) && value.length >= 0;
18908
+ }
18909
+ function getRequestArg(args) {
18910
+ const firstObjectArg = normalizeArgs5(args).find((arg) => isObject(arg));
18911
+ return isObject(firstObjectArg) ? firstObjectArg : void 0;
18912
+ }
18913
+ function addCohereProviderMetadata(metadata) {
18914
+ return {
18915
+ ...metadata,
18916
+ provider: "cohere"
18917
+ };
18918
+ }
18919
+ function pickAllowedMetadata2(metadata, allowlist) {
18920
+ if (!metadata) {
18921
+ return {};
18922
+ }
18923
+ const picked = {};
18924
+ for (const key of allowlist) {
18925
+ const value = metadata[key];
18926
+ if (value !== void 0) {
18927
+ picked[key] = value;
18928
+ }
18929
+ }
18930
+ return picked;
18931
+ }
18932
+ function extractChatInputWithMetadata2(args) {
18933
+ const request = getRequestArg(args);
18934
+ const { message, messages, ...rawMetadata } = request || {};
18935
+ return {
18936
+ input: processInputAttachments(messages ?? message),
18937
+ metadata: addCohereProviderMetadata(
18938
+ pickAllowedMetadata2(rawMetadata, CHAT_REQUEST_METADATA_ALLOWLIST)
18939
+ )
18940
+ };
18941
+ }
18942
+ function extractEmbedInputWithMetadata(args) {
18943
+ const request = getRequestArg(args);
18944
+ const { inputs, texts, images, ...rawMetadata } = request || {};
18945
+ return {
18946
+ input: inputs ?? texts ?? images,
18947
+ metadata: addCohereProviderMetadata(
18948
+ pickAllowedMetadata2(rawMetadata, EMBED_REQUEST_METADATA_ALLOWLIST)
18949
+ )
18950
+ };
18951
+ }
18952
+ function extractRerankInputWithMetadata(args) {
18953
+ const request = getRequestArg(args);
18954
+ const { query, documents, ...rawMetadata } = request || {};
18955
+ return {
18956
+ input: {
18957
+ documents,
18958
+ query
18959
+ },
18960
+ metadata: addCohereProviderMetadata({
18961
+ ...pickAllowedMetadata2(rawMetadata, RERANK_REQUEST_METADATA_ALLOWLIST),
18962
+ ...Array.isArray(documents) ? { document_count: documents.length } : {}
18963
+ })
18964
+ };
18965
+ }
18966
+ function extractCohereResponseMetadata(result) {
18967
+ if (!isObject(result)) {
18968
+ return void 0;
18969
+ }
18970
+ const responseMetadata = pickAllowedMetadata2(
18971
+ result,
18972
+ RESPONSE_METADATA_ALLOWLIST2
18973
+ );
18974
+ const meta = isObject(result.meta) ? result.meta : void 0;
18975
+ const apiVersion = isObject(meta?.apiVersion) && typeof meta.apiVersion.version === "string" && meta.apiVersion.version || isObject(meta?.api_version) && typeof meta.api_version.version === "string" && meta.api_version.version;
18976
+ const metadata = {
18977
+ ...responseMetadata,
18978
+ ...apiVersion ? { api_version: apiVersion } : {}
18979
+ };
18980
+ return Object.keys(metadata).length > 0 ? metadata : void 0;
18981
+ }
18982
+ function extractCohereChatOutput(result) {
18983
+ if (!isObject(result)) {
18984
+ return void 0;
18985
+ }
18986
+ if (isObject(result.message)) {
18987
+ return result.message;
18988
+ }
18989
+ if (typeof result.text !== "string") {
18990
+ return void 0;
18991
+ }
18992
+ const toolCalls = Array.isArray(result.toolCalls) ? result.toolCalls : Array.isArray(result.tool_calls) ? result.tool_calls : void 0;
18993
+ if (toolCalls && toolCalls.length > 0) {
18994
+ return {
18995
+ content: result.text,
18996
+ role: "assistant",
18997
+ toolCalls
18998
+ };
18999
+ }
19000
+ return result.text;
19001
+ }
19002
+ function extractCohereEmbeddingOutput(result) {
19003
+ if (!isObject(result)) {
19004
+ return void 0;
19005
+ }
19006
+ const embeddingLength = getFirstEmbeddingLength(result.embeddings);
19007
+ if (embeddingLength === void 0) {
19008
+ return void 0;
19009
+ }
19010
+ return {
19011
+ embedding_length: embeddingLength
19012
+ };
16334
19013
  }
16335
- function getChoiceFinishReason(choice) {
16336
- if (typeof choice.finishReason === "string" || choice.finishReason === null) {
16337
- return choice.finishReason;
19014
+ function getFirstEmbeddingLength(value) {
19015
+ if (Array.isArray(value) && Array.isArray(value[0])) {
19016
+ return value[0].length;
16338
19017
  }
16339
- if (typeof choice.finish_reason === "string" || choice.finish_reason === null) {
16340
- return choice.finish_reason;
19018
+ if (!isObject(value)) {
19019
+ return void 0;
19020
+ }
19021
+ for (const key of Object.keys(value)) {
19022
+ const entry = value[key];
19023
+ if (Array.isArray(entry) && Array.isArray(entry[0])) {
19024
+ return entry[0].length;
19025
+ }
16341
19026
  }
16342
19027
  return void 0;
16343
19028
  }
16344
- function parseMistralMetricsFromUsage(usage) {
19029
+ function setMetricIfNumber(metrics, key, value) {
19030
+ if (typeof value === "number" && Number.isFinite(value)) {
19031
+ metrics[key] = value;
19032
+ }
19033
+ }
19034
+ function mergeUsageMetrics(metrics, usage) {
16345
19035
  if (!isObject(usage)) {
19036
+ return metrics;
19037
+ }
19038
+ const source = usage;
19039
+ setMetricIfNumber(
19040
+ metrics,
19041
+ "prompt_tokens",
19042
+ source.inputTokens ?? source.input_tokens
19043
+ );
19044
+ setMetricIfNumber(
19045
+ metrics,
19046
+ "completion_tokens",
19047
+ source.outputTokens ?? source.output_tokens
19048
+ );
19049
+ setMetricIfNumber(
19050
+ metrics,
19051
+ "tokens",
19052
+ source.totalTokens ?? source.total_tokens
19053
+ );
19054
+ setMetricIfNumber(
19055
+ metrics,
19056
+ "prompt_cached_tokens",
19057
+ source.cachedTokens ?? source.cached_tokens
19058
+ );
19059
+ const tokenContainer = isObject(source.tokens) ? source.tokens : void 0;
19060
+ if (tokenContainer) {
19061
+ setMetricIfNumber(
19062
+ metrics,
19063
+ "prompt_tokens",
19064
+ tokenContainer.inputTokens ?? tokenContainer.input_tokens
19065
+ );
19066
+ setMetricIfNumber(
19067
+ metrics,
19068
+ "completion_tokens",
19069
+ tokenContainer.outputTokens ?? tokenContainer.output_tokens
19070
+ );
19071
+ setMetricIfNumber(
19072
+ metrics,
19073
+ "tokens",
19074
+ tokenContainer.totalTokens ?? tokenContainer.total_tokens
19075
+ );
19076
+ }
19077
+ const billedUnits = (isObject(source.billedUnits) ? source.billedUnits : void 0) || (isObject(source.billed_units) ? source.billed_units : void 0);
19078
+ if (billedUnits) {
19079
+ setMetricIfNumber(
19080
+ metrics,
19081
+ "prompt_tokens",
19082
+ billedUnits.inputTokens ?? billedUnits.input_tokens
19083
+ );
19084
+ setMetricIfNumber(
19085
+ metrics,
19086
+ "completion_tokens",
19087
+ billedUnits.outputTokens ?? billedUnits.output_tokens
19088
+ );
19089
+ setMetricIfNumber(
19090
+ metrics,
19091
+ "search_units",
19092
+ billedUnits.searchUnits ?? billedUnits.search_units
19093
+ );
19094
+ setMetricIfNumber(metrics, "classifications", billedUnits.classifications);
19095
+ setMetricIfNumber(metrics, "images", billedUnits.images);
19096
+ setMetricIfNumber(
19097
+ metrics,
19098
+ "image_tokens",
19099
+ billedUnits.imageTokens ?? billedUnits.image_tokens
19100
+ );
19101
+ }
19102
+ return metrics;
19103
+ }
19104
+ function parseCohereMetricsFromUsage(source) {
19105
+ if (!isObject(source)) {
16346
19106
  return {};
16347
19107
  }
16348
19108
  const metrics = {};
16349
- for (const [name, value] of Object.entries(usage)) {
16350
- if (typeof value === "number") {
16351
- metrics[TOKEN_NAME_MAP4[name] || camelToSnake3(name)] = value;
16352
- continue;
19109
+ mergeUsageMetrics(metrics, source);
19110
+ if ("usage" in source) {
19111
+ mergeUsageMetrics(metrics, source.usage);
19112
+ }
19113
+ if ("meta" in source) {
19114
+ mergeUsageMetrics(metrics, source.meta);
19115
+ }
19116
+ if (metrics.tokens === void 0 && typeof metrics.prompt_tokens === "number" && typeof metrics.completion_tokens === "number") {
19117
+ metrics.tokens = metrics.prompt_tokens + metrics.completion_tokens;
19118
+ }
19119
+ return metrics;
19120
+ }
19121
+ function toToolCallArray(value) {
19122
+ if (Array.isArray(value)) {
19123
+ return value.filter((item) => isObject(item));
19124
+ }
19125
+ return isObject(value) ? [value] : [];
19126
+ }
19127
+ function getToolCallIndex2(toolCall, fallbackIndex) {
19128
+ return typeof toolCall.index === "number" && Number.isInteger(toolCall.index) ? toolCall.index : fallbackIndex;
19129
+ }
19130
+ function appendToolCallDelta(existing, incoming) {
19131
+ const currentArguments = isObject(existing?.function) && typeof existing.function.arguments === "string" ? existing.function.arguments : "";
19132
+ const incomingArguments = isObject(incoming.function) && typeof incoming.function.arguments === "string" ? incoming.function.arguments : "";
19133
+ return {
19134
+ ...existing,
19135
+ ...incoming,
19136
+ function: {
19137
+ ...isObject(existing?.function) ? existing.function : {},
19138
+ ...isObject(incoming.function) ? incoming.function : {},
19139
+ ...incomingArguments ? { arguments: `${currentArguments}${incomingArguments}` } : {}
16353
19140
  }
16354
- if (!isObject(value)) {
19141
+ };
19142
+ }
19143
+ function extractV8DeltaText(chunk) {
19144
+ if (!isObject(chunk.delta) || !isObject(chunk.delta.message)) {
19145
+ return void 0;
19146
+ }
19147
+ const content = chunk.delta.message.content;
19148
+ if (typeof content === "string") {
19149
+ return content;
19150
+ }
19151
+ if (isObject(content) && typeof content.text === "string") {
19152
+ return content.text;
19153
+ }
19154
+ return void 0;
19155
+ }
19156
+ function aggregateCohereChatStreamChunks(chunks) {
19157
+ const textDeltas = [];
19158
+ const toolCallsByIndex = {};
19159
+ const toolCallOrder = [];
19160
+ let terminalResponse;
19161
+ let role;
19162
+ let finishReason;
19163
+ let metadata = {};
19164
+ let metrics = {};
19165
+ for (const chunk of chunks) {
19166
+ if (!isObject(chunk)) {
16355
19167
  continue;
16356
19168
  }
16357
- const prefix = TOKEN_DETAIL_PREFIX_MAP3[name];
16358
- if (!prefix) {
19169
+ const eventType = typeof chunk.eventType === "string" ? chunk.eventType : typeof chunk.event_type === "string" ? chunk.event_type : typeof chunk.type === "string" ? chunk.type : void 0;
19170
+ if (eventType === "text-generation" && typeof chunk.text === "string") {
19171
+ textDeltas.push(chunk.text);
16359
19172
  continue;
16360
19173
  }
16361
- for (const [nestedName, nestedValue] of Object.entries(value)) {
16362
- if (typeof nestedValue !== "number") {
16363
- continue;
19174
+ if (eventType === "tool-calls-generation") {
19175
+ const generatedToolCalls = toToolCallArray(
19176
+ Array.isArray(chunk.toolCalls) ? chunk.toolCalls : chunk.tool_calls
19177
+ );
19178
+ for (const [index, toolCall] of generatedToolCalls.entries()) {
19179
+ const normalizedIndex = getToolCallIndex2(toolCall, index);
19180
+ if (!toolCallOrder.includes(normalizedIndex)) {
19181
+ toolCallOrder.push(normalizedIndex);
19182
+ }
19183
+ toolCallsByIndex[normalizedIndex] = {
19184
+ ...toolCallsByIndex[normalizedIndex],
19185
+ ...toolCall
19186
+ };
19187
+ }
19188
+ if (typeof chunk.text === "string") {
19189
+ textDeltas.push(chunk.text);
16364
19190
  }
16365
- metrics[`${prefix}_${camelToSnake3(nestedName)}`] = nestedValue;
16366
- }
16367
- }
16368
- return metrics;
16369
- }
16370
- function aggregateMistralStreamChunks(chunks) {
16371
- const choiceAccumulators = /* @__PURE__ */ new Map();
16372
- const indexToAccumulatorKey = /* @__PURE__ */ new Map();
16373
- const positionToAccumulatorKey = /* @__PURE__ */ new Map();
16374
- let nextAccumulatorOrder = 0;
16375
- let metrics = {};
16376
- let metadata;
16377
- for (const event of chunks) {
16378
- const chunk = isMistralChatCompletionChunk(event?.data) ? event.data : void 0;
16379
- if (!chunk) {
16380
19191
  continue;
16381
19192
  }
16382
- if (isObject(chunk.usage)) {
19193
+ if (eventType === "stream-end" && isObject(chunk.response)) {
19194
+ terminalResponse = chunk.response;
16383
19195
  metrics = {
16384
19196
  ...metrics,
16385
- ...parseMistralMetricsFromUsage(chunk.usage)
19197
+ ...parseCohereMetricsFromUsage(chunk.response)
16386
19198
  };
19199
+ metadata = {
19200
+ ...metadata,
19201
+ ...extractCohereResponseMetadata(chunk.response) || {}
19202
+ };
19203
+ const responseFinishReason = typeof chunk.response.finishReason === "string" ? chunk.response.finishReason : typeof chunk.response.finish_reason === "string" ? chunk.response.finish_reason : void 0;
19204
+ finishReason = responseFinishReason ?? finishReason;
19205
+ continue;
16387
19206
  }
16388
- const chunkMetadata = extractMistralResponseMetadata(chunk);
16389
- if (chunkMetadata) {
16390
- metadata = { ...metadata || {}, ...chunkMetadata };
16391
- }
16392
- for (const [choicePosition, rawChoice] of (chunk.choices || []).entries()) {
16393
- if (!isMistralChunkChoice(rawChoice)) {
16394
- continue;
19207
+ if (eventType === "message-start") {
19208
+ if (typeof chunk.id === "string") {
19209
+ metadata.id = chunk.id;
16395
19210
  }
16396
- const choice = rawChoice;
16397
- const choiceIndex = typeof choice.index === "number" && choice.index >= 0 ? choice.index : void 0;
16398
- let accumulatorKey = choiceIndex !== void 0 ? indexToAccumulatorKey.get(choiceIndex) : void 0;
16399
- if (!accumulatorKey) {
16400
- accumulatorKey = positionToAccumulatorKey.get(choicePosition);
16401
- }
16402
- if (!accumulatorKey) {
16403
- const initialIndex = choiceIndex ?? choicePosition;
16404
- const keyPrefix = choiceIndex !== void 0 ? "index" : "position";
16405
- accumulatorKey = `${keyPrefix}:${initialIndex}`;
16406
- choiceAccumulators.set(accumulatorKey, {
16407
- index: initialIndex,
16408
- order: nextAccumulatorOrder++
16409
- });
16410
- }
16411
- const accumulator = choiceAccumulators.get(accumulatorKey);
16412
- if (!accumulator) {
16413
- continue;
19211
+ if (isObject(chunk.delta) && isObject(chunk.delta.message)) {
19212
+ const messageRole = chunk.delta.message.role;
19213
+ if (typeof messageRole === "string") {
19214
+ role = messageRole;
19215
+ }
16414
19216
  }
16415
- if (choiceIndex !== void 0) {
16416
- accumulator.index = choiceIndex;
16417
- indexToAccumulatorKey.set(choiceIndex, accumulatorKey);
19217
+ continue;
19218
+ }
19219
+ if (eventType === "content-delta") {
19220
+ const text = extractV8DeltaText(chunk);
19221
+ if (text) {
19222
+ textDeltas.push(text);
16418
19223
  }
16419
- positionToAccumulatorKey.set(choicePosition, accumulatorKey);
16420
- const delta = isObject(choice.delta) ? choice.delta : void 0;
16421
- if (delta) {
16422
- if (!accumulator.role && typeof delta.role === "string") {
16423
- accumulator.role = delta.role;
19224
+ continue;
19225
+ }
19226
+ if (eventType === "tool-call-start") {
19227
+ const toolCalls = isObject(chunk.delta) && isObject(chunk.delta.message) ? toToolCallArray(
19228
+ Array.isArray(chunk.delta.message.toolCalls) ? chunk.delta.message.toolCalls : chunk.delta.message.toolCalls ?? chunk.delta.message.tool_calls
19229
+ ) : [];
19230
+ for (const [index, toolCall] of toolCalls.entries()) {
19231
+ const normalizedIndex = getToolCallIndex2(
19232
+ toolCall,
19233
+ typeof chunk.index === "number" ? chunk.index : index
19234
+ );
19235
+ if (!toolCallOrder.includes(normalizedIndex)) {
19236
+ toolCallOrder.push(normalizedIndex);
16424
19237
  }
16425
- const deltaText = extractDeltaText(delta.content);
16426
- if (deltaText) {
16427
- accumulator.content = `${accumulator.content || ""}${deltaText}`;
19238
+ toolCallsByIndex[normalizedIndex] = {
19239
+ ...toolCallsByIndex[normalizedIndex],
19240
+ ...toolCall
19241
+ };
19242
+ }
19243
+ continue;
19244
+ }
19245
+ if (eventType === "tool-call-delta") {
19246
+ const toolCallDelta = isObject(chunk.delta) && isObject(chunk.delta.message) ? toToolCallArray(
19247
+ chunk.delta.message.toolCalls ?? chunk.delta.message.tool_calls
19248
+ ) : [];
19249
+ if (toolCallDelta.length > 0) {
19250
+ const delta = toolCallDelta[0];
19251
+ const normalizedIndex = getToolCallIndex2(delta, chunk.index ?? 0);
19252
+ if (!toolCallOrder.includes(normalizedIndex)) {
19253
+ toolCallOrder.push(normalizedIndex);
16428
19254
  }
16429
- accumulator.toolCalls = mergeToolCallDeltas(
16430
- accumulator.toolCalls,
16431
- getDeltaToolCalls(delta)
19255
+ toolCallsByIndex[normalizedIndex] = appendToolCallDelta(
19256
+ toolCallsByIndex[normalizedIndex],
19257
+ delta
16432
19258
  );
16433
19259
  }
16434
- const choiceFinishReason = getChoiceFinishReason(choice);
16435
- if (choiceFinishReason !== void 0) {
16436
- accumulator.finishReason = choiceFinishReason;
19260
+ continue;
19261
+ }
19262
+ if (eventType === "message-end" && isObject(chunk.delta)) {
19263
+ const delta = chunk.delta;
19264
+ if (typeof delta.finishReason === "string") {
19265
+ finishReason = delta.finishReason;
19266
+ } else if (typeof delta.finish_reason === "string") {
19267
+ finishReason = delta.finish_reason;
19268
+ }
19269
+ if (delta.error !== void 0) {
19270
+ metadata.error = delta.error;
16437
19271
  }
19272
+ metrics = {
19273
+ ...metrics,
19274
+ ...parseCohereMetricsFromUsage(delta.usage)
19275
+ };
16438
19276
  }
16439
19277
  }
16440
- const output = Array.from(choiceAccumulators.values()).sort(
16441
- (left, right) => left.index === right.index ? left.order - right.order : left.index - right.index
16442
- ).map((choice) => ({
16443
- index: choice.index,
16444
- message: {
16445
- ...choice.role ? { role: choice.role } : {},
16446
- content: choice.content ?? null,
16447
- ...choice.toolCalls ? { toolCalls: choice.toolCalls } : {}
16448
- },
16449
- ...choice.finishReason !== void 0 ? { finishReason: choice.finishReason } : {}
16450
- }));
19278
+ const mergedToolCalls = toolCallOrder.sort((left, right) => left - right).map((index) => toolCallsByIndex[index]).filter((toolCall) => isObject(toolCall));
19279
+ let output = extractCohereChatOutput(terminalResponse);
19280
+ if (output === void 0) {
19281
+ const mergedText = textDeltas.join("");
19282
+ if (mergedToolCalls.length > 0 || role || mergedText.length > 0) {
19283
+ output = {
19284
+ ...role ? { role } : {},
19285
+ ...mergedText.length > 0 ? { content: mergedText } : {},
19286
+ ...mergedToolCalls.length > 0 ? { toolCalls: mergedToolCalls } : {}
19287
+ };
19288
+ }
19289
+ }
19290
+ if (finishReason) {
19291
+ metadata = {
19292
+ ...metadata,
19293
+ finish_reason: finishReason
19294
+ };
19295
+ }
16451
19296
  return {
16452
- output,
19297
+ metadata,
16453
19298
  metrics,
16454
- ...metadata ? { metadata } : {}
19299
+ output
16455
19300
  };
16456
19301
  }
16457
19302
 
@@ -16463,9 +19308,12 @@ var BraintrustPlugin = class extends BasePlugin {
16463
19308
  aiSDKPlugin = null;
16464
19309
  claudeAgentSDKPlugin = null;
16465
19310
  googleGenAIPlugin = null;
19311
+ huggingFacePlugin = null;
16466
19312
  openRouterPlugin = null;
16467
19313
  openRouterAgentPlugin = null;
16468
19314
  mistralPlugin = null;
19315
+ googleADKPlugin = null;
19316
+ coherePlugin = null;
16469
19317
  constructor(config = {}) {
16470
19318
  super();
16471
19319
  this.config = config;
@@ -16492,6 +19340,10 @@ var BraintrustPlugin = class extends BasePlugin {
16492
19340
  this.googleGenAIPlugin = new GoogleGenAIPlugin();
16493
19341
  this.googleGenAIPlugin.enable();
16494
19342
  }
19343
+ if (integrations.huggingface !== false) {
19344
+ this.huggingFacePlugin = new HuggingFacePlugin();
19345
+ this.huggingFacePlugin.enable();
19346
+ }
16495
19347
  if (integrations.openrouter !== false) {
16496
19348
  this.openRouterPlugin = new OpenRouterPlugin();
16497
19349
  this.openRouterPlugin.enable();
@@ -16504,6 +19356,14 @@ var BraintrustPlugin = class extends BasePlugin {
16504
19356
  this.mistralPlugin = new MistralPlugin();
16505
19357
  this.mistralPlugin.enable();
16506
19358
  }
19359
+ if (integrations.googleADK !== false) {
19360
+ this.googleADKPlugin = new GoogleADKPlugin();
19361
+ this.googleADKPlugin.enable();
19362
+ }
19363
+ if (integrations.cohere !== false) {
19364
+ this.coherePlugin = new CoherePlugin();
19365
+ this.coherePlugin.enable();
19366
+ }
16507
19367
  }
16508
19368
  onDisable() {
16509
19369
  if (this.openaiPlugin) {
@@ -16526,6 +19386,10 @@ var BraintrustPlugin = class extends BasePlugin {
16526
19386
  this.googleGenAIPlugin.disable();
16527
19387
  this.googleGenAIPlugin = null;
16528
19388
  }
19389
+ if (this.huggingFacePlugin) {
19390
+ this.huggingFacePlugin.disable();
19391
+ this.huggingFacePlugin = null;
19392
+ }
16529
19393
  if (this.openRouterPlugin) {
16530
19394
  this.openRouterPlugin.disable();
16531
19395
  this.openRouterPlugin = null;
@@ -16538,6 +19402,14 @@ var BraintrustPlugin = class extends BasePlugin {
16538
19402
  this.mistralPlugin.disable();
16539
19403
  this.mistralPlugin = null;
16540
19404
  }
19405
+ if (this.googleADKPlugin) {
19406
+ this.googleADKPlugin.disable();
19407
+ this.googleADKPlugin = null;
19408
+ }
19409
+ if (this.coherePlugin) {
19410
+ this.coherePlugin.disable();
19411
+ this.coherePlugin = null;
19412
+ }
16541
19413
  }
16542
19414
  };
16543
19415
 
@@ -16609,10 +19481,12 @@ var PluginRegistry = class {
16609
19481
  vercel: true,
16610
19482
  aisdk: true,
16611
19483
  google: true,
19484
+ huggingface: true,
16612
19485
  claudeAgentSDK: true,
16613
19486
  openrouter: true,
16614
19487
  openrouterAgent: true,
16615
- mistral: true
19488
+ mistral: true,
19489
+ cohere: true
16616
19490
  };
16617
19491
  }
16618
19492
  /**
@@ -16797,7 +19671,7 @@ function _asyncMap(eachfn, arr, iteratee, callback) {
16797
19671
  callback(err, results);
16798
19672
  });
16799
19673
  }
16800
- function isArrayLike4(value) {
19674
+ function isArrayLike6(value) {
16801
19675
  return value && typeof value.length === "number" && value.length >= 0 && value.length % 1 === 0;
16802
19676
  }
16803
19677
  var breakLoop = {};
@@ -16845,7 +19719,7 @@ function createObjectIterator(obj) {
16845
19719
  };
16846
19720
  }
16847
19721
  function createIterator(coll) {
16848
- if (isArrayLike4(coll)) {
19722
+ if (isArrayLike6(coll)) {
16849
19723
  return createArrayIterator(coll);
16850
19724
  }
16851
19725
  var iterator = getIterator(coll);
@@ -16991,7 +19865,7 @@ function eachOfGeneric(coll, iteratee, callback) {
16991
19865
  return eachOfLimit$1(coll, Infinity, iteratee, callback);
16992
19866
  }
16993
19867
  function eachOf(coll, iteratee, callback) {
16994
- var eachOfImplementation = isArrayLike4(coll) ? eachOfArrayLike : eachOfGeneric;
19868
+ var eachOfImplementation = isArrayLike6(coll) ? eachOfArrayLike : eachOfGeneric;
16995
19869
  return eachOfImplementation(coll, wrapAsync(iteratee), callback);
16996
19870
  }
16997
19871
  var eachOf$1 = awaitify(eachOf, 3);
@@ -17506,7 +20380,7 @@ function filterGeneric(eachfn, coll, iteratee, callback) {
17506
20380
  });
17507
20381
  }
17508
20382
  function _filter(eachfn, coll, iteratee, callback) {
17509
- var filter2 = isArrayLike4(coll) ? filterArray : filterGeneric;
20383
+ var filter2 = isArrayLike6(coll) ? filterArray : filterGeneric;
17510
20384
  return filter2(eachfn, coll, wrapAsync(iteratee), callback);
17511
20385
  }
17512
20386
  function filter(coll, iteratee, callback) {
@@ -17581,7 +20455,7 @@ if (hasNextTick) {
17581
20455
  }
17582
20456
  var nextTick = wrap(_defer);
17583
20457
  var _parallel = awaitify((eachfn, tasks, callback) => {
17584
- var results = isArrayLike4(tasks) ? [] : {};
20458
+ var results = isArrayLike6(tasks) ? [] : {};
17585
20459
  eachfn(tasks, (task, key, taskCb) => {
17586
20460
  wrapAsync(task)((err, ...result) => {
17587
20461
  if (result.length < 2) {
@@ -18438,7 +21312,88 @@ function evaluateFilter(object, filter2) {
18438
21312
  function scorerName(scorer, scorer_idx) {
18439
21313
  return scorer.name || `scorer_${scorer_idx}`;
18440
21314
  }
21315
+ function classifierName(classifier, classifier_idx) {
21316
+ return classifier.name || `classifier_${classifier_idx}`;
21317
+ }
21318
+ function buildSpanMetadata(results) {
21319
+ return results.length === 1 ? results[0].metadata : results.reduce(
21320
+ (prev, s) => mergeDicts(prev, { [s.name]: s.metadata }),
21321
+ {}
21322
+ );
21323
+ }
21324
+ function buildSpanScores(results) {
21325
+ const scoresRecord = results.reduce(
21326
+ (prev, s) => mergeDicts(prev, { [s.name]: s.score }),
21327
+ {}
21328
+ );
21329
+ return { resultMetadata: buildSpanMetadata(results), scoresRecord };
21330
+ }
21331
+ async function runInScorerSpan(rootSpan, spanName, spanType, propagatedEvent, eventInput, fn) {
21332
+ try {
21333
+ const value = await rootSpan.traced(fn, {
21334
+ name: spanName,
21335
+ spanAttributes: { type: spanType, purpose: "scorer" },
21336
+ propagatedEvent,
21337
+ event: { input: eventInput }
21338
+ });
21339
+ return { kind: "score", value };
21340
+ } catch (e) {
21341
+ return { kind: "error", value: e };
21342
+ }
21343
+ }
21344
+ function collectScoringResults(runResults, names, onResult) {
21345
+ const failing = [];
21346
+ runResults.forEach((r, i) => {
21347
+ if (r.kind === "score") {
21348
+ (r.value ?? []).forEach(onResult);
21349
+ } else {
21350
+ failing.push({ name: names[i], error: r.value });
21351
+ }
21352
+ });
21353
+ return failing;
21354
+ }
21355
+ function validateClassificationResult(value, scorerName2) {
21356
+ if (!(typeof value === "object" && value !== null && !isEmpty2(value))) {
21357
+ throw new Error(
21358
+ `When returning structured classifier results, each classification must be a non-empty object. Got: ${JSON.stringify(value)}`
21359
+ );
21360
+ }
21361
+ if (!("name" in value) || typeof value.name !== "string" || !value.name) {
21362
+ const classification = value;
21363
+ classification.name = scorerName2;
21364
+ return classification;
21365
+ }
21366
+ return value;
21367
+ }
21368
+ function toClassificationItem(c) {
21369
+ return {
21370
+ id: c.id,
21371
+ label: c.label ?? c.id,
21372
+ ...c.metadata !== void 0 ? { metadata: c.metadata } : {}
21373
+ };
21374
+ }
21375
+ function logScoringFailures(kind, failures, metadata, rootSpan, state) {
21376
+ if (!failures.length) return [];
21377
+ const errorMap = Object.fromEntries(
21378
+ failures.map(({ name, error }) => [
21379
+ name,
21380
+ error instanceof Error ? error.stack : `${error}`
21381
+ ])
21382
+ );
21383
+ metadata[`${kind}_errors`] = errorMap;
21384
+ rootSpan.log({ metadata: { [`${kind}_errors`]: errorMap } });
21385
+ debugLogger.forState(state).warn(
21386
+ `Found exceptions for the following ${kind}s: ${Object.keys(errorMap).join(", ")}`,
21387
+ failures.map((f) => f.error)
21388
+ );
21389
+ return Object.keys(errorMap);
21390
+ }
18441
21391
  async function runEvaluator(experiment, evaluator, progressReporter, filters, stream, parameters, collectResults = true, enableCache = true) {
21392
+ if (!evaluator.scores && !evaluator.classifiers) {
21393
+ throw new Error(
21394
+ "Evaluator must include at least one of `scores` or `classifiers`"
21395
+ );
21396
+ }
18442
21397
  return await runEvaluatorInternal(
18443
21398
  experiment,
18444
21399
  evaluator,
@@ -18576,7 +21531,11 @@ async function runEvaluatorInternal(experiment, evaluator, progressReporter, fil
18576
21531
  let error = void 0;
18577
21532
  let tags = [...datum.tags ?? []];
18578
21533
  const scores = {};
18579
- const scorerNames = evaluator.scores.map(scorerName);
21534
+ const classifications = {};
21535
+ const scorerNames = (evaluator.scores ?? []).map(scorerName);
21536
+ const classifierNames = (evaluator.classifiers ?? []).map(
21537
+ classifierName
21538
+ );
18580
21539
  let unhandledScores = scorerNames;
18581
21540
  try {
18582
21541
  const meta = (o) => metadata = { ...metadata, ...o };
@@ -18630,106 +21589,131 @@ async function runEvaluatorInternal(experiment, evaluator, progressReporter, fil
18630
21589
  output,
18631
21590
  trace
18632
21591
  };
18633
- const scoreResults = await Promise.all(
18634
- evaluator.scores.map(async (score, score_idx) => {
18635
- try {
18636
- const runScorer = async (span) => {
18637
- const scoreResult = score(scoringArgs);
18638
- const scoreValue = scoreResult instanceof Promise ? await scoreResult : scoreResult;
18639
- if (scoreValue === null) {
18640
- return null;
18641
- }
18642
- if (Array.isArray(scoreValue)) {
18643
- for (const s of scoreValue) {
18644
- if (!(typeof s === "object" && !isEmpty2(s))) {
18645
- throw new Error(
18646
- `When returning an array of scores, each score must be a non-empty object. Got: ${JSON.stringify(
18647
- s
18648
- )}`
18649
- );
21592
+ const { trace: _trace, ...scoringArgsForLogging } = scoringArgs;
21593
+ const propagatedEvent = makeScorerPropagatedEvent(
21594
+ await rootSpan.export()
21595
+ );
21596
+ const getOtherFields = (s) => {
21597
+ const { metadata: _metadata, name: _name, ...rest } = s;
21598
+ return rest;
21599
+ };
21600
+ const [scoreResults, classificationResults] = await Promise.all([
21601
+ Promise.all(
21602
+ (evaluator.scores ?? []).map(
21603
+ (score, score_idx) => runInScorerSpan(
21604
+ rootSpan,
21605
+ scorerNames[score_idx],
21606
+ "score" /* SCORE */,
21607
+ propagatedEvent,
21608
+ scoringArgsForLogging,
21609
+ async (span) => {
21610
+ const scoreValue = await Promise.resolve(
21611
+ score(scoringArgs)
21612
+ );
21613
+ if (scoreValue === null) return null;
21614
+ if (Array.isArray(scoreValue)) {
21615
+ for (const s of scoreValue) {
21616
+ if (!(typeof s === "object" && !isEmpty2(s))) {
21617
+ throw new Error(
21618
+ `When returning an array of scores, each score must be a non-empty object. Got: ${JSON.stringify(s)}`
21619
+ );
21620
+ }
18650
21621
  }
18651
21622
  }
21623
+ const results = Array.isArray(scoreValue) ? scoreValue : typeof scoreValue === "object" && !isEmpty2(scoreValue) ? [scoreValue] : [
21624
+ {
21625
+ name: scorerNames[score_idx],
21626
+ score: scoreValue
21627
+ }
21628
+ ];
21629
+ const { resultMetadata, scoresRecord } = buildSpanScores(results);
21630
+ const resultOutput = results.length === 1 ? getOtherFields(results[0]) : results.reduce(
21631
+ (prev, s) => mergeDicts(prev, {
21632
+ [s.name]: getOtherFields(s)
21633
+ }),
21634
+ {}
21635
+ );
21636
+ span.log({
21637
+ output: resultOutput,
21638
+ metadata: resultMetadata,
21639
+ scores: scoresRecord
21640
+ });
21641
+ return results;
18652
21642
  }
18653
- const results2 = Array.isArray(scoreValue) ? scoreValue : typeof scoreValue === "object" && !isEmpty2(scoreValue) ? [scoreValue] : [
18654
- {
18655
- name: scorerNames[score_idx],
18656
- score: scoreValue
18657
- }
18658
- ];
18659
- const getOtherFields = (s) => {
18660
- const { metadata: _metadata, name: _name, ...rest } = s;
18661
- return rest;
18662
- };
18663
- const resultMetadata = results2.length === 1 ? results2[0].metadata : results2.reduce(
18664
- (prev, s) => mergeDicts(prev, {
18665
- [s.name]: s.metadata
18666
- }),
18667
- {}
18668
- );
18669
- const resultOutput = results2.length === 1 ? getOtherFields(results2[0]) : results2.reduce(
18670
- (prev, s) => mergeDicts(prev, { [s.name]: getOtherFields(s) }),
18671
- {}
18672
- );
18673
- const scores2 = results2.reduce(
18674
- (prev, s) => mergeDicts(prev, { [s.name]: s.score }),
18675
- {}
18676
- );
18677
- span.log({
18678
- output: resultOutput,
18679
- metadata: resultMetadata,
18680
- scores: scores2
18681
- });
18682
- return results2;
18683
- };
18684
- const { trace: _trace, ...scoringArgsForLogging } = scoringArgs;
18685
- const results = await rootSpan.traced(runScorer, {
18686
- name: scorerNames[score_idx],
18687
- spanAttributes: {
18688
- type: "score" /* SCORE */,
18689
- purpose: "scorer"
18690
- },
18691
- propagatedEvent: makeScorerPropagatedEvent(
18692
- await rootSpan.export()
18693
- ),
18694
- event: { input: scoringArgsForLogging }
18695
- });
18696
- return { kind: "score", value: results };
18697
- } catch (e) {
18698
- return { kind: "error", value: e };
18699
- }
18700
- })
21643
+ )
21644
+ )
21645
+ ),
21646
+ Promise.all(
21647
+ (evaluator.classifiers ?? []).map(
21648
+ (classifier, idx) => runInScorerSpan(
21649
+ rootSpan,
21650
+ classifierNames[idx],
21651
+ "classifier" /* CLASSIFIER */,
21652
+ propagatedEvent,
21653
+ scoringArgsForLogging,
21654
+ async (span) => {
21655
+ const classifierValue = await Promise.resolve(
21656
+ classifier(scoringArgs)
21657
+ );
21658
+ if (classifierValue === null) return null;
21659
+ const rawResults = (Array.isArray(classifierValue) ? classifierValue : [classifierValue]).map(
21660
+ (result) => validateClassificationResult(
21661
+ result,
21662
+ classifierNames[idx]
21663
+ )
21664
+ );
21665
+ const resultOutput = rawResults.length === 1 ? toClassificationItem(rawResults[0]) : rawResults.reduce(
21666
+ (prev, r) => mergeDicts(prev, {
21667
+ [r.name]: toClassificationItem(r)
21668
+ }),
21669
+ {}
21670
+ );
21671
+ span.log({
21672
+ output: resultOutput,
21673
+ metadata: buildSpanMetadata(rawResults)
21674
+ });
21675
+ return rawResults;
21676
+ }
21677
+ )
21678
+ )
21679
+ )
21680
+ ]);
21681
+ const failingScorers = collectScoringResults(
21682
+ scoreResults,
21683
+ scorerNames,
21684
+ (result) => {
21685
+ scores[result.name] = result.score;
21686
+ }
18701
21687
  );
18702
- const failingScorersAndResults = [];
18703
- scoreResults.forEach((results, i) => {
18704
- const name = scorerNames[i];
18705
- if (results.kind === "score") {
18706
- (results.value || []).forEach((result) => {
18707
- scores[result.name] = result.score;
18708
- });
18709
- } else {
18710
- failingScorersAndResults.push({ name, error: results.value });
21688
+ const failingClassifiers = collectScoringResults(
21689
+ classificationResults,
21690
+ classifierNames,
21691
+ (result) => {
21692
+ const item = toClassificationItem(result);
21693
+ if (!classifications[result.name]) {
21694
+ classifications[result.name] = [];
21695
+ }
21696
+ classifications[result.name].push(item);
18711
21697
  }
18712
- });
18713
- unhandledScores = null;
18714
- if (failingScorersAndResults.length) {
18715
- const scorerErrors = Object.fromEntries(
18716
- failingScorersAndResults.map(({ name, error: error2 }) => [
18717
- name,
18718
- error2 instanceof Error ? error2.stack : `${error2}`
18719
- ])
18720
- );
18721
- metadata["scorer_errors"] = scorerErrors;
18722
- rootSpan.log({
18723
- metadata: { scorer_errors: scorerErrors }
18724
- });
18725
- const names = Object.keys(scorerErrors).join(", ");
18726
- const errors = failingScorersAndResults.map((item) => item.error);
18727
- unhandledScores = Object.keys(scorerErrors);
18728
- debugLogger.forState(evaluator.state).warn(
18729
- `Found exceptions for the following scorers: ${names}`,
18730
- errors
18731
- );
21698
+ );
21699
+ if (Object.keys(classifications).length > 0) {
21700
+ rootSpan.log({ classifications });
18732
21701
  }
21702
+ const failedScorerNames = logScoringFailures(
21703
+ "scorer",
21704
+ failingScorers,
21705
+ metadata,
21706
+ rootSpan,
21707
+ evaluator.state
21708
+ );
21709
+ unhandledScores = failedScorerNames.length ? failedScorerNames : null;
21710
+ logScoringFailures(
21711
+ "classifier",
21712
+ failingClassifiers,
21713
+ metadata,
21714
+ rootSpan,
21715
+ evaluator.state
21716
+ );
18733
21717
  } catch (e) {
18734
21718
  logError(rootSpan, e);
18735
21719
  error = e;
@@ -18748,15 +21732,19 @@ async function runEvaluatorInternal(experiment, evaluator, progressReporter, fil
18748
21732
  accumulateScores(localScoreAccumulator, mergedScores);
18749
21733
  }
18750
21734
  if (collectResults) {
18751
- collectedResults.push({
21735
+ const baseResult = {
18752
21736
  input: datum.input,
18753
21737
  ..."expected" in datum ? { expected: datum.expected } : {},
18754
21738
  output,
18755
21739
  tags: tags.length ? tags : void 0,
18756
21740
  metadata,
18757
- scores: mergedScores,
18758
21741
  error,
18759
21742
  origin: baseEvent.event?.origin
21743
+ };
21744
+ collectedResults.push({
21745
+ ...baseResult,
21746
+ scores: mergedScores,
21747
+ ...Object.keys(classifications).length > 0 ? { classifications } : {}
18760
21748
  });
18761
21749
  }
18762
21750
  };
@@ -18785,7 +21773,7 @@ async function runEvaluatorInternal(experiment, evaluator, progressReporter, fil
18785
21773
  if (!filters.every((f) => evaluateFilter(datum, f))) {
18786
21774
  continue;
18787
21775
  }
18788
- const trialCount = evaluator.trialCount ?? 1;
21776
+ const trialCount = datum.trialCount ?? evaluator.trialCount ?? 1;
18789
21777
  for (let trialIndex = 0; trialIndex < trialCount; trialIndex++) {
18790
21778
  if (cancelled) {
18791
21779
  break;
@@ -18891,6 +21879,9 @@ function logError2(e, verbose) {
18891
21879
  }
18892
21880
  }
18893
21881
  function accumulateScores(accumulator, scores) {
21882
+ if (!scores) {
21883
+ return;
21884
+ }
18894
21885
  for (const [name, score] of Object.entries(scores)) {
18895
21886
  if (score === null || score === void 0) {
18896
21887
  continue;
@@ -19221,7 +22212,8 @@ var baseAllowedHeaders = [
19221
22212
  "x-stainless-package-version",
19222
22213
  "x-stainless-runtime",
19223
22214
  "x-stainless-runtime-version",
19224
- "x-stainless-arch"
22215
+ "x-stainless-arch",
22216
+ "x-bt-use-gateway"
19225
22217
  ];
19226
22218
 
19227
22219
  // dev/stream.ts
@@ -19298,7 +22290,8 @@ var serializedParametersContainerSchema = z12.union([
19298
22290
  ]);
19299
22291
  var evaluatorDefinitionSchema = z12.object({
19300
22292
  parameters: serializedParametersContainerSchema.optional(),
19301
- scores: z12.array(z12.object({ name: z12.string() })).optional()
22293
+ scores: z12.array(z12.object({ name: z12.string() })).optional(),
22294
+ classifiers: z12.array(z12.object({ name: z12.string() })).optional()
19302
22295
  });
19303
22296
  var evaluatorDefinitionsSchema = z12.record(
19304
22297
  z12.string(),
@@ -19856,8 +22849,11 @@ function runDevServer(evaluators, opts) {
19856
22849
  }
19857
22850
  evalDefs[name] = {
19858
22851
  parameters,
19859
- scores: evaluator.scores.map((score, idx) => ({
22852
+ scores: (evaluator.scores ?? []).map((score, idx) => ({
19860
22853
  name: scorerName(score, idx)
22854
+ })),
22855
+ classifiers: (evaluator.classifiers ?? []).map((classifier, idx) => ({
22856
+ name: classifierName(classifier, idx)
19861
22857
  }))
19862
22858
  };
19863
22859
  }
@@ -19928,7 +22924,7 @@ function runDevServer(evaluators, opts) {
19928
22924
  {
19929
22925
  ...evaluator,
19930
22926
  data: evalData.data,
19931
- scores: evaluator.scores.concat(
22927
+ scores: (evaluator.scores ?? []).concat(
19932
22928
  scores?.map(
19933
22929
  (score) => makeScorer(
19934
22930
  state,