braintrust 3.29.0 → 3.31.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 (51) hide show
  1. package/dev/dist/index.d.mts +4 -1
  2. package/dev/dist/index.d.ts +4 -1
  3. package/dev/dist/index.js +1492 -887
  4. package/dev/dist/index.mjs +836 -231
  5. package/dist/apply-auto-instrumentation.js +217 -217
  6. package/dist/apply-auto-instrumentation.mjs +2 -2
  7. package/dist/auto-instrumentations/bundler/esbuild.cjs +13 -1
  8. package/dist/auto-instrumentations/bundler/esbuild.mjs +2 -2
  9. package/dist/auto-instrumentations/bundler/next.cjs +22 -4
  10. package/dist/auto-instrumentations/bundler/next.mjs +12 -6
  11. package/dist/auto-instrumentations/bundler/rollup.cjs +13 -1
  12. package/dist/auto-instrumentations/bundler/rollup.mjs +2 -2
  13. package/dist/auto-instrumentations/bundler/vite.cjs +13 -1
  14. package/dist/auto-instrumentations/bundler/vite.mjs +2 -2
  15. package/dist/auto-instrumentations/bundler/webpack-loader.cjs +13 -1
  16. package/dist/auto-instrumentations/bundler/webpack.cjs +13 -1
  17. package/dist/auto-instrumentations/bundler/webpack.mjs +3 -3
  18. package/dist/auto-instrumentations/{chunk-DKTGDNA7.mjs → chunk-LW4HDHXT.mjs} +1 -1
  19. package/dist/auto-instrumentations/{chunk-OMCZ3MV2.mjs → chunk-OXINGIEZ.mjs} +1 -1
  20. package/dist/auto-instrumentations/{chunk-AOIYCVEL.mjs → chunk-U64OYU4Q.mjs} +13 -1
  21. package/dist/auto-instrumentations/hook.mjs +18 -4
  22. package/dist/auto-instrumentations/index.cjs +13 -1
  23. package/dist/auto-instrumentations/index.mjs +1 -1
  24. package/dist/browser.d.mts +614 -480
  25. package/dist/browser.d.ts +614 -480
  26. package/dist/browser.js +1172 -305
  27. package/dist/browser.mjs +1172 -305
  28. package/dist/{chunk-6Z5S7VOU.js → chunk-4AQGZS6X.js} +13 -1
  29. package/dist/{chunk-M6XPNJC4.mjs → chunk-AJT4FR25.mjs} +703 -120
  30. package/dist/{chunk-7FA6VP2S.mjs → chunk-CE3BLB2L.mjs} +13 -1
  31. package/dist/{chunk-XLLGRXGR.js → chunk-V32LW47Z.js} +1819 -1236
  32. package/dist/cli.js +846 -241
  33. package/dist/edge-light.d.mts +1 -1
  34. package/dist/edge-light.d.ts +1 -1
  35. package/dist/edge-light.js +1172 -305
  36. package/dist/edge-light.mjs +1172 -305
  37. package/dist/index.d.mts +614 -480
  38. package/dist/index.d.ts +614 -480
  39. package/dist/index.js +915 -643
  40. package/dist/index.mjs +349 -77
  41. package/dist/instrumentation/index.d.mts +15 -0
  42. package/dist/instrumentation/index.d.ts +15 -0
  43. package/dist/instrumentation/index.js +836 -230
  44. package/dist/instrumentation/index.mjs +836 -230
  45. package/dist/vitest-evals-reporter.js +16 -16
  46. package/dist/vitest-evals-reporter.mjs +2 -2
  47. package/dist/workerd.d.mts +1 -1
  48. package/dist/workerd.d.ts +1 -1
  49. package/dist/workerd.js +1172 -305
  50. package/dist/workerd.mjs +1172 -305
  51. package/package.json +1 -1
@@ -52,7 +52,7 @@ import {
52
52
  strandsAgentSDKChannels,
53
53
  voyageAIChannels,
54
54
  withSpanInstrumentationName
55
- } from "./chunk-7FA6VP2S.mjs";
55
+ } from "./chunk-CE3BLB2L.mjs";
56
56
 
57
57
  // src/id-gen.ts
58
58
  import { v4 as uuidv4 } from "uuid";
@@ -3016,6 +3016,7 @@ var ProjectSettings = z6.union([
3016
3016
  ]),
3017
3017
  disable_realtime_queries: z6.union([z6.boolean(), z6.null()]),
3018
3018
  monitor_charts_use_metrics_start: z6.union([z6.boolean(), z6.null()]),
3019
+ blind_reviews: z6.union([z6.boolean(), z6.null()]),
3019
3020
  default_preprocessor: NullableSavedFunctionId
3020
3021
  }).partial(),
3021
3022
  z6.null()
@@ -3077,6 +3078,7 @@ var WindowedAutomationConfig = z6.object({
3077
3078
  auto_approve_tools: z6.array(z6.string().min(1)).optional().default([]),
3078
3079
  harness: z6.enum(["native", "codex", "claude-code"]).optional(),
3079
3080
  model: z6.string().min(1).optional(),
3081
+ endpoint_name: z6.string().min(1).optional(),
3080
3082
  reasoning_effort: z6.enum(["none", "minimal", "low", "medium", "high", "xhigh", "max"]).optional()
3081
3083
  }).optional(),
3082
3084
  actions: z6.array(
@@ -9030,6 +9032,15 @@ function _internalStartSpanWithInitialMerge(args) {
9030
9032
  [INITIAL_SPAN_WRITE_AS_MERGE]: true
9031
9033
  }).span;
9032
9034
  }
9035
+ function _internalStartSpanWithInitialMergeAndParentSpanIds(args) {
9036
+ return startSpanAndIsLogger(
9037
+ {
9038
+ ...args,
9039
+ [INITIAL_SPAN_WRITE_AS_MERGE]: true
9040
+ },
9041
+ { useParentSpanIdsForObjectParent: true }
9042
+ ).span;
9043
+ }
9033
9044
  function _internalStartSpanWithContext(args, context) {
9034
9045
  return startSpanAndIsLogger({
9035
9046
  ...args,
@@ -9043,7 +9054,7 @@ async function flush(options) {
9043
9054
  function setFetch(fetch2) {
9044
9055
  _internalGetGlobalState().setFetch(fetch2);
9045
9056
  }
9046
- function startSpanAndIsLogger(args) {
9057
+ function startSpanAndIsLogger(args, internalOptions) {
9047
9058
  const state = args?.state ?? _globalState;
9048
9059
  const { parentObject, propagatedState } = getSpanParentObjectAndPropagatedState({
9049
9060
  asyncFlush: args?.asyncFlush,
@@ -9057,7 +9068,7 @@ function startSpanAndIsLogger(args) {
9057
9068
  ) ? {
9058
9069
  spanId: parentObject.data.span_id,
9059
9070
  rootSpanId: parentObject.data.root_span_id
9060
- } : void 0;
9071
+ } : internalOptions?.useParentSpanIdsForObjectParent ? args?.parentSpanIds : void 0;
9061
9072
  const { parent: _ignoredParent, ...spanArgs } = args ?? {};
9062
9073
  const span = new SpanImpl({
9063
9074
  state,
@@ -14978,6 +14989,12 @@ function prepareAISDKChildTracing(params, self, parentSpan, denyOutputPaths, aiS
14978
14989
  if (!activeEntry) {
14979
14990
  return result;
14980
14991
  }
14992
+ const executionOptions = args[1];
14993
+ const toolCallId = isObject(executionOptions) ? executionOptions.toolCallId : void 0;
14994
+ const toolInput = {
14995
+ input: serializeToolExecutionInput(args),
14996
+ ...typeof toolCallId === "string" ? { metadata: { toolCallId } } : {}
14997
+ };
14981
14998
  if (isAsyncGenerator(result)) {
14982
14999
  return (async function* () {
14983
15000
  const span = activeEntry.parentSpan.startSpan(
@@ -14991,7 +15008,7 @@ function prepareAISDKChildTracing(params, self, parentSpan, denyOutputPaths, aiS
14991
15008
  INSTRUMENTATION_NAMES.AI_SDK
14992
15009
  )
14993
15010
  );
14994
- span.log({ input: serializeToolExecutionInput(args) });
15011
+ span.log(toolInput);
14995
15012
  try {
14996
15013
  let lastValue;
14997
15014
  for await (const value of result) {
@@ -15009,7 +15026,7 @@ function prepareAISDKChildTracing(params, self, parentSpan, denyOutputPaths, aiS
15009
15026
  }
15010
15027
  return activeEntry.parentSpan.traced(
15011
15028
  async (span) => {
15012
- span.log({ input: serializeToolExecutionInput(args) });
15029
+ span.log(toolInput);
15013
15030
  const awaitedResult = await result;
15014
15031
  span.log({ output: awaitedResult });
15015
15032
  return awaitedResult;
@@ -18563,14 +18580,17 @@ function getMetricsFromResponse(response) {
18563
18580
  if (!isRecord(usageMetadata)) {
18564
18581
  continue;
18565
18582
  }
18566
- const inputTokenDetails = usageMetadata.input_token_details;
18583
+ const inputTokenDetails = isRecord(usageMetadata.input_token_details) ? usageMetadata.input_token_details : {};
18567
18584
  const outputTokenDetails = usageMetadata.output_token_details;
18568
18585
  return normalizeTokenMetrics({
18569
18586
  total_tokens: usageMetadata.total_tokens,
18570
18587
  prompt_tokens: usageMetadata.input_tokens,
18571
18588
  completion_tokens: usageMetadata.output_tokens,
18572
- prompt_cache_creation_tokens: isRecord(inputTokenDetails) ? inputTokenDetails.cache_creation : void 0,
18573
- prompt_cached_tokens: isRecord(inputTokenDetails) ? inputTokenDetails.cache_read : void 0,
18589
+ // Prefer TTL-specific cache writes over the aggregate when available.
18590
+ prompt_cache_creation_tokens: inputTokenDetails.ephemeral_5m_input_tokens == null && inputTokenDetails.ephemeral_1h_input_tokens == null ? inputTokenDetails.cache_creation : void 0,
18591
+ prompt_cache_creation_5m_tokens: inputTokenDetails.ephemeral_5m_input_tokens,
18592
+ prompt_cache_creation_1h_tokens: inputTokenDetails.ephemeral_1h_input_tokens,
18593
+ prompt_cached_tokens: inputTokenDetails.cache_read,
18574
18594
  completion_reasoning_tokens: isRecord(outputTokenDetails) ? outputTokenDetails.reasoning : void 0
18575
18595
  });
18576
18596
  }
@@ -18593,23 +18613,659 @@ function isRecord(value) {
18593
18613
  return typeof value === "object" && value !== null && !Array.isArray(value);
18594
18614
  }
18595
18615
 
18616
+ // src/instrumentation/plugins/openai-span-data.ts
18617
+ var OPENAI_METADATA_KEYS = [
18618
+ "model",
18619
+ "temperature",
18620
+ "top_p",
18621
+ "max_tokens",
18622
+ "frequency_penalty",
18623
+ "presence_penalty",
18624
+ "stop",
18625
+ "response_format",
18626
+ "tools",
18627
+ "tool_choice",
18628
+ "parallel_tool_calls",
18629
+ "max_tool_calls"
18630
+ ];
18631
+ function batchMetadata(params) {
18632
+ const metadata = { provider: "openai" };
18633
+ for (const key of OPENAI_METADATA_KEYS) {
18634
+ try {
18635
+ const value = Reflect.get(params, key);
18636
+ if (value !== void 0) {
18637
+ metadata[key] = value;
18638
+ }
18639
+ } catch {
18640
+ }
18641
+ }
18642
+ return metadata;
18643
+ }
18644
+ function extractOpenAIBatchInput(endpoint, params) {
18645
+ const input = endpoint === "/v1/chat/completions" ? params.messages : params.input;
18646
+ return {
18647
+ input: processInputAttachments(input),
18648
+ metadata: batchMetadata(params)
18649
+ };
18650
+ }
18651
+ function extractOpenAIChatInput(params) {
18652
+ const { messages, ...metadata } = params;
18653
+ return {
18654
+ input: processInputAttachments(messages),
18655
+ metadata: { ...metadata, provider: "openai" }
18656
+ };
18657
+ }
18658
+ function extractOpenAIResponsesInput(params) {
18659
+ const { input, ...metadata } = params;
18660
+ return {
18661
+ input: processInputAttachments(input),
18662
+ metadata: { ...metadata, provider: "openai" }
18663
+ };
18664
+ }
18665
+ function extractOpenAIResponsesMetadata(result) {
18666
+ if (!result) {
18667
+ return void 0;
18668
+ }
18669
+ const { output: _output, usage: _usage, ...metadata } = result;
18670
+ return Object.keys(metadata).length > 0 ? metadata : void 0;
18671
+ }
18672
+ function processImagesInOutput(output) {
18673
+ if (Array.isArray(output)) {
18674
+ return output.map(processImagesInOutput);
18675
+ }
18676
+ if (isObject(output) && output.type === "image_generation_call" && typeof output.result === "string" && output.result) {
18677
+ const fileExtension = output.output_format || "png";
18678
+ const contentType = `image/${fileExtension}`;
18679
+ const baseFilename = typeof output.revised_prompt === "string" ? output.revised_prompt.slice(0, 50).replace(/[^a-zA-Z0-9]/g, "_") : "generated_image";
18680
+ let binaryString;
18681
+ try {
18682
+ binaryString = atob(output.result);
18683
+ } catch {
18684
+ return output;
18685
+ }
18686
+ const bytes = new Uint8Array(binaryString.length);
18687
+ for (let i = 0; i < binaryString.length; i++) {
18688
+ bytes[i] = binaryString.charCodeAt(i);
18689
+ }
18690
+ return {
18691
+ ...output,
18692
+ result: new Attachment({
18693
+ data: new Blob([bytes], { type: contentType }),
18694
+ filename: `${baseFilename}.${fileExtension}`,
18695
+ contentType
18696
+ })
18697
+ };
18698
+ }
18699
+ return output;
18700
+ }
18701
+
18702
+ // src/instrumentation/plugins/openai-batch-instrumentation.ts
18703
+ var SUPPORTED_ENDPOINTS = /* @__PURE__ */ new Set(["/v1/chat/completions", "/v1/responses"]);
18704
+ var TERMINAL_STATUSES = /* @__PURE__ */ new Set([
18705
+ "completed",
18706
+ "failed",
18707
+ "expired",
18708
+ "cancelled"
18709
+ ]);
18710
+ var pendingBatchTraces = /* @__PURE__ */ new Map();
18711
+ function read(value, key) {
18712
+ if (!isObject(value)) {
18713
+ return void 0;
18714
+ }
18715
+ try {
18716
+ return Reflect.get(value, key);
18717
+ } catch {
18718
+ return void 0;
18719
+ }
18720
+ }
18721
+ function isBatchRecordIterable(value) {
18722
+ if (value === null || typeof value !== "object" && typeof value !== "function") {
18723
+ return false;
18724
+ }
18725
+ return typeof read(value, Symbol.iterator) === "function" || typeof read(value, Symbol.asyncIterator) === "function";
18726
+ }
18727
+ function validCustomId(value) {
18728
+ return typeof value === "string" && value.length > 0 && value.length <= 64;
18729
+ }
18730
+ function logBatchInstrumentationError(context, error) {
18731
+ debugLogger.debug(`OpenAI Batch instrumentation ${context}:`, error);
18732
+ }
18733
+ async function exportParent(parent) {
18734
+ if ("toStr" in parent && typeof parent.toStr === "function") {
18735
+ return parent.toStr();
18736
+ }
18737
+ if ("export" in parent && typeof parent.export === "function") {
18738
+ return await parent.export();
18739
+ }
18740
+ return void 0;
18741
+ }
18742
+ async function deterministicDigest(namespace, ...parts) {
18743
+ const encoded = new TextEncoder().encode(
18744
+ [namespace, ...parts].map((part) => `${part.length}:${part}`).join("\0")
18745
+ );
18746
+ return new Uint8Array(
18747
+ await globalThis.crypto.subtle.digest("SHA-256", encoded)
18748
+ );
18749
+ }
18750
+ function digestHex(bytes, length) {
18751
+ return Array.from(bytes.slice(0, length)).map((byte) => byte.toString(16).padStart(2, "0")).join("");
18752
+ }
18753
+ function digestUuid(bytes) {
18754
+ const hex = digestHex(bytes, 16);
18755
+ return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
18756
+ }
18757
+ async function batchSpanIds(inputFileId) {
18758
+ const [row, span, root] = await Promise.all([
18759
+ deterministicDigest("openai:batch:row", inputFileId),
18760
+ deterministicDigest("openai:batch:span", inputFileId),
18761
+ deterministicDigest("openai:batch:root", inputFileId)
18762
+ ]);
18763
+ return {
18764
+ rowId: digestUuid(row),
18765
+ spanId: digestHex(span, 8),
18766
+ rootSpanId: digestHex(root, 16)
18767
+ };
18768
+ }
18769
+ async function childSpanIds(inputFileId, customId) {
18770
+ const [row, span] = await Promise.all([
18771
+ deterministicDigest("openai:batch:child:row", inputFileId, customId),
18772
+ deterministicDigest("openai:batch:child:span", inputFileId, customId)
18773
+ ]);
18774
+ return { rowId: digestUuid(row), spanId: digestHex(span, 8) };
18775
+ }
18776
+ async function startBatchSpan(context) {
18777
+ const ids = await batchSpanIds(context.inputFileId);
18778
+ const parent = SpanComponentsV4.fromStr(context.parent);
18779
+ const hasParentSpan = Boolean(
18780
+ parent.data.row_id && parent.data.span_id && parent.data.root_span_id
18781
+ );
18782
+ return withCurrent(
18783
+ NOOP_SPAN,
18784
+ () => _internalStartSpanWithInitialMergeAndParentSpanIds(
18785
+ withSpanInstrumentationName(
18786
+ {
18787
+ name: "openai.batch",
18788
+ type: "task" /* TASK */,
18789
+ parent: context.parent,
18790
+ ...!hasParentSpan ? {
18791
+ parentSpanIds: {
18792
+ parentSpanIds: [],
18793
+ rootSpanId: ids.rootSpanId
18794
+ }
18795
+ } : {},
18796
+ spanId: ids.spanId,
18797
+ startTime: context.taskStartTime,
18798
+ event: {
18799
+ id: ids.rowId,
18800
+ metadata: {
18801
+ endpoint: context.endpoint,
18802
+ input_file_id: context.inputFileId,
18803
+ provider: "openai"
18804
+ }
18805
+ }
18806
+ },
18807
+ INSTRUMENTATION_NAMES.OPENAI
18808
+ )
18809
+ )
18810
+ );
18811
+ }
18812
+ async function startBatchChild(context, taskParent, input) {
18813
+ const ids = await childSpanIds(context.inputFileId, input.customId);
18814
+ return withCurrent(
18815
+ NOOP_SPAN,
18816
+ () => _internalStartSpanWithInitialMerge(
18817
+ withSpanInstrumentationName(
18818
+ {
18819
+ name: context.endpoint === "/v1/chat/completions" ? "Chat Completion" : "openai.responses.create",
18820
+ type: "llm" /* LLM */,
18821
+ parent: taskParent,
18822
+ spanId: ids.spanId,
18823
+ startTime: context.childStartTime,
18824
+ event: {
18825
+ id: ids.rowId,
18826
+ ...input.spanData?.input !== void 0 ? { input: input.spanData.input } : {},
18827
+ metadata: {
18828
+ ...input.spanData?.metadata,
18829
+ custom_id: input.customId,
18830
+ provider: "openai"
18831
+ }
18832
+ }
18833
+ },
18834
+ INSTRUMENTATION_NAMES.OPENAI
18835
+ )
18836
+ )
18837
+ );
18838
+ }
18839
+ async function* jsonlRecords(file, onIssue = () => {
18840
+ }) {
18841
+ const resolvedFile = await file;
18842
+ if (typeof resolvedFile === "string") {
18843
+ for (const line of resolvedFile.split("\n")) {
18844
+ if (!line.trim()) {
18845
+ continue;
18846
+ }
18847
+ try {
18848
+ yield JSON.parse(line.replace(/\r$/, ""));
18849
+ } catch (error) {
18850
+ logBatchInstrumentationError("skipped malformed JSONL", error);
18851
+ onIssue(new Error("OpenAI Batch file contains malformed JSONL"));
18852
+ }
18853
+ }
18854
+ return;
18855
+ }
18856
+ const body = read(resolvedFile, "body");
18857
+ const getReader = read(body, "getReader");
18858
+ if (isObject(body) && typeof getReader === "function") {
18859
+ let reader;
18860
+ try {
18861
+ reader = Reflect.apply(getReader, body, []);
18862
+ const decoder = new TextDecoder();
18863
+ let pending = "";
18864
+ while (true) {
18865
+ const readChunk = read(reader, "read");
18866
+ if (typeof readChunk !== "function") {
18867
+ throw new Error("Response body stream has no read method");
18868
+ }
18869
+ const chunk = await Reflect.apply(readChunk, reader, []);
18870
+ if (!isObject(chunk)) {
18871
+ throw new Error("Response body stream returned an invalid chunk");
18872
+ }
18873
+ if (chunk.done === true) {
18874
+ pending += decoder.decode();
18875
+ break;
18876
+ }
18877
+ if (!(chunk.value instanceof Uint8Array)) {
18878
+ throw new Error("Response body stream returned a non-byte chunk");
18879
+ }
18880
+ pending += decoder.decode(chunk.value, { stream: true });
18881
+ let newline = pending.indexOf("\n");
18882
+ while (newline !== -1) {
18883
+ const line = pending.slice(0, newline).replace(/\r$/, "");
18884
+ pending = pending.slice(newline + 1);
18885
+ if (line.trim()) {
18886
+ try {
18887
+ yield JSON.parse(line);
18888
+ } catch (error) {
18889
+ logBatchInstrumentationError("skipped malformed JSONL", error);
18890
+ onIssue(new Error("OpenAI Batch file contains malformed JSONL"));
18891
+ }
18892
+ }
18893
+ newline = pending.indexOf("\n");
18894
+ }
18895
+ }
18896
+ if (pending.trim()) {
18897
+ try {
18898
+ yield JSON.parse(pending.replace(/\r$/, ""));
18899
+ } catch (error) {
18900
+ logBatchInstrumentationError("skipped malformed JSONL", error);
18901
+ onIssue(new Error("OpenAI Batch file contains malformed JSONL"));
18902
+ }
18903
+ }
18904
+ } catch (error) {
18905
+ logBatchInstrumentationError("could not read JSONL response body", error);
18906
+ onIssue(new Error("OpenAI Batch response body could not be read"));
18907
+ } finally {
18908
+ const releaseLock = read(reader, "releaseLock");
18909
+ if (typeof releaseLock === "function") {
18910
+ try {
18911
+ Reflect.apply(releaseLock, reader, []);
18912
+ } catch (error) {
18913
+ logBatchInstrumentationError(
18914
+ "could not release stream reader",
18915
+ error
18916
+ );
18917
+ }
18918
+ }
18919
+ }
18920
+ return;
18921
+ }
18922
+ if (isBatchRecordIterable(resolvedFile)) {
18923
+ for await (const record of resolvedFile) {
18924
+ yield record;
18925
+ }
18926
+ return;
18927
+ }
18928
+ logBatchInstrumentationError("skipped invalid JSONL source", resolvedFile);
18929
+ onIssue(new Error("OpenAI Batch file source is invalid"));
18930
+ }
18931
+ async function readBatchInputs(file) {
18932
+ const inputs = /* @__PURE__ */ new Map();
18933
+ const issues = [];
18934
+ let endpoint;
18935
+ try {
18936
+ for await (const value of jsonlRecords(
18937
+ file,
18938
+ (issue) => issues.push(issue)
18939
+ )) {
18940
+ const customId = read(value, "custom_id");
18941
+ const url = read(value, "url");
18942
+ const body = read(value, "body");
18943
+ if (!validCustomId(customId) || inputs.has(customId) || read(value, "method") !== "POST" || typeof url !== "string" || !SUPPORTED_ENDPOINTS.has(url) || endpoint !== void 0 && endpoint !== url || !isObject(body)) {
18944
+ issues.push(new Error("OpenAI Batch input contains an invalid record"));
18945
+ continue;
18946
+ }
18947
+ endpoint = url;
18948
+ let spanData;
18949
+ try {
18950
+ spanData = extractOpenAIBatchInput(url, body);
18951
+ } catch (error) {
18952
+ logBatchInstrumentationError("could not extract batch input", error);
18953
+ }
18954
+ inputs.set(customId, { customId, spanData });
18955
+ }
18956
+ } catch (error) {
18957
+ logBatchInstrumentationError("could not process input file", error);
18958
+ issues.push(new Error("OpenAI Batch input file could not be processed"));
18959
+ }
18960
+ if (!endpoint || inputs.size === 0) {
18961
+ issues.push(new Error("OpenAI Batch input contains no supported records"));
18962
+ }
18963
+ return { endpoint, inputs, issues };
18964
+ }
18965
+ async function writePendingSpans(trace, endTime) {
18966
+ const task = await startBatchSpan(trace.context);
18967
+ const taskParent = await task.export();
18968
+ for (const input of trace.inputs.values()) {
18969
+ try {
18970
+ const child = await startBatchChild(trace.context, taskParent, input);
18971
+ if (endTime !== void 0) {
18972
+ child.end({ endTime });
18973
+ }
18974
+ } catch (error) {
18975
+ logBatchInstrumentationError("could not write batch request span", error);
18976
+ }
18977
+ }
18978
+ if (endTime !== void 0) {
18979
+ if (trace.status && trace.status !== "completed") {
18980
+ task.log({ error: new Error(`OpenAI Batch ${trace.status}`) });
18981
+ }
18982
+ task.end({ endTime });
18983
+ }
18984
+ }
18985
+ var interceptOpenAIFilesCreateTraced = async (target, thisArg, args) => {
18986
+ const startTime = getCurrentUnixTimestamp();
18987
+ const inputPromise = readBatchInputs(args[0].inputFileContent);
18988
+ const parentPromise = exportParent(args[0].parent);
18989
+ const file = await Reflect.apply(target, thisArg, args);
18990
+ try {
18991
+ const inputFileId = read(file, "id");
18992
+ const [inputData, exportedParent2] = await Promise.all([
18993
+ inputPromise,
18994
+ parentPromise
18995
+ ]);
18996
+ if (typeof inputFileId !== "string" || !exportedParent2 || !inputData.endpoint || inputData.issues.length > 0) {
18997
+ if (inputData.issues[0]) {
18998
+ logBatchInstrumentationError(
18999
+ "skipped invalid input file",
19000
+ inputData.issues[0]
19001
+ );
19002
+ }
19003
+ return file;
19004
+ }
19005
+ const trace = {
19006
+ context: {
19007
+ inputFileId,
19008
+ endpoint: inputData.endpoint,
19009
+ parent: exportedParent2,
19010
+ taskStartTime: startTime,
19011
+ childStartTime: startTime
19012
+ },
19013
+ inputs: inputData.inputs
19014
+ };
19015
+ pendingBatchTraces.set(inputFileId, trace);
19016
+ await writePendingSpans(trace);
19017
+ } catch (error) {
19018
+ logBatchInstrumentationError("could not start batch spans", error);
19019
+ }
19020
+ return file;
19021
+ };
19022
+ function validTimestamp(value) {
19023
+ return typeof value === "number" && Number.isFinite(value) && value >= 0;
19024
+ }
19025
+ function terminalEndTime(batch, startTime) {
19026
+ let timestamp;
19027
+ switch (batch.status) {
19028
+ case "completed":
19029
+ timestamp = batch.completed_at;
19030
+ break;
19031
+ case "failed":
19032
+ timestamp = batch.failed_at;
19033
+ break;
19034
+ case "expired":
19035
+ timestamp = batch.expired_at;
19036
+ break;
19037
+ default:
19038
+ timestamp = batch.cancelled_at;
19039
+ }
19040
+ return validTimestamp(timestamp) ? Math.max(timestamp, startTime) : Math.max(getCurrentUnixTimestamp(), startTime);
19041
+ }
19042
+ async function updateBatchTimestamps(batch) {
19043
+ const trace = pendingBatchTraces.get(batch.input_file_id);
19044
+ if (!trace || trace.context.endpoint !== batch.endpoint) {
19045
+ return;
19046
+ }
19047
+ if (validTimestamp(batch.created_at)) {
19048
+ trace.context.taskStartTime = batch.created_at;
19049
+ }
19050
+ trace.context.childStartTime = validTimestamp(batch.in_progress_at) ? Math.max(batch.in_progress_at, trace.context.taskStartTime) : trace.context.taskStartTime;
19051
+ trace.status = batch.status;
19052
+ if (TERMINAL_STATUSES.has(batch.status)) {
19053
+ trace.endTime = terminalEndTime(batch, trace.context.childStartTime);
19054
+ }
19055
+ await writePendingSpans(trace, trace.endTime);
19056
+ }
19057
+ var interceptOpenAIBatchesRetrieveTraced = (target, thisArg, args) => Promise.resolve(Reflect.apply(target, thisArg, args)).then(async (batch) => {
19058
+ try {
19059
+ await updateBatchTimestamps(batch);
19060
+ } catch (error) {
19061
+ logBatchInstrumentationError("could not update batch timestamps", error);
19062
+ }
19063
+ return batch;
19064
+ });
19065
+ function errorFromResult(result) {
19066
+ const error = read(result.value, "error");
19067
+ if (isObject(error)) {
19068
+ const message = read(error, "message");
19069
+ return new Error(
19070
+ typeof message === "string" ? message : "OpenAI Batch request failed"
19071
+ );
19072
+ }
19073
+ const response = read(result.value, "response");
19074
+ const statusCode = read(response, "status_code");
19075
+ if (result.source === "error" || typeof statusCode === "number" && (statusCode < 200 || statusCode >= 300)) {
19076
+ const message = read(read(read(response, "body"), "error"), "message");
19077
+ return new Error(
19078
+ typeof message === "string" ? message : "OpenAI Batch request failed"
19079
+ );
19080
+ }
19081
+ return void 0;
19082
+ }
19083
+ async function completeBatchResult(context, taskParent, endTime, input, result) {
19084
+ const child = await startBatchChild(context, taskParent, input);
19085
+ try {
19086
+ const resultError = errorFromResult(result);
19087
+ const responseBody = read(read(result.value, "response"), "body");
19088
+ if (resultError) {
19089
+ child.log({ error: resultError });
19090
+ } else if (isObject(responseBody)) {
19091
+ const model = read(responseBody, "model");
19092
+ child.log({
19093
+ output: context.endpoint === "/v1/chat/completions" ? read(responseBody, "choices") : processImagesInOutput(read(responseBody, "output")),
19094
+ ...typeof model === "string" ? { metadata: { model } } : {},
19095
+ metrics: parseMetricsFromUsage(read(responseBody, "usage"))
19096
+ });
19097
+ } else {
19098
+ child.log({ error: new Error("OpenAI Batch response body is missing") });
19099
+ }
19100
+ } catch (error) {
19101
+ child.log({ error });
19102
+ } finally {
19103
+ child.end({ endTime });
19104
+ }
19105
+ }
19106
+ async function completeResultFile({
19107
+ context,
19108
+ endTime,
19109
+ file,
19110
+ inputs,
19111
+ issues,
19112
+ seen,
19113
+ source,
19114
+ taskParent
19115
+ }) {
19116
+ if (file === void 0) {
19117
+ return;
19118
+ }
19119
+ for await (const value of jsonlRecords(file, (issue) => issues.push(issue))) {
19120
+ const customId = read(value, "custom_id");
19121
+ if (!validCustomId(customId) || !isObject(value)) {
19122
+ issues.push(
19123
+ new Error("OpenAI Batch result is missing a valid custom_id")
19124
+ );
19125
+ continue;
19126
+ }
19127
+ if (seen.has(customId)) {
19128
+ issues.push(new Error("OpenAI Batch result contains a duplicate"));
19129
+ continue;
19130
+ }
19131
+ const input = inputs.get(customId);
19132
+ if (!input) {
19133
+ issues.push(
19134
+ new Error("OpenAI Batch result does not match an input record")
19135
+ );
19136
+ continue;
19137
+ }
19138
+ seen.add(customId);
19139
+ await completeBatchResult(context, taskParent, endTime, input, {
19140
+ value,
19141
+ source
19142
+ });
19143
+ }
19144
+ }
19145
+ function sameInputs(first, second) {
19146
+ return first.size === second.size && [...first.keys()].every((customId) => second.has(customId));
19147
+ }
19148
+ async function contextForCompletion(inputFileId, inputData) {
19149
+ if (!inputData.endpoint || inputData.issues.length > 0) {
19150
+ return void 0;
19151
+ }
19152
+ const existing = pendingBatchTraces.get(inputFileId);
19153
+ if (existing) {
19154
+ if (existing.context.endpoint !== inputData.endpoint || !sameInputs(existing.inputs, inputData.inputs)) {
19155
+ return void 0;
19156
+ }
19157
+ return { ...existing, inputs: inputData.inputs };
19158
+ }
19159
+ const parent = await exportParent(getSpanParentObject());
19160
+ if (!parent) {
19161
+ return void 0;
19162
+ }
19163
+ const startTime = getCurrentUnixTimestamp();
19164
+ return {
19165
+ context: {
19166
+ inputFileId,
19167
+ endpoint: inputData.endpoint,
19168
+ parent,
19169
+ taskStartTime: startTime,
19170
+ childStartTime: startTime
19171
+ },
19172
+ inputs: inputData.inputs
19173
+ };
19174
+ }
19175
+ async function completeBatch(args) {
19176
+ const inputData = await readBatchInputs(args.inputFileContent);
19177
+ const trace = await contextForCompletion(args.inputFileId, inputData);
19178
+ if (!trace) {
19179
+ logBatchInstrumentationError(
19180
+ "left batch spans pending",
19181
+ inputData.issues[0] ?? new Error("OpenAI Batch input does not match")
19182
+ );
19183
+ return;
19184
+ }
19185
+ const endTime = trace.endTime ?? getCurrentUnixTimestamp();
19186
+ const task = await startBatchSpan(trace.context);
19187
+ const taskParent = await task.export();
19188
+ const issues = [];
19189
+ const seen = /* @__PURE__ */ new Set();
19190
+ await Promise.all([
19191
+ completeResultFile({
19192
+ context: trace.context,
19193
+ endTime,
19194
+ file: args.outputFileContent,
19195
+ inputs: trace.inputs,
19196
+ issues,
19197
+ seen,
19198
+ source: "output",
19199
+ taskParent
19200
+ }),
19201
+ completeResultFile({
19202
+ context: trace.context,
19203
+ endTime,
19204
+ file: args.errorFileContent,
19205
+ inputs: trace.inputs,
19206
+ issues,
19207
+ seen,
19208
+ source: "error",
19209
+ taskParent
19210
+ })
19211
+ ]);
19212
+ if (issues.length > 0) {
19213
+ logBatchInstrumentationError("left batch spans pending", issues[0]);
19214
+ return;
19215
+ }
19216
+ const missing = [...trace.inputs.values()].filter(
19217
+ ({ customId }) => !seen.has(customId)
19218
+ );
19219
+ if (!trace.status || trace.status === "completed") {
19220
+ if (missing.length > 0) {
19221
+ logBatchInstrumentationError(
19222
+ "left batch spans pending",
19223
+ new Error("OpenAI Batch result files are incomplete")
19224
+ );
19225
+ return;
19226
+ }
19227
+ } else {
19228
+ for (const input of missing) {
19229
+ const child = await startBatchChild(trace.context, taskParent, input);
19230
+ child.log({ error: new Error(`OpenAI Batch ${trace.status}`) });
19231
+ child.end({ endTime });
19232
+ }
19233
+ task.log({ error: new Error(`OpenAI Batch ${trace.status}`) });
19234
+ }
19235
+ task.end({ endTime });
19236
+ pendingBatchTraces.delete(args.inputFileId);
19237
+ }
19238
+ var interceptOpenAIBatchTraceComplete = (target, thisArg, args) => Promise.resolve(Reflect.apply(target, thisArg, args)).then(async (result) => {
19239
+ try {
19240
+ await completeBatch(args[0]);
19241
+ } catch (error) {
19242
+ logBatchInstrumentationError("could not complete batch", error);
19243
+ }
19244
+ return result;
19245
+ });
19246
+
18596
19247
  // src/instrumentation/plugins/openai-plugin.ts
18597
19248
  var OpenAIPlugin = class extends BasePlugin {
18598
19249
  constructor() {
18599
19250
  super();
18600
19251
  }
18601
19252
  onEnable() {
19253
+ this.unsubscribers.push(
19254
+ openAIChannels.filesCreateTraced.intercept(
19255
+ interceptOpenAIFilesCreateTraced
19256
+ ),
19257
+ openAIChannels.batchesRetrieveTraced.intercept(
19258
+ interceptOpenAIBatchesRetrieveTraced
19259
+ ),
19260
+ openAIChannels.batchesCompleteTrace.intercept(
19261
+ interceptOpenAIBatchTraceComplete
19262
+ )
19263
+ );
18602
19264
  this.unsubscribers.push(
18603
19265
  traceStreamingChannel(openAIChannels.chatCompletionsCreate, {
18604
19266
  name: "Chat Completion",
18605
19267
  type: "llm" /* LLM */,
18606
- extractInput: ([params]) => {
18607
- const { messages, ...metadata } = params;
18608
- return {
18609
- input: processInputAttachments(messages),
18610
- metadata: { ...metadata, provider: "openai" }
18611
- };
18612
- },
19268
+ extractInput: ([params]) => extractOpenAIChatInput(params),
18613
19269
  extractOutput: (result) => {
18614
19270
  return result?.choices;
18615
19271
  },
@@ -18655,13 +19311,7 @@ var OpenAIPlugin = class extends BasePlugin {
18655
19311
  traceStreamingChannel(openAIChannels.betaChatCompletionsParse, {
18656
19312
  name: "Chat Completion",
18657
19313
  type: "llm" /* LLM */,
18658
- extractInput: ([params]) => {
18659
- const { messages, ...metadata } = params;
18660
- return {
18661
- input: processInputAttachments(messages),
18662
- metadata: { ...metadata, provider: "openai" }
18663
- };
18664
- },
19314
+ extractInput: ([params]) => extractOpenAIChatInput(params),
18665
19315
  extractOutput: (result) => {
18666
19316
  return result?.choices;
18667
19317
  },
@@ -18683,13 +19333,7 @@ var OpenAIPlugin = class extends BasePlugin {
18683
19333
  traceSyncStreamChannel(openAIChannels.betaChatCompletionsStream, {
18684
19334
  name: "Chat Completion",
18685
19335
  type: "llm" /* LLM */,
18686
- extractInput: ([params]) => {
18687
- const { messages, ...metadata } = params;
18688
- return {
18689
- input: processInputAttachments(messages),
18690
- metadata: { ...metadata, provider: "openai" }
18691
- };
18692
- }
19336
+ extractInput: ([params]) => extractOpenAIChatInput(params)
18693
19337
  })
18694
19338
  );
18695
19339
  this.unsubscribers.push(
@@ -18719,23 +19363,11 @@ var OpenAIPlugin = class extends BasePlugin {
18719
19363
  traceStreamingChannel(openAIChannels.responsesCreate, {
18720
19364
  name: "openai.responses.create",
18721
19365
  type: "llm" /* LLM */,
18722
- extractInput: ([params]) => {
18723
- const { input, ...metadata } = params;
18724
- return {
18725
- input: processInputAttachments(input),
18726
- metadata: { ...metadata, provider: "openai" }
18727
- };
18728
- },
19366
+ extractInput: ([params]) => extractOpenAIResponsesInput(params),
18729
19367
  extractOutput: (result) => {
18730
19368
  return processImagesInOutput(result?.output);
18731
19369
  },
18732
- extractMetadata: (result) => {
18733
- if (!result) {
18734
- return void 0;
18735
- }
18736
- const { output: _output, usage: _usage, ...metadata } = result;
18737
- return Object.keys(metadata).length > 0 ? metadata : void 0;
18738
- },
19370
+ extractMetadata: (result) => extractOpenAIResponsesMetadata(result),
18739
19371
  extractMetrics: (result, startTime, endEvent) => {
18740
19372
  const metrics = withCachedMetric(
18741
19373
  parseMetricsFromUsage(result?.usage),
@@ -18754,13 +19386,7 @@ var OpenAIPlugin = class extends BasePlugin {
18754
19386
  traceSyncStreamChannel(openAIChannels.responsesStream, {
18755
19387
  name: "openai.responses.create",
18756
19388
  type: "llm" /* LLM */,
18757
- extractInput: ([params]) => {
18758
- const { input, ...metadata } = params;
18759
- return {
18760
- input: processInputAttachments(input),
18761
- metadata: { ...metadata, provider: "openai" }
18762
- };
18763
- },
19389
+ extractInput: ([params]) => extractOpenAIResponsesInput(params),
18764
19390
  extractFromEvent: (event) => {
18765
19391
  if (event.type !== "response.completed" || !event.response) {
18766
19392
  return {};
@@ -18783,23 +19409,11 @@ var OpenAIPlugin = class extends BasePlugin {
18783
19409
  traceStreamingChannel(openAIChannels.responsesParse, {
18784
19410
  name: "openai.responses.parse",
18785
19411
  type: "llm" /* LLM */,
18786
- extractInput: ([params]) => {
18787
- const { input, ...metadata } = params;
18788
- return {
18789
- input: processInputAttachments(input),
18790
- metadata: { ...metadata, provider: "openai" }
18791
- };
18792
- },
19412
+ extractInput: ([params]) => extractOpenAIResponsesInput(params),
18793
19413
  extractOutput: (result) => {
18794
19414
  return processImagesInOutput(result?.output);
18795
19415
  },
18796
- extractMetadata: (result) => {
18797
- if (!result) {
18798
- return void 0;
18799
- }
18800
- const { output: _output, usage: _usage, ...metadata } = result;
18801
- return Object.keys(metadata).length > 0 ? metadata : void 0;
18802
- },
19416
+ extractMetadata: (result) => extractOpenAIResponsesMetadata(result),
18803
19417
  extractMetrics: (result, startTime, endEvent) => {
18804
19418
  const metrics = withCachedMetric(
18805
19419
  parseMetricsFromUsage(result?.usage),
@@ -18818,23 +19432,11 @@ var OpenAIPlugin = class extends BasePlugin {
18818
19432
  traceAsyncChannel(openAIChannels.responsesCompact, {
18819
19433
  name: "openai.responses.compact",
18820
19434
  type: "llm" /* LLM */,
18821
- extractInput: ([params]) => {
18822
- const { input, ...metadata } = params;
18823
- return {
18824
- input: processInputAttachments(input),
18825
- metadata: { ...metadata, provider: "openai" }
18826
- };
18827
- },
19435
+ extractInput: ([params]) => extractOpenAIResponsesInput(params),
18828
19436
  extractOutput: (result) => {
18829
19437
  return processImagesInOutput(result?.output);
18830
19438
  },
18831
- extractMetadata: (result) => {
18832
- if (!result) {
18833
- return void 0;
18834
- }
18835
- const { output: _output, usage: _usage, ...metadata } = result;
18836
- return Object.keys(metadata).length > 0 ? metadata : void 0;
18837
- },
19439
+ extractMetadata: (result) => extractOpenAIResponsesMetadata(result),
18838
19440
  extractMetrics: (result, startTime, endEvent) => {
18839
19441
  const metrics = withCachedMetric(
18840
19442
  parseMetricsFromUsage(result?.usage),
@@ -18890,35 +19492,6 @@ function withCachedMetric(metrics, result, endEvent) {
18890
19492
  cached
18891
19493
  };
18892
19494
  }
18893
- function processImagesInOutput(output) {
18894
- if (Array.isArray(output)) {
18895
- return output.map(processImagesInOutput);
18896
- }
18897
- if (isObject(output)) {
18898
- if (output.type === "image_generation_call" && output.result && typeof output.result === "string") {
18899
- const fileExtension = output.output_format || "png";
18900
- const contentType = `image/${fileExtension}`;
18901
- const baseFilename = output.revised_prompt && typeof output.revised_prompt === "string" ? output.revised_prompt.slice(0, 50).replace(/[^a-zA-Z0-9]/g, "_") : "generated_image";
18902
- const filename = `${baseFilename}.${fileExtension}`;
18903
- const binaryString = atob(output.result);
18904
- const bytes = new Uint8Array(binaryString.length);
18905
- for (let i = 0; i < binaryString.length; i++) {
18906
- bytes[i] = binaryString.charCodeAt(i);
18907
- }
18908
- const blob = new Blob([bytes], { type: contentType });
18909
- const attachment = new Attachment({
18910
- data: blob,
18911
- filename,
18912
- contentType
18913
- });
18914
- return {
18915
- ...output,
18916
- result: attachment
18917
- };
18918
- }
18919
- }
18920
- return output;
18921
- }
18922
19495
  function mergeLogprobTokens(existing, incoming) {
18923
19496
  if (incoming === void 0) {
18924
19497
  return existing;
@@ -32442,7 +33015,7 @@ function extractSession(event) {
32442
33015
  return isObject(candidate) && typeof candidate.prompt === "function" ? candidate : void 0;
32443
33016
  }
32444
33017
  function isPiAgent(value) {
32445
- return isObject(value) && typeof value.streamFn === "function" && typeof value.subscribe === "function";
33018
+ return isObject(value) && (typeof value.streamFunction === "function" || typeof value.streamFn === "function") && typeof value.subscribe === "function";
32446
33019
  }
32447
33020
  function promptContextStore() {
32448
33021
  piPromptContextStore ??= isomorph_default.newAsyncLocalStorage();
@@ -32452,17 +33025,21 @@ function currentPiPromptState() {
32452
33025
  return promptContextStore().getStore();
32453
33026
  }
32454
33027
  function installPiAgentInstrumentation(agent) {
33028
+ const property = typeof agent.streamFunction === "function" ? "streamFunction" : "streamFn";
33029
+ const streamFunction = agent[property];
32455
33030
  const existing = piAgentPatchStates.get(agent);
32456
- if (!existing || agent.streamFn !== existing.wrappedStreamFn) {
33031
+ if (streamFunction && (!existing || existing.property !== property || streamFunction !== existing.wrappedStreamFunction)) {
32457
33032
  const patchState = {
32458
- originalStreamFn: agent.streamFn,
32459
- wrappedStreamFn: agent.streamFn
33033
+ originalStreamFunction: streamFunction,
33034
+ property,
33035
+ wrappedStreamFunction: streamFunction
32460
33036
  };
32461
- patchState.wrappedStreamFn = makeInstrumentedStreamFn(
33037
+ patchState.wrappedStreamFunction = makeInstrumentedStreamFunction(
32462
33038
  agent,
32463
- patchState.originalStreamFn
33039
+ patchState.originalStreamFunction,
33040
+ property
32464
33041
  );
32465
- agent.streamFn = patchState.wrappedStreamFn;
33042
+ agent[property] = patchState.wrappedStreamFunction;
32466
33043
  piAgentPatchStates.set(agent, patchState);
32467
33044
  }
32468
33045
  if (piAgentEventSubscriptions.has(agent)) {
@@ -32487,15 +33064,21 @@ function installPiAgentInstrumentation(agent) {
32487
33064
  logInstrumentationError4("Pi Coding Agent event subscription", error);
32488
33065
  }
32489
33066
  }
32490
- function makeInstrumentedStreamFn(agent, originalStreamFn) {
32491
- return async function instrumentedPiStreamFn(model, context, options) {
32492
- const invokeOriginal = () => Reflect.apply(originalStreamFn, this, [model, context, options]);
33067
+ function makeInstrumentedStreamFunction(agent, originalStreamFunction, property) {
33068
+ return async function instrumentedPiStreamFunction(model, context, options) {
33069
+ const invokeOriginal = () => Reflect.apply(originalStreamFunction, this, [model, context, options]);
32493
33070
  const state = currentPiPromptState();
32494
33071
  if (!state || state.agent !== agent || state.finalized) {
32495
33072
  return invokeOriginal();
32496
33073
  }
32497
33074
  wrapPiToolExecutors(context.tools);
32498
- const llmState = await startPiLlmSpan(state, model, context, options);
33075
+ const llmState = await startPiLlmSpan(
33076
+ state,
33077
+ model,
33078
+ context,
33079
+ property,
33080
+ options
33081
+ );
32499
33082
  try {
32500
33083
  const stream = await runWithAutoInstrumentationSuppressed(invokeOriginal);
32501
33084
  return patchAssistantMessageStream(stream, state, llmState);
@@ -32532,12 +33115,12 @@ function wrapPiToolExecutors(tools) {
32532
33115
  }
32533
33116
  }
32534
33117
  }
32535
- async function startPiLlmSpan(state, model, context, options) {
33118
+ async function startPiLlmSpan(state, model, context, property, options) {
32536
33119
  const metadata = {
32537
33120
  ...extractModelMetadata2(model),
32538
33121
  ...extractStreamOptionsMetadata(options),
32539
33122
  ...extractToolMetadata(context.tools),
32540
- "pi_coding_agent.operation": "agent.streamFn"
33123
+ "pi_coding_agent.operation": `agent.${property}`
32541
33124
  };
32542
33125
  const span = startSpan(
32543
33126
  withSpanInstrumentationName(