braintrust 3.30.0 → 3.32.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 (55) hide show
  1. package/dev/dist/index.d.mts +740 -1
  2. package/dev/dist/index.d.ts +740 -1
  3. package/dev/dist/index.js +1307 -434
  4. package/dev/dist/index.mjs +886 -13
  5. package/dist/apply-auto-instrumentation.js +281 -216
  6. package/dist/apply-auto-instrumentation.mjs +66 -1
  7. package/dist/auto-instrumentations/bundler/esbuild.cjs +104 -2
  8. package/dist/auto-instrumentations/bundler/esbuild.mjs +2 -2
  9. package/dist/auto-instrumentations/bundler/next.cjs +113 -5
  10. package/dist/auto-instrumentations/bundler/next.mjs +12 -6
  11. package/dist/auto-instrumentations/bundler/rollup.cjs +104 -2
  12. package/dist/auto-instrumentations/bundler/rollup.mjs +2 -2
  13. package/dist/auto-instrumentations/bundler/vite.cjs +104 -2
  14. package/dist/auto-instrumentations/bundler/vite.mjs +2 -2
  15. package/dist/auto-instrumentations/bundler/webpack-loader.cjs +104 -2
  16. package/dist/auto-instrumentations/bundler/webpack.cjs +104 -2
  17. package/dist/auto-instrumentations/bundler/webpack.mjs +3 -3
  18. package/dist/auto-instrumentations/{chunk-U64OYU4Q.mjs → chunk-AFND2U7E.mjs} +38 -1
  19. package/dist/auto-instrumentations/{chunk-OXINGIEZ.mjs → chunk-QEEPRBIS.mjs} +1 -1
  20. package/dist/auto-instrumentations/{chunk-LW4HDHXT.mjs → chunk-RI4Y55ZF.mjs} +69 -2
  21. package/dist/auto-instrumentations/hook.mjs +126 -3
  22. package/dist/auto-instrumentations/index.cjs +39 -1
  23. package/dist/auto-instrumentations/index.d.mts +3 -1
  24. package/dist/auto-instrumentations/index.d.ts +3 -1
  25. package/dist/auto-instrumentations/index.mjs +3 -1
  26. package/dist/browser.d.mts +3052 -927
  27. package/dist/browser.d.ts +3052 -927
  28. package/dist/browser.js +1023 -18
  29. package/dist/browser.mjs +1023 -18
  30. package/dist/{chunk-BU6SM54N.mjs → chunk-4QSAHP7D.mjs} +834 -10
  31. package/dist/{chunk-2XDW3UCG.js → chunk-AW4QECG5.js} +47 -4
  32. package/dist/{chunk-TWCDSYJN.js → chunk-BTRLPQG5.js} +1679 -855
  33. package/dist/{chunk-N3JKQ3D3.mjs → chunk-WV6QZI2W.mjs} +46 -3
  34. package/dist/cli.js +950 -14
  35. package/dist/edge-light.d.mts +1 -1
  36. package/dist/edge-light.d.ts +1 -1
  37. package/dist/edge-light.js +1023 -18
  38. package/dist/edge-light.mjs +1023 -18
  39. package/dist/index.d.mts +3052 -927
  40. package/dist/index.d.ts +3052 -927
  41. package/dist/index.js +594 -450
  42. package/dist/index.mjs +149 -5
  43. package/dist/instrumentation/index.d.mts +434 -0
  44. package/dist/instrumentation/index.d.ts +434 -0
  45. package/dist/instrumentation/index.js +875 -12
  46. package/dist/instrumentation/index.mjs +875 -12
  47. package/dist/vitest-evals-reporter.js +16 -16
  48. package/dist/vitest-evals-reporter.mjs +2 -2
  49. package/dist/workerd.d.mts +1 -1
  50. package/dist/workerd.d.ts +1 -1
  51. package/dist/workerd.js +1023 -18
  52. package/dist/workerd.mjs +1023 -18
  53. package/package.json +1 -1
  54. package/util/dist/index.d.mts +326 -0
  55. package/util/dist/index.d.ts +326 -0
package/dist/browser.js CHANGED
@@ -192,9 +192,11 @@ __export(browser_exports, {
192
192
  wrapCohere: () => wrapCohere,
193
193
  wrapCopilotClient: () => wrapCopilotClient,
194
194
  wrapCursorSDK: () => wrapCursorSDK,
195
+ wrapElevenLabs: () => wrapElevenLabs,
195
196
  wrapGenkit: () => wrapGenkit,
196
197
  wrapGoogleADK: () => wrapGoogleADK,
197
198
  wrapGoogleGenAI: () => wrapGoogleGenAI,
199
+ wrapGoogleGenerativeAI: () => wrapGoogleGenerativeAI,
198
200
  wrapGroq: () => wrapGroq,
199
201
  wrapHuggingFace: () => wrapHuggingFace,
200
202
  wrapHuggingFaceTransformers: () => wrapHuggingFaceTransformers,
@@ -3028,6 +3030,14 @@ var ChatCompletionContentPartImageWithTitle = import_v36.z.object({
3028
3030
  ttl: import_v36.z.enum(["5m", "1h"]).optional()
3029
3031
  }).optional()
3030
3032
  });
3033
+ var ChatCompletionContentPartInputAudioWithTitle = import_v36.z.object({
3034
+ input_audio: import_v36.z.object({ data: import_v36.z.string(), format: import_v36.z.enum(["wav", "mp3"]) }),
3035
+ type: import_v36.z.literal("input_audio"),
3036
+ cache_control: import_v36.z.object({
3037
+ type: import_v36.z.literal("ephemeral"),
3038
+ ttl: import_v36.z.enum(["5m", "1h"]).optional()
3039
+ }).optional()
3040
+ });
3031
3041
  var ChatCompletionContentPartFileFile = import_v36.z.object({ file_data: import_v36.z.string(), filename: import_v36.z.string(), file_id: import_v36.z.string() }).partial();
3032
3042
  var ChatCompletionContentPartFileWithTitle = import_v36.z.object({
3033
3043
  file: ChatCompletionContentPartFileFile,
@@ -3040,6 +3050,7 @@ var ChatCompletionContentPartFileWithTitle = import_v36.z.object({
3040
3050
  var ChatCompletionContentPart = import_v36.z.union([
3041
3051
  ChatCompletionContentPartTextWithTitle,
3042
3052
  ChatCompletionContentPartImageWithTitle,
3053
+ ChatCompletionContentPartInputAudioWithTitle,
3043
3054
  ChatCompletionContentPartFileWithTitle
3044
3055
  ]);
3045
3056
  var ChatCompletionContentPartText = import_v36.z.object({
@@ -4031,6 +4042,7 @@ var ProjectSettings = import_v36.z.union([
4031
4042
  ]),
4032
4043
  disable_realtime_queries: import_v36.z.union([import_v36.z.boolean(), import_v36.z.null()]),
4033
4044
  monitor_charts_use_metrics_start: import_v36.z.union([import_v36.z.boolean(), import_v36.z.null()]),
4045
+ blind_reviews: import_v36.z.union([import_v36.z.boolean(), import_v36.z.null()]),
4034
4046
  default_preprocessor: NullableSavedFunctionId
4035
4047
  }).partial(),
4036
4048
  import_v36.z.null()
@@ -4092,6 +4104,7 @@ var WindowedAutomationConfig = import_v36.z.object({
4092
4104
  auto_approve_tools: import_v36.z.array(import_v36.z.string().min(1)).optional().default([]),
4093
4105
  harness: import_v36.z.enum(["native", "codex", "claude-code"]).optional(),
4094
4106
  model: import_v36.z.string().min(1).optional(),
4107
+ endpoint_name: import_v36.z.string().min(1).optional(),
4095
4108
  reasoning_effort: import_v36.z.enum(["none", "minimal", "low", "medium", "high", "xhigh", "max"]).optional()
4096
4109
  }).optional(),
4097
4110
  actions: import_v36.z.array(
@@ -5863,6 +5876,7 @@ var INSTRUMENTATION_NAMES = {
5863
5876
  GENKIT: "genkit",
5864
5877
  GITHUB_COPILOT: "github-copilot",
5865
5878
  GOOGLE_ADK: "google-adk",
5879
+ GOOGLE_GENERATIVE_AI: "google-generative-ai",
5866
5880
  GOOGLE_GENAI: "google-genai",
5867
5881
  GROQ: "groq",
5868
5882
  HUGGINGFACE: "huggingface",
@@ -5878,12 +5892,13 @@ var INSTRUMENTATION_NAMES = {
5878
5892
  OPENROUTER_AGENT: "openrouter-agent",
5879
5893
  PI_CODING_AGENT: "pi-coding-agent",
5880
5894
  STRANDS_AGENT_SDK: "strands-agent-sdk",
5881
- VOYAGEAI: "voyageai"
5895
+ VOYAGEAI: "voyageai",
5896
+ ELEVENLABS: "elevenlabs"
5882
5897
  };
5883
5898
  var INTERNAL_SPAN_INSTRUMENTATION_NAME = /* @__PURE__ */ Symbol.for(
5884
5899
  "braintrust.spanInstrumentationName"
5885
5900
  );
5886
- var SDK_VERSION = true ? "3.30.0" : "0.0.0";
5901
+ var SDK_VERSION = true ? "3.32.0" : "0.0.0";
5887
5902
  function withSpanInstrumentationName(args, instrumentationName) {
5888
5903
  return {
5889
5904
  ...args,
@@ -11841,6 +11856,16 @@ function renderMessageImpl(render, message, variables) {
11841
11856
  }
11842
11857
  }
11843
11858
  ];
11859
+ case "input_audio":
11860
+ return [
11861
+ {
11862
+ ...c,
11863
+ input_audio: {
11864
+ ...c.input_audio,
11865
+ data: render(c.input_audio.data)
11866
+ }
11867
+ }
11868
+ ];
11844
11869
  case "file":
11845
11870
  return [
11846
11871
  {
@@ -20000,6 +20025,12 @@ function prepareAISDKChildTracing(params, self, parentSpan, denyOutputPaths, aiS
20000
20025
  if (!activeEntry) {
20001
20026
  return result;
20002
20027
  }
20028
+ const executionOptions = args[1];
20029
+ const toolCallId = isObject(executionOptions) ? executionOptions.toolCallId : void 0;
20030
+ const toolInput = {
20031
+ input: serializeToolExecutionInput(args),
20032
+ ...typeof toolCallId === "string" ? { metadata: { toolCallId } } : {}
20033
+ };
20003
20034
  if (isAsyncGenerator(result)) {
20004
20035
  return (async function* () {
20005
20036
  const span = activeEntry.parentSpan.startSpan(
@@ -20013,7 +20044,7 @@ function prepareAISDKChildTracing(params, self, parentSpan, denyOutputPaths, aiS
20013
20044
  INSTRUMENTATION_NAMES.AI_SDK
20014
20045
  )
20015
20046
  );
20016
- span.log({ input: serializeToolExecutionInput(args) });
20047
+ span.log(toolInput);
20017
20048
  try {
20018
20049
  let lastValue;
20019
20050
  for await (const value of result) {
@@ -20031,7 +20062,7 @@ function prepareAISDKChildTracing(params, self, parentSpan, denyOutputPaths, aiS
20031
20062
  }
20032
20063
  return activeEntry.parentSpan.traced(
20033
20064
  async (span) => {
20034
- span.log({ input: serializeToolExecutionInput(args) });
20065
+ span.log(toolInput);
20035
20066
  const awaitedResult = await result;
20036
20067
  span.log({ output: awaitedResult });
20037
20068
  return awaitedResult;
@@ -24435,6 +24466,342 @@ var OpenAIAgentsPlugin = class extends BasePlugin {
24435
24466
  }
24436
24467
  };
24437
24468
 
24469
+ // src/instrumentation/plugins/google-generative-ai-channels.ts
24470
+ var googleGenerativeAIChannels = defineChannels(
24471
+ "@google/generative-ai",
24472
+ {
24473
+ generateContent: channel({ channelName: "GenerativeModel.generateContent", kind: "async" }),
24474
+ generateContentStream: channel({ channelName: "GenerativeModel.generateContentStream", kind: "async" }),
24475
+ embedContent: channel({ channelName: "GenerativeModel.embedContent", kind: "async" }),
24476
+ batchEmbedContents: channel({ channelName: "GenerativeModel.batchEmbedContents", kind: "async" }),
24477
+ sendMessage: channel({ channelName: "ChatSession.sendMessage", kind: "async" }),
24478
+ sendMessageStream: channel({ channelName: "ChatSession.sendMessageStream", kind: "async" })
24479
+ },
24480
+ { instrumentationName: INSTRUMENTATION_NAMES.GOOGLE_GENERATIVE_AI }
24481
+ );
24482
+
24483
+ // src/instrumentation/plugins/google-generative-ai-plugin.ts
24484
+ var GENERATION_CONFIG_KEYS = [
24485
+ "temperature",
24486
+ "topP",
24487
+ "topK",
24488
+ "candidateCount",
24489
+ "maxOutputTokens",
24490
+ "stopSequences",
24491
+ "responseMimeType",
24492
+ "responseSchema",
24493
+ "presencePenalty",
24494
+ "frequencyPenalty",
24495
+ "responseLogprobs",
24496
+ "logprobs",
24497
+ "thinkingConfig"
24498
+ ];
24499
+ var GoogleGenerativeAIPlugin = class extends BasePlugin {
24500
+ onEnable() {
24501
+ this.unsubscribers.push(
24502
+ interceptCall(
24503
+ googleGenerativeAIChannels.generateContent,
24504
+ "generateContent"
24505
+ ),
24506
+ interceptCall(
24507
+ googleGenerativeAIChannels.generateContentStream,
24508
+ "generateContentStream"
24509
+ ),
24510
+ interceptCall(googleGenerativeAIChannels.sendMessage, "sendMessage"),
24511
+ interceptCall(
24512
+ googleGenerativeAIChannels.sendMessageStream,
24513
+ "sendMessageStream"
24514
+ ),
24515
+ interceptCall(googleGenerativeAIChannels.embedContent, "embedContent"),
24516
+ interceptCall(
24517
+ googleGenerativeAIChannels.batchEmbedContents,
24518
+ "batchEmbedContents"
24519
+ )
24520
+ );
24521
+ }
24522
+ onDisable() {
24523
+ this.unsubscribers = unsubscribeAll(this.unsubscribers);
24524
+ }
24525
+ };
24526
+ function interceptCall(channel2, operation) {
24527
+ return channel2.intercept((target, thisArg, args) => {
24528
+ const invokeTarget = () => Reflect.apply(target, thisArg, args);
24529
+ if (isAutoInstrumentationSuppressed()) return invokeTarget();
24530
+ const self = thisArg;
24531
+ const chat = operation.startsWith("sendMessage");
24532
+ const embedding = operation === "embedContent" || operation === "batchEmbedContents";
24533
+ const start = getCurrentUnixTimestamp();
24534
+ let span;
24535
+ try {
24536
+ span = startSpan(
24537
+ withSpanInstrumentationName(
24538
+ {
24539
+ name: embedding ? operation === "embedContent" ? "embed_content" : "batch_embed_contents" : "generate_content",
24540
+ spanAttributes: { type: "llm" /* LLM */ },
24541
+ event: extractInput(self, args[0], operation)
24542
+ },
24543
+ INSTRUMENTATION_NAMES.GOOGLE_GENERATIVE_AI
24544
+ )
24545
+ );
24546
+ } catch (error) {
24547
+ debugLogger.error("Error starting Google Generative AI span:", error);
24548
+ return invokeTarget();
24549
+ }
24550
+ let ended = false;
24551
+ const finish = (log3) => {
24552
+ if (ended) return;
24553
+ ended = true;
24554
+ try {
24555
+ log3();
24556
+ } catch (error) {
24557
+ debugLogger.error("Error logging Google Generative AI span:", error);
24558
+ }
24559
+ try {
24560
+ span.end();
24561
+ } catch (error) {
24562
+ debugLogger.error("Error ending Google Generative AI span:", error);
24563
+ }
24564
+ };
24565
+ if (chat) {
24566
+ try {
24567
+ void self._sendPromise.then(
24568
+ () => {
24569
+ try {
24570
+ span.log(extractInput(self, args[0], operation));
24571
+ } catch (error) {
24572
+ debugLogger.error("Error capturing Google chat history:", error);
24573
+ }
24574
+ },
24575
+ () => {
24576
+ }
24577
+ );
24578
+ } catch (error) {
24579
+ debugLogger.error("Error observing Google chat history:", error);
24580
+ }
24581
+ }
24582
+ let result;
24583
+ try {
24584
+ result = withCurrent(
24585
+ span,
24586
+ () => runWithAutoInstrumentationSuppressed(invokeTarget)
24587
+ );
24588
+ } catch (error) {
24589
+ finish(() => span.log({ error }));
24590
+ throw error;
24591
+ }
24592
+ void Promise.resolve(result).then(
24593
+ (value) => {
24594
+ try {
24595
+ if ("stream" in value) {
24596
+ let firstToken = false;
24597
+ const partial = { candidates: [] };
24598
+ const candidates = /* @__PURE__ */ new Map();
24599
+ patchStreamIfNeeded(value.stream, {
24600
+ aroundNext: (callback) => withCurrent(span, callback),
24601
+ onChunk: (chunk) => {
24602
+ for (const candidate of chunk.candidates ?? []) {
24603
+ const index = candidate.index ?? 0;
24604
+ const previous = candidates.get(index);
24605
+ const parts = [...previous?.content?.parts ?? []];
24606
+ for (const part of candidate.content?.parts ?? []) {
24607
+ const last = parts[parts.length - 1];
24608
+ if (part.text !== void 0 && last?.text !== void 0) {
24609
+ parts[parts.length - 1] = {
24610
+ ...last,
24611
+ text: last.text + part.text
24612
+ };
24613
+ } else parts.push(part);
24614
+ }
24615
+ candidates.set(index, {
24616
+ ...previous,
24617
+ ...candidate,
24618
+ content: {
24619
+ role: candidate.content?.role ?? previous?.content?.role ?? "model",
24620
+ parts
24621
+ }
24622
+ });
24623
+ }
24624
+ partial.candidates = Array.from(candidates.values());
24625
+ if (chunk.usageMetadata)
24626
+ partial.usageMetadata = chunk.usageMetadata;
24627
+ if (!firstToken && chunk.candidates?.some(
24628
+ (candidate) => candidate.content?.parts.some(
24629
+ (part) => part.text !== void 0 ? part.text.length > 0 : Object.keys(part).length > 0
24630
+ )
24631
+ )) {
24632
+ firstToken = true;
24633
+ span.log({
24634
+ metrics: {
24635
+ time_to_first_token: getCurrentUnixTimestamp() - start
24636
+ }
24637
+ });
24638
+ }
24639
+ },
24640
+ onComplete: () => {
24641
+ },
24642
+ onError: (error) => finish(() => {
24643
+ logResponse(span, partial);
24644
+ span.log({ error });
24645
+ }),
24646
+ onCancel: () => finish(() => logResponse(span, partial))
24647
+ });
24648
+ void value.response.then(
24649
+ (response) => finish(() => logResponse(span, response)),
24650
+ (error) => finish(() => {
24651
+ logResponse(span, partial);
24652
+ span.log({ error });
24653
+ })
24654
+ );
24655
+ } else if ("response" in value) {
24656
+ finish(() => logResponse(span, value.response));
24657
+ } else {
24658
+ const metrics = {};
24659
+ const promptTokens = value.usageMetadata?.promptTokenCount;
24660
+ if (typeof promptTokens === "number" && Number.isFinite(promptTokens) && promptTokens >= 0) {
24661
+ metrics.prompt_tokens = promptTokens;
24662
+ metrics.tokens = promptTokens;
24663
+ }
24664
+ for (const detail of value.usageMetadata?.promptTokenDetails ?? []) {
24665
+ if (detail.modality === "AUDIO" && typeof detail.tokenCount === "number" && Number.isFinite(detail.tokenCount) && detail.tokenCount >= 0) {
24666
+ metrics.prompt_audio_tokens = (metrics.prompt_audio_tokens ?? 0) + detail.tokenCount;
24667
+ }
24668
+ }
24669
+ finish(
24670
+ () => span.log({
24671
+ metrics,
24672
+ output: {
24673
+ count: value.embeddings?.length ?? (value.embedding ? 1 : 0)
24674
+ }
24675
+ })
24676
+ );
24677
+ }
24678
+ } catch (error) {
24679
+ debugLogger.error(
24680
+ "Error observing Google Generative AI result:",
24681
+ error
24682
+ );
24683
+ finish(() => {
24684
+ });
24685
+ }
24686
+ },
24687
+ (error) => finish(() => span.log({ error }))
24688
+ );
24689
+ return result;
24690
+ });
24691
+ }
24692
+ function normalizeContent(message) {
24693
+ const parts = (typeof message === "string" ? [message] : message).map(
24694
+ (part) => typeof part === "string" ? { text: part } : part
24695
+ );
24696
+ return {
24697
+ role: parts.some((part) => part.functionResponse) ? "function" : "user",
24698
+ parts
24699
+ };
24700
+ }
24701
+ function extractInput(self, request, operation) {
24702
+ const model = self.model.replace(/^models\//, "");
24703
+ if (operation === "embedContent" || operation === "batchEmbedContents") {
24704
+ const requests = operation === "batchEmbedContents" ? request.requests : [
24705
+ typeof request === "string" || Array.isArray(request) ? { content: normalizeContent(request) } : request
24706
+ ];
24707
+ const dimensions = requests[0]?.outputDimensionality;
24708
+ return {
24709
+ input: {
24710
+ inputs: convertAttachments(requests).map((item) => ({
24711
+ content: item.content.parts.length === 1 && item.content.parts[0].text !== void 0 ? item.content.parts[0].text : item.content.parts.map((part) => {
24712
+ if (part.text !== void 0)
24713
+ return { type: "text", text: part.text };
24714
+ const mimeType = part.inlineData?.mimeType ?? part.fileData?.mimeType;
24715
+ const data = part.inlineData ? typeof part.inlineData.data === "string" ? `data:${mimeType};base64,${part.inlineData.data}` : part.inlineData.data : part.fileData?.fileUri;
24716
+ return mimeType?.startsWith("image/") ? { type: "image_url", image_url: { url: data } } : { type: "file", file: { file_data: data } };
24717
+ })
24718
+ })),
24719
+ ...dimensions !== void 0 && requests.every((item) => item.outputDimensionality === dimensions) ? { output_dimensions: dimensions } : {}
24720
+ },
24721
+ metadata: { model, provider: "google" }
24722
+ };
24723
+ }
24724
+ const chat = operation.startsWith("sendMessage");
24725
+ const config = chat ? self.params ?? {} : self;
24726
+ const params = typeof request === "string" || Array.isArray(request) ? { contents: [normalizeContent(request)] } : request;
24727
+ const system = params.systemInstruction ?? config.systemInstruction;
24728
+ const systemContent = typeof system === "string" ? { role: "system", parts: [{ text: system }] } : system && "parts" in system ? { ...system, role: "system" } : system ? { role: "system", parts: [system] } : void 0;
24729
+ const contents = [
24730
+ ...systemContent ? [systemContent] : [],
24731
+ ...chat ? self._history : [],
24732
+ ...params.contents
24733
+ ];
24734
+ const metadata = { model, provider: "google" };
24735
+ const generation = params.generationConfig ?? config.generationConfig;
24736
+ for (const key of GENERATION_CONFIG_KEYS) {
24737
+ if (generation && Object.hasOwn(generation, key))
24738
+ metadata[key] = generation[key];
24739
+ }
24740
+ for (const key of ["tools", "toolConfig", "safetySettings"]) {
24741
+ const value = params[key] ?? config[key];
24742
+ if (value !== void 0) metadata[key] = value;
24743
+ }
24744
+ const cached = params.cachedContent ?? config.cachedContent;
24745
+ if (cached)
24746
+ metadata.cachedContent = typeof cached === "string" ? cached : cached.name;
24747
+ return { input: convertAttachments({ model, contents }), metadata };
24748
+ }
24749
+ function convertAttachments(value) {
24750
+ const convert = (node) => {
24751
+ if (Array.isArray(node)) return node.map(convert);
24752
+ if (!isObject(node)) return node;
24753
+ if (isObject(node.inlineData)) {
24754
+ const { data, mimeType } = node.inlineData;
24755
+ const processed = processInputAttachments({
24756
+ type: "file",
24757
+ file: { file_data: `data:${mimeType};base64,${data}` }
24758
+ });
24759
+ if (typeof processed.file.file_data === "string")
24760
+ throw new Error("Unable to convert Google inline data");
24761
+ return {
24762
+ ...node,
24763
+ inlineData: { ...node.inlineData, data: processed.file.file_data }
24764
+ };
24765
+ }
24766
+ return Object.fromEntries(
24767
+ Object.entries(node).map(([key, item]) => [key, convert(item)])
24768
+ );
24769
+ };
24770
+ try {
24771
+ return convert(value);
24772
+ } catch (error) {
24773
+ debugLogger.error(
24774
+ "Error converting Google Generative AI attachments:",
24775
+ error
24776
+ );
24777
+ return value;
24778
+ }
24779
+ }
24780
+ function logResponse(span, response) {
24781
+ const usage = response.usageMetadata;
24782
+ const metrics = {};
24783
+ if (usage) {
24784
+ if (usage.promptTokenCount !== void 0)
24785
+ metrics.prompt_tokens = usage.promptTokenCount;
24786
+ if (usage.candidatesTokenCount !== void 0 || usage.thoughtsTokenCount !== void 0)
24787
+ metrics.completion_tokens = (usage.candidatesTokenCount ?? 0) + (usage.thoughtsTokenCount ?? 0);
24788
+ if (usage.totalTokenCount !== void 0)
24789
+ metrics.tokens = usage.totalTokenCount;
24790
+ if (usage.cachedContentTokenCount !== void 0)
24791
+ metrics.prompt_cached_tokens = usage.cachedContentTokenCount;
24792
+ if (usage.thoughtsTokenCount !== void 0)
24793
+ metrics.completion_reasoning_tokens = usage.thoughtsTokenCount;
24794
+ }
24795
+ span.log({
24796
+ output: convertAttachments({
24797
+ candidates: response.candidates,
24798
+ promptFeedback: response.promptFeedback
24799
+ }),
24800
+ metrics,
24801
+ ...response.modelVersion ? { metadata: { model: response.modelVersion } } : {}
24802
+ });
24803
+ }
24804
+
24438
24805
  // src/instrumentation/plugins/google-genai-channels.ts
24439
24806
  var googleGenAIChannels = defineChannels(
24440
24807
  "@google/genai",
@@ -26078,7 +26445,7 @@ var HuggingFaceTransformersPlugin = class extends BasePlugin {
26078
26445
  getTask(event)
26079
26446
  ),
26080
26447
  extractInput: (args, event) => ({
26081
- input: extractInput(
26448
+ input: extractInput2(
26082
26449
  getTask(event),
26083
26450
  args
26084
26451
  ),
@@ -26168,7 +26535,7 @@ function modelIdentifier(pipeline) {
26168
26535
  }
26169
26536
  return void 0;
26170
26537
  }
26171
- function extractInput(task, args) {
26538
+ function extractInput2(task, args) {
26172
26539
  switch (task) {
26173
26540
  case "feature-extraction":
26174
26541
  return args[0];
@@ -34153,14 +34520,17 @@ function getMetricsFromResponse(response) {
34153
34520
  if (!isRecord(usageMetadata)) {
34154
34521
  continue;
34155
34522
  }
34156
- const inputTokenDetails = usageMetadata.input_token_details;
34523
+ const inputTokenDetails = isRecord(usageMetadata.input_token_details) ? usageMetadata.input_token_details : {};
34157
34524
  const outputTokenDetails = usageMetadata.output_token_details;
34158
34525
  return normalizeTokenMetrics({
34159
34526
  total_tokens: usageMetadata.total_tokens,
34160
34527
  prompt_tokens: usageMetadata.input_tokens,
34161
34528
  completion_tokens: usageMetadata.output_tokens,
34162
- prompt_cache_creation_tokens: isRecord(inputTokenDetails) ? inputTokenDetails.cache_creation : void 0,
34163
- prompt_cached_tokens: isRecord(inputTokenDetails) ? inputTokenDetails.cache_read : void 0,
34529
+ // Prefer TTL-specific cache writes over the aggregate when available.
34530
+ prompt_cache_creation_tokens: inputTokenDetails.ephemeral_5m_input_tokens == null && inputTokenDetails.ephemeral_1h_input_tokens == null ? inputTokenDetails.cache_creation : void 0,
34531
+ prompt_cache_creation_5m_tokens: inputTokenDetails.ephemeral_5m_input_tokens,
34532
+ prompt_cache_creation_1h_tokens: inputTokenDetails.ephemeral_1h_input_tokens,
34533
+ prompt_cached_tokens: inputTokenDetails.cache_read,
34164
34534
  completion_reasoning_tokens: isRecord(outputTokenDetails) ? outputTokenDetails.reasoning : void 0
34165
34535
  });
34166
34536
  }
@@ -36519,6 +36889,477 @@ function logInstrumentationError5(context, error) {
36519
36889
  debugLogger.debug(`${context}:`, error);
36520
36890
  }
36521
36891
 
36892
+ // src/instrumentation/plugins/elevenlabs-channels.ts
36893
+ var elevenLabsChannels = defineChannels(
36894
+ "@elevenlabs/elevenlabs-js",
36895
+ {
36896
+ convert: channel({
36897
+ channelName: "textToSpeech.convert",
36898
+ kind: "async"
36899
+ }),
36900
+ stream: channel({
36901
+ channelName: "textToSpeech.stream",
36902
+ kind: "async"
36903
+ }),
36904
+ convertWithTimestamps: channel({ channelName: "textToSpeech.convertWithTimestamps", kind: "async" }),
36905
+ streamWithTimestamps: channel({ channelName: "textToSpeech.streamWithTimestamps", kind: "async" }),
36906
+ transcribe: channel({ channelName: "speechToText.convert", kind: "async" })
36907
+ },
36908
+ { instrumentationName: INSTRUMENTATION_NAMES.ELEVENLABS }
36909
+ );
36910
+
36911
+ // src/instrumentation/plugins/elevenlabs-plugin.ts
36912
+ var ElevenLabsPlugin = class extends BasePlugin {
36913
+ onEnable() {
36914
+ for (const method of [
36915
+ "convert",
36916
+ "stream",
36917
+ "convertWithTimestamps",
36918
+ "streamWithTimestamps"
36919
+ ]) {
36920
+ this.unsubscribers.push(
36921
+ interceptCall2(
36922
+ elevenLabsChannels[method],
36923
+ `elevenlabs.textToSpeech.${method}`,
36924
+ ([voice, request]) => ({
36925
+ input: {
36926
+ operation: "speech",
36927
+ prompt: request.text,
36928
+ parameters: {
36929
+ voice,
36930
+ format: request.outputFormat,
36931
+ language: request.languageCode,
36932
+ speed: request.voiceSettings?.speed
36933
+ }
36934
+ },
36935
+ metadata: {
36936
+ provider: "elevenlabs",
36937
+ model: request.modelId ?? "eleven_multilingual_v2"
36938
+ }
36939
+ }),
36940
+ (value, args, span, finish, headers, started) => captureSpeech(
36941
+ value,
36942
+ args[1],
36943
+ method,
36944
+ span,
36945
+ finish,
36946
+ started,
36947
+ headers
36948
+ )
36949
+ )
36950
+ );
36951
+ }
36952
+ this.unsubscribers.push(
36953
+ interceptCall2(
36954
+ elevenLabsChannels.transcribe,
36955
+ "elevenlabs.speechToText.convert",
36956
+ ([request]) => {
36957
+ if (request.webhook) return void 0;
36958
+ const file = request.file;
36959
+ const filename = typeof File !== "undefined" && file instanceof File ? file.name : "audio";
36960
+ const contentType = file instanceof Blob ? file.type || "application/octet-stream" : "application/octet-stream";
36961
+ const blob = file instanceof Blob ? file : file instanceof Uint8Array ? new Blob([new Uint8Array(file)], { type: contentType }) : file instanceof ArrayBuffer ? new Blob([file.slice(0)], { type: contentType }) : void 0;
36962
+ const fileData = blob ? new Attachment({ data: blob, filename, contentType }) : request.cloudStorageUrl;
36963
+ return {
36964
+ input: {
36965
+ operation: "transcribe",
36966
+ content: fileData ? [{ type: "file", file: { filename, file_data: fileData } }] : [],
36967
+ parameters: {
36968
+ language: request.languageCode,
36969
+ timestamp_granularities: request.timestampsGranularity
36970
+ }
36971
+ },
36972
+ metadata: { provider: "elevenlabs", model: request.modelId }
36973
+ };
36974
+ },
36975
+ (value, _args, span, finish) => {
36976
+ const result = value;
36977
+ const transcripts = result.transcripts ?? [result];
36978
+ span.log({
36979
+ output: {
36980
+ content: transcripts.flatMap(
36981
+ (transcript) => typeof transcript.text === "string" ? [{ type: "text", text: transcript.text }] : []
36982
+ ),
36983
+ annotations: {
36984
+ language: result.languageCode,
36985
+ words: result.words ?? (result.transcripts ? result.transcripts.flatMap(
36986
+ (transcript) => transcript.words ?? []
36987
+ ) : void 0)
36988
+ }
36989
+ }
36990
+ });
36991
+ finish();
36992
+ },
36993
+ ([request], span) => {
36994
+ const file = request.file;
36995
+ if (!isAsyncIterable(file)) return;
36996
+ const chunks = [];
36997
+ const filename = isObject(file) && typeof file.path === "string" ? file.path.split(/[\\/]/).pop() || "audio" : "audio";
36998
+ observeAudioStream(
36999
+ file,
37000
+ (chunk) => chunks.push(new Uint8Array(chunk)),
37001
+ () => {
37002
+ const contentType = "application/octet-stream";
37003
+ const data = new Blob(chunks, {
37004
+ type: contentType
37005
+ });
37006
+ chunks.length = 0;
37007
+ span.log({
37008
+ input: {
37009
+ content: [
37010
+ {
37011
+ type: "file",
37012
+ file: {
37013
+ filename,
37014
+ file_data: new Attachment({
37015
+ data,
37016
+ filename,
37017
+ contentType
37018
+ })
37019
+ }
37020
+ }
37021
+ ]
37022
+ }
37023
+ });
37024
+ },
37025
+ () => {
37026
+ chunks.length = 0;
37027
+ },
37028
+ span
37029
+ );
37030
+ }
37031
+ )
37032
+ );
37033
+ }
37034
+ onDisable() {
37035
+ this.unsubscribers = unsubscribeAll(this.unsubscribers);
37036
+ }
37037
+ };
37038
+ function interceptCall2(channel2, name, input, output, beforeInvoke) {
37039
+ return channel2.intercept((target, self, args) => {
37040
+ const invoke2 = () => Reflect.apply(target, self, args);
37041
+ if (isAutoInstrumentationSuppressed()) return invoke2();
37042
+ const started = Date.now() / 1e3;
37043
+ let span;
37044
+ try {
37045
+ const event = input(args);
37046
+ if (event !== void 0)
37047
+ span = startSpan(
37048
+ withSpanInstrumentationName(
37049
+ {
37050
+ name,
37051
+ spanAttributes: { type: "llm" /* LLM */ },
37052
+ event
37053
+ },
37054
+ INSTRUMENTATION_NAMES.ELEVENLABS
37055
+ )
37056
+ );
37057
+ } catch (error) {
37058
+ debugLogger.error("Error starting ElevenLabs span", error);
37059
+ return invoke2();
37060
+ }
37061
+ if (!span) return invoke2();
37062
+ const activeSpan = span;
37063
+ let ended = false;
37064
+ const finish = (error) => {
37065
+ if (ended) return;
37066
+ ended = true;
37067
+ try {
37068
+ if (error !== void 0) activeSpan.log({ error });
37069
+ activeSpan.end();
37070
+ } catch (loggingError) {
37071
+ debugLogger.error("Error ending ElevenLabs span", loggingError);
37072
+ }
37073
+ };
37074
+ try {
37075
+ beforeInvoke?.(args, span);
37076
+ } catch (error) {
37077
+ debugLogger.error("Error observing ElevenLabs input", error);
37078
+ }
37079
+ let result;
37080
+ try {
37081
+ result = withCurrent(
37082
+ span,
37083
+ () => runWithAutoInstrumentationSuppressed(invoke2)
37084
+ );
37085
+ } catch (error) {
37086
+ finish(error);
37087
+ throw error;
37088
+ }
37089
+ const capture = (value, headers) => {
37090
+ try {
37091
+ output(value, args, span, finish, headers, started);
37092
+ } catch (error) {
37093
+ debugLogger.error("Error capturing ElevenLabs output", error);
37094
+ finish();
37095
+ }
37096
+ };
37097
+ try {
37098
+ if (isObject(result) && typeof result.withRawResponse === "function") {
37099
+ void result.withRawResponse().then(
37100
+ ({
37101
+ data,
37102
+ rawResponse
37103
+ }) => capture(data, rawResponse?.headers),
37104
+ finish
37105
+ );
37106
+ } else {
37107
+ void Promise.resolve(result).then((value) => capture(value), finish);
37108
+ }
37109
+ } catch (error) {
37110
+ debugLogger.error("Error observing ElevenLabs result", error);
37111
+ finish();
37112
+ }
37113
+ return result;
37114
+ });
37115
+ }
37116
+ function captureSpeech(value, request, method, span, finish, started, headers) {
37117
+ const format = request.outputFormat ?? "mp3_44100_128";
37118
+ const formatType = format.startsWith("mp3_") ? "audio/mpeg" : format.startsWith("pcm_") ? "audio/pcm" : format.startsWith("opus_") ? "audio/ogg" : format.startsWith("ulaw_") ? "audio/basic" : format.startsWith("alaw_") ? "audio/x-alaw" : void 0;
37119
+ const headerType = headers?.get("content-type")?.split(";")[0];
37120
+ const contentType = headerType?.startsWith("audio/") ? headerType : formatType;
37121
+ const disposition = headers?.get("content-disposition");
37122
+ const headerFilename = disposition?.match(
37123
+ /filename="([^"]+)"|filename=([^;]+)/i
37124
+ );
37125
+ const filename = headerFilename?.[1] ?? headerFilename?.[2]?.trim() ?? `speech.${contentType ? getExtensionFromMediaType(contentType) : "bin"}`;
37126
+ const chunks = [];
37127
+ const alignments = [];
37128
+ let bytes = 0;
37129
+ let first = true;
37130
+ let stopped = false;
37131
+ const observe = (chunk) => {
37132
+ if (stopped || chunk.byteLength === 0) return;
37133
+ if (first && method.startsWith("stream")) {
37134
+ span.log({
37135
+ metrics: { time_to_first_token: Date.now() / 1e3 - started }
37136
+ });
37137
+ }
37138
+ first = false;
37139
+ chunks.push(new Uint8Array(chunk));
37140
+ bytes += chunk.byteLength;
37141
+ };
37142
+ const complete = () => {
37143
+ if (stopped) return;
37144
+ stopped = true;
37145
+ try {
37146
+ const content = [];
37147
+ if (contentType && bytes) {
37148
+ const data = new Uint8Array(bytes);
37149
+ let offset = 0;
37150
+ for (const chunk of chunks) {
37151
+ data.set(chunk, offset);
37152
+ offset += chunk.length;
37153
+ }
37154
+ content.push({
37155
+ type: "file",
37156
+ file: {
37157
+ filename,
37158
+ byte_size: bytes,
37159
+ file_data: new Attachment({
37160
+ data: new Blob([data], { type: contentType }),
37161
+ filename,
37162
+ contentType
37163
+ })
37164
+ }
37165
+ });
37166
+ }
37167
+ span.log({
37168
+ output: {
37169
+ content,
37170
+ ...alignments.length ? { annotations: alignments } : {}
37171
+ }
37172
+ });
37173
+ } finally {
37174
+ chunks.length = 0;
37175
+ finish();
37176
+ }
37177
+ };
37178
+ const cancel = (error) => {
37179
+ stopped = true;
37180
+ chunks.length = 0;
37181
+ finish(error);
37182
+ };
37183
+ const timestampChunk = (chunk) => {
37184
+ const binary = atob(chunk.audioBase64);
37185
+ observe(Uint8Array.from(binary, (character) => character.charCodeAt(0)));
37186
+ if (chunk.alignment || chunk.normalizedAlignment)
37187
+ alignments.push({
37188
+ alignment: chunk.alignment,
37189
+ normalized_alignment: chunk.normalizedAlignment
37190
+ });
37191
+ };
37192
+ if (method === "convertWithTimestamps") {
37193
+ timestampChunk(value);
37194
+ complete();
37195
+ } else if (method === "streamWithTimestamps") {
37196
+ patchStreamIfNeeded(value, {
37197
+ shouldCollect: (chunk) => {
37198
+ try {
37199
+ timestampChunk(chunk);
37200
+ } catch (error) {
37201
+ debugLogger.error("Error collecting ElevenLabs timestamps", error);
37202
+ cancel();
37203
+ }
37204
+ return false;
37205
+ },
37206
+ onComplete: complete,
37207
+ onCancel: () => cancel(),
37208
+ onError: cancel,
37209
+ aroundNext: (next) => withCurrent(span, next)
37210
+ });
37211
+ } else {
37212
+ observeAudioStream(value, observe, complete, cancel, span);
37213
+ }
37214
+ }
37215
+ function observeAudioStream(value, observe, complete, cancel, span) {
37216
+ let ended = false;
37217
+ const safeObserve = (chunk) => {
37218
+ if (ended) return;
37219
+ try {
37220
+ observe(chunk);
37221
+ } catch (error) {
37222
+ debugLogger.error("Error collecting ElevenLabs audio", error);
37223
+ end(false);
37224
+ }
37225
+ };
37226
+ const end = (success, error) => {
37227
+ if (ended) return;
37228
+ ended = true;
37229
+ try {
37230
+ if (success) complete();
37231
+ else cancel(error);
37232
+ } catch (loggingError) {
37233
+ debugLogger.error("Error logging ElevenLabs audio", loggingError);
37234
+ cancel();
37235
+ }
37236
+ };
37237
+ if (!isObject(value) || !Object.isExtensible(value)) {
37238
+ end(false);
37239
+ return;
37240
+ }
37241
+ if (typeof value.read === "function" && typeof value.on === "function") {
37242
+ value.on("end", () => end(true));
37243
+ value.on("close", () => end(false));
37244
+ const emit2 = value.emit;
37245
+ if (typeof emit2 === "function")
37246
+ value.emit = function(event, ...args) {
37247
+ if (event === "data" && args[0] instanceof Uint8Array)
37248
+ safeObserve(args[0]);
37249
+ if (event === "error") end(false, args[0]);
37250
+ return Reflect.apply(emit2, this, [event, ...args]);
37251
+ };
37252
+ return;
37253
+ }
37254
+ if (typeof value.getReader === "function") {
37255
+ const webStream = value;
37256
+ const pipeTo = webStream.pipeTo;
37257
+ const pipeThrough = webStream.pipeThrough;
37258
+ webStream.pipeTo = function(destination, options) {
37259
+ if (!isObject(destination) || this.locked || destination.locked)
37260
+ return pipeTo.call(this, destination, options);
37261
+ const tap = new TransformStream({
37262
+ transform(chunk, controller) {
37263
+ safeObserve(chunk);
37264
+ controller.enqueue(chunk);
37265
+ },
37266
+ flush() {
37267
+ end(true);
37268
+ }
37269
+ });
37270
+ const observed = pipeThrough.call(
37271
+ this,
37272
+ tap,
37273
+ options
37274
+ );
37275
+ return observed.pipeTo(destination, options).catch((error) => {
37276
+ end(false, error);
37277
+ throw error;
37278
+ });
37279
+ };
37280
+ webStream.pipeThrough = function(transform, options) {
37281
+ if (this.locked || transform.writable.locked || transform.readable.locked)
37282
+ return pipeThrough.call(this, transform, options);
37283
+ const result = webStream.pipeTo.call(this, transform.writable, options);
37284
+ void result.catch(() => {
37285
+ });
37286
+ return transform.readable;
37287
+ };
37288
+ const getReader = value.getReader;
37289
+ value.getReader = function(...args) {
37290
+ const reader = Reflect.apply(getReader, this, args);
37291
+ const read3 = reader.read;
37292
+ reader.read = function(...readArgs) {
37293
+ return Promise.resolve(
37294
+ withCurrent(span, () => Reflect.apply(read3, this, readArgs))
37295
+ ).then(
37296
+ (result) => {
37297
+ if (result.value) safeObserve(result.value);
37298
+ if (result.done) end(true);
37299
+ return result;
37300
+ },
37301
+ (error) => {
37302
+ end(false, error);
37303
+ throw error;
37304
+ }
37305
+ );
37306
+ };
37307
+ const readerCancel = reader.cancel;
37308
+ reader.cancel = function(...cancelArgs) {
37309
+ const result = Reflect.apply(readerCancel, this, cancelArgs);
37310
+ end(false);
37311
+ return result;
37312
+ };
37313
+ return reader;
37314
+ };
37315
+ const streamCancel = value.cancel;
37316
+ if (typeof streamCancel === "function")
37317
+ value.cancel = function(...args) {
37318
+ const result = Reflect.apply(streamCancel, this, args);
37319
+ void Promise.resolve(result).then(
37320
+ () => end(false),
37321
+ () => {
37322
+ }
37323
+ );
37324
+ return result;
37325
+ };
37326
+ }
37327
+ if (typeof value.getReader === "function" && typeof value.values === "function") {
37328
+ const values = value.values;
37329
+ const iterate = function(...args) {
37330
+ const iterator = Reflect.apply(values, this, args);
37331
+ patchStreamIfNeeded(iterator, {
37332
+ shouldCollect(chunk) {
37333
+ safeObserve(chunk);
37334
+ return false;
37335
+ },
37336
+ onComplete: () => end(true),
37337
+ onCancel: () => end(false),
37338
+ onError: (error) => end(false, error),
37339
+ aroundNext: (next) => withCurrent(span, next)
37340
+ });
37341
+ return iterator;
37342
+ };
37343
+ value.values = iterate;
37344
+ Object.defineProperty(value, Symbol.asyncIterator, {
37345
+ configurable: true,
37346
+ writable: true,
37347
+ value: iterate
37348
+ });
37349
+ } else if (isAsyncIterable(value)) {
37350
+ patchStreamIfNeeded(value, {
37351
+ shouldCollect: (chunk) => {
37352
+ safeObserve(chunk);
37353
+ return false;
37354
+ },
37355
+ onComplete: () => end(true),
37356
+ onCancel: () => end(false),
37357
+ onError: (error) => end(false, error),
37358
+ aroundNext: (next) => withCurrent(span, next)
37359
+ });
37360
+ } else if (typeof value.getReader !== "function") end(false);
37361
+ }
37362
+
36522
37363
  // src/instrumentation/plugins/voyageai-channels.ts
36523
37364
  var voyageAIChannels = defineChannels(
36524
37365
  "voyageai",
@@ -36586,7 +37427,7 @@ var VoyageAIPlugin = class extends BasePlugin {
36586
37427
  this.unsubscribers = unsubscribeAll(this.unsubscribers);
36587
37428
  }
36588
37429
  };
36589
- function interceptVoyageAICall(channel2, name, extractInput3, extractOutput2, extractMetrics2 = extractUsageMetrics3) {
37430
+ function interceptVoyageAICall(channel2, name, extractInput4, extractOutput2, extractMetrics2 = extractUsageMetrics3) {
36590
37431
  return channel2.intercept((target, thisArg, args) => {
36591
37432
  const invokeTarget = () => Reflect.apply(target, thisArg, args);
36592
37433
  if (isAutoInstrumentationSuppressed()) {
@@ -36594,7 +37435,7 @@ function interceptVoyageAICall(channel2, name, extractInput3, extractOutput2, ex
36594
37435
  }
36595
37436
  let span;
36596
37437
  try {
36597
- const { input, metadata } = extractInput3(args);
37438
+ const { input, metadata } = extractInput4(args);
36598
37439
  span = startSpan(
36599
37440
  withSpanInstrumentationName(
36600
37441
  {
@@ -37393,6 +38234,7 @@ var BraintrustPlugin = class extends BasePlugin {
37393
38234
  cloudflareThinkPlugin = null;
37394
38235
  cursorSDKPlugin = null;
37395
38236
  openAIAgentsPlugin = null;
38237
+ googleGenerativeAIPlugin = null;
37396
38238
  googleGenAIPlugin = null;
37397
38239
  huggingFacePlugin = null;
37398
38240
  huggingFaceTransformersPlugin = null;
@@ -37411,6 +38253,7 @@ var BraintrustPlugin = class extends BasePlugin {
37411
38253
  langSmithPlugin = null;
37412
38254
  piCodingAgentPlugin = null;
37413
38255
  strandsAgentSDKPlugin = null;
38256
+ elevenLabsPlugin = null;
37414
38257
  voyageAIPlugin = null;
37415
38258
  cloudflareAIChatPlugin = null;
37416
38259
  cloudflareAgentsPlugin = null;
@@ -37452,6 +38295,10 @@ var BraintrustPlugin = class extends BasePlugin {
37452
38295
  this.openAIAgentsPlugin = new OpenAIAgentsPlugin();
37453
38296
  this.openAIAgentsPlugin.enable();
37454
38297
  }
38298
+ if (integrations.googleGenerativeAI !== false) {
38299
+ this.googleGenerativeAIPlugin = new GoogleGenerativeAIPlugin();
38300
+ this.googleGenerativeAIPlugin.enable();
38301
+ }
37455
38302
  if (integrations.googleGenAI !== false && integrations.google !== false) {
37456
38303
  this.googleGenAIPlugin = new GoogleGenAIPlugin();
37457
38304
  this.googleGenAIPlugin.enable();
@@ -37486,6 +38333,10 @@ var BraintrustPlugin = class extends BasePlugin {
37486
38333
  this.coherePlugin = new CoherePlugin();
37487
38334
  this.coherePlugin.enable();
37488
38335
  }
38336
+ if (integrations.elevenlabs !== false) {
38337
+ this.elevenLabsPlugin = new ElevenLabsPlugin();
38338
+ this.elevenLabsPlugin.enable();
38339
+ }
37489
38340
  if (integrations.voyageai !== false) {
37490
38341
  this.voyageAIPlugin = new VoyageAIPlugin();
37491
38342
  this.voyageAIPlugin.enable();
@@ -37570,6 +38421,10 @@ var BraintrustPlugin = class extends BasePlugin {
37570
38421
  this.openAIAgentsPlugin.disable();
37571
38422
  this.openAIAgentsPlugin = null;
37572
38423
  }
38424
+ if (this.googleGenerativeAIPlugin) {
38425
+ this.googleGenerativeAIPlugin.disable();
38426
+ this.googleGenerativeAIPlugin = null;
38427
+ }
37573
38428
  if (this.googleGenAIPlugin) {
37574
38429
  this.googleGenAIPlugin.disable();
37575
38430
  this.googleGenAIPlugin = null;
@@ -37606,6 +38461,10 @@ var BraintrustPlugin = class extends BasePlugin {
37606
38461
  this.coherePlugin.disable();
37607
38462
  this.coherePlugin = null;
37608
38463
  }
38464
+ if (this.elevenLabsPlugin) {
38465
+ this.elevenLabsPlugin.disable();
38466
+ this.elevenLabsPlugin = null;
38467
+ }
37609
38468
  if (this.voyageAIPlugin) {
37610
38469
  this.voyageAIPlugin.disable();
37611
38470
  this.voyageAIPlugin = null;
@@ -37699,6 +38558,8 @@ var envIntegrationAliases = {
37699
38558
  "openai-agents-core": "openAIAgents",
37700
38559
  openaiagentscore: "openAIAgents",
37701
38560
  google: "google",
38561
+ "google-generative-ai": "googleGenerativeAI",
38562
+ googlegenerativeai: "googleGenerativeAI",
37702
38563
  "google-genai": "googleGenAI",
37703
38564
  googlegenai: "googleGenAI",
37704
38565
  huggingface: "huggingface",
@@ -37732,7 +38593,9 @@ var envIntegrationAliases = {
37732
38593
  langsmith: "langsmith",
37733
38594
  voyage: "voyageai",
37734
38595
  "voyage-ai": "voyageai",
37735
- voyageai: "voyageai"
38596
+ voyageai: "voyageai",
38597
+ elevenlabs: "elevenlabs",
38598
+ "@elevenlabs/elevenlabs-js": "elevenlabs"
37736
38599
  };
37737
38600
  function getDefaultInstrumentationIntegrations() {
37738
38601
  return {
@@ -37743,6 +38606,7 @@ function getDefaultInstrumentationIntegrations() {
37743
38606
  aisdk: true,
37744
38607
  google: true,
37745
38608
  googleGenAI: true,
38609
+ googleGenerativeAI: true,
37746
38610
  googleADK: true,
37747
38611
  huggingface: true,
37748
38612
  claudeAgentSDK: true,
@@ -37768,6 +38632,7 @@ function getDefaultInstrumentationIntegrations() {
37768
38632
  langgraph: true,
37769
38633
  langsmith: true,
37770
38634
  voyageai: true,
38635
+ elevenlabs: true,
37771
38636
  piCodingAgent: true,
37772
38637
  strandsAgentSDK: true,
37773
38638
  cloudflareAgents: true
@@ -38086,9 +38951,11 @@ __export(exports_exports, {
38086
38951
  wrapCohere: () => wrapCohere,
38087
38952
  wrapCopilotClient: () => wrapCopilotClient,
38088
38953
  wrapCursorSDK: () => wrapCursorSDK,
38954
+ wrapElevenLabs: () => wrapElevenLabs,
38089
38955
  wrapGenkit: () => wrapGenkit,
38090
38956
  wrapGoogleADK: () => wrapGoogleADK,
38091
38957
  wrapGoogleGenAI: () => wrapGoogleGenAI,
38958
+ wrapGoogleGenerativeAI: () => wrapGoogleGenerativeAI,
38092
38959
  wrapGroq: () => wrapGroq,
38093
38960
  wrapHuggingFace: () => wrapHuggingFace,
38094
38961
  wrapHuggingFaceTransformers: () => wrapHuggingFaceTransformers,
@@ -39698,7 +40565,7 @@ function extractToolCallsFromBlocks(blocks) {
39698
40565
  if (!Array.isArray(blocks)) return [];
39699
40566
  return extractToolCallsFromSteps([{ content: blocks }]);
39700
40567
  }
39701
- function extractInput2(params) {
40568
+ function extractInput3(params) {
39702
40569
  return params?.prompt ?? params?.messages ?? params?.system;
39703
40570
  }
39704
40571
  var V2_EXCLUDE_KEYS = /* @__PURE__ */ new Set([
@@ -39720,7 +40587,7 @@ function BraintrustMiddleware(config = {}) {
39720
40587
  params,
39721
40588
  model: modelFromWrapGenerate
39722
40589
  }) => {
39723
- const rawInput = extractInput2(params);
40590
+ const rawInput = extractInput3(params);
39724
40591
  const processedInput = processInputAttachments(rawInput);
39725
40592
  const spanArgs = {
39726
40593
  name: config.spanInfo?.name || "ai-sdk.doGenerate",
@@ -39784,7 +40651,7 @@ function BraintrustMiddleware(config = {}) {
39784
40651
  }
39785
40652
  },
39786
40653
  wrapStream: async ({ doStream, params }) => {
39787
- const rawInput = extractInput2(params);
40654
+ const rawInput = extractInput3(params);
39788
40655
  const processedInput = processInputAttachments(rawInput);
39789
40656
  const spanArgs = {
39790
40657
  name: config.spanInfo?.name || "ai-sdk.doStream",
@@ -43177,6 +44044,75 @@ function isModuleNamespace5(value) {
43177
44044
  }
43178
44045
  }
43179
44046
 
44047
+ // src/wrappers/google-generative-ai.ts
44048
+ function wrapGoogleGenerativeAI(client) {
44049
+ if (!isObject(client) || typeof client.getGenerativeModel !== "function")
44050
+ return client;
44051
+ return wrapClient(client);
44052
+ }
44053
+ var proxies = /* @__PURE__ */ new WeakMap();
44054
+ function wrapClient(client) {
44055
+ const cached = proxies.get(client);
44056
+ if (cached) return cached;
44057
+ const proxy = new Proxy(client, {
44058
+ get(target, prop, receiver) {
44059
+ const value = Reflect.get(target, prop, receiver);
44060
+ if (typeof value !== "function") return value;
44061
+ if (prop === "getGenerativeModel" || prop === "getGenerativeModelFromCachedContent" || prop === "startChat") {
44062
+ return (...args) => wrapClient(Reflect.apply(value, target, args));
44063
+ }
44064
+ switch (prop) {
44065
+ case "generateContent":
44066
+ return (...args) => googleGenerativeAIChannels.generateContent.invoke(
44067
+ value,
44068
+ target,
44069
+ args,
44070
+ {}
44071
+ );
44072
+ case "generateContentStream":
44073
+ return (...args) => googleGenerativeAIChannels.generateContentStream.invoke(
44074
+ value,
44075
+ target,
44076
+ args,
44077
+ {}
44078
+ );
44079
+ case "embedContent":
44080
+ return (...args) => googleGenerativeAIChannels.embedContent.invoke(
44081
+ value,
44082
+ target,
44083
+ args,
44084
+ {}
44085
+ );
44086
+ case "batchEmbedContents":
44087
+ return (...args) => googleGenerativeAIChannels.batchEmbedContents.invoke(
44088
+ value,
44089
+ target,
44090
+ args,
44091
+ {}
44092
+ );
44093
+ case "sendMessage":
44094
+ return (...args) => googleGenerativeAIChannels.sendMessage.invoke(
44095
+ value,
44096
+ target,
44097
+ args,
44098
+ {}
44099
+ );
44100
+ case "sendMessageStream":
44101
+ return (...args) => googleGenerativeAIChannels.sendMessageStream.invoke(
44102
+ value,
44103
+ target,
44104
+ args,
44105
+ {}
44106
+ );
44107
+ }
44108
+ return value.bind(target);
44109
+ }
44110
+ });
44111
+ proxies.set(client, proxy);
44112
+ proxies.set(proxy, proxy);
44113
+ return proxy;
44114
+ }
44115
+
43180
44116
  // src/wrappers/google-genai.ts
43181
44117
  function wrapGoogleGenAI(googleGenAI) {
43182
44118
  if (!googleGenAI || typeof googleGenAI !== "object") {
@@ -45174,8 +46110,8 @@ function normalizeScores(result) {
45174
46110
  (s) => s !== null && s !== void 0 && typeof s === "object" && isScore(s)
45175
46111
  );
45176
46112
  }
45177
- if (typeof result === "object" && result !== null && isScore(result)) {
45178
- return [result];
46113
+ if (typeof result === "object" && result !== null && "score" in result) {
46114
+ return [{ ...result, name: result.name ?? "score" }];
45179
46115
  }
45180
46116
  return [];
45181
46117
  }
@@ -47758,19 +48694,29 @@ function buildSpanScores(results) {
47758
48694
  function _internalPrepareEvaluatorScore(scoreValue, name) {
47759
48695
  if (scoreValue === null) return { results: null };
47760
48696
  if (Array.isArray(scoreValue)) {
48697
+ const names = /* @__PURE__ */ new Set();
47761
48698
  for (const score of scoreValue) {
47762
48699
  if (!(typeof score === "object" && !isEmpty2(score))) {
47763
48700
  throw new Error(
47764
48701
  `When returning an array of scores, each score must be a non-empty object. Got: ${JSON.stringify(score)}`
47765
48702
  );
47766
48703
  }
48704
+ if (typeof score.name !== "string") {
48705
+ throw new Error(
48706
+ `When returning an array of scores, each score must have a name. Got: ${JSON.stringify(score)}`
48707
+ );
48708
+ }
48709
+ if (names.has(score.name)) {
48710
+ throw new Error(`Duplicate score name '${score.name}' in score array`);
48711
+ }
48712
+ names.add(score.name);
47767
48713
  }
47768
48714
  }
47769
48715
  let results;
47770
48716
  if (Array.isArray(scoreValue)) {
47771
48717
  results = scoreValue;
47772
48718
  } else if (typeof scoreValue === "object" && !isEmpty2(scoreValue)) {
47773
- results = [scoreValue];
48719
+ results = [{ ...scoreValue, name: scoreValue.name ?? name }];
47774
48720
  } else {
47775
48721
  results = [{ name, score: scoreValue }];
47776
48722
  }
@@ -50528,5 +51474,64 @@ var evaluatorDefinitionsSchema = import_v313.z.record(
50528
51474
  evaluatorDefinitionSchema
50529
51475
  );
50530
51476
 
51477
+ // src/wrappers/elevenlabs.ts
51478
+ var clients = /* @__PURE__ */ new WeakMap();
51479
+ function wrapElevenLabs(client) {
51480
+ if (!isObject(client) || !isObject(client.textToSpeech) || typeof client.textToSpeech.convert !== "function") {
51481
+ debugLogger.warn("Unsupported ElevenLabs client. Not wrapping.");
51482
+ return client;
51483
+ }
51484
+ const cached = clients.get(client);
51485
+ if (cached) return cached;
51486
+ const sdk = client;
51487
+ const speech = new Proxy(sdk.textToSpeech, {
51488
+ get(target, prop, receiver) {
51489
+ switch (prop) {
51490
+ case "convert":
51491
+ case "stream":
51492
+ return (...args) => elevenLabsChannels[prop].invoke(target[prop], target, args, {});
51493
+ case "convertWithTimestamps":
51494
+ return (...args) => elevenLabsChannels.convertWithTimestamps.invoke(
51495
+ target.convertWithTimestamps,
51496
+ target,
51497
+ args,
51498
+ {}
51499
+ );
51500
+ case "streamWithTimestamps":
51501
+ return (...args) => elevenLabsChannels.streamWithTimestamps.invoke(
51502
+ target.streamWithTimestamps,
51503
+ target,
51504
+ args,
51505
+ {}
51506
+ );
51507
+ default:
51508
+ return Reflect.get(target, prop, receiver);
51509
+ }
51510
+ }
51511
+ });
51512
+ const transcription = new Proxy(sdk.speechToText, {
51513
+ get(target, prop, receiver) {
51514
+ if (prop === "convert")
51515
+ return (request, options) => elevenLabsChannels.transcribe.invoke(
51516
+ target.convert,
51517
+ target,
51518
+ [request, options],
51519
+ {}
51520
+ );
51521
+ return Reflect.get(target, prop, receiver);
51522
+ }
51523
+ });
51524
+ const proxy = new Proxy(sdk, {
51525
+ get(target, prop, receiver) {
51526
+ if (prop === "textToSpeech") return speech;
51527
+ if (prop === "speechToText") return transcription;
51528
+ return Reflect.get(target, prop, receiver);
51529
+ }
51530
+ });
51531
+ clients.set(client, proxy);
51532
+ clients.set(proxy, proxy);
51533
+ return proxy;
51534
+ }
51535
+
50531
51536
  // src/browser/index.ts
50532
51537
  configureBrowser();