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/workerd.js CHANGED
@@ -192,9 +192,11 @@ __export(workerd_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
  {
@@ -20034,6 +20059,12 @@ function prepareAISDKChildTracing(params, self, parentSpan, denyOutputPaths, aiS
20034
20059
  if (!activeEntry) {
20035
20060
  return result;
20036
20061
  }
20062
+ const executionOptions = args[1];
20063
+ const toolCallId = isObject(executionOptions) ? executionOptions.toolCallId : void 0;
20064
+ const toolInput = {
20065
+ input: serializeToolExecutionInput(args),
20066
+ ...typeof toolCallId === "string" ? { metadata: { toolCallId } } : {}
20067
+ };
20037
20068
  if (isAsyncGenerator(result)) {
20038
20069
  return (async function* () {
20039
20070
  const span = activeEntry.parentSpan.startSpan(
@@ -20047,7 +20078,7 @@ function prepareAISDKChildTracing(params, self, parentSpan, denyOutputPaths, aiS
20047
20078
  INSTRUMENTATION_NAMES.AI_SDK
20048
20079
  )
20049
20080
  );
20050
- span.log({ input: serializeToolExecutionInput(args) });
20081
+ span.log(toolInput);
20051
20082
  try {
20052
20083
  let lastValue;
20053
20084
  for await (const value of result) {
@@ -20065,7 +20096,7 @@ function prepareAISDKChildTracing(params, self, parentSpan, denyOutputPaths, aiS
20065
20096
  }
20066
20097
  return activeEntry.parentSpan.traced(
20067
20098
  async (span) => {
20068
- span.log({ input: serializeToolExecutionInput(args) });
20099
+ span.log(toolInput);
20069
20100
  const awaitedResult = await result;
20070
20101
  span.log({ output: awaitedResult });
20071
20102
  return awaitedResult;
@@ -24469,6 +24500,342 @@ var OpenAIAgentsPlugin = class extends BasePlugin {
24469
24500
  }
24470
24501
  };
24471
24502
 
24503
+ // src/instrumentation/plugins/google-generative-ai-channels.ts
24504
+ var googleGenerativeAIChannels = defineChannels(
24505
+ "@google/generative-ai",
24506
+ {
24507
+ generateContent: channel({ channelName: "GenerativeModel.generateContent", kind: "async" }),
24508
+ generateContentStream: channel({ channelName: "GenerativeModel.generateContentStream", kind: "async" }),
24509
+ embedContent: channel({ channelName: "GenerativeModel.embedContent", kind: "async" }),
24510
+ batchEmbedContents: channel({ channelName: "GenerativeModel.batchEmbedContents", kind: "async" }),
24511
+ sendMessage: channel({ channelName: "ChatSession.sendMessage", kind: "async" }),
24512
+ sendMessageStream: channel({ channelName: "ChatSession.sendMessageStream", kind: "async" })
24513
+ },
24514
+ { instrumentationName: INSTRUMENTATION_NAMES.GOOGLE_GENERATIVE_AI }
24515
+ );
24516
+
24517
+ // src/instrumentation/plugins/google-generative-ai-plugin.ts
24518
+ var GENERATION_CONFIG_KEYS = [
24519
+ "temperature",
24520
+ "topP",
24521
+ "topK",
24522
+ "candidateCount",
24523
+ "maxOutputTokens",
24524
+ "stopSequences",
24525
+ "responseMimeType",
24526
+ "responseSchema",
24527
+ "presencePenalty",
24528
+ "frequencyPenalty",
24529
+ "responseLogprobs",
24530
+ "logprobs",
24531
+ "thinkingConfig"
24532
+ ];
24533
+ var GoogleGenerativeAIPlugin = class extends BasePlugin {
24534
+ onEnable() {
24535
+ this.unsubscribers.push(
24536
+ interceptCall(
24537
+ googleGenerativeAIChannels.generateContent,
24538
+ "generateContent"
24539
+ ),
24540
+ interceptCall(
24541
+ googleGenerativeAIChannels.generateContentStream,
24542
+ "generateContentStream"
24543
+ ),
24544
+ interceptCall(googleGenerativeAIChannels.sendMessage, "sendMessage"),
24545
+ interceptCall(
24546
+ googleGenerativeAIChannels.sendMessageStream,
24547
+ "sendMessageStream"
24548
+ ),
24549
+ interceptCall(googleGenerativeAIChannels.embedContent, "embedContent"),
24550
+ interceptCall(
24551
+ googleGenerativeAIChannels.batchEmbedContents,
24552
+ "batchEmbedContents"
24553
+ )
24554
+ );
24555
+ }
24556
+ onDisable() {
24557
+ this.unsubscribers = unsubscribeAll(this.unsubscribers);
24558
+ }
24559
+ };
24560
+ function interceptCall(channel2, operation) {
24561
+ return channel2.intercept((target, thisArg, args) => {
24562
+ const invokeTarget = () => Reflect.apply(target, thisArg, args);
24563
+ if (isAutoInstrumentationSuppressed()) return invokeTarget();
24564
+ const self = thisArg;
24565
+ const chat = operation.startsWith("sendMessage");
24566
+ const embedding = operation === "embedContent" || operation === "batchEmbedContents";
24567
+ const start = getCurrentUnixTimestamp();
24568
+ let span;
24569
+ try {
24570
+ span = startSpan(
24571
+ withSpanInstrumentationName(
24572
+ {
24573
+ name: embedding ? operation === "embedContent" ? "embed_content" : "batch_embed_contents" : "generate_content",
24574
+ spanAttributes: { type: "llm" /* LLM */ },
24575
+ event: extractInput(self, args[0], operation)
24576
+ },
24577
+ INSTRUMENTATION_NAMES.GOOGLE_GENERATIVE_AI
24578
+ )
24579
+ );
24580
+ } catch (error) {
24581
+ debugLogger.error("Error starting Google Generative AI span:", error);
24582
+ return invokeTarget();
24583
+ }
24584
+ let ended = false;
24585
+ const finish = (log3) => {
24586
+ if (ended) return;
24587
+ ended = true;
24588
+ try {
24589
+ log3();
24590
+ } catch (error) {
24591
+ debugLogger.error("Error logging Google Generative AI span:", error);
24592
+ }
24593
+ try {
24594
+ span.end();
24595
+ } catch (error) {
24596
+ debugLogger.error("Error ending Google Generative AI span:", error);
24597
+ }
24598
+ };
24599
+ if (chat) {
24600
+ try {
24601
+ void self._sendPromise.then(
24602
+ () => {
24603
+ try {
24604
+ span.log(extractInput(self, args[0], operation));
24605
+ } catch (error) {
24606
+ debugLogger.error("Error capturing Google chat history:", error);
24607
+ }
24608
+ },
24609
+ () => {
24610
+ }
24611
+ );
24612
+ } catch (error) {
24613
+ debugLogger.error("Error observing Google chat history:", error);
24614
+ }
24615
+ }
24616
+ let result;
24617
+ try {
24618
+ result = withCurrent(
24619
+ span,
24620
+ () => runWithAutoInstrumentationSuppressed(invokeTarget)
24621
+ );
24622
+ } catch (error) {
24623
+ finish(() => span.log({ error }));
24624
+ throw error;
24625
+ }
24626
+ void Promise.resolve(result).then(
24627
+ (value) => {
24628
+ try {
24629
+ if ("stream" in value) {
24630
+ let firstToken = false;
24631
+ const partial = { candidates: [] };
24632
+ const candidates = /* @__PURE__ */ new Map();
24633
+ patchStreamIfNeeded(value.stream, {
24634
+ aroundNext: (callback) => withCurrent(span, callback),
24635
+ onChunk: (chunk) => {
24636
+ for (const candidate of chunk.candidates ?? []) {
24637
+ const index = candidate.index ?? 0;
24638
+ const previous = candidates.get(index);
24639
+ const parts = [...previous?.content?.parts ?? []];
24640
+ for (const part of candidate.content?.parts ?? []) {
24641
+ const last = parts[parts.length - 1];
24642
+ if (part.text !== void 0 && last?.text !== void 0) {
24643
+ parts[parts.length - 1] = {
24644
+ ...last,
24645
+ text: last.text + part.text
24646
+ };
24647
+ } else parts.push(part);
24648
+ }
24649
+ candidates.set(index, {
24650
+ ...previous,
24651
+ ...candidate,
24652
+ content: {
24653
+ role: candidate.content?.role ?? previous?.content?.role ?? "model",
24654
+ parts
24655
+ }
24656
+ });
24657
+ }
24658
+ partial.candidates = Array.from(candidates.values());
24659
+ if (chunk.usageMetadata)
24660
+ partial.usageMetadata = chunk.usageMetadata;
24661
+ if (!firstToken && chunk.candidates?.some(
24662
+ (candidate) => candidate.content?.parts.some(
24663
+ (part) => part.text !== void 0 ? part.text.length > 0 : Object.keys(part).length > 0
24664
+ )
24665
+ )) {
24666
+ firstToken = true;
24667
+ span.log({
24668
+ metrics: {
24669
+ time_to_first_token: getCurrentUnixTimestamp() - start
24670
+ }
24671
+ });
24672
+ }
24673
+ },
24674
+ onComplete: () => {
24675
+ },
24676
+ onError: (error) => finish(() => {
24677
+ logResponse(span, partial);
24678
+ span.log({ error });
24679
+ }),
24680
+ onCancel: () => finish(() => logResponse(span, partial))
24681
+ });
24682
+ void value.response.then(
24683
+ (response) => finish(() => logResponse(span, response)),
24684
+ (error) => finish(() => {
24685
+ logResponse(span, partial);
24686
+ span.log({ error });
24687
+ })
24688
+ );
24689
+ } else if ("response" in value) {
24690
+ finish(() => logResponse(span, value.response));
24691
+ } else {
24692
+ const metrics = {};
24693
+ const promptTokens = value.usageMetadata?.promptTokenCount;
24694
+ if (typeof promptTokens === "number" && Number.isFinite(promptTokens) && promptTokens >= 0) {
24695
+ metrics.prompt_tokens = promptTokens;
24696
+ metrics.tokens = promptTokens;
24697
+ }
24698
+ for (const detail of value.usageMetadata?.promptTokenDetails ?? []) {
24699
+ if (detail.modality === "AUDIO" && typeof detail.tokenCount === "number" && Number.isFinite(detail.tokenCount) && detail.tokenCount >= 0) {
24700
+ metrics.prompt_audio_tokens = (metrics.prompt_audio_tokens ?? 0) + detail.tokenCount;
24701
+ }
24702
+ }
24703
+ finish(
24704
+ () => span.log({
24705
+ metrics,
24706
+ output: {
24707
+ count: value.embeddings?.length ?? (value.embedding ? 1 : 0)
24708
+ }
24709
+ })
24710
+ );
24711
+ }
24712
+ } catch (error) {
24713
+ debugLogger.error(
24714
+ "Error observing Google Generative AI result:",
24715
+ error
24716
+ );
24717
+ finish(() => {
24718
+ });
24719
+ }
24720
+ },
24721
+ (error) => finish(() => span.log({ error }))
24722
+ );
24723
+ return result;
24724
+ });
24725
+ }
24726
+ function normalizeContent(message) {
24727
+ const parts = (typeof message === "string" ? [message] : message).map(
24728
+ (part) => typeof part === "string" ? { text: part } : part
24729
+ );
24730
+ return {
24731
+ role: parts.some((part) => part.functionResponse) ? "function" : "user",
24732
+ parts
24733
+ };
24734
+ }
24735
+ function extractInput(self, request, operation) {
24736
+ const model = self.model.replace(/^models\//, "");
24737
+ if (operation === "embedContent" || operation === "batchEmbedContents") {
24738
+ const requests = operation === "batchEmbedContents" ? request.requests : [
24739
+ typeof request === "string" || Array.isArray(request) ? { content: normalizeContent(request) } : request
24740
+ ];
24741
+ const dimensions = requests[0]?.outputDimensionality;
24742
+ return {
24743
+ input: {
24744
+ inputs: convertAttachments(requests).map((item) => ({
24745
+ content: item.content.parts.length === 1 && item.content.parts[0].text !== void 0 ? item.content.parts[0].text : item.content.parts.map((part) => {
24746
+ if (part.text !== void 0)
24747
+ return { type: "text", text: part.text };
24748
+ const mimeType = part.inlineData?.mimeType ?? part.fileData?.mimeType;
24749
+ const data = part.inlineData ? typeof part.inlineData.data === "string" ? `data:${mimeType};base64,${part.inlineData.data}` : part.inlineData.data : part.fileData?.fileUri;
24750
+ return mimeType?.startsWith("image/") ? { type: "image_url", image_url: { url: data } } : { type: "file", file: { file_data: data } };
24751
+ })
24752
+ })),
24753
+ ...dimensions !== void 0 && requests.every((item) => item.outputDimensionality === dimensions) ? { output_dimensions: dimensions } : {}
24754
+ },
24755
+ metadata: { model, provider: "google" }
24756
+ };
24757
+ }
24758
+ const chat = operation.startsWith("sendMessage");
24759
+ const config = chat ? self.params ?? {} : self;
24760
+ const params = typeof request === "string" || Array.isArray(request) ? { contents: [normalizeContent(request)] } : request;
24761
+ const system = params.systemInstruction ?? config.systemInstruction;
24762
+ const systemContent = typeof system === "string" ? { role: "system", parts: [{ text: system }] } : system && "parts" in system ? { ...system, role: "system" } : system ? { role: "system", parts: [system] } : void 0;
24763
+ const contents = [
24764
+ ...systemContent ? [systemContent] : [],
24765
+ ...chat ? self._history : [],
24766
+ ...params.contents
24767
+ ];
24768
+ const metadata = { model, provider: "google" };
24769
+ const generation = params.generationConfig ?? config.generationConfig;
24770
+ for (const key of GENERATION_CONFIG_KEYS) {
24771
+ if (generation && Object.hasOwn(generation, key))
24772
+ metadata[key] = generation[key];
24773
+ }
24774
+ for (const key of ["tools", "toolConfig", "safetySettings"]) {
24775
+ const value = params[key] ?? config[key];
24776
+ if (value !== void 0) metadata[key] = value;
24777
+ }
24778
+ const cached = params.cachedContent ?? config.cachedContent;
24779
+ if (cached)
24780
+ metadata.cachedContent = typeof cached === "string" ? cached : cached.name;
24781
+ return { input: convertAttachments({ model, contents }), metadata };
24782
+ }
24783
+ function convertAttachments(value) {
24784
+ const convert = (node) => {
24785
+ if (Array.isArray(node)) return node.map(convert);
24786
+ if (!isObject(node)) return node;
24787
+ if (isObject(node.inlineData)) {
24788
+ const { data, mimeType } = node.inlineData;
24789
+ const processed = processInputAttachments({
24790
+ type: "file",
24791
+ file: { file_data: `data:${mimeType};base64,${data}` }
24792
+ });
24793
+ if (typeof processed.file.file_data === "string")
24794
+ throw new Error("Unable to convert Google inline data");
24795
+ return {
24796
+ ...node,
24797
+ inlineData: { ...node.inlineData, data: processed.file.file_data }
24798
+ };
24799
+ }
24800
+ return Object.fromEntries(
24801
+ Object.entries(node).map(([key, item]) => [key, convert(item)])
24802
+ );
24803
+ };
24804
+ try {
24805
+ return convert(value);
24806
+ } catch (error) {
24807
+ debugLogger.error(
24808
+ "Error converting Google Generative AI attachments:",
24809
+ error
24810
+ );
24811
+ return value;
24812
+ }
24813
+ }
24814
+ function logResponse(span, response) {
24815
+ const usage = response.usageMetadata;
24816
+ const metrics = {};
24817
+ if (usage) {
24818
+ if (usage.promptTokenCount !== void 0)
24819
+ metrics.prompt_tokens = usage.promptTokenCount;
24820
+ if (usage.candidatesTokenCount !== void 0 || usage.thoughtsTokenCount !== void 0)
24821
+ metrics.completion_tokens = (usage.candidatesTokenCount ?? 0) + (usage.thoughtsTokenCount ?? 0);
24822
+ if (usage.totalTokenCount !== void 0)
24823
+ metrics.tokens = usage.totalTokenCount;
24824
+ if (usage.cachedContentTokenCount !== void 0)
24825
+ metrics.prompt_cached_tokens = usage.cachedContentTokenCount;
24826
+ if (usage.thoughtsTokenCount !== void 0)
24827
+ metrics.completion_reasoning_tokens = usage.thoughtsTokenCount;
24828
+ }
24829
+ span.log({
24830
+ output: convertAttachments({
24831
+ candidates: response.candidates,
24832
+ promptFeedback: response.promptFeedback
24833
+ }),
24834
+ metrics,
24835
+ ...response.modelVersion ? { metadata: { model: response.modelVersion } } : {}
24836
+ });
24837
+ }
24838
+
24472
24839
  // src/instrumentation/plugins/google-genai-channels.ts
24473
24840
  var googleGenAIChannels = defineChannels(
24474
24841
  "@google/genai",
@@ -26112,7 +26479,7 @@ var HuggingFaceTransformersPlugin = class extends BasePlugin {
26112
26479
  getTask(event)
26113
26480
  ),
26114
26481
  extractInput: (args, event) => ({
26115
- input: extractInput(
26482
+ input: extractInput2(
26116
26483
  getTask(event),
26117
26484
  args
26118
26485
  ),
@@ -26202,7 +26569,7 @@ function modelIdentifier(pipeline) {
26202
26569
  }
26203
26570
  return void 0;
26204
26571
  }
26205
- function extractInput(task, args) {
26572
+ function extractInput2(task, args) {
26206
26573
  switch (task) {
26207
26574
  case "feature-extraction":
26208
26575
  return args[0];
@@ -34187,14 +34554,17 @@ function getMetricsFromResponse(response) {
34187
34554
  if (!isRecord(usageMetadata)) {
34188
34555
  continue;
34189
34556
  }
34190
- const inputTokenDetails = usageMetadata.input_token_details;
34557
+ const inputTokenDetails = isRecord(usageMetadata.input_token_details) ? usageMetadata.input_token_details : {};
34191
34558
  const outputTokenDetails = usageMetadata.output_token_details;
34192
34559
  return normalizeTokenMetrics({
34193
34560
  total_tokens: usageMetadata.total_tokens,
34194
34561
  prompt_tokens: usageMetadata.input_tokens,
34195
34562
  completion_tokens: usageMetadata.output_tokens,
34196
- prompt_cache_creation_tokens: isRecord(inputTokenDetails) ? inputTokenDetails.cache_creation : void 0,
34197
- prompt_cached_tokens: isRecord(inputTokenDetails) ? inputTokenDetails.cache_read : void 0,
34563
+ // Prefer TTL-specific cache writes over the aggregate when available.
34564
+ prompt_cache_creation_tokens: inputTokenDetails.ephemeral_5m_input_tokens == null && inputTokenDetails.ephemeral_1h_input_tokens == null ? inputTokenDetails.cache_creation : void 0,
34565
+ prompt_cache_creation_5m_tokens: inputTokenDetails.ephemeral_5m_input_tokens,
34566
+ prompt_cache_creation_1h_tokens: inputTokenDetails.ephemeral_1h_input_tokens,
34567
+ prompt_cached_tokens: inputTokenDetails.cache_read,
34198
34568
  completion_reasoning_tokens: isRecord(outputTokenDetails) ? outputTokenDetails.reasoning : void 0
34199
34569
  });
34200
34570
  }
@@ -36553,6 +36923,477 @@ function logInstrumentationError5(context, error) {
36553
36923
  debugLogger.debug(`${context}:`, error);
36554
36924
  }
36555
36925
 
36926
+ // src/instrumentation/plugins/elevenlabs-channels.ts
36927
+ var elevenLabsChannels = defineChannels(
36928
+ "@elevenlabs/elevenlabs-js",
36929
+ {
36930
+ convert: channel({
36931
+ channelName: "textToSpeech.convert",
36932
+ kind: "async"
36933
+ }),
36934
+ stream: channel({
36935
+ channelName: "textToSpeech.stream",
36936
+ kind: "async"
36937
+ }),
36938
+ convertWithTimestamps: channel({ channelName: "textToSpeech.convertWithTimestamps", kind: "async" }),
36939
+ streamWithTimestamps: channel({ channelName: "textToSpeech.streamWithTimestamps", kind: "async" }),
36940
+ transcribe: channel({ channelName: "speechToText.convert", kind: "async" })
36941
+ },
36942
+ { instrumentationName: INSTRUMENTATION_NAMES.ELEVENLABS }
36943
+ );
36944
+
36945
+ // src/instrumentation/plugins/elevenlabs-plugin.ts
36946
+ var ElevenLabsPlugin = class extends BasePlugin {
36947
+ onEnable() {
36948
+ for (const method of [
36949
+ "convert",
36950
+ "stream",
36951
+ "convertWithTimestamps",
36952
+ "streamWithTimestamps"
36953
+ ]) {
36954
+ this.unsubscribers.push(
36955
+ interceptCall2(
36956
+ elevenLabsChannels[method],
36957
+ `elevenlabs.textToSpeech.${method}`,
36958
+ ([voice, request]) => ({
36959
+ input: {
36960
+ operation: "speech",
36961
+ prompt: request.text,
36962
+ parameters: {
36963
+ voice,
36964
+ format: request.outputFormat,
36965
+ language: request.languageCode,
36966
+ speed: request.voiceSettings?.speed
36967
+ }
36968
+ },
36969
+ metadata: {
36970
+ provider: "elevenlabs",
36971
+ model: request.modelId ?? "eleven_multilingual_v2"
36972
+ }
36973
+ }),
36974
+ (value, args, span, finish, headers, started) => captureSpeech(
36975
+ value,
36976
+ args[1],
36977
+ method,
36978
+ span,
36979
+ finish,
36980
+ started,
36981
+ headers
36982
+ )
36983
+ )
36984
+ );
36985
+ }
36986
+ this.unsubscribers.push(
36987
+ interceptCall2(
36988
+ elevenLabsChannels.transcribe,
36989
+ "elevenlabs.speechToText.convert",
36990
+ ([request]) => {
36991
+ if (request.webhook) return void 0;
36992
+ const file = request.file;
36993
+ const filename = typeof File !== "undefined" && file instanceof File ? file.name : "audio";
36994
+ const contentType = file instanceof Blob ? file.type || "application/octet-stream" : "application/octet-stream";
36995
+ 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;
36996
+ const fileData = blob ? new Attachment({ data: blob, filename, contentType }) : request.cloudStorageUrl;
36997
+ return {
36998
+ input: {
36999
+ operation: "transcribe",
37000
+ content: fileData ? [{ type: "file", file: { filename, file_data: fileData } }] : [],
37001
+ parameters: {
37002
+ language: request.languageCode,
37003
+ timestamp_granularities: request.timestampsGranularity
37004
+ }
37005
+ },
37006
+ metadata: { provider: "elevenlabs", model: request.modelId }
37007
+ };
37008
+ },
37009
+ (value, _args, span, finish) => {
37010
+ const result = value;
37011
+ const transcripts = result.transcripts ?? [result];
37012
+ span.log({
37013
+ output: {
37014
+ content: transcripts.flatMap(
37015
+ (transcript) => typeof transcript.text === "string" ? [{ type: "text", text: transcript.text }] : []
37016
+ ),
37017
+ annotations: {
37018
+ language: result.languageCode,
37019
+ words: result.words ?? (result.transcripts ? result.transcripts.flatMap(
37020
+ (transcript) => transcript.words ?? []
37021
+ ) : void 0)
37022
+ }
37023
+ }
37024
+ });
37025
+ finish();
37026
+ },
37027
+ ([request], span) => {
37028
+ const file = request.file;
37029
+ if (!isAsyncIterable(file)) return;
37030
+ const chunks = [];
37031
+ const filename = isObject(file) && typeof file.path === "string" ? file.path.split(/[\\/]/).pop() || "audio" : "audio";
37032
+ observeAudioStream(
37033
+ file,
37034
+ (chunk) => chunks.push(new Uint8Array(chunk)),
37035
+ () => {
37036
+ const contentType = "application/octet-stream";
37037
+ const data = new Blob(chunks, {
37038
+ type: contentType
37039
+ });
37040
+ chunks.length = 0;
37041
+ span.log({
37042
+ input: {
37043
+ content: [
37044
+ {
37045
+ type: "file",
37046
+ file: {
37047
+ filename,
37048
+ file_data: new Attachment({
37049
+ data,
37050
+ filename,
37051
+ contentType
37052
+ })
37053
+ }
37054
+ }
37055
+ ]
37056
+ }
37057
+ });
37058
+ },
37059
+ () => {
37060
+ chunks.length = 0;
37061
+ },
37062
+ span
37063
+ );
37064
+ }
37065
+ )
37066
+ );
37067
+ }
37068
+ onDisable() {
37069
+ this.unsubscribers = unsubscribeAll(this.unsubscribers);
37070
+ }
37071
+ };
37072
+ function interceptCall2(channel2, name, input, output, beforeInvoke) {
37073
+ return channel2.intercept((target, self, args) => {
37074
+ const invoke2 = () => Reflect.apply(target, self, args);
37075
+ if (isAutoInstrumentationSuppressed()) return invoke2();
37076
+ const started = Date.now() / 1e3;
37077
+ let span;
37078
+ try {
37079
+ const event = input(args);
37080
+ if (event !== void 0)
37081
+ span = startSpan(
37082
+ withSpanInstrumentationName(
37083
+ {
37084
+ name,
37085
+ spanAttributes: { type: "llm" /* LLM */ },
37086
+ event
37087
+ },
37088
+ INSTRUMENTATION_NAMES.ELEVENLABS
37089
+ )
37090
+ );
37091
+ } catch (error) {
37092
+ debugLogger.error("Error starting ElevenLabs span", error);
37093
+ return invoke2();
37094
+ }
37095
+ if (!span) return invoke2();
37096
+ const activeSpan = span;
37097
+ let ended = false;
37098
+ const finish = (error) => {
37099
+ if (ended) return;
37100
+ ended = true;
37101
+ try {
37102
+ if (error !== void 0) activeSpan.log({ error });
37103
+ activeSpan.end();
37104
+ } catch (loggingError) {
37105
+ debugLogger.error("Error ending ElevenLabs span", loggingError);
37106
+ }
37107
+ };
37108
+ try {
37109
+ beforeInvoke?.(args, span);
37110
+ } catch (error) {
37111
+ debugLogger.error("Error observing ElevenLabs input", error);
37112
+ }
37113
+ let result;
37114
+ try {
37115
+ result = withCurrent(
37116
+ span,
37117
+ () => runWithAutoInstrumentationSuppressed(invoke2)
37118
+ );
37119
+ } catch (error) {
37120
+ finish(error);
37121
+ throw error;
37122
+ }
37123
+ const capture = (value, headers) => {
37124
+ try {
37125
+ output(value, args, span, finish, headers, started);
37126
+ } catch (error) {
37127
+ debugLogger.error("Error capturing ElevenLabs output", error);
37128
+ finish();
37129
+ }
37130
+ };
37131
+ try {
37132
+ if (isObject(result) && typeof result.withRawResponse === "function") {
37133
+ void result.withRawResponse().then(
37134
+ ({
37135
+ data,
37136
+ rawResponse
37137
+ }) => capture(data, rawResponse?.headers),
37138
+ finish
37139
+ );
37140
+ } else {
37141
+ void Promise.resolve(result).then((value) => capture(value), finish);
37142
+ }
37143
+ } catch (error) {
37144
+ debugLogger.error("Error observing ElevenLabs result", error);
37145
+ finish();
37146
+ }
37147
+ return result;
37148
+ });
37149
+ }
37150
+ function captureSpeech(value, request, method, span, finish, started, headers) {
37151
+ const format = request.outputFormat ?? "mp3_44100_128";
37152
+ 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;
37153
+ const headerType = headers?.get("content-type")?.split(";")[0];
37154
+ const contentType = headerType?.startsWith("audio/") ? headerType : formatType;
37155
+ const disposition = headers?.get("content-disposition");
37156
+ const headerFilename = disposition?.match(
37157
+ /filename="([^"]+)"|filename=([^;]+)/i
37158
+ );
37159
+ const filename = headerFilename?.[1] ?? headerFilename?.[2]?.trim() ?? `speech.${contentType ? getExtensionFromMediaType(contentType) : "bin"}`;
37160
+ const chunks = [];
37161
+ const alignments = [];
37162
+ let bytes = 0;
37163
+ let first = true;
37164
+ let stopped = false;
37165
+ const observe = (chunk) => {
37166
+ if (stopped || chunk.byteLength === 0) return;
37167
+ if (first && method.startsWith("stream")) {
37168
+ span.log({
37169
+ metrics: { time_to_first_token: Date.now() / 1e3 - started }
37170
+ });
37171
+ }
37172
+ first = false;
37173
+ chunks.push(new Uint8Array(chunk));
37174
+ bytes += chunk.byteLength;
37175
+ };
37176
+ const complete = () => {
37177
+ if (stopped) return;
37178
+ stopped = true;
37179
+ try {
37180
+ const content = [];
37181
+ if (contentType && bytes) {
37182
+ const data = new Uint8Array(bytes);
37183
+ let offset = 0;
37184
+ for (const chunk of chunks) {
37185
+ data.set(chunk, offset);
37186
+ offset += chunk.length;
37187
+ }
37188
+ content.push({
37189
+ type: "file",
37190
+ file: {
37191
+ filename,
37192
+ byte_size: bytes,
37193
+ file_data: new Attachment({
37194
+ data: new Blob([data], { type: contentType }),
37195
+ filename,
37196
+ contentType
37197
+ })
37198
+ }
37199
+ });
37200
+ }
37201
+ span.log({
37202
+ output: {
37203
+ content,
37204
+ ...alignments.length ? { annotations: alignments } : {}
37205
+ }
37206
+ });
37207
+ } finally {
37208
+ chunks.length = 0;
37209
+ finish();
37210
+ }
37211
+ };
37212
+ const cancel = (error) => {
37213
+ stopped = true;
37214
+ chunks.length = 0;
37215
+ finish(error);
37216
+ };
37217
+ const timestampChunk = (chunk) => {
37218
+ const binary = atob(chunk.audioBase64);
37219
+ observe(Uint8Array.from(binary, (character) => character.charCodeAt(0)));
37220
+ if (chunk.alignment || chunk.normalizedAlignment)
37221
+ alignments.push({
37222
+ alignment: chunk.alignment,
37223
+ normalized_alignment: chunk.normalizedAlignment
37224
+ });
37225
+ };
37226
+ if (method === "convertWithTimestamps") {
37227
+ timestampChunk(value);
37228
+ complete();
37229
+ } else if (method === "streamWithTimestamps") {
37230
+ patchStreamIfNeeded(value, {
37231
+ shouldCollect: (chunk) => {
37232
+ try {
37233
+ timestampChunk(chunk);
37234
+ } catch (error) {
37235
+ debugLogger.error("Error collecting ElevenLabs timestamps", error);
37236
+ cancel();
37237
+ }
37238
+ return false;
37239
+ },
37240
+ onComplete: complete,
37241
+ onCancel: () => cancel(),
37242
+ onError: cancel,
37243
+ aroundNext: (next) => withCurrent(span, next)
37244
+ });
37245
+ } else {
37246
+ observeAudioStream(value, observe, complete, cancel, span);
37247
+ }
37248
+ }
37249
+ function observeAudioStream(value, observe, complete, cancel, span) {
37250
+ let ended = false;
37251
+ const safeObserve = (chunk) => {
37252
+ if (ended) return;
37253
+ try {
37254
+ observe(chunk);
37255
+ } catch (error) {
37256
+ debugLogger.error("Error collecting ElevenLabs audio", error);
37257
+ end(false);
37258
+ }
37259
+ };
37260
+ const end = (success, error) => {
37261
+ if (ended) return;
37262
+ ended = true;
37263
+ try {
37264
+ if (success) complete();
37265
+ else cancel(error);
37266
+ } catch (loggingError) {
37267
+ debugLogger.error("Error logging ElevenLabs audio", loggingError);
37268
+ cancel();
37269
+ }
37270
+ };
37271
+ if (!isObject(value) || !Object.isExtensible(value)) {
37272
+ end(false);
37273
+ return;
37274
+ }
37275
+ if (typeof value.read === "function" && typeof value.on === "function") {
37276
+ value.on("end", () => end(true));
37277
+ value.on("close", () => end(false));
37278
+ const emit2 = value.emit;
37279
+ if (typeof emit2 === "function")
37280
+ value.emit = function(event, ...args) {
37281
+ if (event === "data" && args[0] instanceof Uint8Array)
37282
+ safeObserve(args[0]);
37283
+ if (event === "error") end(false, args[0]);
37284
+ return Reflect.apply(emit2, this, [event, ...args]);
37285
+ };
37286
+ return;
37287
+ }
37288
+ if (typeof value.getReader === "function") {
37289
+ const webStream = value;
37290
+ const pipeTo = webStream.pipeTo;
37291
+ const pipeThrough = webStream.pipeThrough;
37292
+ webStream.pipeTo = function(destination, options) {
37293
+ if (!isObject(destination) || this.locked || destination.locked)
37294
+ return pipeTo.call(this, destination, options);
37295
+ const tap = new TransformStream({
37296
+ transform(chunk, controller) {
37297
+ safeObserve(chunk);
37298
+ controller.enqueue(chunk);
37299
+ },
37300
+ flush() {
37301
+ end(true);
37302
+ }
37303
+ });
37304
+ const observed = pipeThrough.call(
37305
+ this,
37306
+ tap,
37307
+ options
37308
+ );
37309
+ return observed.pipeTo(destination, options).catch((error) => {
37310
+ end(false, error);
37311
+ throw error;
37312
+ });
37313
+ };
37314
+ webStream.pipeThrough = function(transform, options) {
37315
+ if (this.locked || transform.writable.locked || transform.readable.locked)
37316
+ return pipeThrough.call(this, transform, options);
37317
+ const result = webStream.pipeTo.call(this, transform.writable, options);
37318
+ void result.catch(() => {
37319
+ });
37320
+ return transform.readable;
37321
+ };
37322
+ const getReader = value.getReader;
37323
+ value.getReader = function(...args) {
37324
+ const reader = Reflect.apply(getReader, this, args);
37325
+ const read3 = reader.read;
37326
+ reader.read = function(...readArgs) {
37327
+ return Promise.resolve(
37328
+ withCurrent(span, () => Reflect.apply(read3, this, readArgs))
37329
+ ).then(
37330
+ (result) => {
37331
+ if (result.value) safeObserve(result.value);
37332
+ if (result.done) end(true);
37333
+ return result;
37334
+ },
37335
+ (error) => {
37336
+ end(false, error);
37337
+ throw error;
37338
+ }
37339
+ );
37340
+ };
37341
+ const readerCancel = reader.cancel;
37342
+ reader.cancel = function(...cancelArgs) {
37343
+ const result = Reflect.apply(readerCancel, this, cancelArgs);
37344
+ end(false);
37345
+ return result;
37346
+ };
37347
+ return reader;
37348
+ };
37349
+ const streamCancel = value.cancel;
37350
+ if (typeof streamCancel === "function")
37351
+ value.cancel = function(...args) {
37352
+ const result = Reflect.apply(streamCancel, this, args);
37353
+ void Promise.resolve(result).then(
37354
+ () => end(false),
37355
+ () => {
37356
+ }
37357
+ );
37358
+ return result;
37359
+ };
37360
+ }
37361
+ if (typeof value.getReader === "function" && typeof value.values === "function") {
37362
+ const values = value.values;
37363
+ const iterate = function(...args) {
37364
+ const iterator = Reflect.apply(values, this, args);
37365
+ patchStreamIfNeeded(iterator, {
37366
+ shouldCollect(chunk) {
37367
+ safeObserve(chunk);
37368
+ return false;
37369
+ },
37370
+ onComplete: () => end(true),
37371
+ onCancel: () => end(false),
37372
+ onError: (error) => end(false, error),
37373
+ aroundNext: (next) => withCurrent(span, next)
37374
+ });
37375
+ return iterator;
37376
+ };
37377
+ value.values = iterate;
37378
+ Object.defineProperty(value, Symbol.asyncIterator, {
37379
+ configurable: true,
37380
+ writable: true,
37381
+ value: iterate
37382
+ });
37383
+ } else if (isAsyncIterable(value)) {
37384
+ patchStreamIfNeeded(value, {
37385
+ shouldCollect: (chunk) => {
37386
+ safeObserve(chunk);
37387
+ return false;
37388
+ },
37389
+ onComplete: () => end(true),
37390
+ onCancel: () => end(false),
37391
+ onError: (error) => end(false, error),
37392
+ aroundNext: (next) => withCurrent(span, next)
37393
+ });
37394
+ } else if (typeof value.getReader !== "function") end(false);
37395
+ }
37396
+
36556
37397
  // src/instrumentation/plugins/voyageai-channels.ts
36557
37398
  var voyageAIChannels = defineChannels(
36558
37399
  "voyageai",
@@ -36620,7 +37461,7 @@ var VoyageAIPlugin = class extends BasePlugin {
36620
37461
  this.unsubscribers = unsubscribeAll(this.unsubscribers);
36621
37462
  }
36622
37463
  };
36623
- function interceptVoyageAICall(channel2, name, extractInput3, extractOutput2, extractMetrics2 = extractUsageMetrics3) {
37464
+ function interceptVoyageAICall(channel2, name, extractInput4, extractOutput2, extractMetrics2 = extractUsageMetrics3) {
36624
37465
  return channel2.intercept((target, thisArg, args) => {
36625
37466
  const invokeTarget = () => Reflect.apply(target, thisArg, args);
36626
37467
  if (isAutoInstrumentationSuppressed()) {
@@ -36628,7 +37469,7 @@ function interceptVoyageAICall(channel2, name, extractInput3, extractOutput2, ex
36628
37469
  }
36629
37470
  let span;
36630
37471
  try {
36631
- const { input, metadata } = extractInput3(args);
37472
+ const { input, metadata } = extractInput4(args);
36632
37473
  span = startSpan(
36633
37474
  withSpanInstrumentationName(
36634
37475
  {
@@ -37427,6 +38268,7 @@ var BraintrustPlugin = class extends BasePlugin {
37427
38268
  cloudflareThinkPlugin = null;
37428
38269
  cursorSDKPlugin = null;
37429
38270
  openAIAgentsPlugin = null;
38271
+ googleGenerativeAIPlugin = null;
37430
38272
  googleGenAIPlugin = null;
37431
38273
  huggingFacePlugin = null;
37432
38274
  huggingFaceTransformersPlugin = null;
@@ -37445,6 +38287,7 @@ var BraintrustPlugin = class extends BasePlugin {
37445
38287
  langSmithPlugin = null;
37446
38288
  piCodingAgentPlugin = null;
37447
38289
  strandsAgentSDKPlugin = null;
38290
+ elevenLabsPlugin = null;
37448
38291
  voyageAIPlugin = null;
37449
38292
  cloudflareAIChatPlugin = null;
37450
38293
  cloudflareAgentsPlugin = null;
@@ -37486,6 +38329,10 @@ var BraintrustPlugin = class extends BasePlugin {
37486
38329
  this.openAIAgentsPlugin = new OpenAIAgentsPlugin();
37487
38330
  this.openAIAgentsPlugin.enable();
37488
38331
  }
38332
+ if (integrations.googleGenerativeAI !== false) {
38333
+ this.googleGenerativeAIPlugin = new GoogleGenerativeAIPlugin();
38334
+ this.googleGenerativeAIPlugin.enable();
38335
+ }
37489
38336
  if (integrations.googleGenAI !== false && integrations.google !== false) {
37490
38337
  this.googleGenAIPlugin = new GoogleGenAIPlugin();
37491
38338
  this.googleGenAIPlugin.enable();
@@ -37520,6 +38367,10 @@ var BraintrustPlugin = class extends BasePlugin {
37520
38367
  this.coherePlugin = new CoherePlugin();
37521
38368
  this.coherePlugin.enable();
37522
38369
  }
38370
+ if (integrations.elevenlabs !== false) {
38371
+ this.elevenLabsPlugin = new ElevenLabsPlugin();
38372
+ this.elevenLabsPlugin.enable();
38373
+ }
37523
38374
  if (integrations.voyageai !== false) {
37524
38375
  this.voyageAIPlugin = new VoyageAIPlugin();
37525
38376
  this.voyageAIPlugin.enable();
@@ -37604,6 +38455,10 @@ var BraintrustPlugin = class extends BasePlugin {
37604
38455
  this.openAIAgentsPlugin.disable();
37605
38456
  this.openAIAgentsPlugin = null;
37606
38457
  }
38458
+ if (this.googleGenerativeAIPlugin) {
38459
+ this.googleGenerativeAIPlugin.disable();
38460
+ this.googleGenerativeAIPlugin = null;
38461
+ }
37607
38462
  if (this.googleGenAIPlugin) {
37608
38463
  this.googleGenAIPlugin.disable();
37609
38464
  this.googleGenAIPlugin = null;
@@ -37640,6 +38495,10 @@ var BraintrustPlugin = class extends BasePlugin {
37640
38495
  this.coherePlugin.disable();
37641
38496
  this.coherePlugin = null;
37642
38497
  }
38498
+ if (this.elevenLabsPlugin) {
38499
+ this.elevenLabsPlugin.disable();
38500
+ this.elevenLabsPlugin = null;
38501
+ }
37643
38502
  if (this.voyageAIPlugin) {
37644
38503
  this.voyageAIPlugin.disable();
37645
38504
  this.voyageAIPlugin = null;
@@ -37733,6 +38592,8 @@ var envIntegrationAliases = {
37733
38592
  "openai-agents-core": "openAIAgents",
37734
38593
  openaiagentscore: "openAIAgents",
37735
38594
  google: "google",
38595
+ "google-generative-ai": "googleGenerativeAI",
38596
+ googlegenerativeai: "googleGenerativeAI",
37736
38597
  "google-genai": "googleGenAI",
37737
38598
  googlegenai: "googleGenAI",
37738
38599
  huggingface: "huggingface",
@@ -37766,7 +38627,9 @@ var envIntegrationAliases = {
37766
38627
  langsmith: "langsmith",
37767
38628
  voyage: "voyageai",
37768
38629
  "voyage-ai": "voyageai",
37769
- voyageai: "voyageai"
38630
+ voyageai: "voyageai",
38631
+ elevenlabs: "elevenlabs",
38632
+ "@elevenlabs/elevenlabs-js": "elevenlabs"
37770
38633
  };
37771
38634
  function getDefaultInstrumentationIntegrations() {
37772
38635
  return {
@@ -37777,6 +38640,7 @@ function getDefaultInstrumentationIntegrations() {
37777
38640
  aisdk: true,
37778
38641
  google: true,
37779
38642
  googleGenAI: true,
38643
+ googleGenerativeAI: true,
37780
38644
  googleADK: true,
37781
38645
  huggingface: true,
37782
38646
  claudeAgentSDK: true,
@@ -37802,6 +38666,7 @@ function getDefaultInstrumentationIntegrations() {
37802
38666
  langgraph: true,
37803
38667
  langsmith: true,
37804
38668
  voyageai: true,
38669
+ elevenlabs: true,
37805
38670
  piCodingAgent: true,
37806
38671
  strandsAgentSDK: true,
37807
38672
  cloudflareAgents: true
@@ -38118,9 +38983,11 @@ __export(exports_exports, {
38118
38983
  wrapCohere: () => wrapCohere,
38119
38984
  wrapCopilotClient: () => wrapCopilotClient,
38120
38985
  wrapCursorSDK: () => wrapCursorSDK,
38986
+ wrapElevenLabs: () => wrapElevenLabs,
38121
38987
  wrapGenkit: () => wrapGenkit,
38122
38988
  wrapGoogleADK: () => wrapGoogleADK,
38123
38989
  wrapGoogleGenAI: () => wrapGoogleGenAI,
38990
+ wrapGoogleGenerativeAI: () => wrapGoogleGenerativeAI,
38124
38991
  wrapGroq: () => wrapGroq,
38125
38992
  wrapHuggingFace: () => wrapHuggingFace,
38126
38993
  wrapHuggingFaceTransformers: () => wrapHuggingFaceTransformers,
@@ -39730,7 +40597,7 @@ function extractToolCallsFromBlocks(blocks) {
39730
40597
  if (!Array.isArray(blocks)) return [];
39731
40598
  return extractToolCallsFromSteps([{ content: blocks }]);
39732
40599
  }
39733
- function extractInput2(params) {
40600
+ function extractInput3(params) {
39734
40601
  return params?.prompt ?? params?.messages ?? params?.system;
39735
40602
  }
39736
40603
  var V2_EXCLUDE_KEYS = /* @__PURE__ */ new Set([
@@ -39752,7 +40619,7 @@ function BraintrustMiddleware(config = {}) {
39752
40619
  params,
39753
40620
  model: modelFromWrapGenerate
39754
40621
  }) => {
39755
- const rawInput = extractInput2(params);
40622
+ const rawInput = extractInput3(params);
39756
40623
  const processedInput = processInputAttachments(rawInput);
39757
40624
  const spanArgs = {
39758
40625
  name: config.spanInfo?.name || "ai-sdk.doGenerate",
@@ -39816,7 +40683,7 @@ function BraintrustMiddleware(config = {}) {
39816
40683
  }
39817
40684
  },
39818
40685
  wrapStream: async ({ doStream, params }) => {
39819
- const rawInput = extractInput2(params);
40686
+ const rawInput = extractInput3(params);
39820
40687
  const processedInput = processInputAttachments(rawInput);
39821
40688
  const spanArgs = {
39822
40689
  name: config.spanInfo?.name || "ai-sdk.doStream",
@@ -43209,6 +44076,75 @@ function isModuleNamespace5(value) {
43209
44076
  }
43210
44077
  }
43211
44078
 
44079
+ // src/wrappers/google-generative-ai.ts
44080
+ function wrapGoogleGenerativeAI(client) {
44081
+ if (!isObject(client) || typeof client.getGenerativeModel !== "function")
44082
+ return client;
44083
+ return wrapClient(client);
44084
+ }
44085
+ var proxies = /* @__PURE__ */ new WeakMap();
44086
+ function wrapClient(client) {
44087
+ const cached = proxies.get(client);
44088
+ if (cached) return cached;
44089
+ const proxy = new Proxy(client, {
44090
+ get(target, prop, receiver) {
44091
+ const value = Reflect.get(target, prop, receiver);
44092
+ if (typeof value !== "function") return value;
44093
+ if (prop === "getGenerativeModel" || prop === "getGenerativeModelFromCachedContent" || prop === "startChat") {
44094
+ return (...args) => wrapClient(Reflect.apply(value, target, args));
44095
+ }
44096
+ switch (prop) {
44097
+ case "generateContent":
44098
+ return (...args) => googleGenerativeAIChannels.generateContent.invoke(
44099
+ value,
44100
+ target,
44101
+ args,
44102
+ {}
44103
+ );
44104
+ case "generateContentStream":
44105
+ return (...args) => googleGenerativeAIChannels.generateContentStream.invoke(
44106
+ value,
44107
+ target,
44108
+ args,
44109
+ {}
44110
+ );
44111
+ case "embedContent":
44112
+ return (...args) => googleGenerativeAIChannels.embedContent.invoke(
44113
+ value,
44114
+ target,
44115
+ args,
44116
+ {}
44117
+ );
44118
+ case "batchEmbedContents":
44119
+ return (...args) => googleGenerativeAIChannels.batchEmbedContents.invoke(
44120
+ value,
44121
+ target,
44122
+ args,
44123
+ {}
44124
+ );
44125
+ case "sendMessage":
44126
+ return (...args) => googleGenerativeAIChannels.sendMessage.invoke(
44127
+ value,
44128
+ target,
44129
+ args,
44130
+ {}
44131
+ );
44132
+ case "sendMessageStream":
44133
+ return (...args) => googleGenerativeAIChannels.sendMessageStream.invoke(
44134
+ value,
44135
+ target,
44136
+ args,
44137
+ {}
44138
+ );
44139
+ }
44140
+ return value.bind(target);
44141
+ }
44142
+ });
44143
+ proxies.set(client, proxy);
44144
+ proxies.set(proxy, proxy);
44145
+ return proxy;
44146
+ }
44147
+
43212
44148
  // src/wrappers/google-genai.ts
43213
44149
  function wrapGoogleGenAI(googleGenAI) {
43214
44150
  if (!googleGenAI || typeof googleGenAI !== "object") {
@@ -45206,8 +46142,8 @@ function normalizeScores(result) {
45206
46142
  (s) => s !== null && s !== void 0 && typeof s === "object" && isScore(s)
45207
46143
  );
45208
46144
  }
45209
- if (typeof result === "object" && result !== null && isScore(result)) {
45210
- return [result];
46145
+ if (typeof result === "object" && result !== null && "score" in result) {
46146
+ return [{ ...result, name: result.name ?? "score" }];
45211
46147
  }
45212
46148
  return [];
45213
46149
  }
@@ -47790,19 +48726,29 @@ function buildSpanScores(results) {
47790
48726
  function _internalPrepareEvaluatorScore(scoreValue, name) {
47791
48727
  if (scoreValue === null) return { results: null };
47792
48728
  if (Array.isArray(scoreValue)) {
48729
+ const names = /* @__PURE__ */ new Set();
47793
48730
  for (const score of scoreValue) {
47794
48731
  if (!(typeof score === "object" && !isEmpty2(score))) {
47795
48732
  throw new Error(
47796
48733
  `When returning an array of scores, each score must be a non-empty object. Got: ${JSON.stringify(score)}`
47797
48734
  );
47798
48735
  }
48736
+ if (typeof score.name !== "string") {
48737
+ throw new Error(
48738
+ `When returning an array of scores, each score must have a name. Got: ${JSON.stringify(score)}`
48739
+ );
48740
+ }
48741
+ if (names.has(score.name)) {
48742
+ throw new Error(`Duplicate score name '${score.name}' in score array`);
48743
+ }
48744
+ names.add(score.name);
47799
48745
  }
47800
48746
  }
47801
48747
  let results;
47802
48748
  if (Array.isArray(scoreValue)) {
47803
48749
  results = scoreValue;
47804
48750
  } else if (typeof scoreValue === "object" && !isEmpty2(scoreValue)) {
47805
- results = [scoreValue];
48751
+ results = [{ ...scoreValue, name: scoreValue.name ?? name }];
47806
48752
  } else {
47807
48753
  results = [{ name, score: scoreValue }];
47808
48754
  }
@@ -50560,5 +51506,64 @@ var evaluatorDefinitionsSchema = import_v313.z.record(
50560
51506
  evaluatorDefinitionSchema
50561
51507
  );
50562
51508
 
51509
+ // src/wrappers/elevenlabs.ts
51510
+ var clients = /* @__PURE__ */ new WeakMap();
51511
+ function wrapElevenLabs(client) {
51512
+ if (!isObject(client) || !isObject(client.textToSpeech) || typeof client.textToSpeech.convert !== "function") {
51513
+ debugLogger.warn("Unsupported ElevenLabs client. Not wrapping.");
51514
+ return client;
51515
+ }
51516
+ const cached = clients.get(client);
51517
+ if (cached) return cached;
51518
+ const sdk = client;
51519
+ const speech = new Proxy(sdk.textToSpeech, {
51520
+ get(target, prop, receiver) {
51521
+ switch (prop) {
51522
+ case "convert":
51523
+ case "stream":
51524
+ return (...args) => elevenLabsChannels[prop].invoke(target[prop], target, args, {});
51525
+ case "convertWithTimestamps":
51526
+ return (...args) => elevenLabsChannels.convertWithTimestamps.invoke(
51527
+ target.convertWithTimestamps,
51528
+ target,
51529
+ args,
51530
+ {}
51531
+ );
51532
+ case "streamWithTimestamps":
51533
+ return (...args) => elevenLabsChannels.streamWithTimestamps.invoke(
51534
+ target.streamWithTimestamps,
51535
+ target,
51536
+ args,
51537
+ {}
51538
+ );
51539
+ default:
51540
+ return Reflect.get(target, prop, receiver);
51541
+ }
51542
+ }
51543
+ });
51544
+ const transcription = new Proxy(sdk.speechToText, {
51545
+ get(target, prop, receiver) {
51546
+ if (prop === "convert")
51547
+ return (request, options) => elevenLabsChannels.transcribe.invoke(
51548
+ target.convert,
51549
+ target,
51550
+ [request, options],
51551
+ {}
51552
+ );
51553
+ return Reflect.get(target, prop, receiver);
51554
+ }
51555
+ });
51556
+ const proxy = new Proxy(sdk, {
51557
+ get(target, prop, receiver) {
51558
+ if (prop === "textToSpeech") return speech;
51559
+ if (prop === "speechToText") return transcription;
51560
+ return Reflect.get(target, prop, receiver);
51561
+ }
51562
+ });
51563
+ clients.set(client, proxy);
51564
+ clients.set(proxy, proxy);
51565
+ return proxy;
51566
+ }
51567
+
50563
51568
  // src/workerd/index.ts
50564
51569
  configureWorkerd();