braintrust 3.31.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 +736 -0
  2. package/dev/dist/index.d.ts +736 -0
  3. package/dev/dist/index.js +1280 -428
  4. package/dev/dist/index.mjs +859 -7
  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 +104 -2
  10. package/dist/auto-instrumentations/bundler/next.mjs +3 -3
  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 +124 -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 +2124 -2
  27. package/dist/browser.d.ts +2124 -2
  28. package/dist/browser.js +994 -10
  29. package/dist/browser.mjs +994 -10
  30. package/dist/{chunk-AJT4FR25.mjs → chunk-4QSAHP7D.mjs} +818 -5
  31. package/dist/{chunk-4AQGZS6X.js → chunk-AW4QECG5.js} +47 -4
  32. package/dist/{chunk-V32LW47Z.js → chunk-BTRLPQG5.js} +1663 -850
  33. package/dist/{chunk-CE3BLB2L.mjs → chunk-WV6QZI2W.mjs} +46 -3
  34. package/dist/cli.js +923 -8
  35. package/dist/edge-light.d.mts +1 -1
  36. package/dist/edge-light.d.ts +1 -1
  37. package/dist/edge-light.js +994 -10
  38. package/dist/edge-light.mjs +994 -10
  39. package/dist/index.d.mts +2124 -2
  40. package/dist/index.d.ts +2124 -2
  41. package/dist/index.js +581 -447
  42. package/dist/index.mjs +136 -2
  43. package/dist/instrumentation/index.d.mts +434 -0
  44. package/dist/instrumentation/index.d.ts +434 -0
  45. package/dist/instrumentation/index.js +859 -7
  46. package/dist/instrumentation/index.mjs +859 -7
  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 +994 -10
  52. package/dist/workerd.mjs +994 -10
  53. package/package.json +1 -1
  54. package/util/dist/index.d.mts +326 -0
  55. package/util/dist/index.d.ts +326 -0
@@ -2914,6 +2914,14 @@ var ChatCompletionContentPartImageWithTitle = z6.object({
2914
2914
  ttl: z6.enum(["5m", "1h"]).optional()
2915
2915
  }).optional()
2916
2916
  });
2917
+ var ChatCompletionContentPartInputAudioWithTitle = z6.object({
2918
+ input_audio: z6.object({ data: z6.string(), format: z6.enum(["wav", "mp3"]) }),
2919
+ type: z6.literal("input_audio"),
2920
+ cache_control: z6.object({
2921
+ type: z6.literal("ephemeral"),
2922
+ ttl: z6.enum(["5m", "1h"]).optional()
2923
+ }).optional()
2924
+ });
2917
2925
  var ChatCompletionContentPartFileFile = z6.object({ file_data: z6.string(), filename: z6.string(), file_id: z6.string() }).partial();
2918
2926
  var ChatCompletionContentPartFileWithTitle = z6.object({
2919
2927
  file: ChatCompletionContentPartFileFile,
@@ -2926,6 +2934,7 @@ var ChatCompletionContentPartFileWithTitle = z6.object({
2926
2934
  var ChatCompletionContentPart = z6.union([
2927
2935
  ChatCompletionContentPartTextWithTitle,
2928
2936
  ChatCompletionContentPartImageWithTitle,
2937
+ ChatCompletionContentPartInputAudioWithTitle,
2929
2938
  ChatCompletionContentPartFileWithTitle
2930
2939
  ]);
2931
2940
  var ChatCompletionContentPartText = z6.object({
@@ -5753,6 +5762,7 @@ var INSTRUMENTATION_NAMES = {
5753
5762
  GENKIT: "genkit",
5754
5763
  GITHUB_COPILOT: "github-copilot",
5755
5764
  GOOGLE_ADK: "google-adk",
5765
+ GOOGLE_GENERATIVE_AI: "google-generative-ai",
5756
5766
  GOOGLE_GENAI: "google-genai",
5757
5767
  GROQ: "groq",
5758
5768
  HUGGINGFACE: "huggingface",
@@ -5768,12 +5778,13 @@ var INSTRUMENTATION_NAMES = {
5768
5778
  OPENROUTER_AGENT: "openrouter-agent",
5769
5779
  PI_CODING_AGENT: "pi-coding-agent",
5770
5780
  STRANDS_AGENT_SDK: "strands-agent-sdk",
5771
- VOYAGEAI: "voyageai"
5781
+ VOYAGEAI: "voyageai",
5782
+ ELEVENLABS: "elevenlabs"
5772
5783
  };
5773
5784
  var INTERNAL_SPAN_INSTRUMENTATION_NAME = /* @__PURE__ */ Symbol.for(
5774
5785
  "braintrust.spanInstrumentationName"
5775
5786
  );
5776
- var SDK_VERSION = true ? "3.31.0" : "0.0.0";
5787
+ var SDK_VERSION = true ? "3.32.0" : "0.0.0";
5777
5788
  function withSpanInstrumentationName(args, instrumentationName) {
5778
5789
  return {
5779
5790
  ...args,
@@ -10351,6 +10362,16 @@ function renderMessageImpl(render, message, variables) {
10351
10362
  }
10352
10363
  }
10353
10364
  ];
10365
+ case "input_audio":
10366
+ return [
10367
+ {
10368
+ ...c,
10369
+ input_audio: {
10370
+ ...c.input_audio,
10371
+ data: render(c.input_audio.data)
10372
+ }
10373
+ }
10374
+ ];
10354
10375
  case "file":
10355
10376
  return [
10356
10377
  {
@@ -22619,6 +22640,342 @@ var OpenAIAgentsPlugin = class extends BasePlugin {
22619
22640
  }
22620
22641
  };
22621
22642
 
22643
+ // src/instrumentation/plugins/google-generative-ai-channels.ts
22644
+ var googleGenerativeAIChannels = defineChannels(
22645
+ "@google/generative-ai",
22646
+ {
22647
+ generateContent: channel({ channelName: "GenerativeModel.generateContent", kind: "async" }),
22648
+ generateContentStream: channel({ channelName: "GenerativeModel.generateContentStream", kind: "async" }),
22649
+ embedContent: channel({ channelName: "GenerativeModel.embedContent", kind: "async" }),
22650
+ batchEmbedContents: channel({ channelName: "GenerativeModel.batchEmbedContents", kind: "async" }),
22651
+ sendMessage: channel({ channelName: "ChatSession.sendMessage", kind: "async" }),
22652
+ sendMessageStream: channel({ channelName: "ChatSession.sendMessageStream", kind: "async" })
22653
+ },
22654
+ { instrumentationName: INSTRUMENTATION_NAMES.GOOGLE_GENERATIVE_AI }
22655
+ );
22656
+
22657
+ // src/instrumentation/plugins/google-generative-ai-plugin.ts
22658
+ var GENERATION_CONFIG_KEYS = [
22659
+ "temperature",
22660
+ "topP",
22661
+ "topK",
22662
+ "candidateCount",
22663
+ "maxOutputTokens",
22664
+ "stopSequences",
22665
+ "responseMimeType",
22666
+ "responseSchema",
22667
+ "presencePenalty",
22668
+ "frequencyPenalty",
22669
+ "responseLogprobs",
22670
+ "logprobs",
22671
+ "thinkingConfig"
22672
+ ];
22673
+ var GoogleGenerativeAIPlugin = class extends BasePlugin {
22674
+ onEnable() {
22675
+ this.unsubscribers.push(
22676
+ interceptCall(
22677
+ googleGenerativeAIChannels.generateContent,
22678
+ "generateContent"
22679
+ ),
22680
+ interceptCall(
22681
+ googleGenerativeAIChannels.generateContentStream,
22682
+ "generateContentStream"
22683
+ ),
22684
+ interceptCall(googleGenerativeAIChannels.sendMessage, "sendMessage"),
22685
+ interceptCall(
22686
+ googleGenerativeAIChannels.sendMessageStream,
22687
+ "sendMessageStream"
22688
+ ),
22689
+ interceptCall(googleGenerativeAIChannels.embedContent, "embedContent"),
22690
+ interceptCall(
22691
+ googleGenerativeAIChannels.batchEmbedContents,
22692
+ "batchEmbedContents"
22693
+ )
22694
+ );
22695
+ }
22696
+ onDisable() {
22697
+ this.unsubscribers = unsubscribeAll(this.unsubscribers);
22698
+ }
22699
+ };
22700
+ function interceptCall(channel2, operation) {
22701
+ return channel2.intercept((target, thisArg, args) => {
22702
+ const invokeTarget = () => Reflect.apply(target, thisArg, args);
22703
+ if (isAutoInstrumentationSuppressed()) return invokeTarget();
22704
+ const self = thisArg;
22705
+ const chat = operation.startsWith("sendMessage");
22706
+ const embedding = operation === "embedContent" || operation === "batchEmbedContents";
22707
+ const start = getCurrentUnixTimestamp();
22708
+ let span;
22709
+ try {
22710
+ span = startSpan(
22711
+ withSpanInstrumentationName(
22712
+ {
22713
+ name: embedding ? operation === "embedContent" ? "embed_content" : "batch_embed_contents" : "generate_content",
22714
+ spanAttributes: { type: "llm" /* LLM */ },
22715
+ event: extractInput(self, args[0], operation)
22716
+ },
22717
+ INSTRUMENTATION_NAMES.GOOGLE_GENERATIVE_AI
22718
+ )
22719
+ );
22720
+ } catch (error) {
22721
+ debugLogger.error("Error starting Google Generative AI span:", error);
22722
+ return invokeTarget();
22723
+ }
22724
+ let ended = false;
22725
+ const finish = (log) => {
22726
+ if (ended) return;
22727
+ ended = true;
22728
+ try {
22729
+ log();
22730
+ } catch (error) {
22731
+ debugLogger.error("Error logging Google Generative AI span:", error);
22732
+ }
22733
+ try {
22734
+ span.end();
22735
+ } catch (error) {
22736
+ debugLogger.error("Error ending Google Generative AI span:", error);
22737
+ }
22738
+ };
22739
+ if (chat) {
22740
+ try {
22741
+ void self._sendPromise.then(
22742
+ () => {
22743
+ try {
22744
+ span.log(extractInput(self, args[0], operation));
22745
+ } catch (error) {
22746
+ debugLogger.error("Error capturing Google chat history:", error);
22747
+ }
22748
+ },
22749
+ () => {
22750
+ }
22751
+ );
22752
+ } catch (error) {
22753
+ debugLogger.error("Error observing Google chat history:", error);
22754
+ }
22755
+ }
22756
+ let result;
22757
+ try {
22758
+ result = withCurrent(
22759
+ span,
22760
+ () => runWithAutoInstrumentationSuppressed(invokeTarget)
22761
+ );
22762
+ } catch (error) {
22763
+ finish(() => span.log({ error }));
22764
+ throw error;
22765
+ }
22766
+ void Promise.resolve(result).then(
22767
+ (value) => {
22768
+ try {
22769
+ if ("stream" in value) {
22770
+ let firstToken = false;
22771
+ const partial = { candidates: [] };
22772
+ const candidates = /* @__PURE__ */ new Map();
22773
+ patchStreamIfNeeded(value.stream, {
22774
+ aroundNext: (callback) => withCurrent(span, callback),
22775
+ onChunk: (chunk) => {
22776
+ for (const candidate of chunk.candidates ?? []) {
22777
+ const index = candidate.index ?? 0;
22778
+ const previous = candidates.get(index);
22779
+ const parts = [...previous?.content?.parts ?? []];
22780
+ for (const part of candidate.content?.parts ?? []) {
22781
+ const last = parts[parts.length - 1];
22782
+ if (part.text !== void 0 && last?.text !== void 0) {
22783
+ parts[parts.length - 1] = {
22784
+ ...last,
22785
+ text: last.text + part.text
22786
+ };
22787
+ } else parts.push(part);
22788
+ }
22789
+ candidates.set(index, {
22790
+ ...previous,
22791
+ ...candidate,
22792
+ content: {
22793
+ role: candidate.content?.role ?? previous?.content?.role ?? "model",
22794
+ parts
22795
+ }
22796
+ });
22797
+ }
22798
+ partial.candidates = Array.from(candidates.values());
22799
+ if (chunk.usageMetadata)
22800
+ partial.usageMetadata = chunk.usageMetadata;
22801
+ if (!firstToken && chunk.candidates?.some(
22802
+ (candidate) => candidate.content?.parts.some(
22803
+ (part) => part.text !== void 0 ? part.text.length > 0 : Object.keys(part).length > 0
22804
+ )
22805
+ )) {
22806
+ firstToken = true;
22807
+ span.log({
22808
+ metrics: {
22809
+ time_to_first_token: getCurrentUnixTimestamp() - start
22810
+ }
22811
+ });
22812
+ }
22813
+ },
22814
+ onComplete: () => {
22815
+ },
22816
+ onError: (error) => finish(() => {
22817
+ logResponse(span, partial);
22818
+ span.log({ error });
22819
+ }),
22820
+ onCancel: () => finish(() => logResponse(span, partial))
22821
+ });
22822
+ void value.response.then(
22823
+ (response) => finish(() => logResponse(span, response)),
22824
+ (error) => finish(() => {
22825
+ logResponse(span, partial);
22826
+ span.log({ error });
22827
+ })
22828
+ );
22829
+ } else if ("response" in value) {
22830
+ finish(() => logResponse(span, value.response));
22831
+ } else {
22832
+ const metrics = {};
22833
+ const promptTokens = value.usageMetadata?.promptTokenCount;
22834
+ if (typeof promptTokens === "number" && Number.isFinite(promptTokens) && promptTokens >= 0) {
22835
+ metrics.prompt_tokens = promptTokens;
22836
+ metrics.tokens = promptTokens;
22837
+ }
22838
+ for (const detail of value.usageMetadata?.promptTokenDetails ?? []) {
22839
+ if (detail.modality === "AUDIO" && typeof detail.tokenCount === "number" && Number.isFinite(detail.tokenCount) && detail.tokenCount >= 0) {
22840
+ metrics.prompt_audio_tokens = (metrics.prompt_audio_tokens ?? 0) + detail.tokenCount;
22841
+ }
22842
+ }
22843
+ finish(
22844
+ () => span.log({
22845
+ metrics,
22846
+ output: {
22847
+ count: value.embeddings?.length ?? (value.embedding ? 1 : 0)
22848
+ }
22849
+ })
22850
+ );
22851
+ }
22852
+ } catch (error) {
22853
+ debugLogger.error(
22854
+ "Error observing Google Generative AI result:",
22855
+ error
22856
+ );
22857
+ finish(() => {
22858
+ });
22859
+ }
22860
+ },
22861
+ (error) => finish(() => span.log({ error }))
22862
+ );
22863
+ return result;
22864
+ });
22865
+ }
22866
+ function normalizeContent(message) {
22867
+ const parts = (typeof message === "string" ? [message] : message).map(
22868
+ (part) => typeof part === "string" ? { text: part } : part
22869
+ );
22870
+ return {
22871
+ role: parts.some((part) => part.functionResponse) ? "function" : "user",
22872
+ parts
22873
+ };
22874
+ }
22875
+ function extractInput(self, request, operation) {
22876
+ const model = self.model.replace(/^models\//, "");
22877
+ if (operation === "embedContent" || operation === "batchEmbedContents") {
22878
+ const requests = operation === "batchEmbedContents" ? request.requests : [
22879
+ typeof request === "string" || Array.isArray(request) ? { content: normalizeContent(request) } : request
22880
+ ];
22881
+ const dimensions = requests[0]?.outputDimensionality;
22882
+ return {
22883
+ input: {
22884
+ inputs: convertAttachments(requests).map((item) => ({
22885
+ content: item.content.parts.length === 1 && item.content.parts[0].text !== void 0 ? item.content.parts[0].text : item.content.parts.map((part) => {
22886
+ if (part.text !== void 0)
22887
+ return { type: "text", text: part.text };
22888
+ const mimeType = part.inlineData?.mimeType ?? part.fileData?.mimeType;
22889
+ const data = part.inlineData ? typeof part.inlineData.data === "string" ? `data:${mimeType};base64,${part.inlineData.data}` : part.inlineData.data : part.fileData?.fileUri;
22890
+ return mimeType?.startsWith("image/") ? { type: "image_url", image_url: { url: data } } : { type: "file", file: { file_data: data } };
22891
+ })
22892
+ })),
22893
+ ...dimensions !== void 0 && requests.every((item) => item.outputDimensionality === dimensions) ? { output_dimensions: dimensions } : {}
22894
+ },
22895
+ metadata: { model, provider: "google" }
22896
+ };
22897
+ }
22898
+ const chat = operation.startsWith("sendMessage");
22899
+ const config = chat ? self.params ?? {} : self;
22900
+ const params = typeof request === "string" || Array.isArray(request) ? { contents: [normalizeContent(request)] } : request;
22901
+ const system = params.systemInstruction ?? config.systemInstruction;
22902
+ const systemContent = typeof system === "string" ? { role: "system", parts: [{ text: system }] } : system && "parts" in system ? { ...system, role: "system" } : system ? { role: "system", parts: [system] } : void 0;
22903
+ const contents = [
22904
+ ...systemContent ? [systemContent] : [],
22905
+ ...chat ? self._history : [],
22906
+ ...params.contents
22907
+ ];
22908
+ const metadata = { model, provider: "google" };
22909
+ const generation = params.generationConfig ?? config.generationConfig;
22910
+ for (const key of GENERATION_CONFIG_KEYS) {
22911
+ if (generation && Object.hasOwn(generation, key))
22912
+ metadata[key] = generation[key];
22913
+ }
22914
+ for (const key of ["tools", "toolConfig", "safetySettings"]) {
22915
+ const value = params[key] ?? config[key];
22916
+ if (value !== void 0) metadata[key] = value;
22917
+ }
22918
+ const cached = params.cachedContent ?? config.cachedContent;
22919
+ if (cached)
22920
+ metadata.cachedContent = typeof cached === "string" ? cached : cached.name;
22921
+ return { input: convertAttachments({ model, contents }), metadata };
22922
+ }
22923
+ function convertAttachments(value) {
22924
+ const convert = (node) => {
22925
+ if (Array.isArray(node)) return node.map(convert);
22926
+ if (!isObject(node)) return node;
22927
+ if (isObject(node.inlineData)) {
22928
+ const { data, mimeType } = node.inlineData;
22929
+ const processed = processInputAttachments({
22930
+ type: "file",
22931
+ file: { file_data: `data:${mimeType};base64,${data}` }
22932
+ });
22933
+ if (typeof processed.file.file_data === "string")
22934
+ throw new Error("Unable to convert Google inline data");
22935
+ return {
22936
+ ...node,
22937
+ inlineData: { ...node.inlineData, data: processed.file.file_data }
22938
+ };
22939
+ }
22940
+ return Object.fromEntries(
22941
+ Object.entries(node).map(([key, item]) => [key, convert(item)])
22942
+ );
22943
+ };
22944
+ try {
22945
+ return convert(value);
22946
+ } catch (error) {
22947
+ debugLogger.error(
22948
+ "Error converting Google Generative AI attachments:",
22949
+ error
22950
+ );
22951
+ return value;
22952
+ }
22953
+ }
22954
+ function logResponse(span, response) {
22955
+ const usage = response.usageMetadata;
22956
+ const metrics = {};
22957
+ if (usage) {
22958
+ if (usage.promptTokenCount !== void 0)
22959
+ metrics.prompt_tokens = usage.promptTokenCount;
22960
+ if (usage.candidatesTokenCount !== void 0 || usage.thoughtsTokenCount !== void 0)
22961
+ metrics.completion_tokens = (usage.candidatesTokenCount ?? 0) + (usage.thoughtsTokenCount ?? 0);
22962
+ if (usage.totalTokenCount !== void 0)
22963
+ metrics.tokens = usage.totalTokenCount;
22964
+ if (usage.cachedContentTokenCount !== void 0)
22965
+ metrics.prompt_cached_tokens = usage.cachedContentTokenCount;
22966
+ if (usage.thoughtsTokenCount !== void 0)
22967
+ metrics.completion_reasoning_tokens = usage.thoughtsTokenCount;
22968
+ }
22969
+ span.log({
22970
+ output: convertAttachments({
22971
+ candidates: response.candidates,
22972
+ promptFeedback: response.promptFeedback
22973
+ }),
22974
+ metrics,
22975
+ ...response.modelVersion ? { metadata: { model: response.modelVersion } } : {}
22976
+ });
22977
+ }
22978
+
22622
22979
  // src/instrumentation/plugins/google-genai-channels.ts
22623
22980
  var googleGenAIChannels = defineChannels(
22624
22981
  "@google/genai",
@@ -24262,7 +24619,7 @@ var HuggingFaceTransformersPlugin = class extends BasePlugin {
24262
24619
  getTask(event)
24263
24620
  ),
24264
24621
  extractInput: (args, event) => ({
24265
- input: extractInput(
24622
+ input: extractInput2(
24266
24623
  getTask(event),
24267
24624
  args
24268
24625
  ),
@@ -24352,7 +24709,7 @@ function modelIdentifier(pipeline) {
24352
24709
  }
24353
24710
  return void 0;
24354
24711
  }
24355
- function extractInput(task, args) {
24712
+ function extractInput2(task, args) {
24356
24713
  switch (task) {
24357
24714
  case "feature-extraction":
24358
24715
  return args[0];
@@ -34706,6 +35063,477 @@ function logInstrumentationError5(context, error) {
34706
35063
  debugLogger.debug(`${context}:`, error);
34707
35064
  }
34708
35065
 
35066
+ // src/instrumentation/plugins/elevenlabs-channels.ts
35067
+ var elevenLabsChannels = defineChannels(
35068
+ "@elevenlabs/elevenlabs-js",
35069
+ {
35070
+ convert: channel({
35071
+ channelName: "textToSpeech.convert",
35072
+ kind: "async"
35073
+ }),
35074
+ stream: channel({
35075
+ channelName: "textToSpeech.stream",
35076
+ kind: "async"
35077
+ }),
35078
+ convertWithTimestamps: channel({ channelName: "textToSpeech.convertWithTimestamps", kind: "async" }),
35079
+ streamWithTimestamps: channel({ channelName: "textToSpeech.streamWithTimestamps", kind: "async" }),
35080
+ transcribe: channel({ channelName: "speechToText.convert", kind: "async" })
35081
+ },
35082
+ { instrumentationName: INSTRUMENTATION_NAMES.ELEVENLABS }
35083
+ );
35084
+
35085
+ // src/instrumentation/plugins/elevenlabs-plugin.ts
35086
+ var ElevenLabsPlugin = class extends BasePlugin {
35087
+ onEnable() {
35088
+ for (const method of [
35089
+ "convert",
35090
+ "stream",
35091
+ "convertWithTimestamps",
35092
+ "streamWithTimestamps"
35093
+ ]) {
35094
+ this.unsubscribers.push(
35095
+ interceptCall2(
35096
+ elevenLabsChannels[method],
35097
+ `elevenlabs.textToSpeech.${method}`,
35098
+ ([voice, request]) => ({
35099
+ input: {
35100
+ operation: "speech",
35101
+ prompt: request.text,
35102
+ parameters: {
35103
+ voice,
35104
+ format: request.outputFormat,
35105
+ language: request.languageCode,
35106
+ speed: request.voiceSettings?.speed
35107
+ }
35108
+ },
35109
+ metadata: {
35110
+ provider: "elevenlabs",
35111
+ model: request.modelId ?? "eleven_multilingual_v2"
35112
+ }
35113
+ }),
35114
+ (value, args, span, finish, headers, started) => captureSpeech(
35115
+ value,
35116
+ args[1],
35117
+ method,
35118
+ span,
35119
+ finish,
35120
+ started,
35121
+ headers
35122
+ )
35123
+ )
35124
+ );
35125
+ }
35126
+ this.unsubscribers.push(
35127
+ interceptCall2(
35128
+ elevenLabsChannels.transcribe,
35129
+ "elevenlabs.speechToText.convert",
35130
+ ([request]) => {
35131
+ if (request.webhook) return void 0;
35132
+ const file = request.file;
35133
+ const filename = typeof File !== "undefined" && file instanceof File ? file.name : "audio";
35134
+ const contentType = file instanceof Blob ? file.type || "application/octet-stream" : "application/octet-stream";
35135
+ 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;
35136
+ const fileData = blob ? new Attachment({ data: blob, filename, contentType }) : request.cloudStorageUrl;
35137
+ return {
35138
+ input: {
35139
+ operation: "transcribe",
35140
+ content: fileData ? [{ type: "file", file: { filename, file_data: fileData } }] : [],
35141
+ parameters: {
35142
+ language: request.languageCode,
35143
+ timestamp_granularities: request.timestampsGranularity
35144
+ }
35145
+ },
35146
+ metadata: { provider: "elevenlabs", model: request.modelId }
35147
+ };
35148
+ },
35149
+ (value, _args, span, finish) => {
35150
+ const result = value;
35151
+ const transcripts = result.transcripts ?? [result];
35152
+ span.log({
35153
+ output: {
35154
+ content: transcripts.flatMap(
35155
+ (transcript) => typeof transcript.text === "string" ? [{ type: "text", text: transcript.text }] : []
35156
+ ),
35157
+ annotations: {
35158
+ language: result.languageCode,
35159
+ words: result.words ?? (result.transcripts ? result.transcripts.flatMap(
35160
+ (transcript) => transcript.words ?? []
35161
+ ) : void 0)
35162
+ }
35163
+ }
35164
+ });
35165
+ finish();
35166
+ },
35167
+ ([request], span) => {
35168
+ const file = request.file;
35169
+ if (!isAsyncIterable(file)) return;
35170
+ const chunks = [];
35171
+ const filename = isObject(file) && typeof file.path === "string" ? file.path.split(/[\\/]/).pop() || "audio" : "audio";
35172
+ observeAudioStream(
35173
+ file,
35174
+ (chunk) => chunks.push(new Uint8Array(chunk)),
35175
+ () => {
35176
+ const contentType = "application/octet-stream";
35177
+ const data = new Blob(chunks, {
35178
+ type: contentType
35179
+ });
35180
+ chunks.length = 0;
35181
+ span.log({
35182
+ input: {
35183
+ content: [
35184
+ {
35185
+ type: "file",
35186
+ file: {
35187
+ filename,
35188
+ file_data: new Attachment({
35189
+ data,
35190
+ filename,
35191
+ contentType
35192
+ })
35193
+ }
35194
+ }
35195
+ ]
35196
+ }
35197
+ });
35198
+ },
35199
+ () => {
35200
+ chunks.length = 0;
35201
+ },
35202
+ span
35203
+ );
35204
+ }
35205
+ )
35206
+ );
35207
+ }
35208
+ onDisable() {
35209
+ this.unsubscribers = unsubscribeAll(this.unsubscribers);
35210
+ }
35211
+ };
35212
+ function interceptCall2(channel2, name, input, output, beforeInvoke) {
35213
+ return channel2.intercept((target, self, args) => {
35214
+ const invoke = () => Reflect.apply(target, self, args);
35215
+ if (isAutoInstrumentationSuppressed()) return invoke();
35216
+ const started = Date.now() / 1e3;
35217
+ let span;
35218
+ try {
35219
+ const event = input(args);
35220
+ if (event !== void 0)
35221
+ span = startSpan(
35222
+ withSpanInstrumentationName(
35223
+ {
35224
+ name,
35225
+ spanAttributes: { type: "llm" /* LLM */ },
35226
+ event
35227
+ },
35228
+ INSTRUMENTATION_NAMES.ELEVENLABS
35229
+ )
35230
+ );
35231
+ } catch (error) {
35232
+ debugLogger.error("Error starting ElevenLabs span", error);
35233
+ return invoke();
35234
+ }
35235
+ if (!span) return invoke();
35236
+ const activeSpan = span;
35237
+ let ended = false;
35238
+ const finish = (error) => {
35239
+ if (ended) return;
35240
+ ended = true;
35241
+ try {
35242
+ if (error !== void 0) activeSpan.log({ error });
35243
+ activeSpan.end();
35244
+ } catch (loggingError) {
35245
+ debugLogger.error("Error ending ElevenLabs span", loggingError);
35246
+ }
35247
+ };
35248
+ try {
35249
+ beforeInvoke?.(args, span);
35250
+ } catch (error) {
35251
+ debugLogger.error("Error observing ElevenLabs input", error);
35252
+ }
35253
+ let result;
35254
+ try {
35255
+ result = withCurrent(
35256
+ span,
35257
+ () => runWithAutoInstrumentationSuppressed(invoke)
35258
+ );
35259
+ } catch (error) {
35260
+ finish(error);
35261
+ throw error;
35262
+ }
35263
+ const capture = (value, headers) => {
35264
+ try {
35265
+ output(value, args, span, finish, headers, started);
35266
+ } catch (error) {
35267
+ debugLogger.error("Error capturing ElevenLabs output", error);
35268
+ finish();
35269
+ }
35270
+ };
35271
+ try {
35272
+ if (isObject(result) && typeof result.withRawResponse === "function") {
35273
+ void result.withRawResponse().then(
35274
+ ({
35275
+ data,
35276
+ rawResponse
35277
+ }) => capture(data, rawResponse?.headers),
35278
+ finish
35279
+ );
35280
+ } else {
35281
+ void Promise.resolve(result).then((value) => capture(value), finish);
35282
+ }
35283
+ } catch (error) {
35284
+ debugLogger.error("Error observing ElevenLabs result", error);
35285
+ finish();
35286
+ }
35287
+ return result;
35288
+ });
35289
+ }
35290
+ function captureSpeech(value, request, method, span, finish, started, headers) {
35291
+ const format = request.outputFormat ?? "mp3_44100_128";
35292
+ 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;
35293
+ const headerType = headers?.get("content-type")?.split(";")[0];
35294
+ const contentType = headerType?.startsWith("audio/") ? headerType : formatType;
35295
+ const disposition = headers?.get("content-disposition");
35296
+ const headerFilename = disposition?.match(
35297
+ /filename="([^"]+)"|filename=([^;]+)/i
35298
+ );
35299
+ const filename = headerFilename?.[1] ?? headerFilename?.[2]?.trim() ?? `speech.${contentType ? getExtensionFromMediaType(contentType) : "bin"}`;
35300
+ const chunks = [];
35301
+ const alignments = [];
35302
+ let bytes = 0;
35303
+ let first = true;
35304
+ let stopped = false;
35305
+ const observe = (chunk) => {
35306
+ if (stopped || chunk.byteLength === 0) return;
35307
+ if (first && method.startsWith("stream")) {
35308
+ span.log({
35309
+ metrics: { time_to_first_token: Date.now() / 1e3 - started }
35310
+ });
35311
+ }
35312
+ first = false;
35313
+ chunks.push(new Uint8Array(chunk));
35314
+ bytes += chunk.byteLength;
35315
+ };
35316
+ const complete = () => {
35317
+ if (stopped) return;
35318
+ stopped = true;
35319
+ try {
35320
+ const content = [];
35321
+ if (contentType && bytes) {
35322
+ const data = new Uint8Array(bytes);
35323
+ let offset = 0;
35324
+ for (const chunk of chunks) {
35325
+ data.set(chunk, offset);
35326
+ offset += chunk.length;
35327
+ }
35328
+ content.push({
35329
+ type: "file",
35330
+ file: {
35331
+ filename,
35332
+ byte_size: bytes,
35333
+ file_data: new Attachment({
35334
+ data: new Blob([data], { type: contentType }),
35335
+ filename,
35336
+ contentType
35337
+ })
35338
+ }
35339
+ });
35340
+ }
35341
+ span.log({
35342
+ output: {
35343
+ content,
35344
+ ...alignments.length ? { annotations: alignments } : {}
35345
+ }
35346
+ });
35347
+ } finally {
35348
+ chunks.length = 0;
35349
+ finish();
35350
+ }
35351
+ };
35352
+ const cancel = (error) => {
35353
+ stopped = true;
35354
+ chunks.length = 0;
35355
+ finish(error);
35356
+ };
35357
+ const timestampChunk = (chunk) => {
35358
+ const binary = atob(chunk.audioBase64);
35359
+ observe(Uint8Array.from(binary, (character) => character.charCodeAt(0)));
35360
+ if (chunk.alignment || chunk.normalizedAlignment)
35361
+ alignments.push({
35362
+ alignment: chunk.alignment,
35363
+ normalized_alignment: chunk.normalizedAlignment
35364
+ });
35365
+ };
35366
+ if (method === "convertWithTimestamps") {
35367
+ timestampChunk(value);
35368
+ complete();
35369
+ } else if (method === "streamWithTimestamps") {
35370
+ patchStreamIfNeeded(value, {
35371
+ shouldCollect: (chunk) => {
35372
+ try {
35373
+ timestampChunk(chunk);
35374
+ } catch (error) {
35375
+ debugLogger.error("Error collecting ElevenLabs timestamps", error);
35376
+ cancel();
35377
+ }
35378
+ return false;
35379
+ },
35380
+ onComplete: complete,
35381
+ onCancel: () => cancel(),
35382
+ onError: cancel,
35383
+ aroundNext: (next) => withCurrent(span, next)
35384
+ });
35385
+ } else {
35386
+ observeAudioStream(value, observe, complete, cancel, span);
35387
+ }
35388
+ }
35389
+ function observeAudioStream(value, observe, complete, cancel, span) {
35390
+ let ended = false;
35391
+ const safeObserve = (chunk) => {
35392
+ if (ended) return;
35393
+ try {
35394
+ observe(chunk);
35395
+ } catch (error) {
35396
+ debugLogger.error("Error collecting ElevenLabs audio", error);
35397
+ end(false);
35398
+ }
35399
+ };
35400
+ const end = (success, error) => {
35401
+ if (ended) return;
35402
+ ended = true;
35403
+ try {
35404
+ if (success) complete();
35405
+ else cancel(error);
35406
+ } catch (loggingError) {
35407
+ debugLogger.error("Error logging ElevenLabs audio", loggingError);
35408
+ cancel();
35409
+ }
35410
+ };
35411
+ if (!isObject(value) || !Object.isExtensible(value)) {
35412
+ end(false);
35413
+ return;
35414
+ }
35415
+ if (typeof value.read === "function" && typeof value.on === "function") {
35416
+ value.on("end", () => end(true));
35417
+ value.on("close", () => end(false));
35418
+ const emit2 = value.emit;
35419
+ if (typeof emit2 === "function")
35420
+ value.emit = function(event, ...args) {
35421
+ if (event === "data" && args[0] instanceof Uint8Array)
35422
+ safeObserve(args[0]);
35423
+ if (event === "error") end(false, args[0]);
35424
+ return Reflect.apply(emit2, this, [event, ...args]);
35425
+ };
35426
+ return;
35427
+ }
35428
+ if (typeof value.getReader === "function") {
35429
+ const webStream = value;
35430
+ const pipeTo = webStream.pipeTo;
35431
+ const pipeThrough = webStream.pipeThrough;
35432
+ webStream.pipeTo = function(destination, options) {
35433
+ if (!isObject(destination) || this.locked || destination.locked)
35434
+ return pipeTo.call(this, destination, options);
35435
+ const tap = new TransformStream({
35436
+ transform(chunk, controller) {
35437
+ safeObserve(chunk);
35438
+ controller.enqueue(chunk);
35439
+ },
35440
+ flush() {
35441
+ end(true);
35442
+ }
35443
+ });
35444
+ const observed = pipeThrough.call(
35445
+ this,
35446
+ tap,
35447
+ options
35448
+ );
35449
+ return observed.pipeTo(destination, options).catch((error) => {
35450
+ end(false, error);
35451
+ throw error;
35452
+ });
35453
+ };
35454
+ webStream.pipeThrough = function(transform, options) {
35455
+ if (this.locked || transform.writable.locked || transform.readable.locked)
35456
+ return pipeThrough.call(this, transform, options);
35457
+ const result = webStream.pipeTo.call(this, transform.writable, options);
35458
+ void result.catch(() => {
35459
+ });
35460
+ return transform.readable;
35461
+ };
35462
+ const getReader = value.getReader;
35463
+ value.getReader = function(...args) {
35464
+ const reader = Reflect.apply(getReader, this, args);
35465
+ const read2 = reader.read;
35466
+ reader.read = function(...readArgs) {
35467
+ return Promise.resolve(
35468
+ withCurrent(span, () => Reflect.apply(read2, this, readArgs))
35469
+ ).then(
35470
+ (result) => {
35471
+ if (result.value) safeObserve(result.value);
35472
+ if (result.done) end(true);
35473
+ return result;
35474
+ },
35475
+ (error) => {
35476
+ end(false, error);
35477
+ throw error;
35478
+ }
35479
+ );
35480
+ };
35481
+ const readerCancel = reader.cancel;
35482
+ reader.cancel = function(...cancelArgs) {
35483
+ const result = Reflect.apply(readerCancel, this, cancelArgs);
35484
+ end(false);
35485
+ return result;
35486
+ };
35487
+ return reader;
35488
+ };
35489
+ const streamCancel = value.cancel;
35490
+ if (typeof streamCancel === "function")
35491
+ value.cancel = function(...args) {
35492
+ const result = Reflect.apply(streamCancel, this, args);
35493
+ void Promise.resolve(result).then(
35494
+ () => end(false),
35495
+ () => {
35496
+ }
35497
+ );
35498
+ return result;
35499
+ };
35500
+ }
35501
+ if (typeof value.getReader === "function" && typeof value.values === "function") {
35502
+ const values = value.values;
35503
+ const iterate = function(...args) {
35504
+ const iterator = Reflect.apply(values, this, args);
35505
+ patchStreamIfNeeded(iterator, {
35506
+ shouldCollect(chunk) {
35507
+ safeObserve(chunk);
35508
+ return false;
35509
+ },
35510
+ onComplete: () => end(true),
35511
+ onCancel: () => end(false),
35512
+ onError: (error) => end(false, error),
35513
+ aroundNext: (next) => withCurrent(span, next)
35514
+ });
35515
+ return iterator;
35516
+ };
35517
+ value.values = iterate;
35518
+ Object.defineProperty(value, Symbol.asyncIterator, {
35519
+ configurable: true,
35520
+ writable: true,
35521
+ value: iterate
35522
+ });
35523
+ } else if (isAsyncIterable(value)) {
35524
+ patchStreamIfNeeded(value, {
35525
+ shouldCollect: (chunk) => {
35526
+ safeObserve(chunk);
35527
+ return false;
35528
+ },
35529
+ onComplete: () => end(true),
35530
+ onCancel: () => end(false),
35531
+ onError: (error) => end(false, error),
35532
+ aroundNext: (next) => withCurrent(span, next)
35533
+ });
35534
+ } else if (typeof value.getReader !== "function") end(false);
35535
+ }
35536
+
34709
35537
  // src/instrumentation/plugins/voyageai-channels.ts
34710
35538
  var voyageAIChannels = defineChannels(
34711
35539
  "voyageai",
@@ -34773,7 +35601,7 @@ var VoyageAIPlugin = class extends BasePlugin {
34773
35601
  this.unsubscribers = unsubscribeAll(this.unsubscribers);
34774
35602
  }
34775
35603
  };
34776
- function interceptVoyageAICall(channel2, name, extractInput2, extractOutput2, extractMetrics2 = extractUsageMetrics3) {
35604
+ function interceptVoyageAICall(channel2, name, extractInput3, extractOutput2, extractMetrics2 = extractUsageMetrics3) {
34777
35605
  return channel2.intercept((target, thisArg, args) => {
34778
35606
  const invokeTarget = () => Reflect.apply(target, thisArg, args);
34779
35607
  if (isAutoInstrumentationSuppressed()) {
@@ -34781,7 +35609,7 @@ function interceptVoyageAICall(channel2, name, extractInput2, extractOutput2, ex
34781
35609
  }
34782
35610
  let span;
34783
35611
  try {
34784
- const { input, metadata } = extractInput2(args);
35612
+ const { input, metadata } = extractInput3(args);
34785
35613
  span = startSpan(
34786
35614
  withSpanInstrumentationName(
34787
35615
  {
@@ -35557,6 +36385,7 @@ var BraintrustPlugin = class extends BasePlugin {
35557
36385
  cloudflareThinkPlugin = null;
35558
36386
  cursorSDKPlugin = null;
35559
36387
  openAIAgentsPlugin = null;
36388
+ googleGenerativeAIPlugin = null;
35560
36389
  googleGenAIPlugin = null;
35561
36390
  huggingFacePlugin = null;
35562
36391
  huggingFaceTransformersPlugin = null;
@@ -35575,6 +36404,7 @@ var BraintrustPlugin = class extends BasePlugin {
35575
36404
  langSmithPlugin = null;
35576
36405
  piCodingAgentPlugin = null;
35577
36406
  strandsAgentSDKPlugin = null;
36407
+ elevenLabsPlugin = null;
35578
36408
  voyageAIPlugin = null;
35579
36409
  cloudflareAIChatPlugin = null;
35580
36410
  cloudflareAgentsPlugin = null;
@@ -35616,6 +36446,10 @@ var BraintrustPlugin = class extends BasePlugin {
35616
36446
  this.openAIAgentsPlugin = new OpenAIAgentsPlugin();
35617
36447
  this.openAIAgentsPlugin.enable();
35618
36448
  }
36449
+ if (integrations.googleGenerativeAI !== false) {
36450
+ this.googleGenerativeAIPlugin = new GoogleGenerativeAIPlugin();
36451
+ this.googleGenerativeAIPlugin.enable();
36452
+ }
35619
36453
  if (integrations.googleGenAI !== false && integrations.google !== false) {
35620
36454
  this.googleGenAIPlugin = new GoogleGenAIPlugin();
35621
36455
  this.googleGenAIPlugin.enable();
@@ -35650,6 +36484,10 @@ var BraintrustPlugin = class extends BasePlugin {
35650
36484
  this.coherePlugin = new CoherePlugin();
35651
36485
  this.coherePlugin.enable();
35652
36486
  }
36487
+ if (integrations.elevenlabs !== false) {
36488
+ this.elevenLabsPlugin = new ElevenLabsPlugin();
36489
+ this.elevenLabsPlugin.enable();
36490
+ }
35653
36491
  if (integrations.voyageai !== false) {
35654
36492
  this.voyageAIPlugin = new VoyageAIPlugin();
35655
36493
  this.voyageAIPlugin.enable();
@@ -35734,6 +36572,10 @@ var BraintrustPlugin = class extends BasePlugin {
35734
36572
  this.openAIAgentsPlugin.disable();
35735
36573
  this.openAIAgentsPlugin = null;
35736
36574
  }
36575
+ if (this.googleGenerativeAIPlugin) {
36576
+ this.googleGenerativeAIPlugin.disable();
36577
+ this.googleGenerativeAIPlugin = null;
36578
+ }
35737
36579
  if (this.googleGenAIPlugin) {
35738
36580
  this.googleGenAIPlugin.disable();
35739
36581
  this.googleGenAIPlugin = null;
@@ -35770,6 +36612,10 @@ var BraintrustPlugin = class extends BasePlugin {
35770
36612
  this.coherePlugin.disable();
35771
36613
  this.coherePlugin = null;
35772
36614
  }
36615
+ if (this.elevenLabsPlugin) {
36616
+ this.elevenLabsPlugin.disable();
36617
+ this.elevenLabsPlugin = null;
36618
+ }
35773
36619
  if (this.voyageAIPlugin) {
35774
36620
  this.voyageAIPlugin.disable();
35775
36621
  this.voyageAIPlugin = null;
@@ -37982,6 +38828,8 @@ var envIntegrationAliases = {
37982
38828
  "openai-agents-core": "openAIAgents",
37983
38829
  openaiagentscore: "openAIAgents",
37984
38830
  google: "google",
38831
+ "google-generative-ai": "googleGenerativeAI",
38832
+ googlegenerativeai: "googleGenerativeAI",
37985
38833
  "google-genai": "googleGenAI",
37986
38834
  googlegenai: "googleGenAI",
37987
38835
  huggingface: "huggingface",
@@ -38015,7 +38863,9 @@ var envIntegrationAliases = {
38015
38863
  langsmith: "langsmith",
38016
38864
  voyage: "voyageai",
38017
38865
  "voyage-ai": "voyageai",
38018
- voyageai: "voyageai"
38866
+ voyageai: "voyageai",
38867
+ elevenlabs: "elevenlabs",
38868
+ "@elevenlabs/elevenlabs-js": "elevenlabs"
38019
38869
  };
38020
38870
  function getDefaultInstrumentationIntegrations() {
38021
38871
  return {
@@ -38026,6 +38876,7 @@ function getDefaultInstrumentationIntegrations() {
38026
38876
  aisdk: true,
38027
38877
  google: true,
38028
38878
  googleGenAI: true,
38879
+ googleGenerativeAI: true,
38029
38880
  googleADK: true,
38030
38881
  huggingface: true,
38031
38882
  claudeAgentSDK: true,
@@ -38051,6 +38902,7 @@ function getDefaultInstrumentationIntegrations() {
38051
38902
  langgraph: true,
38052
38903
  langsmith: true,
38053
38904
  voyageai: true,
38905
+ elevenlabs: true,
38054
38906
  piCodingAgent: true,
38055
38907
  strandsAgentSDK: true,
38056
38908
  cloudflareAgents: true