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
package/dist/browser.mjs CHANGED
@@ -3818,6 +3818,7 @@ var ProjectSettings = z6.union([
3818
3818
  ]),
3819
3819
  disable_realtime_queries: z6.union([z6.boolean(), z6.null()]),
3820
3820
  monitor_charts_use_metrics_start: z6.union([z6.boolean(), z6.null()]),
3821
+ blind_reviews: z6.union([z6.boolean(), z6.null()]),
3821
3822
  default_preprocessor: NullableSavedFunctionId
3822
3823
  }).partial(),
3823
3824
  z6.null()
@@ -3879,6 +3880,7 @@ var WindowedAutomationConfig = z6.object({
3879
3880
  auto_approve_tools: z6.array(z6.string().min(1)).optional().default([]),
3880
3881
  harness: z6.enum(["native", "codex", "claude-code"]).optional(),
3881
3882
  model: z6.string().min(1).optional(),
3883
+ endpoint_name: z6.string().min(1).optional(),
3882
3884
  reasoning_effort: z6.enum(["none", "minimal", "low", "medium", "high", "xhigh", "max"]).optional()
3883
3885
  }).optional(),
3884
3886
  actions: z6.array(
@@ -5672,7 +5674,7 @@ var INSTRUMENTATION_NAMES = {
5672
5674
  var INTERNAL_SPAN_INSTRUMENTATION_NAME = /* @__PURE__ */ Symbol.for(
5673
5675
  "braintrust.spanInstrumentationName"
5674
5676
  );
5675
- var SDK_VERSION = true ? "3.29.0" : "0.0.0";
5677
+ var SDK_VERSION = true ? "3.31.0" : "0.0.0";
5676
5678
  function withSpanInstrumentationName(args, instrumentationName) {
5677
5679
  return {
5678
5680
  ...args,
@@ -9919,6 +9921,15 @@ function _internalStartSpanWithInitialMerge(args) {
9919
9921
  [INITIAL_SPAN_WRITE_AS_MERGE]: true
9920
9922
  }).span;
9921
9923
  }
9924
+ function _internalStartSpanWithInitialMergeAndParentSpanIds(args) {
9925
+ return startSpanAndIsLogger(
9926
+ {
9927
+ ...args,
9928
+ [INITIAL_SPAN_WRITE_AS_MERGE]: true
9929
+ },
9930
+ { useParentSpanIdsForObjectParent: true }
9931
+ ).span;
9932
+ }
9922
9933
  function _internalStartSpanWithContext(args, context) {
9923
9934
  return startSpanAndIsLogger({
9924
9935
  ...args,
@@ -9932,7 +9943,7 @@ async function flush(options) {
9932
9943
  function setFetch(fetch2) {
9933
9944
  _internalGetGlobalState().setFetch(fetch2);
9934
9945
  }
9935
- function startSpanAndIsLogger(args) {
9946
+ function startSpanAndIsLogger(args, internalOptions) {
9936
9947
  const state = args?.state ?? _globalState;
9937
9948
  const { parentObject, propagatedState } = getSpanParentObjectAndPropagatedState({
9938
9949
  asyncFlush: args?.asyncFlush,
@@ -9946,7 +9957,7 @@ function startSpanAndIsLogger(args) {
9946
9957
  ) ? {
9947
9958
  spanId: parentObject.data.span_id,
9948
9959
  rootSpanId: parentObject.data.root_span_id
9949
- } : void 0;
9960
+ } : internalOptions?.useParentSpanIdsForObjectParent ? args?.parentSpanIds : void 0;
9950
9961
  const { parent: _ignoredParent, ...spanArgs } = args ?? {};
9951
9962
  const span = new SpanImpl({
9952
9963
  state,
@@ -13390,6 +13401,131 @@ function unsubscribeAll(unsubscribers) {
13390
13401
  return [];
13391
13402
  }
13392
13403
 
13404
+ // src/instrumentation/core/channel-definitions.ts
13405
+ function channel(spec) {
13406
+ return spec;
13407
+ }
13408
+ function defineChannels(pkg, channels, options) {
13409
+ const { instrumentationName } = options;
13410
+ return Object.fromEntries(
13411
+ Object.entries(channels).map(([key, spec]) => {
13412
+ const fullChannelName = `orchestrion:${pkg}:${spec.channelName}`;
13413
+ if (spec.kind === "async") {
13414
+ const asyncSpec = spec;
13415
+ const tracingChannel2 = () => isomorph_default.newTracingChannel(
13416
+ fullChannelName
13417
+ );
13418
+ const intercept2 = (interceptor) => {
13419
+ const hook = tracingChannel2();
13420
+ return typeof hook.intercept === "function" ? hook.intercept(interceptor) : () => {
13421
+ };
13422
+ };
13423
+ return [
13424
+ key,
13425
+ {
13426
+ ...asyncSpec,
13427
+ instrumentationName,
13428
+ intercept: intercept2,
13429
+ invoke: (target, thisArg, args, additional) => {
13430
+ const hook = tracingChannel2();
13431
+ return typeof hook.invoke === "function" ? hook.invoke(target, thisArg, args, additional) : Reflect.apply(target, thisArg, args);
13432
+ },
13433
+ tracingChannel: tracingChannel2,
13434
+ tracePromise: (fn, context) => tracingChannel2().tracePromise(
13435
+ fn,
13436
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
13437
+ context
13438
+ )
13439
+ }
13440
+ ];
13441
+ }
13442
+ const syncSpec = spec;
13443
+ const tracingChannel = () => isomorph_default.newTracingChannel(
13444
+ fullChannelName
13445
+ );
13446
+ const intercept = (interceptor) => {
13447
+ const hook = tracingChannel();
13448
+ return typeof hook.intercept === "function" ? hook.intercept(interceptor) : () => {
13449
+ };
13450
+ };
13451
+ return [
13452
+ key,
13453
+ {
13454
+ ...syncSpec,
13455
+ instrumentationName,
13456
+ intercept,
13457
+ invoke: (target, thisArg, args, additional) => {
13458
+ const hook = tracingChannel();
13459
+ return typeof hook.invoke === "function" ? hook.invoke(target, thisArg, args, additional) : Reflect.apply(target, thisArg, args);
13460
+ },
13461
+ tracingChannel,
13462
+ traceSync: (fn, context) => tracingChannel().traceSync(
13463
+ fn,
13464
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
13465
+ context
13466
+ )
13467
+ }
13468
+ ];
13469
+ })
13470
+ );
13471
+ }
13472
+
13473
+ // src/instrumentation/plugins/openai-channels.ts
13474
+ var openAIChannels = defineChannels(
13475
+ "openai",
13476
+ {
13477
+ filesCreateTraced: channel({
13478
+ channelName: "files.create-traced",
13479
+ kind: "async"
13480
+ }),
13481
+ batchesRetrieveTraced: channel({
13482
+ channelName: "batches.retrieve-traced",
13483
+ kind: "async"
13484
+ }),
13485
+ batchesCompleteTrace: channel({
13486
+ channelName: "batches.complete-trace",
13487
+ kind: "async"
13488
+ }),
13489
+ chatCompletionsCreate: channel({
13490
+ channelName: "chat.completions.create",
13491
+ kind: "async"
13492
+ }),
13493
+ embeddingsCreate: channel({
13494
+ channelName: "embeddings.create",
13495
+ kind: "async"
13496
+ }),
13497
+ betaChatCompletionsParse: channel({
13498
+ channelName: "beta.chat.completions.parse",
13499
+ kind: "async"
13500
+ }),
13501
+ betaChatCompletionsStream: channel({
13502
+ channelName: "beta.chat.completions.stream",
13503
+ kind: "sync-stream"
13504
+ }),
13505
+ moderationsCreate: channel({
13506
+ channelName: "moderations.create",
13507
+ kind: "async"
13508
+ }),
13509
+ responsesCreate: channel({
13510
+ channelName: "responses.create",
13511
+ kind: "async"
13512
+ }),
13513
+ responsesStream: channel({
13514
+ channelName: "responses.stream",
13515
+ kind: "sync-stream"
13516
+ }),
13517
+ responsesParse: channel({
13518
+ channelName: "responses.parse",
13519
+ kind: "async"
13520
+ }),
13521
+ responsesCompact: channel({
13522
+ channelName: "responses.compact",
13523
+ kind: "async"
13524
+ })
13525
+ },
13526
+ { instrumentationName: INSTRUMENTATION_NAMES.OPENAI }
13527
+ );
13528
+
13393
13529
  // src/wrappers/attachment-utils.ts
13394
13530
  function getExtensionFromMediaType(mediaType) {
13395
13531
  const extensionMap = {
@@ -13565,118 +13701,91 @@ function processInputAttachments(input) {
13565
13701
  return processNode(input);
13566
13702
  }
13567
13703
 
13568
- // src/instrumentation/core/channel-definitions.ts
13569
- function channel(spec) {
13570
- return spec;
13571
- }
13572
- function defineChannels(pkg, channels, options) {
13573
- const { instrumentationName } = options;
13574
- return Object.fromEntries(
13575
- Object.entries(channels).map(([key, spec]) => {
13576
- const fullChannelName = `orchestrion:${pkg}:${spec.channelName}`;
13577
- if (spec.kind === "async") {
13578
- const asyncSpec = spec;
13579
- const tracingChannel2 = () => isomorph_default.newTracingChannel(
13580
- fullChannelName
13581
- );
13582
- const intercept2 = (interceptor) => {
13583
- const hook = tracingChannel2();
13584
- return typeof hook.intercept === "function" ? hook.intercept(interceptor) : () => {
13585
- };
13586
- };
13587
- return [
13588
- key,
13589
- {
13590
- ...asyncSpec,
13591
- instrumentationName,
13592
- intercept: intercept2,
13593
- invoke: (target, thisArg, args, additional) => {
13594
- const hook = tracingChannel2();
13595
- return typeof hook.invoke === "function" ? hook.invoke(target, thisArg, args, additional) : Reflect.apply(target, thisArg, args);
13596
- },
13597
- tracingChannel: tracingChannel2,
13598
- tracePromise: (fn, context) => tracingChannel2().tracePromise(
13599
- fn,
13600
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
13601
- context
13602
- )
13603
- }
13604
- ];
13704
+ // src/instrumentation/plugins/openai-span-data.ts
13705
+ var OPENAI_METADATA_KEYS = [
13706
+ "model",
13707
+ "temperature",
13708
+ "top_p",
13709
+ "max_tokens",
13710
+ "frequency_penalty",
13711
+ "presence_penalty",
13712
+ "stop",
13713
+ "response_format",
13714
+ "tools",
13715
+ "tool_choice",
13716
+ "parallel_tool_calls",
13717
+ "max_tool_calls"
13718
+ ];
13719
+ function batchMetadata(params) {
13720
+ const metadata = { provider: "openai" };
13721
+ for (const key of OPENAI_METADATA_KEYS) {
13722
+ try {
13723
+ const value = Reflect.get(params, key);
13724
+ if (value !== void 0) {
13725
+ metadata[key] = value;
13605
13726
  }
13606
- const syncSpec = spec;
13607
- const tracingChannel = () => isomorph_default.newTracingChannel(
13608
- fullChannelName
13609
- );
13610
- const intercept = (interceptor) => {
13611
- const hook = tracingChannel();
13612
- return typeof hook.intercept === "function" ? hook.intercept(interceptor) : () => {
13613
- };
13614
- };
13615
- return [
13616
- key,
13617
- {
13618
- ...syncSpec,
13619
- instrumentationName,
13620
- intercept,
13621
- invoke: (target, thisArg, args, additional) => {
13622
- const hook = tracingChannel();
13623
- return typeof hook.invoke === "function" ? hook.invoke(target, thisArg, args, additional) : Reflect.apply(target, thisArg, args);
13624
- },
13625
- tracingChannel,
13626
- traceSync: (fn, context) => tracingChannel().traceSync(
13627
- fn,
13628
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
13629
- context
13630
- )
13631
- }
13632
- ];
13633
- })
13634
- );
13727
+ } catch {
13728
+ }
13729
+ }
13730
+ return metadata;
13731
+ }
13732
+ function extractOpenAIBatchInput(endpoint, params) {
13733
+ const input = endpoint === "/v1/chat/completions" ? params.messages : params.input;
13734
+ return {
13735
+ input: processInputAttachments(input),
13736
+ metadata: batchMetadata(params)
13737
+ };
13738
+ }
13739
+ function extractOpenAIChatInput(params) {
13740
+ const { messages, ...metadata } = params;
13741
+ return {
13742
+ input: processInputAttachments(messages),
13743
+ metadata: { ...metadata, provider: "openai" }
13744
+ };
13745
+ }
13746
+ function extractOpenAIResponsesInput(params) {
13747
+ const { input, ...metadata } = params;
13748
+ return {
13749
+ input: processInputAttachments(input),
13750
+ metadata: { ...metadata, provider: "openai" }
13751
+ };
13752
+ }
13753
+ function extractOpenAIResponsesMetadata(result) {
13754
+ if (!result) {
13755
+ return void 0;
13756
+ }
13757
+ const { output: _output, usage: _usage, ...metadata } = result;
13758
+ return Object.keys(metadata).length > 0 ? metadata : void 0;
13759
+ }
13760
+ function processImagesInOutput(output) {
13761
+ if (Array.isArray(output)) {
13762
+ return output.map(processImagesInOutput);
13763
+ }
13764
+ if (isObject(output) && output.type === "image_generation_call" && typeof output.result === "string" && output.result) {
13765
+ const fileExtension = output.output_format || "png";
13766
+ const contentType = `image/${fileExtension}`;
13767
+ const baseFilename = typeof output.revised_prompt === "string" ? output.revised_prompt.slice(0, 50).replace(/[^a-zA-Z0-9]/g, "_") : "generated_image";
13768
+ let binaryString;
13769
+ try {
13770
+ binaryString = atob(output.result);
13771
+ } catch {
13772
+ return output;
13773
+ }
13774
+ const bytes = new Uint8Array(binaryString.length);
13775
+ for (let i = 0; i < binaryString.length; i++) {
13776
+ bytes[i] = binaryString.charCodeAt(i);
13777
+ }
13778
+ return {
13779
+ ...output,
13780
+ result: new Attachment({
13781
+ data: new Blob([bytes], { type: contentType }),
13782
+ filename: `${baseFilename}.${fileExtension}`,
13783
+ contentType
13784
+ })
13785
+ };
13786
+ }
13787
+ return output;
13635
13788
  }
13636
-
13637
- // src/instrumentation/plugins/openai-channels.ts
13638
- var openAIChannels = defineChannels(
13639
- "openai",
13640
- {
13641
- chatCompletionsCreate: channel({
13642
- channelName: "chat.completions.create",
13643
- kind: "async"
13644
- }),
13645
- embeddingsCreate: channel({
13646
- channelName: "embeddings.create",
13647
- kind: "async"
13648
- }),
13649
- betaChatCompletionsParse: channel({
13650
- channelName: "beta.chat.completions.parse",
13651
- kind: "async"
13652
- }),
13653
- betaChatCompletionsStream: channel({
13654
- channelName: "beta.chat.completions.stream",
13655
- kind: "sync-stream"
13656
- }),
13657
- moderationsCreate: channel({
13658
- channelName: "moderations.create",
13659
- kind: "async"
13660
- }),
13661
- responsesCreate: channel({
13662
- channelName: "responses.create",
13663
- kind: "async"
13664
- }),
13665
- responsesStream: channel({
13666
- channelName: "responses.stream",
13667
- kind: "sync-stream"
13668
- }),
13669
- responsesParse: channel({
13670
- channelName: "responses.parse",
13671
- kind: "async"
13672
- }),
13673
- responsesCompact: channel({
13674
- channelName: "responses.compact",
13675
- kind: "async"
13676
- })
13677
- },
13678
- { instrumentationName: INSTRUMENTATION_NAMES.OPENAI }
13679
- );
13680
13789
 
13681
13790
  // src/openai-utils.ts
13682
13791
  var BRAINTRUST_CACHED_STREAM_METRIC = "__braintrust_cached_metric";
@@ -13733,23 +13842,573 @@ function getCachedMetricFromHeaders(headers) {
13733
13842
  return parseCachedHeader(headers.get(LEGACY_CACHED_HEADER));
13734
13843
  }
13735
13844
 
13845
+ // src/instrumentation/plugins/openai-batch-instrumentation.ts
13846
+ var SUPPORTED_ENDPOINTS = /* @__PURE__ */ new Set(["/v1/chat/completions", "/v1/responses"]);
13847
+ var TERMINAL_STATUSES = /* @__PURE__ */ new Set([
13848
+ "completed",
13849
+ "failed",
13850
+ "expired",
13851
+ "cancelled"
13852
+ ]);
13853
+ var pendingBatchTraces = /* @__PURE__ */ new Map();
13854
+ function read(value, key) {
13855
+ if (!isObject(value)) {
13856
+ return void 0;
13857
+ }
13858
+ try {
13859
+ return Reflect.get(value, key);
13860
+ } catch {
13861
+ return void 0;
13862
+ }
13863
+ }
13864
+ function isBatchRecordIterable(value) {
13865
+ if (value === null || typeof value !== "object" && typeof value !== "function") {
13866
+ return false;
13867
+ }
13868
+ return typeof read(value, Symbol.iterator) === "function" || typeof read(value, Symbol.asyncIterator) === "function";
13869
+ }
13870
+ function validCustomId(value) {
13871
+ return typeof value === "string" && value.length > 0 && value.length <= 64;
13872
+ }
13873
+ function logBatchInstrumentationError(context, error) {
13874
+ debugLogger.debug(`OpenAI Batch instrumentation ${context}:`, error);
13875
+ }
13876
+ async function exportParent(parent) {
13877
+ if ("toStr" in parent && typeof parent.toStr === "function") {
13878
+ return parent.toStr();
13879
+ }
13880
+ if ("export" in parent && typeof parent.export === "function") {
13881
+ return await parent.export();
13882
+ }
13883
+ return void 0;
13884
+ }
13885
+ async function deterministicDigest(namespace, ...parts) {
13886
+ const encoded = new TextEncoder().encode(
13887
+ [namespace, ...parts].map((part) => `${part.length}:${part}`).join("\0")
13888
+ );
13889
+ return new Uint8Array(
13890
+ await globalThis.crypto.subtle.digest("SHA-256", encoded)
13891
+ );
13892
+ }
13893
+ function digestHex(bytes, length) {
13894
+ return Array.from(bytes.slice(0, length)).map((byte) => byte.toString(16).padStart(2, "0")).join("");
13895
+ }
13896
+ function digestUuid(bytes) {
13897
+ const hex = digestHex(bytes, 16);
13898
+ return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
13899
+ }
13900
+ async function batchSpanIds(inputFileId) {
13901
+ const [row, span, root] = await Promise.all([
13902
+ deterministicDigest("openai:batch:row", inputFileId),
13903
+ deterministicDigest("openai:batch:span", inputFileId),
13904
+ deterministicDigest("openai:batch:root", inputFileId)
13905
+ ]);
13906
+ return {
13907
+ rowId: digestUuid(row),
13908
+ spanId: digestHex(span, 8),
13909
+ rootSpanId: digestHex(root, 16)
13910
+ };
13911
+ }
13912
+ async function childSpanIds(inputFileId, customId) {
13913
+ const [row, span] = await Promise.all([
13914
+ deterministicDigest("openai:batch:child:row", inputFileId, customId),
13915
+ deterministicDigest("openai:batch:child:span", inputFileId, customId)
13916
+ ]);
13917
+ return { rowId: digestUuid(row), spanId: digestHex(span, 8) };
13918
+ }
13919
+ async function startBatchSpan(context) {
13920
+ const ids = await batchSpanIds(context.inputFileId);
13921
+ const parent = SpanComponentsV4.fromStr(context.parent);
13922
+ const hasParentSpan = Boolean(
13923
+ parent.data.row_id && parent.data.span_id && parent.data.root_span_id
13924
+ );
13925
+ return withCurrent(
13926
+ NOOP_SPAN,
13927
+ () => _internalStartSpanWithInitialMergeAndParentSpanIds(
13928
+ withSpanInstrumentationName(
13929
+ {
13930
+ name: "openai.batch",
13931
+ type: "task" /* TASK */,
13932
+ parent: context.parent,
13933
+ ...!hasParentSpan ? {
13934
+ parentSpanIds: {
13935
+ parentSpanIds: [],
13936
+ rootSpanId: ids.rootSpanId
13937
+ }
13938
+ } : {},
13939
+ spanId: ids.spanId,
13940
+ startTime: context.taskStartTime,
13941
+ event: {
13942
+ id: ids.rowId,
13943
+ metadata: {
13944
+ endpoint: context.endpoint,
13945
+ input_file_id: context.inputFileId,
13946
+ provider: "openai"
13947
+ }
13948
+ }
13949
+ },
13950
+ INSTRUMENTATION_NAMES.OPENAI
13951
+ )
13952
+ )
13953
+ );
13954
+ }
13955
+ async function startBatchChild(context, taskParent, input) {
13956
+ const ids = await childSpanIds(context.inputFileId, input.customId);
13957
+ return withCurrent(
13958
+ NOOP_SPAN,
13959
+ () => _internalStartSpanWithInitialMerge(
13960
+ withSpanInstrumentationName(
13961
+ {
13962
+ name: context.endpoint === "/v1/chat/completions" ? "Chat Completion" : "openai.responses.create",
13963
+ type: "llm" /* LLM */,
13964
+ parent: taskParent,
13965
+ spanId: ids.spanId,
13966
+ startTime: context.childStartTime,
13967
+ event: {
13968
+ id: ids.rowId,
13969
+ ...input.spanData?.input !== void 0 ? { input: input.spanData.input } : {},
13970
+ metadata: {
13971
+ ...input.spanData?.metadata,
13972
+ custom_id: input.customId,
13973
+ provider: "openai"
13974
+ }
13975
+ }
13976
+ },
13977
+ INSTRUMENTATION_NAMES.OPENAI
13978
+ )
13979
+ )
13980
+ );
13981
+ }
13982
+ async function* jsonlRecords(file, onIssue = () => {
13983
+ }) {
13984
+ const resolvedFile = await file;
13985
+ if (typeof resolvedFile === "string") {
13986
+ for (const line of resolvedFile.split("\n")) {
13987
+ if (!line.trim()) {
13988
+ continue;
13989
+ }
13990
+ try {
13991
+ yield JSON.parse(line.replace(/\r$/, ""));
13992
+ } catch (error) {
13993
+ logBatchInstrumentationError("skipped malformed JSONL", error);
13994
+ onIssue(new Error("OpenAI Batch file contains malformed JSONL"));
13995
+ }
13996
+ }
13997
+ return;
13998
+ }
13999
+ const body = read(resolvedFile, "body");
14000
+ const getReader = read(body, "getReader");
14001
+ if (isObject(body) && typeof getReader === "function") {
14002
+ let reader;
14003
+ try {
14004
+ reader = Reflect.apply(getReader, body, []);
14005
+ const decoder2 = new TextDecoder();
14006
+ let pending = "";
14007
+ while (true) {
14008
+ const readChunk = read(reader, "read");
14009
+ if (typeof readChunk !== "function") {
14010
+ throw new Error("Response body stream has no read method");
14011
+ }
14012
+ const chunk = await Reflect.apply(readChunk, reader, []);
14013
+ if (!isObject(chunk)) {
14014
+ throw new Error("Response body stream returned an invalid chunk");
14015
+ }
14016
+ if (chunk.done === true) {
14017
+ pending += decoder2.decode();
14018
+ break;
14019
+ }
14020
+ if (!(chunk.value instanceof Uint8Array)) {
14021
+ throw new Error("Response body stream returned a non-byte chunk");
14022
+ }
14023
+ pending += decoder2.decode(chunk.value, { stream: true });
14024
+ let newline = pending.indexOf("\n");
14025
+ while (newline !== -1) {
14026
+ const line = pending.slice(0, newline).replace(/\r$/, "");
14027
+ pending = pending.slice(newline + 1);
14028
+ if (line.trim()) {
14029
+ try {
14030
+ yield JSON.parse(line);
14031
+ } catch (error) {
14032
+ logBatchInstrumentationError("skipped malformed JSONL", error);
14033
+ onIssue(new Error("OpenAI Batch file contains malformed JSONL"));
14034
+ }
14035
+ }
14036
+ newline = pending.indexOf("\n");
14037
+ }
14038
+ }
14039
+ if (pending.trim()) {
14040
+ try {
14041
+ yield JSON.parse(pending.replace(/\r$/, ""));
14042
+ } catch (error) {
14043
+ logBatchInstrumentationError("skipped malformed JSONL", error);
14044
+ onIssue(new Error("OpenAI Batch file contains malformed JSONL"));
14045
+ }
14046
+ }
14047
+ } catch (error) {
14048
+ logBatchInstrumentationError("could not read JSONL response body", error);
14049
+ onIssue(new Error("OpenAI Batch response body could not be read"));
14050
+ } finally {
14051
+ const releaseLock = read(reader, "releaseLock");
14052
+ if (typeof releaseLock === "function") {
14053
+ try {
14054
+ Reflect.apply(releaseLock, reader, []);
14055
+ } catch (error) {
14056
+ logBatchInstrumentationError(
14057
+ "could not release stream reader",
14058
+ error
14059
+ );
14060
+ }
14061
+ }
14062
+ }
14063
+ return;
14064
+ }
14065
+ if (isBatchRecordIterable(resolvedFile)) {
14066
+ for await (const record of resolvedFile) {
14067
+ yield record;
14068
+ }
14069
+ return;
14070
+ }
14071
+ logBatchInstrumentationError("skipped invalid JSONL source", resolvedFile);
14072
+ onIssue(new Error("OpenAI Batch file source is invalid"));
14073
+ }
14074
+ async function readBatchInputs(file) {
14075
+ const inputs = /* @__PURE__ */ new Map();
14076
+ const issues = [];
14077
+ let endpoint;
14078
+ try {
14079
+ for await (const value of jsonlRecords(
14080
+ file,
14081
+ (issue) => issues.push(issue)
14082
+ )) {
14083
+ const customId = read(value, "custom_id");
14084
+ const url = read(value, "url");
14085
+ const body = read(value, "body");
14086
+ if (!validCustomId(customId) || inputs.has(customId) || read(value, "method") !== "POST" || typeof url !== "string" || !SUPPORTED_ENDPOINTS.has(url) || endpoint !== void 0 && endpoint !== url || !isObject(body)) {
14087
+ issues.push(new Error("OpenAI Batch input contains an invalid record"));
14088
+ continue;
14089
+ }
14090
+ endpoint = url;
14091
+ let spanData;
14092
+ try {
14093
+ spanData = extractOpenAIBatchInput(url, body);
14094
+ } catch (error) {
14095
+ logBatchInstrumentationError("could not extract batch input", error);
14096
+ }
14097
+ inputs.set(customId, { customId, spanData });
14098
+ }
14099
+ } catch (error) {
14100
+ logBatchInstrumentationError("could not process input file", error);
14101
+ issues.push(new Error("OpenAI Batch input file could not be processed"));
14102
+ }
14103
+ if (!endpoint || inputs.size === 0) {
14104
+ issues.push(new Error("OpenAI Batch input contains no supported records"));
14105
+ }
14106
+ return { endpoint, inputs, issues };
14107
+ }
14108
+ async function writePendingSpans(trace, endTime) {
14109
+ const task = await startBatchSpan(trace.context);
14110
+ const taskParent = await task.export();
14111
+ for (const input of trace.inputs.values()) {
14112
+ try {
14113
+ const child = await startBatchChild(trace.context, taskParent, input);
14114
+ if (endTime !== void 0) {
14115
+ child.end({ endTime });
14116
+ }
14117
+ } catch (error) {
14118
+ logBatchInstrumentationError("could not write batch request span", error);
14119
+ }
14120
+ }
14121
+ if (endTime !== void 0) {
14122
+ if (trace.status && trace.status !== "completed") {
14123
+ task.log({ error: new Error(`OpenAI Batch ${trace.status}`) });
14124
+ }
14125
+ task.end({ endTime });
14126
+ }
14127
+ }
14128
+ var interceptOpenAIFilesCreateTraced = async (target, thisArg, args) => {
14129
+ const startTime = getCurrentUnixTimestamp();
14130
+ const inputPromise = readBatchInputs(args[0].inputFileContent);
14131
+ const parentPromise = exportParent(args[0].parent);
14132
+ const file = await Reflect.apply(target, thisArg, args);
14133
+ try {
14134
+ const inputFileId = read(file, "id");
14135
+ const [inputData, exportedParent2] = await Promise.all([
14136
+ inputPromise,
14137
+ parentPromise
14138
+ ]);
14139
+ if (typeof inputFileId !== "string" || !exportedParent2 || !inputData.endpoint || inputData.issues.length > 0) {
14140
+ if (inputData.issues[0]) {
14141
+ logBatchInstrumentationError(
14142
+ "skipped invalid input file",
14143
+ inputData.issues[0]
14144
+ );
14145
+ }
14146
+ return file;
14147
+ }
14148
+ const trace = {
14149
+ context: {
14150
+ inputFileId,
14151
+ endpoint: inputData.endpoint,
14152
+ parent: exportedParent2,
14153
+ taskStartTime: startTime,
14154
+ childStartTime: startTime
14155
+ },
14156
+ inputs: inputData.inputs
14157
+ };
14158
+ pendingBatchTraces.set(inputFileId, trace);
14159
+ await writePendingSpans(trace);
14160
+ } catch (error) {
14161
+ logBatchInstrumentationError("could not start batch spans", error);
14162
+ }
14163
+ return file;
14164
+ };
14165
+ function validTimestamp(value) {
14166
+ return typeof value === "number" && Number.isFinite(value) && value >= 0;
14167
+ }
14168
+ function terminalEndTime(batch, startTime) {
14169
+ let timestamp;
14170
+ switch (batch.status) {
14171
+ case "completed":
14172
+ timestamp = batch.completed_at;
14173
+ break;
14174
+ case "failed":
14175
+ timestamp = batch.failed_at;
14176
+ break;
14177
+ case "expired":
14178
+ timestamp = batch.expired_at;
14179
+ break;
14180
+ default:
14181
+ timestamp = batch.cancelled_at;
14182
+ }
14183
+ return validTimestamp(timestamp) ? Math.max(timestamp, startTime) : Math.max(getCurrentUnixTimestamp(), startTime);
14184
+ }
14185
+ async function updateBatchTimestamps(batch) {
14186
+ const trace = pendingBatchTraces.get(batch.input_file_id);
14187
+ if (!trace || trace.context.endpoint !== batch.endpoint) {
14188
+ return;
14189
+ }
14190
+ if (validTimestamp(batch.created_at)) {
14191
+ trace.context.taskStartTime = batch.created_at;
14192
+ }
14193
+ trace.context.childStartTime = validTimestamp(batch.in_progress_at) ? Math.max(batch.in_progress_at, trace.context.taskStartTime) : trace.context.taskStartTime;
14194
+ trace.status = batch.status;
14195
+ if (TERMINAL_STATUSES.has(batch.status)) {
14196
+ trace.endTime = terminalEndTime(batch, trace.context.childStartTime);
14197
+ }
14198
+ await writePendingSpans(trace, trace.endTime);
14199
+ }
14200
+ var interceptOpenAIBatchesRetrieveTraced = (target, thisArg, args) => Promise.resolve(Reflect.apply(target, thisArg, args)).then(async (batch) => {
14201
+ try {
14202
+ await updateBatchTimestamps(batch);
14203
+ } catch (error) {
14204
+ logBatchInstrumentationError("could not update batch timestamps", error);
14205
+ }
14206
+ return batch;
14207
+ });
14208
+ function errorFromResult(result) {
14209
+ const error = read(result.value, "error");
14210
+ if (isObject(error)) {
14211
+ const message = read(error, "message");
14212
+ return new Error(
14213
+ typeof message === "string" ? message : "OpenAI Batch request failed"
14214
+ );
14215
+ }
14216
+ const response = read(result.value, "response");
14217
+ const statusCode = read(response, "status_code");
14218
+ if (result.source === "error" || typeof statusCode === "number" && (statusCode < 200 || statusCode >= 300)) {
14219
+ const message = read(read(read(response, "body"), "error"), "message");
14220
+ return new Error(
14221
+ typeof message === "string" ? message : "OpenAI Batch request failed"
14222
+ );
14223
+ }
14224
+ return void 0;
14225
+ }
14226
+ async function completeBatchResult(context, taskParent, endTime, input, result) {
14227
+ const child = await startBatchChild(context, taskParent, input);
14228
+ try {
14229
+ const resultError = errorFromResult(result);
14230
+ const responseBody = read(read(result.value, "response"), "body");
14231
+ if (resultError) {
14232
+ child.log({ error: resultError });
14233
+ } else if (isObject(responseBody)) {
14234
+ const model = read(responseBody, "model");
14235
+ child.log({
14236
+ output: context.endpoint === "/v1/chat/completions" ? read(responseBody, "choices") : processImagesInOutput(read(responseBody, "output")),
14237
+ ...typeof model === "string" ? { metadata: { model } } : {},
14238
+ metrics: parseMetricsFromUsage(read(responseBody, "usage"))
14239
+ });
14240
+ } else {
14241
+ child.log({ error: new Error("OpenAI Batch response body is missing") });
14242
+ }
14243
+ } catch (error) {
14244
+ child.log({ error });
14245
+ } finally {
14246
+ child.end({ endTime });
14247
+ }
14248
+ }
14249
+ async function completeResultFile({
14250
+ context,
14251
+ endTime,
14252
+ file,
14253
+ inputs,
14254
+ issues,
14255
+ seen,
14256
+ source,
14257
+ taskParent
14258
+ }) {
14259
+ if (file === void 0) {
14260
+ return;
14261
+ }
14262
+ for await (const value of jsonlRecords(file, (issue) => issues.push(issue))) {
14263
+ const customId = read(value, "custom_id");
14264
+ if (!validCustomId(customId) || !isObject(value)) {
14265
+ issues.push(
14266
+ new Error("OpenAI Batch result is missing a valid custom_id")
14267
+ );
14268
+ continue;
14269
+ }
14270
+ if (seen.has(customId)) {
14271
+ issues.push(new Error("OpenAI Batch result contains a duplicate"));
14272
+ continue;
14273
+ }
14274
+ const input = inputs.get(customId);
14275
+ if (!input) {
14276
+ issues.push(
14277
+ new Error("OpenAI Batch result does not match an input record")
14278
+ );
14279
+ continue;
14280
+ }
14281
+ seen.add(customId);
14282
+ await completeBatchResult(context, taskParent, endTime, input, {
14283
+ value,
14284
+ source
14285
+ });
14286
+ }
14287
+ }
14288
+ function sameInputs(first, second) {
14289
+ return first.size === second.size && [...first.keys()].every((customId) => second.has(customId));
14290
+ }
14291
+ async function contextForCompletion(inputFileId, inputData) {
14292
+ if (!inputData.endpoint || inputData.issues.length > 0) {
14293
+ return void 0;
14294
+ }
14295
+ const existing = pendingBatchTraces.get(inputFileId);
14296
+ if (existing) {
14297
+ if (existing.context.endpoint !== inputData.endpoint || !sameInputs(existing.inputs, inputData.inputs)) {
14298
+ return void 0;
14299
+ }
14300
+ return { ...existing, inputs: inputData.inputs };
14301
+ }
14302
+ const parent = await exportParent(getSpanParentObject());
14303
+ if (!parent) {
14304
+ return void 0;
14305
+ }
14306
+ const startTime = getCurrentUnixTimestamp();
14307
+ return {
14308
+ context: {
14309
+ inputFileId,
14310
+ endpoint: inputData.endpoint,
14311
+ parent,
14312
+ taskStartTime: startTime,
14313
+ childStartTime: startTime
14314
+ },
14315
+ inputs: inputData.inputs
14316
+ };
14317
+ }
14318
+ async function completeBatch(args) {
14319
+ const inputData = await readBatchInputs(args.inputFileContent);
14320
+ const trace = await contextForCompletion(args.inputFileId, inputData);
14321
+ if (!trace) {
14322
+ logBatchInstrumentationError(
14323
+ "left batch spans pending",
14324
+ inputData.issues[0] ?? new Error("OpenAI Batch input does not match")
14325
+ );
14326
+ return;
14327
+ }
14328
+ const endTime = trace.endTime ?? getCurrentUnixTimestamp();
14329
+ const task = await startBatchSpan(trace.context);
14330
+ const taskParent = await task.export();
14331
+ const issues = [];
14332
+ const seen = /* @__PURE__ */ new Set();
14333
+ await Promise.all([
14334
+ completeResultFile({
14335
+ context: trace.context,
14336
+ endTime,
14337
+ file: args.outputFileContent,
14338
+ inputs: trace.inputs,
14339
+ issues,
14340
+ seen,
14341
+ source: "output",
14342
+ taskParent
14343
+ }),
14344
+ completeResultFile({
14345
+ context: trace.context,
14346
+ endTime,
14347
+ file: args.errorFileContent,
14348
+ inputs: trace.inputs,
14349
+ issues,
14350
+ seen,
14351
+ source: "error",
14352
+ taskParent
14353
+ })
14354
+ ]);
14355
+ if (issues.length > 0) {
14356
+ logBatchInstrumentationError("left batch spans pending", issues[0]);
14357
+ return;
14358
+ }
14359
+ const missing = [...trace.inputs.values()].filter(
14360
+ ({ customId }) => !seen.has(customId)
14361
+ );
14362
+ if (!trace.status || trace.status === "completed") {
14363
+ if (missing.length > 0) {
14364
+ logBatchInstrumentationError(
14365
+ "left batch spans pending",
14366
+ new Error("OpenAI Batch result files are incomplete")
14367
+ );
14368
+ return;
14369
+ }
14370
+ } else {
14371
+ for (const input of missing) {
14372
+ const child = await startBatchChild(trace.context, taskParent, input);
14373
+ child.log({ error: new Error(`OpenAI Batch ${trace.status}`) });
14374
+ child.end({ endTime });
14375
+ }
14376
+ task.log({ error: new Error(`OpenAI Batch ${trace.status}`) });
14377
+ }
14378
+ task.end({ endTime });
14379
+ pendingBatchTraces.delete(args.inputFileId);
14380
+ }
14381
+ var interceptOpenAIBatchTraceComplete = (target, thisArg, args) => Promise.resolve(Reflect.apply(target, thisArg, args)).then(async (result) => {
14382
+ try {
14383
+ await completeBatch(args[0]);
14384
+ } catch (error) {
14385
+ logBatchInstrumentationError("could not complete batch", error);
14386
+ }
14387
+ return result;
14388
+ });
14389
+
13736
14390
  // src/instrumentation/plugins/openai-plugin.ts
13737
14391
  var OpenAIPlugin = class extends BasePlugin {
13738
14392
  constructor() {
13739
14393
  super();
13740
14394
  }
13741
14395
  onEnable() {
14396
+ this.unsubscribers.push(
14397
+ openAIChannels.filesCreateTraced.intercept(
14398
+ interceptOpenAIFilesCreateTraced
14399
+ ),
14400
+ openAIChannels.batchesRetrieveTraced.intercept(
14401
+ interceptOpenAIBatchesRetrieveTraced
14402
+ ),
14403
+ openAIChannels.batchesCompleteTrace.intercept(
14404
+ interceptOpenAIBatchTraceComplete
14405
+ )
14406
+ );
13742
14407
  this.unsubscribers.push(
13743
14408
  traceStreamingChannel(openAIChannels.chatCompletionsCreate, {
13744
14409
  name: "Chat Completion",
13745
14410
  type: "llm" /* LLM */,
13746
- extractInput: ([params]) => {
13747
- const { messages, ...metadata } = params;
13748
- return {
13749
- input: processInputAttachments(messages),
13750
- metadata: { ...metadata, provider: "openai" }
13751
- };
13752
- },
14411
+ extractInput: ([params]) => extractOpenAIChatInput(params),
13753
14412
  extractOutput: (result) => {
13754
14413
  return result?.choices;
13755
14414
  },
@@ -13795,13 +14454,7 @@ var OpenAIPlugin = class extends BasePlugin {
13795
14454
  traceStreamingChannel(openAIChannels.betaChatCompletionsParse, {
13796
14455
  name: "Chat Completion",
13797
14456
  type: "llm" /* LLM */,
13798
- extractInput: ([params]) => {
13799
- const { messages, ...metadata } = params;
13800
- return {
13801
- input: processInputAttachments(messages),
13802
- metadata: { ...metadata, provider: "openai" }
13803
- };
13804
- },
14457
+ extractInput: ([params]) => extractOpenAIChatInput(params),
13805
14458
  extractOutput: (result) => {
13806
14459
  return result?.choices;
13807
14460
  },
@@ -13823,13 +14476,7 @@ var OpenAIPlugin = class extends BasePlugin {
13823
14476
  traceSyncStreamChannel(openAIChannels.betaChatCompletionsStream, {
13824
14477
  name: "Chat Completion",
13825
14478
  type: "llm" /* LLM */,
13826
- extractInput: ([params]) => {
13827
- const { messages, ...metadata } = params;
13828
- return {
13829
- input: processInputAttachments(messages),
13830
- metadata: { ...metadata, provider: "openai" }
13831
- };
13832
- }
14479
+ extractInput: ([params]) => extractOpenAIChatInput(params)
13833
14480
  })
13834
14481
  );
13835
14482
  this.unsubscribers.push(
@@ -13859,23 +14506,11 @@ var OpenAIPlugin = class extends BasePlugin {
13859
14506
  traceStreamingChannel(openAIChannels.responsesCreate, {
13860
14507
  name: "openai.responses.create",
13861
14508
  type: "llm" /* LLM */,
13862
- extractInput: ([params]) => {
13863
- const { input, ...metadata } = params;
13864
- return {
13865
- input: processInputAttachments(input),
13866
- metadata: { ...metadata, provider: "openai" }
13867
- };
13868
- },
14509
+ extractInput: ([params]) => extractOpenAIResponsesInput(params),
13869
14510
  extractOutput: (result) => {
13870
14511
  return processImagesInOutput(result?.output);
13871
14512
  },
13872
- extractMetadata: (result) => {
13873
- if (!result) {
13874
- return void 0;
13875
- }
13876
- const { output: _output, usage: _usage, ...metadata } = result;
13877
- return Object.keys(metadata).length > 0 ? metadata : void 0;
13878
- },
14513
+ extractMetadata: (result) => extractOpenAIResponsesMetadata(result),
13879
14514
  extractMetrics: (result, startTime, endEvent) => {
13880
14515
  const metrics = withCachedMetric(
13881
14516
  parseMetricsFromUsage(result?.usage),
@@ -13894,13 +14529,7 @@ var OpenAIPlugin = class extends BasePlugin {
13894
14529
  traceSyncStreamChannel(openAIChannels.responsesStream, {
13895
14530
  name: "openai.responses.create",
13896
14531
  type: "llm" /* LLM */,
13897
- extractInput: ([params]) => {
13898
- const { input, ...metadata } = params;
13899
- return {
13900
- input: processInputAttachments(input),
13901
- metadata: { ...metadata, provider: "openai" }
13902
- };
13903
- },
14532
+ extractInput: ([params]) => extractOpenAIResponsesInput(params),
13904
14533
  extractFromEvent: (event) => {
13905
14534
  if (event.type !== "response.completed" || !event.response) {
13906
14535
  return {};
@@ -13923,23 +14552,11 @@ var OpenAIPlugin = class extends BasePlugin {
13923
14552
  traceStreamingChannel(openAIChannels.responsesParse, {
13924
14553
  name: "openai.responses.parse",
13925
14554
  type: "llm" /* LLM */,
13926
- extractInput: ([params]) => {
13927
- const { input, ...metadata } = params;
13928
- return {
13929
- input: processInputAttachments(input),
13930
- metadata: { ...metadata, provider: "openai" }
13931
- };
13932
- },
14555
+ extractInput: ([params]) => extractOpenAIResponsesInput(params),
13933
14556
  extractOutput: (result) => {
13934
14557
  return processImagesInOutput(result?.output);
13935
14558
  },
13936
- extractMetadata: (result) => {
13937
- if (!result) {
13938
- return void 0;
13939
- }
13940
- const { output: _output, usage: _usage, ...metadata } = result;
13941
- return Object.keys(metadata).length > 0 ? metadata : void 0;
13942
- },
14559
+ extractMetadata: (result) => extractOpenAIResponsesMetadata(result),
13943
14560
  extractMetrics: (result, startTime, endEvent) => {
13944
14561
  const metrics = withCachedMetric(
13945
14562
  parseMetricsFromUsage(result?.usage),
@@ -13958,23 +14575,11 @@ var OpenAIPlugin = class extends BasePlugin {
13958
14575
  traceAsyncChannel(openAIChannels.responsesCompact, {
13959
14576
  name: "openai.responses.compact",
13960
14577
  type: "llm" /* LLM */,
13961
- extractInput: ([params]) => {
13962
- const { input, ...metadata } = params;
13963
- return {
13964
- input: processInputAttachments(input),
13965
- metadata: { ...metadata, provider: "openai" }
13966
- };
13967
- },
14578
+ extractInput: ([params]) => extractOpenAIResponsesInput(params),
13968
14579
  extractOutput: (result) => {
13969
14580
  return processImagesInOutput(result?.output);
13970
14581
  },
13971
- extractMetadata: (result) => {
13972
- if (!result) {
13973
- return void 0;
13974
- }
13975
- const { output: _output, usage: _usage, ...metadata } = result;
13976
- return Object.keys(metadata).length > 0 ? metadata : void 0;
13977
- },
14582
+ extractMetadata: (result) => extractOpenAIResponsesMetadata(result),
13978
14583
  extractMetrics: (result, startTime, endEvent) => {
13979
14584
  const metrics = withCachedMetric(
13980
14585
  parseMetricsFromUsage(result?.usage),
@@ -14030,35 +14635,6 @@ function withCachedMetric(metrics, result, endEvent) {
14030
14635
  cached
14031
14636
  };
14032
14637
  }
14033
- function processImagesInOutput(output) {
14034
- if (Array.isArray(output)) {
14035
- return output.map(processImagesInOutput);
14036
- }
14037
- if (isObject(output)) {
14038
- if (output.type === "image_generation_call" && output.result && typeof output.result === "string") {
14039
- const fileExtension = output.output_format || "png";
14040
- const contentType = `image/${fileExtension}`;
14041
- const baseFilename = output.revised_prompt && typeof output.revised_prompt === "string" ? output.revised_prompt.slice(0, 50).replace(/[^a-zA-Z0-9]/g, "_") : "generated_image";
14042
- const filename = `${baseFilename}.${fileExtension}`;
14043
- const binaryString = atob(output.result);
14044
- const bytes = new Uint8Array(binaryString.length);
14045
- for (let i = 0; i < binaryString.length; i++) {
14046
- bytes[i] = binaryString.charCodeAt(i);
14047
- }
14048
- const blob = new Blob([bytes], { type: contentType });
14049
- const attachment = new Attachment({
14050
- data: blob,
14051
- filename,
14052
- contentType
14053
- });
14054
- return {
14055
- ...output,
14056
- result: attachment
14057
- };
14058
- }
14059
- }
14060
- return output;
14061
- }
14062
14638
  function mergeLogprobTokens(existing, incoming) {
14063
14639
  if (incoming === void 0) {
14064
14640
  return existing;
@@ -19215,6 +19791,12 @@ function prepareAISDKChildTracing(params, self, parentSpan, denyOutputPaths, aiS
19215
19791
  if (!activeEntry) {
19216
19792
  return result;
19217
19793
  }
19794
+ const executionOptions = args[1];
19795
+ const toolCallId = isObject(executionOptions) ? executionOptions.toolCallId : void 0;
19796
+ const toolInput = {
19797
+ input: serializeToolExecutionInput(args),
19798
+ ...typeof toolCallId === "string" ? { metadata: { toolCallId } } : {}
19799
+ };
19218
19800
  if (isAsyncGenerator(result)) {
19219
19801
  return (async function* () {
19220
19802
  const span = activeEntry.parentSpan.startSpan(
@@ -19228,7 +19810,7 @@ function prepareAISDKChildTracing(params, self, parentSpan, denyOutputPaths, aiS
19228
19810
  INSTRUMENTATION_NAMES.AI_SDK
19229
19811
  )
19230
19812
  );
19231
- span.log({ input: serializeToolExecutionInput(args) });
19813
+ span.log(toolInput);
19232
19814
  try {
19233
19815
  let lastValue;
19234
19816
  for await (const value of result) {
@@ -19246,7 +19828,7 @@ function prepareAISDKChildTracing(params, self, parentSpan, denyOutputPaths, aiS
19246
19828
  }
19247
19829
  return activeEntry.parentSpan.traced(
19248
19830
  async (span) => {
19249
- span.log({ input: serializeToolExecutionInput(args) });
19831
+ span.log(toolInput);
19250
19832
  const awaitedResult = await result;
19251
19833
  span.log({ output: awaitedResult });
19252
19834
  return awaitedResult;
@@ -33368,14 +33950,17 @@ function getMetricsFromResponse(response) {
33368
33950
  if (!isRecord(usageMetadata)) {
33369
33951
  continue;
33370
33952
  }
33371
- const inputTokenDetails = usageMetadata.input_token_details;
33953
+ const inputTokenDetails = isRecord(usageMetadata.input_token_details) ? usageMetadata.input_token_details : {};
33372
33954
  const outputTokenDetails = usageMetadata.output_token_details;
33373
33955
  return normalizeTokenMetrics({
33374
33956
  total_tokens: usageMetadata.total_tokens,
33375
33957
  prompt_tokens: usageMetadata.input_tokens,
33376
33958
  completion_tokens: usageMetadata.output_tokens,
33377
- prompt_cache_creation_tokens: isRecord(inputTokenDetails) ? inputTokenDetails.cache_creation : void 0,
33378
- prompt_cached_tokens: isRecord(inputTokenDetails) ? inputTokenDetails.cache_read : void 0,
33959
+ // Prefer TTL-specific cache writes over the aggregate when available.
33960
+ prompt_cache_creation_tokens: inputTokenDetails.ephemeral_5m_input_tokens == null && inputTokenDetails.ephemeral_1h_input_tokens == null ? inputTokenDetails.cache_creation : void 0,
33961
+ prompt_cache_creation_5m_tokens: inputTokenDetails.ephemeral_5m_input_tokens,
33962
+ prompt_cache_creation_1h_tokens: inputTokenDetails.ephemeral_1h_input_tokens,
33963
+ prompt_cached_tokens: inputTokenDetails.cache_read,
33379
33964
  completion_reasoning_tokens: isRecord(outputTokenDetails) ? outputTokenDetails.reasoning : void 0
33380
33965
  });
33381
33966
  }
@@ -34091,7 +34676,7 @@ function extractSession(event) {
34091
34676
  return isObject(candidate) && typeof candidate.prompt === "function" ? candidate : void 0;
34092
34677
  }
34093
34678
  function isPiAgent(value) {
34094
- return isObject(value) && typeof value.streamFn === "function" && typeof value.subscribe === "function";
34679
+ return isObject(value) && (typeof value.streamFunction === "function" || typeof value.streamFn === "function") && typeof value.subscribe === "function";
34095
34680
  }
34096
34681
  function promptContextStore() {
34097
34682
  piPromptContextStore ??= isomorph_default.newAsyncLocalStorage();
@@ -34101,17 +34686,21 @@ function currentPiPromptState() {
34101
34686
  return promptContextStore().getStore();
34102
34687
  }
34103
34688
  function installPiAgentInstrumentation(agent) {
34689
+ const property = typeof agent.streamFunction === "function" ? "streamFunction" : "streamFn";
34690
+ const streamFunction = agent[property];
34104
34691
  const existing = piAgentPatchStates.get(agent);
34105
- if (!existing || agent.streamFn !== existing.wrappedStreamFn) {
34692
+ if (streamFunction && (!existing || existing.property !== property || streamFunction !== existing.wrappedStreamFunction)) {
34106
34693
  const patchState = {
34107
- originalStreamFn: agent.streamFn,
34108
- wrappedStreamFn: agent.streamFn
34694
+ originalStreamFunction: streamFunction,
34695
+ property,
34696
+ wrappedStreamFunction: streamFunction
34109
34697
  };
34110
- patchState.wrappedStreamFn = makeInstrumentedStreamFn(
34698
+ patchState.wrappedStreamFunction = makeInstrumentedStreamFunction(
34111
34699
  agent,
34112
- patchState.originalStreamFn
34700
+ patchState.originalStreamFunction,
34701
+ property
34113
34702
  );
34114
- agent.streamFn = patchState.wrappedStreamFn;
34703
+ agent[property] = patchState.wrappedStreamFunction;
34115
34704
  piAgentPatchStates.set(agent, patchState);
34116
34705
  }
34117
34706
  if (piAgentEventSubscriptions.has(agent)) {
@@ -34136,15 +34725,21 @@ function installPiAgentInstrumentation(agent) {
34136
34725
  logInstrumentationError4("Pi Coding Agent event subscription", error);
34137
34726
  }
34138
34727
  }
34139
- function makeInstrumentedStreamFn(agent, originalStreamFn) {
34140
- return async function instrumentedPiStreamFn(model, context, options) {
34141
- const invokeOriginal = () => Reflect.apply(originalStreamFn, this, [model, context, options]);
34728
+ function makeInstrumentedStreamFunction(agent, originalStreamFunction, property) {
34729
+ return async function instrumentedPiStreamFunction(model, context, options) {
34730
+ const invokeOriginal = () => Reflect.apply(originalStreamFunction, this, [model, context, options]);
34142
34731
  const state = currentPiPromptState();
34143
34732
  if (!state || state.agent !== agent || state.finalized) {
34144
34733
  return invokeOriginal();
34145
34734
  }
34146
34735
  wrapPiToolExecutors(context.tools);
34147
- const llmState = await startPiLlmSpan(state, model, context, options);
34736
+ const llmState = await startPiLlmSpan(
34737
+ state,
34738
+ model,
34739
+ context,
34740
+ property,
34741
+ options
34742
+ );
34148
34743
  try {
34149
34744
  const stream = await runWithAutoInstrumentationSuppressed(invokeOriginal);
34150
34745
  return patchAssistantMessageStream(stream, state, llmState);
@@ -34181,12 +34776,12 @@ function wrapPiToolExecutors(tools) {
34181
34776
  }
34182
34777
  }
34183
34778
  }
34184
- async function startPiLlmSpan(state, model, context, options) {
34779
+ async function startPiLlmSpan(state, model, context, property, options) {
34185
34780
  const metadata = {
34186
34781
  ...extractModelMetadata2(model),
34187
34782
  ...extractStreamOptionsMetadata(options),
34188
34783
  ...extractToolMetadata(context.tools),
34189
- "pi_coding_agent.operation": "agent.streamFn"
34784
+ "pi_coding_agent.operation": `agent.${property}`
34190
34785
  };
34191
34786
  const span = startSpan(
34192
34787
  withSpanInstrumentationName(
@@ -37204,6 +37799,7 @@ __export(exports_exports, {
37204
37799
  braintrustStreamChunkSchema: () => braintrustStreamChunkSchema,
37205
37800
  buildLocalSummary: () => buildLocalSummary,
37206
37801
  collectAnthropicSession: () => collectAnthropicSession,
37802
+ completeOpenAIBatchTrace: () => completeOpenAIBatchTrace,
37207
37803
  configureInstrumentation: () => configureInstrumentation,
37208
37804
  constructLogs3OverflowRequest: () => constructLogs3OverflowRequest,
37209
37805
  createFinalValuePassThroughStream: () => createFinalValuePassThroughStream,
@@ -37242,6 +37838,8 @@ __export(exports_exports, {
37242
37838
  loginToState: () => loginToState,
37243
37839
  logs3OverflowUploadSchema: () => logs3OverflowUploadSchema,
37244
37840
  newId: () => newId,
37841
+ openaiBatchesRetrieveTraced: () => openaiBatchesRetrieveTraced,
37842
+ openaiFilesCreateTraced: () => openaiFilesCreateTraced,
37245
37843
  parseCachedHeader: () => parseCachedHeader,
37246
37844
  parseTemplateFormat: () => parseTemplateFormat,
37247
37845
  permalink: () => permalink,
@@ -37406,6 +38004,260 @@ async function registerSandbox(options) {
37406
38004
  };
37407
38005
  }
37408
38006
 
38007
+ // src/wrappers/openai-promise-utils.ts
38008
+ function splitSpanInfo(allParams) {
38009
+ const { span_info, ...params } = allParams;
38010
+ return {
38011
+ params,
38012
+ span_info
38013
+ };
38014
+ }
38015
+ function createChannelContext(_channel, params, span_info) {
38016
+ return {
38017
+ arguments: (
38018
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
38019
+ [params]
38020
+ ),
38021
+ span_info
38022
+ };
38023
+ }
38024
+ async function tracePromiseWithResponse(channel2, traceContext, apiPromise) {
38025
+ let enhancedResponse;
38026
+ const tracePromise = (
38027
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
38028
+ channel2.tracePromise
38029
+ );
38030
+ const data = await tracePromise(async () => {
38031
+ enhancedResponse = await apiPromise.withResponse();
38032
+ traceContext.response = enhancedResponse.response;
38033
+ return enhancedResponse.data;
38034
+ }, traceContext);
38035
+ if (!enhancedResponse) {
38036
+ throw new Error("Expected withResponse() to provide response");
38037
+ }
38038
+ return {
38039
+ data,
38040
+ response: enhancedResponse.response,
38041
+ request_id: enhancedResponse.request_id
38042
+ };
38043
+ }
38044
+ async function tracePromiseAsResponse(channel2, traceContext, apiPromise) {
38045
+ const tracePromise = (
38046
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
38047
+ channel2.tracePromise
38048
+ );
38049
+ let response;
38050
+ await tracePromise(async () => {
38051
+ response = await apiPromise.asResponse();
38052
+ traceContext.response = response;
38053
+ return void 0;
38054
+ }, traceContext);
38055
+ if (!response) {
38056
+ throw new Error("Expected asResponse() to provide response");
38057
+ }
38058
+ return response;
38059
+ }
38060
+ function createLazyAPIPromise(ensureExecuted, ensureResponse, getAPIPromise) {
38061
+ let firstConsumption;
38062
+ let enhancedResponsePromise;
38063
+ let dataPromise;
38064
+ let responsePromise;
38065
+ const withResponse = () => {
38066
+ firstConsumption ??= "data";
38067
+ enhancedResponsePromise ??= firstConsumption === "data" ? ensureExecuted() : getAPIPromise().withResponse();
38068
+ return enhancedResponsePromise;
38069
+ };
38070
+ const asResponse = () => {
38071
+ firstConsumption ??= "response";
38072
+ responsePromise ??= firstConsumption === "response" ? ensureResponse() : getAPIPromise().asResponse();
38073
+ return responsePromise;
38074
+ };
38075
+ return new Proxy({}, {
38076
+ get(target, prop, receiver) {
38077
+ if (prop === "withResponse") {
38078
+ return withResponse;
38079
+ }
38080
+ if (prop === "asResponse") {
38081
+ return asResponse;
38082
+ }
38083
+ if (prop === "then" || prop === "catch" || prop === "finally" || prop in Promise.prototype) {
38084
+ dataPromise ??= withResponse().then((result) => result.data);
38085
+ const value = Reflect.get(dataPromise, prop, receiver);
38086
+ return typeof value === "function" ? value.bind(dataPromise) : value;
38087
+ }
38088
+ return Reflect.get(target, prop, receiver);
38089
+ }
38090
+ });
38091
+ }
38092
+
38093
+ // src/openai-batch.ts
38094
+ function read2(value, key) {
38095
+ if (value === null || typeof value !== "object" && typeof value !== "function") {
38096
+ return void 0;
38097
+ }
38098
+ try {
38099
+ return Reflect.get(value, key);
38100
+ } catch {
38101
+ return void 0;
38102
+ }
38103
+ }
38104
+ function isAsyncIterable5(value) {
38105
+ return typeof read2(value, Symbol.asyncIterator) === "function";
38106
+ }
38107
+ function teeAsyncIterable(source) {
38108
+ const iterator = source[Symbol.asyncIterator]();
38109
+ const stream = new ReadableStream({
38110
+ async pull(controller) {
38111
+ try {
38112
+ const result = await iterator.next();
38113
+ if (result.done) {
38114
+ controller.close();
38115
+ return;
38116
+ }
38117
+ if (!(result.value instanceof Uint8Array)) {
38118
+ throw new TypeError(
38119
+ "OpenAI upload streams must yield Uint8Array chunks"
38120
+ );
38121
+ }
38122
+ controller.enqueue(result.value);
38123
+ } catch (error) {
38124
+ controller.error(error);
38125
+ }
38126
+ },
38127
+ async cancel(reason) {
38128
+ await iterator.return?.(reason);
38129
+ }
38130
+ });
38131
+ const [uploadStream, trace] = stream.tee();
38132
+ const upload = {
38133
+ async *[Symbol.asyncIterator]() {
38134
+ const reader = uploadStream.getReader();
38135
+ try {
38136
+ while (true) {
38137
+ const result = await reader.read();
38138
+ if (result.done) {
38139
+ return;
38140
+ }
38141
+ yield result.value;
38142
+ }
38143
+ } finally {
38144
+ reader.releaseLock();
38145
+ }
38146
+ }
38147
+ };
38148
+ const path = read2(source, "path");
38149
+ if (typeof path === "string") {
38150
+ Object.defineProperty(upload, "path", { value: path });
38151
+ }
38152
+ return { upload, trace: new Response(trace) };
38153
+ }
38154
+ function teeUpload(upload) {
38155
+ if (upload instanceof Blob) {
38156
+ return { upload, trace: new Response(upload) };
38157
+ }
38158
+ if (upload instanceof Response) {
38159
+ return { upload, trace: upload.clone() };
38160
+ }
38161
+ if (isAsyncIterable5(upload)) {
38162
+ return teeAsyncIterable(upload);
38163
+ }
38164
+ return void 0;
38165
+ }
38166
+ function openaiFilesCreateTraced(files) {
38167
+ return (params, options) => {
38168
+ const parent = getSpanParentObject();
38169
+ const purpose = read2(params, "purpose");
38170
+ const file = read2(params, "file");
38171
+ if (purpose !== "batch") {
38172
+ return files.create(params, options);
38173
+ }
38174
+ let branches;
38175
+ try {
38176
+ branches = teeUpload(file);
38177
+ } catch {
38178
+ return files.create(params, options);
38179
+ }
38180
+ if (!branches) {
38181
+ return files.create(params, options);
38182
+ }
38183
+ const tracedParams = {
38184
+ ...Object(params),
38185
+ file: branches.upload
38186
+ };
38187
+ const apiPromise = files.create(tracedParams, options);
38188
+ let enhancedResponse;
38189
+ const tracedResponse = openAIChannels.filesCreateTraced.invoke(
38190
+ async () => {
38191
+ enhancedResponse = await apiPromise.withResponse();
38192
+ return enhancedResponse.data;
38193
+ },
38194
+ files,
38195
+ [{ params, inputFileContent: branches.trace, parent }],
38196
+ {}
38197
+ ).then((data) => {
38198
+ if (!enhancedResponse) {
38199
+ throw new Error(
38200
+ "Expected OpenAI withResponse() to provide a response"
38201
+ );
38202
+ }
38203
+ return { ...enhancedResponse, data };
38204
+ });
38205
+ return createLazyAPIPromise(
38206
+ () => tracedResponse,
38207
+ () => tracedResponse.then(({ response }) => response),
38208
+ () => apiPromise
38209
+ );
38210
+ };
38211
+ }
38212
+ function openaiBatchesRetrieveTraced(batches) {
38213
+ return (batchId, options) => {
38214
+ const apiPromise = batches.retrieve(batchId, options);
38215
+ let enhancedResponse;
38216
+ const tracedResponse = openAIChannels.batchesRetrieveTraced.invoke(
38217
+ async () => {
38218
+ enhancedResponse = await apiPromise.withResponse();
38219
+ return enhancedResponse.data;
38220
+ },
38221
+ batches,
38222
+ [{ batchId }],
38223
+ {}
38224
+ ).then((data) => {
38225
+ if (!enhancedResponse) {
38226
+ throw new Error(
38227
+ "Expected OpenAI withResponse() to provide a response"
38228
+ );
38229
+ }
38230
+ return { ...enhancedResponse, data };
38231
+ });
38232
+ return createLazyAPIPromise(
38233
+ () => tracedResponse,
38234
+ () => tracedResponse.then(({ response }) => response),
38235
+ () => apiPromise
38236
+ );
38237
+ };
38238
+ }
38239
+ async function completeOpenAIBatchTrace(args) {
38240
+ const inputFileContent = Promise.resolve(args.inputFileContent);
38241
+ const outputFileContent = args.outputFileContent === void 0 ? void 0 : Promise.resolve(args.outputFileContent);
38242
+ const errorFileContent = args.errorFileContent === void 0 ? void 0 : Promise.resolve(args.errorFileContent);
38243
+ void inputFileContent.catch(() => void 0);
38244
+ void outputFileContent?.catch(() => void 0);
38245
+ void errorFileContent?.catch(() => void 0);
38246
+ await openAIChannels.batchesCompleteTrace.invoke(
38247
+ async () => void 0,
38248
+ void 0,
38249
+ [
38250
+ {
38251
+ ...args,
38252
+ inputFileContent,
38253
+ outputFileContent,
38254
+ errorFileContent
38255
+ }
38256
+ ],
38257
+ {}
38258
+ );
38259
+ }
38260
+
37409
38261
  // src/functions/invoke.ts
37410
38262
  async function invoke(args) {
37411
38263
  const {
@@ -37508,58 +38360,6 @@ function initFunction({
37508
38360
  return f;
37509
38361
  }
37510
38362
 
37511
- // src/wrappers/openai-promise-utils.ts
37512
- function splitSpanInfo(allParams) {
37513
- const { span_info, ...params } = allParams;
37514
- return {
37515
- params,
37516
- span_info
37517
- };
37518
- }
37519
- function createChannelContext(_channel, params, span_info) {
37520
- return {
37521
- arguments: (
37522
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
37523
- [params]
37524
- ),
37525
- span_info
37526
- };
37527
- }
37528
- async function tracePromiseWithResponse(channel2, traceContext, apiPromise) {
37529
- let enhancedResponse;
37530
- const tracePromise = (
37531
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
37532
- channel2.tracePromise
37533
- );
37534
- const data = await tracePromise(async () => {
37535
- enhancedResponse = await apiPromise.withResponse();
37536
- traceContext.response = enhancedResponse.response;
37537
- return enhancedResponse.data;
37538
- }, traceContext);
37539
- if (!enhancedResponse) {
37540
- throw new Error("Expected withResponse() to provide response");
37541
- }
37542
- return { data, response: enhancedResponse.response };
37543
- }
37544
- function createLazyAPIPromise(ensureExecuted) {
37545
- let dataPromise = null;
37546
- return new Proxy({}, {
37547
- get(target, prop, receiver) {
37548
- if (prop === "withResponse") {
37549
- return () => ensureExecuted();
37550
- }
37551
- if (prop === "then" || prop === "catch" || prop === "finally" || prop in Promise.prototype) {
37552
- if (!dataPromise) {
37553
- dataPromise = ensureExecuted().then((result) => result.data);
37554
- }
37555
- const value = Reflect.get(dataPromise, prop, receiver);
37556
- return typeof value === "function" ? value.bind(dataPromise) : value;
37557
- }
37558
- return Reflect.get(target, prop, receiver);
37559
- }
37560
- });
37561
- }
37562
-
37563
38363
  // src/wrappers/oai_responses.ts
37564
38364
  function responsesProxy(openai) {
37565
38365
  if (!openai.responses) {
@@ -37596,17 +38396,33 @@ function wrapResponsesAsync(target, channel2) {
37596
38396
  return (allParams, options) => {
37597
38397
  const { span_info, params } = splitSpanInfo(allParams);
37598
38398
  let executionPromise = null;
38399
+ let apiPromise = null;
38400
+ const getAPIPromise = () => {
38401
+ apiPromise ??= target(params, options);
38402
+ return apiPromise;
38403
+ };
37599
38404
  const ensureExecuted = () => {
37600
38405
  if (!executionPromise) {
37601
38406
  executionPromise = (async () => {
37602
38407
  const traceContext = createChannelContext(channel2, params, span_info);
37603
- const apiPromise = target(params, options);
37604
- return tracePromiseWithResponse(channel2, traceContext, apiPromise);
38408
+ return tracePromiseWithResponse(
38409
+ channel2,
38410
+ traceContext,
38411
+ getAPIPromise()
38412
+ );
37605
38413
  })();
37606
38414
  }
37607
38415
  return executionPromise;
37608
38416
  };
37609
- return createLazyAPIPromise(ensureExecuted);
38417
+ return createLazyAPIPromise(
38418
+ ensureExecuted,
38419
+ () => tracePromiseAsResponse(
38420
+ channel2,
38421
+ createChannelContext(channel2, params, span_info),
38422
+ getAPIPromise()
38423
+ ),
38424
+ getAPIPromise
38425
+ );
37610
38426
  };
37611
38427
  }
37612
38428
  function wrapResponsesSyncStream(target, channel2) {
@@ -37752,6 +38568,11 @@ function wrapChatCompletion(completion) {
37752
38568
  allParams
37753
38569
  );
37754
38570
  let executionPromise = null;
38571
+ let apiPromise = null;
38572
+ const getAPIPromise = () => {
38573
+ apiPromise ??= completion(params, options);
38574
+ return apiPromise;
38575
+ };
37755
38576
  const ensureExecuted = () => {
37756
38577
  if (!executionPromise) {
37757
38578
  executionPromise = (async () => {
@@ -37761,32 +38582,44 @@ function wrapChatCompletion(completion) {
37761
38582
  span_info
37762
38583
  );
37763
38584
  if (params.stream) {
37764
- const completionPromise = completion(
37765
- params,
37766
- options
38585
+ const completionPromise = (
38586
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
38587
+ getAPIPromise()
37767
38588
  );
37768
- const { data: data2, response: response2 } = await tracePromiseWithResponse(
38589
+ const { data: data2, response: response2, request_id: request_id2 } = await tracePromiseWithResponse(
37769
38590
  openAIChannels.chatCompletionsCreate,
37770
38591
  traceContext,
37771
38592
  completionPromise
37772
38593
  );
37773
- return { data: data2, response: response2 };
38594
+ return { data: data2, response: response2, request_id: request_id2 };
37774
38595
  }
37775
- const completionResponse = completion(
37776
- params,
37777
- options
38596
+ const completionResponse = (
38597
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
38598
+ getAPIPromise()
37778
38599
  );
37779
- const { data, response } = await tracePromiseWithResponse(
38600
+ const { data, response, request_id } = await tracePromiseWithResponse(
37780
38601
  openAIChannels.chatCompletionsCreate,
37781
38602
  traceContext,
37782
38603
  completionResponse
37783
38604
  );
37784
- return { data, response };
38605
+ return { data, response, request_id };
37785
38606
  })();
37786
38607
  }
37787
38608
  return executionPromise;
37788
38609
  };
37789
- return createLazyAPIPromise(ensureExecuted);
38610
+ return createLazyAPIPromise(
38611
+ ensureExecuted,
38612
+ () => tracePromiseAsResponse(
38613
+ openAIChannels.chatCompletionsCreate,
38614
+ createChannelContext(
38615
+ openAIChannels.chatCompletionsCreate,
38616
+ params,
38617
+ span_info
38618
+ ),
38619
+ getAPIPromise()
38620
+ ),
38621
+ getAPIPromise
38622
+ );
37790
38623
  };
37791
38624
  }
37792
38625
  function createEndpointProxy(target, wrapperFn) {
@@ -37804,6 +38637,11 @@ function wrapApiCreateWithChannel(create, channel2) {
37804
38637
  return (allParams, options) => {
37805
38638
  const { span_info, params } = splitSpanInfo(allParams);
37806
38639
  let executionPromise = null;
38640
+ let apiPromise = null;
38641
+ const getAPIPromise = () => {
38642
+ apiPromise ??= create(params, options);
38643
+ return apiPromise;
38644
+ };
37807
38645
  const ensureExecuted = () => {
37808
38646
  if (!executionPromise) {
37809
38647
  executionPromise = (async () => {
@@ -37811,13 +38649,21 @@ function wrapApiCreateWithChannel(create, channel2) {
37811
38649
  return tracePromiseWithResponse(
37812
38650
  channel2,
37813
38651
  traceContext,
37814
- create(params, options)
38652
+ getAPIPromise()
37815
38653
  );
37816
38654
  })();
37817
38655
  }
37818
38656
  return executionPromise;
37819
38657
  };
37820
- return createLazyAPIPromise(ensureExecuted);
38658
+ return createLazyAPIPromise(
38659
+ ensureExecuted,
38660
+ () => tracePromiseAsResponse(
38661
+ channel2,
38662
+ createChannelContext(channel2, params, span_info),
38663
+ getAPIPromise()
38664
+ ),
38665
+ getAPIPromise
38666
+ );
37821
38667
  };
37822
38668
  }
37823
38669
  var wrapEmbeddings = (create) => wrapApiCreateWithChannel(create, openAIChannels.embeddingsCreate);
@@ -40512,7 +41358,15 @@ var MAX_EVE_PROVIDER_CACHE_ENTRIES = 1e4;
40512
41358
  function createEveInstrumentationProvider(options = {}) {
40513
41359
  const bridge = new EveProviderBridge(options.metadata);
40514
41360
  return {
41361
+ // Eve versions before tracePolicy use capture to decide whether provider
41362
+ // events include content. Newer versions prefer tracePolicy when both are
41363
+ // present, so keep the deprecated field for backwards compatibility.
40515
41364
  capture: "content",
41365
+ tracePolicy: () => ({
41366
+ emit: true,
41367
+ recordInputs: true,
41368
+ recordOutputs: true
41369
+ }),
40516
41370
  events: {
40517
41371
  "action.completed": (event, context) => bridge.handleActionTerminal(event, context),
40518
41372
  "action.failed": (event, context) => bridge.handleActionTerminal(event, context),
@@ -44120,8 +44974,8 @@ function normalizeScores(result) {
44120
44974
  (s) => s !== null && s !== void 0 && typeof s === "object" && isScore(s)
44121
44975
  );
44122
44976
  }
44123
- if (typeof result === "object" && result !== null && isScore(result)) {
44124
- return [result];
44977
+ if (typeof result === "object" && result !== null && "score" in result) {
44978
+ return [{ ...result, name: result.name ?? "score" }];
44125
44979
  }
44126
44980
  return [];
44127
44981
  }
@@ -44941,7 +45795,7 @@ function isAsync(fn) {
44941
45795
  function isAsyncGenerator2(fn) {
44942
45796
  return fn[Symbol.toStringTag] === "AsyncGenerator";
44943
45797
  }
44944
- function isAsyncIterable5(obj) {
45798
+ function isAsyncIterable6(obj) {
44945
45799
  return typeof obj[Symbol.asyncIterator] === "function";
44946
45800
  }
44947
45801
  function wrapAsync(asyncFn) {
@@ -45113,7 +45967,7 @@ var eachOfLimit$2 = (limit) => {
45113
45967
  if (isAsyncGenerator2(obj)) {
45114
45968
  return asyncEachOfLimit(obj, limit, iteratee, callback);
45115
45969
  }
45116
- if (isAsyncIterable5(obj)) {
45970
+ if (isAsyncIterable6(obj)) {
45117
45971
  return asyncEachOfLimit(obj[Symbol.asyncIterator](), limit, iteratee, callback);
45118
45972
  }
45119
45973
  var nextElem = createIterator(obj);
@@ -46468,7 +47322,7 @@ function callEvaluatorData(data) {
46468
47322
  baseExperiment
46469
47323
  };
46470
47324
  }
46471
- function isAsyncIterable6(value) {
47325
+ function isAsyncIterable7(value) {
46472
47326
  return typeof value === "object" && value !== null && Symbol.asyncIterator in value && typeof value[Symbol.asyncIterator] === "function";
46473
47327
  }
46474
47328
  function isIterable(value) {
@@ -46503,7 +47357,7 @@ async function _internalResolveEvaluatorData(evaluator, experiment) {
46503
47357
  }).asDataset();
46504
47358
  }
46505
47359
  const resolvedDataResult = dataResult instanceof Promise ? await dataResult : dataResult;
46506
- if (isAsyncIterable6(resolvedDataResult)) {
47360
+ if (isAsyncIterable7(resolvedDataResult)) {
46507
47361
  return resolvedDataResult;
46508
47362
  }
46509
47363
  if (Array.isArray(resolvedDataResult) || isIterable(resolvedDataResult)) {
@@ -46704,19 +47558,29 @@ function buildSpanScores(results) {
46704
47558
  function _internalPrepareEvaluatorScore(scoreValue, name) {
46705
47559
  if (scoreValue === null) return { results: null };
46706
47560
  if (Array.isArray(scoreValue)) {
47561
+ const names = /* @__PURE__ */ new Set();
46707
47562
  for (const score of scoreValue) {
46708
47563
  if (!(typeof score === "object" && !isEmpty2(score))) {
46709
47564
  throw new Error(
46710
47565
  `When returning an array of scores, each score must be a non-empty object. Got: ${JSON.stringify(score)}`
46711
47566
  );
46712
47567
  }
47568
+ if (typeof score.name !== "string") {
47569
+ throw new Error(
47570
+ `When returning an array of scores, each score must have a name. Got: ${JSON.stringify(score)}`
47571
+ );
47572
+ }
47573
+ if (names.has(score.name)) {
47574
+ throw new Error(`Duplicate score name '${score.name}' in score array`);
47575
+ }
47576
+ names.add(score.name);
46713
47577
  }
46714
47578
  }
46715
47579
  let results;
46716
47580
  if (Array.isArray(scoreValue)) {
46717
47581
  results = scoreValue;
46718
47582
  } else if (typeof scoreValue === "object" && !isEmpty2(scoreValue)) {
46719
- results = [scoreValue];
47583
+ results = [{ ...scoreValue, name: scoreValue.name ?? name }];
46720
47584
  } else {
46721
47585
  results = [{ name, score: scoreValue }];
46722
47586
  }
@@ -49551,6 +50415,7 @@ export {
49551
50415
  braintrustStreamChunkSchema,
49552
50416
  buildLocalSummary,
49553
50417
  collectAnthropicSession,
50418
+ completeOpenAIBatchTrace,
49554
50419
  configureInstrumentation,
49555
50420
  constructLogs3OverflowRequest,
49556
50421
  createFinalValuePassThroughStream,
@@ -49590,6 +50455,8 @@ export {
49590
50455
  loginToState,
49591
50456
  logs3OverflowUploadSchema,
49592
50457
  newId,
50458
+ openaiBatchesRetrieveTraced,
50459
+ openaiFilesCreateTraced,
49593
50460
  parseCachedHeader,
49594
50461
  parseTemplateFormat,
49595
50462
  permalink,