braintrust 3.17.0 → 3.18.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 (52) hide show
  1. package/dev/dist/index.d.mts +13 -0
  2. package/dev/dist/index.d.ts +13 -0
  3. package/dev/dist/index.js +4300 -2199
  4. package/dev/dist/index.mjs +2211 -110
  5. package/dist/apply-auto-instrumentation.js +238 -186
  6. package/dist/apply-auto-instrumentation.mjs +68 -16
  7. package/dist/auto-instrumentations/bundler/esbuild.cjs +90 -15
  8. package/dist/auto-instrumentations/bundler/esbuild.mjs +2 -2
  9. package/dist/auto-instrumentations/bundler/next.cjs +90 -15
  10. package/dist/auto-instrumentations/bundler/next.mjs +3 -3
  11. package/dist/auto-instrumentations/bundler/rollup.cjs +90 -15
  12. package/dist/auto-instrumentations/bundler/rollup.mjs +2 -2
  13. package/dist/auto-instrumentations/bundler/vite.cjs +90 -15
  14. package/dist/auto-instrumentations/bundler/vite.mjs +2 -2
  15. package/dist/auto-instrumentations/bundler/webpack-loader.cjs +89 -14
  16. package/dist/auto-instrumentations/bundler/webpack.cjs +90 -15
  17. package/dist/auto-instrumentations/bundler/webpack.mjs +3 -3
  18. package/dist/auto-instrumentations/{chunk-VXJONZVX.mjs → chunk-GNUEZ2PE.mjs} +13 -3
  19. package/dist/auto-instrumentations/{chunk-CNQ7BUKN.mjs → chunk-MYCHHXOE.mjs} +1 -1
  20. package/dist/auto-instrumentations/{chunk-E5DUYJWK.mjs → chunk-ZYKZEMRT.mjs} +82 -15
  21. package/dist/auto-instrumentations/hook.mjs +102 -15
  22. package/dist/auto-instrumentations/index.cjs +84 -16
  23. package/dist/auto-instrumentations/index.d.mts +3 -1
  24. package/dist/auto-instrumentations/index.d.ts +3 -1
  25. package/dist/auto-instrumentations/index.mjs +5 -3
  26. package/dist/auto-instrumentations/loader/cjs-patch.cjs +1 -1
  27. package/dist/auto-instrumentations/loader/cjs-patch.mjs +1 -1
  28. package/dist/auto-instrumentations/loader/esm-hook.mjs +1 -1
  29. package/dist/browser.d.mts +177 -11
  30. package/dist/browser.d.ts +177 -11
  31. package/dist/browser.js +2296 -104
  32. package/dist/browser.mjs +2455 -263
  33. package/dist/{chunk-VMBQETG3.js → chunk-73IYIIOL.js} +28 -2
  34. package/dist/{chunk-O4ZIWXO3.mjs → chunk-BYFADLEZ.mjs} +27 -1
  35. package/dist/cli.js +2219 -118
  36. package/dist/edge-light.d.mts +1 -1
  37. package/dist/edge-light.d.ts +1 -1
  38. package/dist/edge-light.js +2296 -104
  39. package/dist/edge-light.mjs +2455 -263
  40. package/dist/index.d.mts +177 -11
  41. package/dist/index.d.ts +177 -11
  42. package/dist/index.js +3296 -1128
  43. package/dist/index.mjs +2272 -104
  44. package/dist/instrumentation/index.d.mts +3 -0
  45. package/dist/instrumentation/index.d.ts +3 -0
  46. package/dist/instrumentation/index.js +2171 -105
  47. package/dist/instrumentation/index.mjs +2171 -105
  48. package/dist/workerd.d.mts +1 -1
  49. package/dist/workerd.d.ts +1 -1
  50. package/dist/workerd.js +2296 -104
  51. package/dist/workerd.mjs +2455 -263
  52. package/package.json +10 -10
package/dist/browser.js CHANGED
@@ -86,6 +86,7 @@ __export(browser_exports, {
86
86
  _internalIso: () => isomorph_default,
87
87
  _internalSetInitialState: () => _internalSetInitialState,
88
88
  addAzureBlobHeaders: () => addAzureBlobHeaders,
89
+ braintrustAISDKTelemetry: () => braintrustAISDKTelemetry,
89
90
  braintrustFlueObserver: () => braintrustFlueObserver,
90
91
  braintrustStreamChunkSchema: () => braintrustStreamChunkSchema,
91
92
  buildLocalSummary: () => buildLocalSummary,
@@ -179,6 +180,7 @@ __export(browser_exports, {
179
180
  wrapOpenAIv4: () => wrapOpenAIv4,
180
181
  wrapOpenRouter: () => wrapOpenRouter,
181
182
  wrapOpenRouterAgent: () => wrapOpenRouterAgent,
183
+ wrapPiCodingAgentSDK: () => wrapPiCodingAgentSDK,
182
184
  wrapTraced: () => wrapTraced,
183
185
  wrapVitest: () => wrapVitest
184
186
  });
@@ -5135,14 +5137,18 @@ function useTestBackgroundLogger() {
5135
5137
  function clearTestBackgroundLogger() {
5136
5138
  _internalGetGlobalState()?.setOverrideBgLogger(null);
5137
5139
  }
5138
- function initTestExperiment(experimentName, projectName) {
5140
+ function initTestExperiment(experimentName, projectName, experimentFullInfo = {}) {
5139
5141
  setInitialTestState();
5140
5142
  const state = _internalGetGlobalState();
5141
5143
  const project = projectName ?? experimentName;
5142
5144
  const lazyMetadata = new LazyValue(
5143
5145
  async () => ({
5144
5146
  project: { id: project, name: project, fullInfo: {} },
5145
- experiment: { id: experimentName, name: experimentName, fullInfo: {} }
5147
+ experiment: {
5148
+ id: experimentName,
5149
+ name: experimentName,
5150
+ fullInfo: experimentFullInfo
5151
+ }
5146
5152
  })
5147
5153
  );
5148
5154
  return new Experiment2(state, lazyMetadata);
@@ -8507,6 +8513,10 @@ var Experiment2 = class extends ObjectFetcher {
8507
8513
  return (await this.lazyMetadata.get()).project;
8508
8514
  })();
8509
8515
  }
8516
+ async _getBaseExperimentId() {
8517
+ const baseExperimentId = (await this.lazyMetadata.get()).experiment.fullInfo["base_exp_id"];
8518
+ return typeof baseExperimentId === "string" && baseExperimentId ? baseExperimentId : void 0;
8519
+ }
8510
8520
  parentObjectType() {
8511
8521
  return 1 /* EXPERIMENT */;
8512
8522
  }
@@ -8647,6 +8657,14 @@ var Experiment2 = class extends ObjectFetcher {
8647
8657
  comparisonExperimentId = baseExperiment.id;
8648
8658
  comparisonExperimentName = baseExperiment.name;
8649
8659
  }
8660
+ } else {
8661
+ try {
8662
+ const comparisonExperiment = await state.apiConn().get_json(`v1/experiment/${comparisonExperimentId}`);
8663
+ if (typeof comparisonExperiment["name"] === "string") {
8664
+ comparisonExperimentName = comparisonExperiment["name"];
8665
+ }
8666
+ } catch {
8667
+ }
8650
8668
  }
8651
8669
  try {
8652
8670
  const results = await state.apiConn().get_json(
@@ -10688,6 +10706,64 @@ var BasePlugin = class {
10688
10706
  }
10689
10707
  };
10690
10708
 
10709
+ // src/instrumentation/auto-instrumentation-suppression.ts
10710
+ var autoInstrumentationSuppressionStore;
10711
+ function suppressionStore() {
10712
+ autoInstrumentationSuppressionStore ??= isomorph_default.newAsyncLocalStorage();
10713
+ return autoInstrumentationSuppressionStore;
10714
+ }
10715
+ function currentFrames() {
10716
+ return suppressionStore().getStore()?.frames ?? [];
10717
+ }
10718
+ function isAutoInstrumentationSuppressed() {
10719
+ const frames = currentFrames();
10720
+ return frames[frames.length - 1]?.mode === "suppress";
10721
+ }
10722
+ function runWithAutoInstrumentationSuppressed(callback) {
10723
+ const frame = {
10724
+ id: /* @__PURE__ */ Symbol("braintrust.auto-instrumentation-suppress"),
10725
+ mode: "suppress"
10726
+ };
10727
+ return suppressionStore().run(
10728
+ { frames: [...currentFrames(), frame] },
10729
+ callback
10730
+ );
10731
+ }
10732
+ function bindAutoInstrumentationSuppressionToStart(tracingChannel2) {
10733
+ const startChannel = tracingChannel2.start;
10734
+ if (!startChannel) {
10735
+ return void 0;
10736
+ }
10737
+ const store = suppressionStore();
10738
+ startChannel.bindStore(store, () => ({
10739
+ frames: [
10740
+ ...currentFrames(),
10741
+ {
10742
+ id: /* @__PURE__ */ Symbol("braintrust.auto-instrumentation-suppress"),
10743
+ mode: "suppress"
10744
+ }
10745
+ ]
10746
+ }));
10747
+ return () => {
10748
+ startChannel.unbindStore(store);
10749
+ };
10750
+ }
10751
+ function enterAutoInstrumentationAllowed() {
10752
+ const frame = {
10753
+ id: /* @__PURE__ */ Symbol("braintrust.auto-instrumentation-allow"),
10754
+ mode: "allow"
10755
+ };
10756
+ suppressionStore().enterWith({
10757
+ frames: [...currentFrames(), frame]
10758
+ });
10759
+ return () => {
10760
+ const frames = currentFrames().filter(
10761
+ (candidate) => candidate.id !== frame.id
10762
+ );
10763
+ suppressionStore().enterWith(frames.length > 0 ? { frames } : void 0);
10764
+ };
10765
+ }
10766
+
10691
10767
  // src/instrumentation/core/channel-tracing.ts
10692
10768
  function isSyncStreamLike(value) {
10693
10769
  return !!value && typeof value === "object" && typeof value.on === "function";
@@ -10719,16 +10795,33 @@ function startSpanForEvent(config, event, channelName) {
10719
10795
  metadata: mergeInputMetadata(metadata, spanInfoMetadata)
10720
10796
  });
10721
10797
  } catch (error) {
10722
- console.error(`Error extracting input for ${channelName}:`, error);
10798
+ debugLogger.error(`Error extracting input for ${channelName}:`, error);
10723
10799
  }
10724
10800
  return { span, startTime };
10725
10801
  }
10802
+ function shouldTraceEvent(config, event, channelName) {
10803
+ if (!config.shouldTrace) {
10804
+ return true;
10805
+ }
10806
+ try {
10807
+ return config.shouldTrace(event.arguments, event);
10808
+ } catch (error) {
10809
+ debugLogger.error(
10810
+ `Error checking trace predicate for ${channelName}:`,
10811
+ error
10812
+ );
10813
+ return true;
10814
+ }
10815
+ }
10726
10816
  function ensureSpanStateForEvent(states, config, event, channelName) {
10727
10817
  const key = event;
10728
10818
  const existing = states.get(key);
10729
10819
  if (existing) {
10730
10820
  return existing;
10731
10821
  }
10822
+ if (!shouldTraceEvent(config, event, channelName)) {
10823
+ return void 0;
10824
+ }
10732
10825
  const created = startSpanForEvent(config, event, channelName);
10733
10826
  states.set(key, created);
10734
10827
  return created;
@@ -10744,13 +10837,16 @@ function bindCurrentSpanStoreToStart(tracingChannel2, states, config, channelNam
10744
10837
  startChannel.bindStore(
10745
10838
  currentSpanStore,
10746
10839
  (event) => {
10747
- const span = ensureSpanStateForEvent(
10840
+ if (isAutoInstrumentationSuppressed()) {
10841
+ return currentSpanStore.getStore();
10842
+ }
10843
+ const spanState = ensureSpanStateForEvent(
10748
10844
  states,
10749
10845
  config,
10750
10846
  event,
10751
10847
  channelName
10752
- ).span;
10753
- return contextManager.wrapSpanForStore(span);
10848
+ );
10849
+ return spanState ? contextManager.wrapSpanForStore(spanState.span) : currentSpanStore.getStore();
10754
10850
  }
10755
10851
  );
10756
10852
  return () => {
@@ -10785,7 +10881,10 @@ function runStreamingCompletionHook(args) {
10785
10881
  startTime: args.startTime
10786
10882
  });
10787
10883
  } catch (error) {
10788
- console.error(`Error in onComplete hook for ${args.channelName}:`, error);
10884
+ debugLogger.error(
10885
+ `Error in onComplete hook for ${args.channelName}:`,
10886
+ error
10887
+ );
10789
10888
  }
10790
10889
  }
10791
10890
  function traceAsyncChannel(channel2, config) {
@@ -10800,6 +10899,9 @@ function traceAsyncChannel(channel2, config) {
10800
10899
  );
10801
10900
  const handlers = {
10802
10901
  start: (event) => {
10902
+ if (isAutoInstrumentationSuppressed()) {
10903
+ return;
10904
+ }
10803
10905
  ensureSpanStateForEvent(
10804
10906
  states,
10805
10907
  config,
@@ -10834,7 +10936,7 @@ function traceAsyncChannel(channel2, config) {
10834
10936
  metrics
10835
10937
  });
10836
10938
  } catch (error) {
10837
- console.error(`Error extracting output for ${channelName}:`, error);
10939
+ debugLogger.error(`Error extracting output for ${channelName}:`, error);
10838
10940
  } finally {
10839
10941
  span.end();
10840
10942
  states.delete(event);
@@ -10862,6 +10964,9 @@ function traceStreamingChannel(channel2, config) {
10862
10964
  );
10863
10965
  const handlers = {
10864
10966
  start: (event) => {
10967
+ if (isAutoInstrumentationSuppressed()) {
10968
+ return;
10969
+ }
10865
10970
  ensureSpanStateForEvent(
10866
10971
  states,
10867
10972
  config,
@@ -10933,7 +11038,7 @@ function traceStreamingChannel(channel2, config) {
10933
11038
  metrics
10934
11039
  });
10935
11040
  } catch (error) {
10936
- console.error(
11041
+ debugLogger.error(
10937
11042
  `Error extracting output for ${channelName}:`,
10938
11043
  error
10939
11044
  );
@@ -10993,7 +11098,7 @@ function traceStreamingChannel(channel2, config) {
10993
11098
  metrics
10994
11099
  });
10995
11100
  } catch (error) {
10996
- console.error(`Error extracting output for ${channelName}:`, error);
11101
+ debugLogger.error(`Error extracting output for ${channelName}:`, error);
10997
11102
  } finally {
10998
11103
  span.end();
10999
11104
  states.delete(event);
@@ -11021,6 +11126,9 @@ function traceSyncStreamChannel(channel2, config) {
11021
11126
  );
11022
11127
  const handlers = {
11023
11128
  start: (event) => {
11129
+ if (isAutoInstrumentationSuppressed()) {
11130
+ return;
11131
+ }
11024
11132
  ensureSpanStateForEvent(
11025
11133
  states,
11026
11134
  config,
@@ -11074,7 +11182,7 @@ function traceSyncStreamChannel(channel2, config) {
11074
11182
  });
11075
11183
  }
11076
11184
  } catch (error) {
11077
- console.error(
11185
+ debugLogger.error(
11078
11186
  `Error extracting chatCompletion for ${channelName}:`,
11079
11187
  error
11080
11188
  );
@@ -11098,7 +11206,10 @@ function traceSyncStreamChannel(channel2, config) {
11098
11206
  span.log(extracted);
11099
11207
  }
11100
11208
  } catch (error) {
11101
- console.error(`Error extracting event for ${channelName}:`, error);
11209
+ debugLogger.error(
11210
+ `Error extracting event for ${channelName}:`,
11211
+ error
11212
+ );
11102
11213
  }
11103
11214
  });
11104
11215
  stream.on("end", () => {
@@ -12627,6 +12738,9 @@ var AnthropicPlugin = class extends BasePlugin {
12627
12738
  const states = /* @__PURE__ */ new WeakMap();
12628
12739
  const handlers = {
12629
12740
  start: (event) => {
12741
+ if (isAutoInstrumentationSuppressed()) {
12742
+ return;
12743
+ }
12630
12744
  const params = event.arguments[0] ?? {};
12631
12745
  const span = startSpan({
12632
12746
  name: "anthropic.beta.messages.toolRunner",
@@ -13356,6 +13470,520 @@ function serializeAISDKToolsForLogging(tools) {
13356
13470
  return serialized;
13357
13471
  }
13358
13472
 
13473
+ // src/wrappers/ai-sdk/telemetry.ts
13474
+ function braintrustAISDKTelemetry() {
13475
+ const operations = /* @__PURE__ */ new Map();
13476
+ const modelSpans = /* @__PURE__ */ new Map();
13477
+ const objectSpans = /* @__PURE__ */ new Map();
13478
+ const embedSpans = /* @__PURE__ */ new Map();
13479
+ const rerankSpans = /* @__PURE__ */ new Map();
13480
+ const toolSpans = /* @__PURE__ */ new Map();
13481
+ const runSafely = (name, callback) => {
13482
+ try {
13483
+ callback();
13484
+ } catch (error) {
13485
+ console.error(`Error in Braintrust AI SDK telemetry ${name}:`, error);
13486
+ }
13487
+ };
13488
+ const startChildSpan = (callId, name, type, event) => {
13489
+ const parent = operations.get(callId)?.span;
13490
+ const spanArgs = {
13491
+ name,
13492
+ spanAttributes: { type },
13493
+ ...event ? { event } : {}
13494
+ };
13495
+ const span = parent ? parent.startSpan(spanArgs) : startSpan(spanArgs);
13496
+ const state = operations.get(callId);
13497
+ if (state && type === "llm" /* LLM */) {
13498
+ state.hadModelChild = true;
13499
+ }
13500
+ return span;
13501
+ };
13502
+ return {
13503
+ onStart(event) {
13504
+ runSafely("onStart", () => {
13505
+ const operationName = operationNameFromId(event.operationId);
13506
+ const span = startSpan({
13507
+ name: operationName,
13508
+ spanAttributes: { type: "function" /* FUNCTION */ }
13509
+ });
13510
+ operations.set(event.callId, {
13511
+ hadModelChild: false,
13512
+ operationName,
13513
+ span,
13514
+ startTime: getCurrentUnixTimestamp()
13515
+ });
13516
+ const metadata = metadataFromEvent(event);
13517
+ const logPayload = { metadata };
13518
+ if (shouldRecordInputs(event)) {
13519
+ const { input, outputPromise } = processAISDKCallInput(
13520
+ operationInput(event, operationName)
13521
+ );
13522
+ logPayload.input = input;
13523
+ if (outputPromise && input && typeof input === "object") {
13524
+ outputPromise.then((resolvedData) => {
13525
+ span.log({
13526
+ input: {
13527
+ ...input,
13528
+ ...resolvedData
13529
+ }
13530
+ });
13531
+ }).catch(() => {
13532
+ });
13533
+ }
13534
+ }
13535
+ span.log(logPayload);
13536
+ });
13537
+ },
13538
+ onLanguageModelCallStart(event) {
13539
+ runSafely("onLanguageModelCallStart", () => {
13540
+ const state = operations.get(event.callId);
13541
+ const openSpans = modelSpans.get(event.callId);
13542
+ if (openSpans) {
13543
+ for (const span2 of openSpans) {
13544
+ span2.end();
13545
+ }
13546
+ modelSpans.delete(event.callId);
13547
+ }
13548
+ const span = startChildSpan(
13549
+ event.callId,
13550
+ state?.operationName === "streamText" ? "doStream" : "doGenerate",
13551
+ "llm" /* LLM */,
13552
+ {
13553
+ ...shouldRecordInputs(event) ? {
13554
+ input: processAISDKCallInput(
13555
+ operationInput(
13556
+ event,
13557
+ state?.operationName ?? "generateText"
13558
+ )
13559
+ ).input
13560
+ } : {},
13561
+ metadata: metadataFromEvent(event)
13562
+ }
13563
+ );
13564
+ const spans = modelSpans.get(event.callId) ?? [];
13565
+ spans.push(span);
13566
+ modelSpans.set(event.callId, spans);
13567
+ });
13568
+ },
13569
+ onLanguageModelCallEnd(event) {
13570
+ runSafely("onLanguageModelCallEnd", () => {
13571
+ const span = shiftModelSpan(modelSpans, event.callId);
13572
+ if (!span) {
13573
+ return;
13574
+ }
13575
+ const result = {
13576
+ ...event,
13577
+ response: event.responseId ? { id: event.responseId } : void 0
13578
+ };
13579
+ span.log({
13580
+ ...shouldRecordOutputs(event) ? {
13581
+ output: processAISDKOutput(result, DEFAULT_DENY_OUTPUT_PATHS)
13582
+ } : {},
13583
+ metrics: extractTokenMetrics(result)
13584
+ });
13585
+ span.end();
13586
+ });
13587
+ },
13588
+ onObjectStepStart(event) {
13589
+ runSafely("onObjectStepStart", () => {
13590
+ const state = operations.get(event.callId);
13591
+ const openSpan = objectSpans.get(event.callId);
13592
+ if (openSpan) {
13593
+ openSpan.end();
13594
+ objectSpans.delete(event.callId);
13595
+ }
13596
+ const span = startChildSpan(
13597
+ event.callId,
13598
+ state?.operationName === "streamObject" ? "doStream" : "doGenerate",
13599
+ "llm" /* LLM */,
13600
+ {
13601
+ ...shouldRecordInputs(event) ? {
13602
+ input: {
13603
+ prompt: event.promptMessages
13604
+ }
13605
+ } : {},
13606
+ metadata: metadataFromEvent(event)
13607
+ }
13608
+ );
13609
+ objectSpans.set(event.callId, span);
13610
+ });
13611
+ },
13612
+ onObjectStepFinish(event) {
13613
+ runSafely("onObjectStepFinish", () => {
13614
+ const span = objectSpans.get(event.callId);
13615
+ if (!span) {
13616
+ return;
13617
+ }
13618
+ const result = {
13619
+ ...event,
13620
+ text: event.objectText
13621
+ };
13622
+ span.log({
13623
+ ...shouldRecordOutputs(event) ? {
13624
+ output: processAISDKOutput(result, DEFAULT_DENY_OUTPUT_PATHS)
13625
+ } : {},
13626
+ metrics: extractTokenMetrics(result)
13627
+ });
13628
+ span.end();
13629
+ objectSpans.delete(event.callId);
13630
+ });
13631
+ },
13632
+ onEmbedStart(event) {
13633
+ runSafely("onEmbedStart", () => {
13634
+ const state = operations.get(event.callId);
13635
+ for (const [embedCallId, embedState] of embedSpans) {
13636
+ if (embedState.callId === event.callId && (state?.operationName === "embed" || embedState.values === event.values)) {
13637
+ embedState.span.end();
13638
+ embedSpans.delete(embedCallId);
13639
+ }
13640
+ }
13641
+ const span = startChildSpan(
13642
+ event.callId,
13643
+ "doEmbed",
13644
+ "llm" /* LLM */,
13645
+ {
13646
+ ...shouldRecordInputs(event) ? {
13647
+ input: {
13648
+ values: event.values
13649
+ }
13650
+ } : {},
13651
+ metadata: metadataFromEvent(event)
13652
+ }
13653
+ );
13654
+ embedSpans.set(event.embedCallId, {
13655
+ callId: event.callId,
13656
+ span,
13657
+ values: event.values
13658
+ });
13659
+ });
13660
+ },
13661
+ onEmbedFinish(event) {
13662
+ runSafely("onEmbedFinish", () => {
13663
+ const state = embedSpans.get(event.embedCallId);
13664
+ if (!state) {
13665
+ return;
13666
+ }
13667
+ const result = {
13668
+ ...event,
13669
+ embeddings: event.embeddings
13670
+ };
13671
+ state.span.log({
13672
+ ...shouldRecordOutputs(event) ? {
13673
+ output: processAISDKEmbeddingOutput(
13674
+ result,
13675
+ DEFAULT_DENY_OUTPUT_PATHS
13676
+ )
13677
+ } : {},
13678
+ metrics: extractTokenMetrics(result)
13679
+ });
13680
+ state.span.end();
13681
+ embedSpans.delete(event.embedCallId);
13682
+ });
13683
+ },
13684
+ onRerankStart(event) {
13685
+ runSafely("onRerankStart", () => {
13686
+ const openSpan = rerankSpans.get(event.callId);
13687
+ if (openSpan) {
13688
+ openSpan.end();
13689
+ rerankSpans.delete(event.callId);
13690
+ }
13691
+ const span = startChildSpan(
13692
+ event.callId,
13693
+ "doRerank",
13694
+ "llm" /* LLM */,
13695
+ {
13696
+ ...shouldRecordInputs(event) ? {
13697
+ input: {
13698
+ documents: event.documents,
13699
+ query: event.query,
13700
+ topN: event.topN
13701
+ }
13702
+ } : {},
13703
+ metadata: metadataFromEvent(event)
13704
+ }
13705
+ );
13706
+ rerankSpans.set(event.callId, span);
13707
+ });
13708
+ },
13709
+ onRerankFinish(event) {
13710
+ runSafely("onRerankFinish", () => {
13711
+ const span = rerankSpans.get(event.callId);
13712
+ if (!span) {
13713
+ return;
13714
+ }
13715
+ const result = {
13716
+ ranking: event.ranking?.map((entry) => ({
13717
+ originalIndex: entry.index,
13718
+ score: entry.relevanceScore
13719
+ }))
13720
+ };
13721
+ span.log({
13722
+ ...shouldRecordOutputs(event) ? {
13723
+ output: processAISDKRerankOutput(
13724
+ result,
13725
+ DEFAULT_DENY_OUTPUT_PATHS
13726
+ )
13727
+ } : {}
13728
+ });
13729
+ span.end();
13730
+ rerankSpans.delete(event.callId);
13731
+ });
13732
+ },
13733
+ onToolExecutionStart(event) {
13734
+ runSafely("onToolExecutionStart", () => {
13735
+ const toolCallId = event.toolCall.toolCallId;
13736
+ if (!toolCallId) {
13737
+ return;
13738
+ }
13739
+ const span = startChildSpan(
13740
+ event.callId,
13741
+ event.toolCall.toolName || "tool",
13742
+ "tool" /* TOOL */,
13743
+ {
13744
+ ...shouldRecordInputs(event) ? {
13745
+ input: event.toolCall.input
13746
+ } : {},
13747
+ metadata: {
13748
+ ...createAISDKIntegrationMetadata(),
13749
+ toolCallId,
13750
+ ...typeof event.toolCall.toolName === "string" ? { toolName: event.toolCall.toolName } : {}
13751
+ }
13752
+ }
13753
+ );
13754
+ toolSpans.set(toolCallId, { callId: event.callId, span });
13755
+ });
13756
+ },
13757
+ onToolExecutionEnd(event) {
13758
+ runSafely("onToolExecutionEnd", () => {
13759
+ const toolCallId = event.toolCall.toolCallId;
13760
+ const state = toolCallId ? toolSpans.get(toolCallId) : void 0;
13761
+ if (!toolCallId || !state) {
13762
+ return;
13763
+ }
13764
+ const toolOutput = event.toolOutput;
13765
+ if (toolOutput?.type === "tool-error") {
13766
+ state.span.log({
13767
+ error: toolOutput.error instanceof Error ? toolOutput.error.message : String(toolOutput?.error),
13768
+ metrics: typeof event.durationMs === "number" ? { duration_ms: event.durationMs } : {}
13769
+ });
13770
+ } else {
13771
+ state.span.log({
13772
+ ...shouldRecordOutputs(event) ? { output: toolOutput?.output } : {},
13773
+ metrics: typeof event.durationMs === "number" ? { duration_ms: event.durationMs } : {}
13774
+ });
13775
+ }
13776
+ state.span.end();
13777
+ toolSpans.delete(toolCallId);
13778
+ });
13779
+ },
13780
+ onChunk(event) {
13781
+ runSafely("onChunk", () => {
13782
+ const callId = event.chunk?.callId;
13783
+ if (!callId) {
13784
+ return;
13785
+ }
13786
+ const state = operations.get(callId);
13787
+ if (!state || state.firstChunkTime !== void 0) {
13788
+ return;
13789
+ }
13790
+ state.firstChunkTime = getCurrentUnixTimestamp();
13791
+ });
13792
+ },
13793
+ onFinish(event) {
13794
+ runSafely("onFinish", () => {
13795
+ const state = operations.get(event.callId);
13796
+ if (!state) {
13797
+ return;
13798
+ }
13799
+ const result = finishResult(event, state.operationName);
13800
+ const metrics = state.hadModelChild ? {} : extractTokenMetrics(result);
13801
+ if (state.firstChunkTime !== void 0) {
13802
+ metrics.time_to_first_token = state.firstChunkTime - state.startTime;
13803
+ }
13804
+ state.span.log({
13805
+ ...shouldRecordOutputs(event) ? {
13806
+ output: finishOutput(result, state.operationName)
13807
+ } : {},
13808
+ metrics
13809
+ });
13810
+ state.span.end();
13811
+ operations.delete(event.callId);
13812
+ });
13813
+ },
13814
+ onError(event) {
13815
+ runSafely("onError", () => {
13816
+ const errorEvent = isObject(event) ? event : {};
13817
+ const callId = typeof errorEvent.callId === "string" ? errorEvent.callId : void 0;
13818
+ if (!callId) {
13819
+ return;
13820
+ }
13821
+ const state = operations.get(callId);
13822
+ if (!state) {
13823
+ return;
13824
+ }
13825
+ const error = errorEvent.error ?? event;
13826
+ const openModelSpans = modelSpans.get(callId);
13827
+ if (openModelSpans) {
13828
+ for (const span of openModelSpans) {
13829
+ logError(span, error);
13830
+ span.end();
13831
+ }
13832
+ modelSpans.delete(callId);
13833
+ }
13834
+ const openObjectSpan = objectSpans.get(callId);
13835
+ if (openObjectSpan) {
13836
+ logError(openObjectSpan, error);
13837
+ openObjectSpan.end();
13838
+ objectSpans.delete(callId);
13839
+ }
13840
+ for (const [embedCallId, embedState] of embedSpans) {
13841
+ if (embedState.callId === callId) {
13842
+ logError(embedState.span, error);
13843
+ embedState.span.end();
13844
+ embedSpans.delete(embedCallId);
13845
+ }
13846
+ }
13847
+ const openRerankSpan = rerankSpans.get(callId);
13848
+ if (openRerankSpan) {
13849
+ logError(openRerankSpan, error);
13850
+ openRerankSpan.end();
13851
+ rerankSpans.delete(callId);
13852
+ }
13853
+ for (const [toolCallId, toolState] of toolSpans) {
13854
+ if (toolState.callId === callId) {
13855
+ logError(toolState.span, error);
13856
+ toolState.span.end();
13857
+ toolSpans.delete(toolCallId);
13858
+ }
13859
+ }
13860
+ logError(state.span, error);
13861
+ state.span.end();
13862
+ operations.delete(callId);
13863
+ });
13864
+ },
13865
+ executeTool({ toolCallId, execute }) {
13866
+ const state = toolSpans.get(toolCallId);
13867
+ return state ? withCurrent(state.span, () => execute()) : execute();
13868
+ }
13869
+ };
13870
+ }
13871
+ function shouldRecordInputs(event) {
13872
+ return event.recordInputs !== false;
13873
+ }
13874
+ function shouldRecordOutputs(event) {
13875
+ return event.recordOutputs !== false;
13876
+ }
13877
+ function operationNameFromId(operationId) {
13878
+ return operationId?.startsWith("ai.") ? operationId.slice("ai.".length) : operationId || "ai-sdk";
13879
+ }
13880
+ function modelFromEvent(event) {
13881
+ return event.modelId ? {
13882
+ modelId: event.modelId,
13883
+ ...event.provider ? { provider: event.provider } : {}
13884
+ } : void 0;
13885
+ }
13886
+ function metadataFromEvent(event) {
13887
+ const metadata = createAISDKIntegrationMetadata();
13888
+ const { model, provider } = serializeModelWithProvider(modelFromEvent(event));
13889
+ if (model) {
13890
+ metadata.model = model;
13891
+ }
13892
+ if (provider) {
13893
+ metadata.provider = provider;
13894
+ }
13895
+ if (typeof event.functionId === "string") {
13896
+ metadata.functionId = event.functionId;
13897
+ }
13898
+ return metadata;
13899
+ }
13900
+ function operationInput(event, operationName) {
13901
+ if (operationName === "embed") {
13902
+ return {
13903
+ model: modelFromEvent(event),
13904
+ value: event.value
13905
+ };
13906
+ }
13907
+ if (operationName === "embedMany") {
13908
+ return {
13909
+ model: modelFromEvent(event),
13910
+ values: Array.isArray(event.value) ? event.value ?? [] : void 0
13911
+ };
13912
+ }
13913
+ if (operationName === "rerank") {
13914
+ return {
13915
+ model: modelFromEvent(event),
13916
+ documents: event.documents,
13917
+ query: event.query,
13918
+ topN: event.topN
13919
+ };
13920
+ }
13921
+ return {
13922
+ model: modelFromEvent(event),
13923
+ system: event.system,
13924
+ prompt: event.prompt,
13925
+ messages: event.messages,
13926
+ tools: event.tools,
13927
+ toolChoice: event.toolChoice,
13928
+ activeTools: event.activeTools,
13929
+ output: event.output,
13930
+ schema: event.schema,
13931
+ schemaName: event.schemaName,
13932
+ schemaDescription: event.schemaDescription,
13933
+ maxOutputTokens: event.maxOutputTokens,
13934
+ temperature: event.temperature,
13935
+ topP: event.topP,
13936
+ topK: event.topK,
13937
+ presencePenalty: event.presencePenalty,
13938
+ frequencyPenalty: event.frequencyPenalty,
13939
+ seed: event.seed,
13940
+ maxRetries: event.maxRetries,
13941
+ headers: event.headers,
13942
+ providerOptions: event.providerOptions
13943
+ };
13944
+ }
13945
+ function shiftModelSpan(modelSpans, callId) {
13946
+ const spans = modelSpans.get(callId);
13947
+ const span = spans?.shift();
13948
+ if (spans && spans.length === 0) {
13949
+ modelSpans.delete(callId);
13950
+ }
13951
+ return span;
13952
+ }
13953
+ function finishResult(event, operationName) {
13954
+ if (operationName === "embed") {
13955
+ return {
13956
+ ...event,
13957
+ embedding: event.embedding
13958
+ };
13959
+ }
13960
+ if (operationName === "embedMany") {
13961
+ return {
13962
+ ...event,
13963
+ embeddings: event.embedding
13964
+ };
13965
+ }
13966
+ if (operationName === "rerank") {
13967
+ return event;
13968
+ }
13969
+ return event;
13970
+ }
13971
+ function finishOutput(result, operationName) {
13972
+ if (operationName === "embed" || operationName === "embedMany") {
13973
+ return processAISDKEmbeddingOutput(
13974
+ result,
13975
+ DEFAULT_DENY_OUTPUT_PATHS
13976
+ );
13977
+ }
13978
+ if (operationName === "rerank") {
13979
+ return processAISDKRerankOutput(
13980
+ result,
13981
+ DEFAULT_DENY_OUTPUT_PATHS
13982
+ );
13983
+ }
13984
+ return processAISDKOutput(result, DEFAULT_DENY_OUTPUT_PATHS);
13985
+ }
13986
+
13359
13987
  // src/instrumentation/plugins/ai-sdk-channels.ts
13360
13988
  var aiSDKChannels = defineChannels("ai", {
13361
13989
  generateText: channel({
@@ -13415,6 +14043,10 @@ var aiSDKChannels = defineChannels("ai", {
13415
14043
  toolLoopAgentStream: channel({
13416
14044
  channelName: "ToolLoopAgent.stream",
13417
14045
  kind: "async"
14046
+ }),
14047
+ v7CreateTelemetryDispatcher: channel({
14048
+ channelName: "createTelemetryDispatcher",
14049
+ kind: "sync-stream"
13418
14050
  })
13419
14051
  });
13420
14052
 
@@ -13435,9 +14067,30 @@ var DEFAULT_DENY_OUTPUT_PATHS = [
13435
14067
  ];
13436
14068
  var AUTO_PATCHED_MODEL = /* @__PURE__ */ Symbol.for("braintrust.ai-sdk.auto-patched-model");
13437
14069
  var AUTO_PATCHED_TOOL = /* @__PURE__ */ Symbol.for("braintrust.ai-sdk.auto-patched-tool");
14070
+ var AUTO_PATCHED_V7_TELEMETRY_DISPATCHER = /* @__PURE__ */ Symbol.for(
14071
+ "braintrust.ai-sdk.v7.auto-patched-telemetry-dispatcher"
14072
+ );
13438
14073
  var RUNTIME_DENY_OUTPUT_PATHS = /* @__PURE__ */ Symbol.for(
13439
14074
  "braintrust.ai-sdk.deny-output-paths"
13440
14075
  );
14076
+ var AI_SDK_V7_TELEMETRY_CALLBACKS = [
14077
+ "onStart",
14078
+ "onStepStart",
14079
+ "onLanguageModelCallStart",
14080
+ "onLanguageModelCallEnd",
14081
+ "onToolExecutionStart",
14082
+ "onToolExecutionEnd",
14083
+ "onChunk",
14084
+ "onStepFinish",
14085
+ "onObjectStepStart",
14086
+ "onObjectStepFinish",
14087
+ "onEmbedStart",
14088
+ "onEmbedFinish",
14089
+ "onRerankStart",
14090
+ "onRerankFinish",
14091
+ "onFinish",
14092
+ "onError"
14093
+ ];
13441
14094
  var AISDKPlugin = class extends BasePlugin {
13442
14095
  config;
13443
14096
  constructor(config = {}) {
@@ -13452,6 +14105,7 @@ var AISDKPlugin = class extends BasePlugin {
13452
14105
  }
13453
14106
  subscribeToAISDK() {
13454
14107
  const denyOutputPaths = this.config.denyOutputPaths || DEFAULT_DENY_OUTPUT_PATHS;
14108
+ this.unsubscribers.push(subscribeToAISDKV7TelemetryDispatcher());
13455
14109
  this.unsubscribers.push(
13456
14110
  traceStreamingChannel(aiSDKChannels.generateText, {
13457
14111
  name: "generateText",
@@ -13676,6 +14330,57 @@ var AISDKPlugin = class extends BasePlugin {
13676
14330
  );
13677
14331
  }
13678
14332
  };
14333
+ function subscribeToAISDKV7TelemetryDispatcher() {
14334
+ const channel2 = aiSDKChannels.v7CreateTelemetryDispatcher.tracingChannel();
14335
+ const telemetry = braintrustAISDKTelemetry();
14336
+ const handlers = {
14337
+ end: (event) => {
14338
+ const telemetryOptions = event.arguments?.[0]?.telemetry;
14339
+ if (telemetryOptions?.isEnabled === false) {
14340
+ return;
14341
+ }
14342
+ patchAISDKV7TelemetryDispatcher(event.result, telemetry);
14343
+ }
14344
+ };
14345
+ channel2.subscribe(handlers);
14346
+ return () => {
14347
+ channel2.unsubscribe(handlers);
14348
+ };
14349
+ }
14350
+ function patchAISDKV7TelemetryDispatcher(dispatcher, telemetry) {
14351
+ if (!isObject(dispatcher)) {
14352
+ return;
14353
+ }
14354
+ const dispatcherRecord = dispatcher;
14355
+ if (dispatcherRecord[AUTO_PATCHED_V7_TELEMETRY_DISPATCHER]) {
14356
+ return;
14357
+ }
14358
+ dispatcherRecord[AUTO_PATCHED_V7_TELEMETRY_DISPATCHER] = true;
14359
+ for (const key of AI_SDK_V7_TELEMETRY_CALLBACKS) {
14360
+ const braintrustCallback = telemetry[key];
14361
+ if (typeof braintrustCallback !== "function") {
14362
+ continue;
14363
+ }
14364
+ const existingCallback = dispatcherRecord[key];
14365
+ dispatcherRecord[key] = (event) => {
14366
+ const existingResult = typeof existingCallback === "function" ? existingCallback.call(dispatcher, event) : void 0;
14367
+ const braintrustResult = braintrustCallback.call(telemetry, event);
14368
+ const pending = [existingResult, braintrustResult].filter(isPromiseLike);
14369
+ if (pending.length > 0) {
14370
+ return Promise.allSettled(pending).then(() => void 0);
14371
+ }
14372
+ };
14373
+ }
14374
+ const braintrustExecuteTool = telemetry.executeTool;
14375
+ if (typeof braintrustExecuteTool !== "function") {
14376
+ return;
14377
+ }
14378
+ const existingExecuteTool = dispatcherRecord.executeTool;
14379
+ dispatcherRecord.executeTool = (args) => braintrustExecuteTool.call(telemetry, {
14380
+ ...args,
14381
+ execute: () => typeof existingExecuteTool === "function" ? existingExecuteTool.call(dispatcher, args) : args.execute()
14382
+ });
14383
+ }
13679
14384
  function resolveDenyOutputPaths(event, defaultDenyOutputPaths) {
13680
14385
  if (Array.isArray(event?.denyOutputPaths)) {
13681
14386
  return event.denyOutputPaths;
@@ -14127,11 +14832,11 @@ function prepareAISDKChildTracing(params, self, parentSpan, denyOutputPaths, aiS
14127
14832
  metadata: baseMetadata
14128
14833
  }
14129
14834
  });
14835
+ const streamStartTime = getCurrentUnixTimestamp();
14130
14836
  const result = await withCurrent(
14131
14837
  span,
14132
14838
  () => Reflect.apply(originalDoStream, resolvedModel, [options])
14133
14839
  );
14134
- const streamStartTime = getCurrentUnixTimestamp();
14135
14840
  let firstChunkTime;
14136
14841
  const output = {};
14137
14842
  let text = "";
@@ -14140,7 +14845,7 @@ function prepareAISDKChildTracing(params, self, parentSpan, denyOutputPaths, aiS
14140
14845
  let object = void 0;
14141
14846
  const transformStream = new TransformStream({
14142
14847
  transform(chunk, controller) {
14143
- if (firstChunkTime === void 0) {
14848
+ if (firstChunkTime === void 0 && isAISDKContentStreamChunk(chunk)) {
14144
14849
  firstChunkTime = getCurrentUnixTimestamp();
14145
14850
  }
14146
14851
  switch (chunk.type) {
@@ -14332,6 +15037,78 @@ function finalizeAISDKChildTracing(event) {
14332
15037
  delete event.__braintrust_ai_sdk_cleanup;
14333
15038
  }
14334
15039
  }
15040
+ function extractAISDKStreamPart(chunk) {
15041
+ if (!isObject(chunk) || !isObject(chunk.part)) {
15042
+ return chunk;
15043
+ }
15044
+ return chunk.part;
15045
+ }
15046
+ function stringContent(value) {
15047
+ return typeof value === "string" && value.length > 0 ? value : void 0;
15048
+ }
15049
+ function rawValueHasAISDKContent(value) {
15050
+ if (value === void 0 || value === null) {
15051
+ return false;
15052
+ }
15053
+ if (typeof value === "string") {
15054
+ return value.length > 0;
15055
+ }
15056
+ if (!isObject(value)) {
15057
+ return true;
15058
+ }
15059
+ const delta = value.delta;
15060
+ if (stringContent(value.content) || stringContent(value.text) || stringContent(value.delta) || stringContent(value.arguments) || stringContent(value.partial_json) || isObject(delta) && (stringContent(delta.content) || stringContent(delta.text) || stringContent(delta.arguments) || stringContent(delta.partial_json) || stringContent(delta.thinking)) || Array.isArray(value.choices) && value.choices.some((choice) => {
15061
+ if (!isObject(choice) || !isObject(choice.delta)) {
15062
+ return false;
15063
+ }
15064
+ const choiceDelta = choice.delta;
15065
+ if (stringContent(choiceDelta.content) || stringContent(choiceDelta.text)) {
15066
+ return true;
15067
+ }
15068
+ if (isObject(choiceDelta.function_call) && stringContent(choiceDelta.function_call.arguments)) {
15069
+ return true;
15070
+ }
15071
+ return Array.isArray(choiceDelta.tool_calls) && choiceDelta.tool_calls.some(
15072
+ (toolCall) => isObject(toolCall) && isObject(toolCall.function) && stringContent(toolCall.function.arguments)
15073
+ );
15074
+ })) {
15075
+ return true;
15076
+ }
15077
+ return false;
15078
+ }
15079
+ function isAISDKContentStreamChunk(chunk) {
15080
+ const part = extractAISDKStreamPart(chunk);
15081
+ if (typeof part === "string") {
15082
+ return part.length > 0;
15083
+ }
15084
+ if (!isObject(part) || typeof part.type !== "string") {
15085
+ return false;
15086
+ }
15087
+ switch (part.type) {
15088
+ case "text-delta":
15089
+ return stringContent(part.textDelta) !== void 0 || stringContent(part.delta) !== void 0 || stringContent(part.text) !== void 0 || stringContent(part.content) !== void 0;
15090
+ case "reasoning-delta":
15091
+ return stringContent(part.delta) !== void 0 || stringContent(part.text) !== void 0 || stringContent(part.content) !== void 0;
15092
+ case "tool-call":
15093
+ case "object":
15094
+ case "file":
15095
+ return true;
15096
+ case "tool-input-delta":
15097
+ case "tool-call-delta":
15098
+ return stringContent(part.argsTextDelta) !== void 0 || stringContent(part.inputTextDelta) !== void 0 || stringContent(part.delta) !== void 0 || stringContent(part.text) !== void 0 || stringContent(part.content) !== void 0;
15099
+ case "raw":
15100
+ return rawValueHasAISDKContent(part.rawValue);
15101
+ default:
15102
+ return false;
15103
+ }
15104
+ }
15105
+ function isAISDKContentAsyncIterableChunk(chunk) {
15106
+ if (isAISDKContentStreamChunk(chunk)) {
15107
+ return true;
15108
+ }
15109
+ const part = extractAISDKStreamPart(chunk);
15110
+ return isObject(part) && typeof part.type !== "string";
15111
+ }
14335
15112
  function patchAISDKStreamingResult(args) {
14336
15113
  const { defaultDenyOutputPaths, endEvent, result, span, startTime } = args;
14337
15114
  if (!result || typeof result !== "object") {
@@ -14344,7 +15121,7 @@ function patchAISDKStreamingResult(args) {
14344
15121
  const wrappedBaseStream = resultRecord.baseStream.pipeThrough(
14345
15122
  new TransformStream({
14346
15123
  transform(chunk, controller) {
14347
- if (firstChunkTime2 === void 0) {
15124
+ if (firstChunkTime2 === void 0 && isAISDKContentStreamChunk(chunk)) {
14348
15125
  firstChunkTime2 = getCurrentUnixTimestamp();
14349
15126
  }
14350
15127
  controller.enqueue(chunk);
@@ -14388,8 +15165,8 @@ function patchAISDKStreamingResult(args) {
14388
15165
  }
14389
15166
  let firstChunkTime;
14390
15167
  const wrappedStream = createPatchedAsyncIterable(streamField.stream, {
14391
- onChunk: () => {
14392
- if (firstChunkTime === void 0) {
15168
+ onChunk: (chunk) => {
15169
+ if (firstChunkTime === void 0 && isAISDKContentAsyncIterableChunk(chunk)) {
14393
15170
  firstChunkTime = getCurrentUnixTimestamp();
14394
15171
  }
14395
15172
  },
@@ -15361,15 +16138,17 @@ function collectLocalMcpServerToolHookNames(serverName, serverConfig) {
15361
16138
 
15362
16139
  // src/instrumentation/plugins/claude-agent-sdk-plugin.ts
15363
16140
  var ROOT_LLM_PARENT_KEY = "__root__";
16141
+ var SUB_AGENT_PROMPT_SOURCE_PRIORITY = {
16142
+ delegation: 0,
16143
+ lifecycle: 1,
16144
+ sidechain: 2
16145
+ };
15364
16146
  function llmParentKey(parentToolUseId) {
15365
16147
  return parentToolUseId ?? ROOT_LLM_PARENT_KEY;
15366
16148
  }
15367
16149
  function isSubAgentDelegationToolName(toolName) {
15368
16150
  return toolName === "Agent" || toolName === "Task";
15369
16151
  }
15370
- function shouldParentToolAsTaskSibling(toolName) {
15371
- return toolName === "Agent" || toolName === "Task" || toolName === "Bash";
15372
- }
15373
16152
  function filterSerializableOptions(options) {
15374
16153
  const allowedKeys = [
15375
16154
  "model",
@@ -15506,26 +16285,39 @@ function extractUsageFromMessage(message) {
15506
16285
  }
15507
16286
  return metrics;
15508
16287
  }
15509
- function buildLLMInput(prompt, conversationHistory, capturedPromptMessages) {
15510
- const promptMessages = [];
15511
- if (typeof prompt === "string") {
15512
- promptMessages.push({ content: prompt, role: "user" });
15513
- } else if (capturedPromptMessages && capturedPromptMessages.length > 0) {
15514
- for (const msg of capturedPromptMessages) {
15515
- const role = msg.message?.role;
15516
- const content = msg.message?.content;
15517
- if (role && content !== void 0) {
15518
- promptMessages.push({ content, role });
15519
- }
15520
- }
15521
- }
16288
+ function buildLLMInput(promptMessages, conversationHistory) {
15522
16289
  const inputParts = [...promptMessages, ...conversationHistory];
15523
16290
  return inputParts.length > 0 ? inputParts : void 0;
15524
16291
  }
16292
+ function conversationMessageFromSDKMessage(message) {
16293
+ const role = message.message?.role;
16294
+ const content = message.message?.content;
16295
+ if (role && content !== void 0) {
16296
+ return { content, role };
16297
+ }
16298
+ return void 0;
16299
+ }
16300
+ function messageContentHasBlockType(message, blockType) {
16301
+ const content = message.message?.content;
16302
+ return Array.isArray(content) && content.some(
16303
+ (block) => typeof block === "object" && block !== null && "type" in block && block.type === blockType
16304
+ );
16305
+ }
16306
+ function buildRootPromptMessages(prompt, capturedPromptMessages) {
16307
+ if (typeof prompt === "string") {
16308
+ return [{ content: prompt, role: "user" }];
16309
+ }
16310
+ if (!capturedPromptMessages || capturedPromptMessages.length === 0) {
16311
+ return [];
16312
+ }
16313
+ return capturedPromptMessages.map(conversationMessageFromSDKMessage).filter(
16314
+ (message) => message !== void 0
16315
+ );
16316
+ }
15525
16317
  function formatCapturedMessages(messages) {
15526
16318
  return messages.length > 0 ? messages : [];
15527
16319
  }
15528
- async function createLLMSpanForMessages(messages, prompt, conversationHistory, options, startTime, capturedPromptMessages, parentSpan, existingSpan) {
16320
+ async function createLLMSpanForMessages(messages, promptMessages, conversationHistory, options, startTime, parentSpan, existingSpan) {
15529
16321
  if (messages.length === 0) {
15530
16322
  return void 0;
15531
16323
  }
@@ -15535,11 +16327,7 @@ async function createLLMSpanForMessages(messages, prompt, conversationHistory, o
15535
16327
  }
15536
16328
  const model = lastMessage.message.model || options.model;
15537
16329
  const usage = extractUsageFromMessage(lastMessage);
15538
- const input = buildLLMInput(
15539
- prompt,
15540
- conversationHistory,
15541
- capturedPromptMessages
15542
- );
16330
+ const input = buildLLMInput(promptMessages, conversationHistory);
15543
16331
  const outputs = messages.map(
15544
16332
  (m) => m.message?.content && m.message?.role ? { content: m.message.content, role: m.message.role } : void 0
15545
16333
  ).filter(
@@ -15670,8 +16458,7 @@ function createToolTracingHooks(resolveParentSpan, activeToolSpans, mcpServers,
15670
16458
  },
15671
16459
  name: parsed.displayName,
15672
16460
  parent: await resolveParentSpan(toolUseID, {
15673
- agentId: input.agent_id,
15674
- preferTaskSiblingParent: shouldParentToolAsTaskSibling(parsed.toolName)
16461
+ agentId: input.agent_id
15675
16462
  }),
15676
16463
  spanAttributes: { type: "tool" /* TOOL */ }
15677
16464
  });
@@ -15917,12 +16704,37 @@ function injectTracingHooks(options, resolveParentSpan, activeToolSpans, localTo
15917
16704
  }
15918
16705
  };
15919
16706
  }
16707
+ function setSubAgentPromptMessages(state, parentToolUseId, promptMessages, source) {
16708
+ if (promptMessages.length === 0) {
16709
+ return;
16710
+ }
16711
+ const parentKey = llmParentKey(parentToolUseId);
16712
+ const sourcePriority = SUB_AGENT_PROMPT_SOURCE_PRIORITY[source];
16713
+ const currentPriority = state.promptSourcePriorityByParentKey.get(parentKey) ?? -1;
16714
+ if (sourcePriority > currentPriority) {
16715
+ state.promptMessagesByParentKey.set(parentKey, promptMessages);
16716
+ state.promptSourcePriorityByParentKey.set(parentKey, sourcePriority);
16717
+ }
16718
+ }
16719
+ function getConversationHistory(state, parentKey) {
16720
+ let conversationHistory = state.conversationHistoryByParentKey.get(parentKey);
16721
+ if (!conversationHistory) {
16722
+ conversationHistory = [];
16723
+ state.conversationHistoryByParentKey.set(parentKey, conversationHistory);
16724
+ }
16725
+ return conversationHistory;
16726
+ }
15920
16727
  async function finalizeCurrentMessageGroup(state) {
15921
16728
  if (state.currentMessages.length === 0) {
15922
16729
  return;
15923
16730
  }
15924
16731
  const parentToolUseId = state.currentMessages[0]?.parent_tool_use_id ?? null;
15925
16732
  const parentKey = llmParentKey(parentToolUseId);
16733
+ const conversationHistory = getConversationHistory(state, parentKey);
16734
+ const promptMessages = parentToolUseId ? state.promptMessagesByParentKey.get(parentKey) ?? [] : buildRootPromptMessages(
16735
+ state.originalPrompt,
16736
+ state.capturedPromptMessages
16737
+ );
15926
16738
  let parentSpan = await state.span.export();
15927
16739
  if (parentToolUseId) {
15928
16740
  const subAgentSpan = state.subAgentSpans.get(parentToolUseId);
@@ -15933,11 +16745,10 @@ async function finalizeCurrentMessageGroup(state) {
15933
16745
  const existingLlmSpan = state.activeLlmSpansByParentToolUse.get(parentKey);
15934
16746
  const llmSpanResult = await createLLMSpanForMessages(
15935
16747
  state.currentMessages,
15936
- state.originalPrompt,
15937
- state.finalResults,
16748
+ promptMessages,
16749
+ conversationHistory,
15938
16750
  state.options,
15939
16751
  state.currentMessageStartTime,
15940
- state.capturedPromptMessages,
15941
16752
  parentSpan,
15942
16753
  existingLlmSpan
15943
16754
  );
@@ -15951,6 +16762,7 @@ async function finalizeCurrentMessageGroup(state) {
15951
16762
  state.latestRootLlmParentRef.value = llmSpanResult.spanExport;
15952
16763
  }
15953
16764
  if (llmSpanResult.finalMessage) {
16765
+ conversationHistory.push(llmSpanResult.finalMessage);
15954
16766
  state.finalResults.push(llmSpanResult.finalMessage);
15955
16767
  }
15956
16768
  }
@@ -15978,6 +16790,15 @@ function maybeTrackToolUseContext(state, message) {
15978
16790
  description: getStringProperty(block.input, "description"),
15979
16791
  toolUseId: block.id
15980
16792
  });
16793
+ const prompt = getStringProperty(block.input, "prompt");
16794
+ if (prompt) {
16795
+ setSubAgentPromptMessages(
16796
+ state,
16797
+ block.id,
16798
+ [{ content: prompt, role: "user" }],
16799
+ "delegation"
16800
+ );
16801
+ }
15981
16802
  }
15982
16803
  }
15983
16804
  }
@@ -16096,6 +16917,14 @@ async function maybeHandleTaskLifecycleMessage(state, message) {
16096
16917
  };
16097
16918
  if (message.subtype === "task_started") {
16098
16919
  const prompt = getStringProperty(message, "prompt");
16920
+ if (prompt) {
16921
+ setSubAgentPromptMessages(
16922
+ state,
16923
+ toolUseId,
16924
+ [{ content: prompt, role: "user" }],
16925
+ "lifecycle"
16926
+ );
16927
+ }
16099
16928
  subAgentSpan.log({
16100
16929
  input: prompt,
16101
16930
  metadata
@@ -16146,6 +16975,28 @@ async function handleStreamMessage(state, message) {
16146
16975
  return;
16147
16976
  }
16148
16977
  await maybeStartSubAgentSpan(state, message);
16978
+ const messageParentToolUseId = message.parent_tool_use_id;
16979
+ if (messageParentToolUseId && message.type === "user") {
16980
+ const conversationMessage = conversationMessageFromSDKMessage(message);
16981
+ if (conversationMessage?.role === "user") {
16982
+ await finalizeCurrentMessageGroup(state);
16983
+ const parentKey = llmParentKey(messageParentToolUseId);
16984
+ const conversationHistory = getConversationHistory(state, parentKey);
16985
+ const currentPromptSourcePriority = state.promptSourcePriorityByParentKey.get(parentKey) ?? -1;
16986
+ const canUseAsInitialSidechainPrompt = conversationHistory.length === 0 && currentPromptSourcePriority < SUB_AGENT_PROMPT_SOURCE_PRIORITY.sidechain && !messageContentHasBlockType(message, "tool_result");
16987
+ if (!canUseAsInitialSidechainPrompt) {
16988
+ conversationHistory.push(conversationMessage);
16989
+ return;
16990
+ }
16991
+ setSubAgentPromptMessages(
16992
+ state,
16993
+ messageParentToolUseId,
16994
+ [conversationMessage],
16995
+ "sidechain"
16996
+ );
16997
+ return;
16998
+ }
16999
+ }
16149
17000
  const messageId = message.message?.id;
16150
17001
  if (messageId && messageId !== state.currentMessageId) {
16151
17002
  await finalizeCurrentMessageGroup(state);
@@ -16297,6 +17148,7 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
16297
17148
  }
16298
17149
  const activeToolSpans = /* @__PURE__ */ new Map();
16299
17150
  const activeLlmSpansByParentToolUse = /* @__PURE__ */ new Map();
17151
+ const conversationHistoryByParentKey = /* @__PURE__ */ new Map();
16300
17152
  const subAgentSpans = /* @__PURE__ */ new Map();
16301
17153
  const endedSubAgentSpans = /* @__PURE__ */ new Set();
16302
17154
  const toolUseToParent = /* @__PURE__ */ new Map();
@@ -16306,6 +17158,8 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
16306
17158
  };
16307
17159
  const subAgentDetailsByToolUseId = /* @__PURE__ */ new Map();
16308
17160
  const taskIdToToolUseId = /* @__PURE__ */ new Map();
17161
+ const promptMessagesByParentKey = /* @__PURE__ */ new Map();
17162
+ const promptSourcePriorityByParentKey = /* @__PURE__ */ new Map();
16309
17163
  const localToolContext = createClaudeLocalToolContext();
16310
17164
  const { hasLocalToolHandlers, localToolHookNames } = prepareLocalToolHandlersInMcpServers(options.mcpServers);
16311
17165
  const skipLocalToolHooks = options[CLAUDE_AGENT_SDK_SKIP_LOCAL_TOOL_HOOKS_OPTION] === true || hasLocalToolHandlers;
@@ -16314,38 +17168,19 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
16314
17168
  const parentToolUseId = trackedParentToolUseId ?? (context?.agentId ? taskIdToToolUseId.get(context.agentId) ?? null : null);
16315
17169
  const parentKey = llmParentKey(parentToolUseId);
16316
17170
  const activeLlmSpan = activeLlmSpansByParentToolUse.get(parentKey);
16317
- if (context?.preferTaskSiblingParent) {
16318
- if (!activeLlmSpan) {
16319
- await ensureActiveLlmSpanForParentToolUse(
16320
- span,
16321
- activeLlmSpansByParentToolUse,
16322
- subAgentDetailsByToolUseId,
16323
- activeToolSpans,
16324
- subAgentSpans,
16325
- parentToolUseId,
16326
- getCurrentUnixTimestamp()
16327
- );
16328
- }
16329
- if (parentToolUseId) {
16330
- const subAgentSpan = await ensureSubAgentSpan(
16331
- subAgentDetailsByToolUseId,
16332
- span,
16333
- activeToolSpans,
16334
- subAgentSpans,
16335
- parentToolUseId
16336
- );
16337
- return subAgentSpan.export();
16338
- }
16339
- return span.export();
16340
- }
16341
- if (activeLlmSpan) {
16342
- return activeLlmSpan.export();
17171
+ const latestLlmParent = parentToolUseId ? latestLlmParentBySubAgentToolUse.get(parentToolUseId) : latestRootLlmParentRef.value;
17172
+ if (!activeLlmSpan && !latestLlmParent) {
17173
+ await ensureActiveLlmSpanForParentToolUse(
17174
+ span,
17175
+ activeLlmSpansByParentToolUse,
17176
+ subAgentDetailsByToolUseId,
17177
+ activeToolSpans,
17178
+ subAgentSpans,
17179
+ parentToolUseId,
17180
+ getCurrentUnixTimestamp()
17181
+ );
16343
17182
  }
16344
17183
  if (parentToolUseId) {
16345
- const parentLlm = latestLlmParentBySubAgentToolUse.get(parentToolUseId);
16346
- if (parentLlm) {
16347
- return parentLlm;
16348
- }
16349
17184
  const subAgentSpan = await ensureSubAgentSpan(
16350
17185
  subAgentDetailsByToolUseId,
16351
17186
  span,
@@ -16355,9 +17190,6 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
16355
17190
  );
16356
17191
  return subAgentSpan.export();
16357
17192
  }
16358
- if (latestRootLlmParentRef.value) {
16359
- return latestRootLlmParentRef.value;
16360
- }
16361
17193
  return span.export();
16362
17194
  };
16363
17195
  localToolContext.resolveLocalToolParent = resolveToolUseParentSpan;
@@ -16378,6 +17210,7 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
16378
17210
  accumulatedOutputTokens: 0,
16379
17211
  activeLlmSpansByParentToolUse,
16380
17212
  activeToolSpans,
17213
+ conversationHistoryByParentKey,
16381
17214
  capturedPromptMessages,
16382
17215
  currentMessageId: void 0,
16383
17216
  currentMessageStartTime: startTime,
@@ -16388,7 +17221,9 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
16388
17221
  originalPrompt,
16389
17222
  processing: Promise.resolve(),
16390
17223
  promptDone,
17224
+ promptMessagesByParentKey,
16391
17225
  promptStarted: () => promptStarted,
17226
+ promptSourcePriorityByParentKey,
16392
17227
  span,
16393
17228
  subAgentDetailsByToolUseId,
16394
17229
  subAgentSpans,
@@ -17817,6 +18652,10 @@ var googleGenAIChannels = defineChannels("@google/genai", {
17817
18652
  embedContent: channel({
17818
18653
  channelName: "models.embedContent",
17819
18654
  kind: "async"
18655
+ }),
18656
+ interactionsCreate: channel({
18657
+ channelName: "interactions.create",
18658
+ kind: "async"
17820
18659
  })
17821
18660
  });
17822
18661
 
@@ -17844,6 +18683,7 @@ var GoogleGenAIPlugin = class extends BasePlugin {
17844
18683
  this.subscribeToGenerateContentChannel();
17845
18684
  this.subscribeToGenerateContentStreamChannel();
17846
18685
  this.subscribeToEmbedContentChannel();
18686
+ this.subscribeToInteractionsCreateChannel();
17847
18687
  }
17848
18688
  subscribeToGenerateContentChannel() {
17849
18689
  const tracingChannel2 = googleGenAIChannels.generateContent.tracingChannel();
@@ -18016,7 +18856,30 @@ var GoogleGenAIPlugin = class extends BasePlugin {
18016
18856
  tracingChannel2.unsubscribe(handlers);
18017
18857
  });
18018
18858
  }
18859
+ subscribeToInteractionsCreateChannel() {
18860
+ this.unsubscribers.push(
18861
+ traceStreamingChannel(
18862
+ googleGenAIChannels.interactionsCreate,
18863
+ {
18864
+ name: "create_interaction",
18865
+ shouldTrace: ([params]) => !isBackgroundInteractionCreate(params),
18866
+ type: "llm" /* LLM */,
18867
+ extractInput: ([params]) => ({
18868
+ input: serializeInteractionInput(params),
18869
+ metadata: extractInteractionMetadata(params)
18870
+ }),
18871
+ extractOutput: (result) => serializeInteractionValue(result),
18872
+ extractMetadata: (result) => extractInteractionResponseMetadata(result),
18873
+ extractMetrics: (result, startTime) => cleanMetrics3(extractInteractionMetrics(result, startTime)),
18874
+ aggregateChunks: (chunks, _result, _event, startTime) => aggregateInteractionEvents(chunks, startTime)
18875
+ }
18876
+ )
18877
+ );
18878
+ }
18019
18879
  };
18880
+ function isBackgroundInteractionCreate(params) {
18881
+ return tryToDict(params)?.background === true;
18882
+ }
18020
18883
  function ensureSpanState(states, event, create) {
18021
18884
  const existing = states.get(event);
18022
18885
  if (existing) {
@@ -18224,6 +19087,60 @@ function serializeEmbedContentInput(params) {
18224
19087
  }
18225
19088
  return input;
18226
19089
  }
19090
+ function serializeInteractionInput(params) {
19091
+ const input = {
19092
+ input: serializeInteractionValue(params.input)
19093
+ };
19094
+ for (const key of [
19095
+ "model",
19096
+ "agent",
19097
+ "agent_config",
19098
+ "api_version",
19099
+ "background",
19100
+ "environment",
19101
+ "generation_config",
19102
+ "previous_interaction_id",
19103
+ "response_format",
19104
+ "response_mime_type",
19105
+ "response_modalities",
19106
+ "service_tier",
19107
+ "store",
19108
+ "stream",
19109
+ "system_instruction",
19110
+ "webhook_config"
19111
+ ]) {
19112
+ const value = params[key];
19113
+ if (value !== void 0) {
19114
+ input[key] = serializeInteractionValue(value);
19115
+ }
19116
+ }
19117
+ return input;
19118
+ }
19119
+ function extractInteractionMetadata(params) {
19120
+ const metadata = {};
19121
+ for (const key of [
19122
+ "model",
19123
+ "agent",
19124
+ "agent_config",
19125
+ "generation_config",
19126
+ "system_instruction",
19127
+ "response_format",
19128
+ "response_mime_type",
19129
+ "response_modalities",
19130
+ "service_tier"
19131
+ ]) {
19132
+ const value = params[key];
19133
+ if (value !== void 0) {
19134
+ metadata[key] = serializeInteractionValue(value);
19135
+ }
19136
+ }
19137
+ if (Array.isArray(params.tools)) {
19138
+ metadata.tools = params.tools.map(
19139
+ (tool) => serializeInteractionValue(tool)
19140
+ );
19141
+ }
19142
+ return metadata;
19143
+ }
18227
19144
  function serializeContentCollection(contents) {
18228
19145
  if (contents === null || contents === void 0) {
18229
19146
  return null;
@@ -18254,21 +19171,8 @@ function serializePart(part) {
18254
19171
  }
18255
19172
  if (part.inlineData && part.inlineData.data) {
18256
19173
  const { data, mimeType } = part.inlineData;
18257
- if (data instanceof Uint8Array || typeof Buffer !== "undefined" && Buffer.isBuffer(data) || typeof data === "string") {
18258
- const extension = mimeType ? mimeType.split("/")[1] : "bin";
18259
- const filename = `file.${extension}`;
18260
- const buffer = typeof data === "string" ? typeof Buffer !== "undefined" ? Buffer.from(data, "base64") : new Uint8Array(
18261
- atob(data).split("").map((c) => c.charCodeAt(0))
18262
- ) : typeof Buffer !== "undefined" ? Buffer.from(data) : new Uint8Array(data);
18263
- const arrayBuffer = buffer instanceof Uint8Array ? buffer.buffer.slice(
18264
- buffer.byteOffset,
18265
- buffer.byteOffset + buffer.byteLength
18266
- ) : buffer;
18267
- const attachment = new Attachment({
18268
- data: arrayBuffer,
18269
- filename,
18270
- contentType: mimeType || "application/octet-stream"
18271
- });
19174
+ const attachment = createAttachmentFromInlineData(data, mimeType);
19175
+ if (attachment) {
18272
19176
  return {
18273
19177
  image_url: { url: attachment }
18274
19178
  };
@@ -18276,6 +19180,59 @@ function serializePart(part) {
18276
19180
  }
18277
19181
  return part;
18278
19182
  }
19183
+ function serializeInteractionValue(value, seen = /* @__PURE__ */ new WeakSet()) {
19184
+ if (value === null || value === void 0 || typeof value !== "object") {
19185
+ return value;
19186
+ }
19187
+ if (Array.isArray(value)) {
19188
+ return value.map((item) => serializeInteractionValue(item, seen));
19189
+ }
19190
+ const dict = tryToDict(value);
19191
+ if (dict === null || dict === void 0 || typeof dict !== "object") {
19192
+ return dict;
19193
+ }
19194
+ if (Array.isArray(dict)) {
19195
+ return dict.map((item) => serializeInteractionValue(item, seen));
19196
+ }
19197
+ if (seen.has(dict)) {
19198
+ return "[Circular]";
19199
+ }
19200
+ seen.add(dict);
19201
+ try {
19202
+ const serialized = {};
19203
+ const mimeType = "mime_type" in dict && typeof dict.mime_type === "string" ? dict.mime_type : "mimeType" in dict && typeof dict.mimeType === "string" ? dict.mimeType : void 0;
19204
+ const attachment = mimeType && "data" in dict && dict.data !== void 0 ? createAttachmentFromInlineData(dict.data, mimeType) : null;
19205
+ for (const [key, entry] of Object.entries(dict)) {
19206
+ if (key === "data" && attachment) {
19207
+ serialized[key] = attachment;
19208
+ } else {
19209
+ serialized[key] = serializeInteractionValue(entry, seen);
19210
+ }
19211
+ }
19212
+ return serialized;
19213
+ } finally {
19214
+ seen.delete(dict);
19215
+ }
19216
+ }
19217
+ function createAttachmentFromInlineData(data, mimeType) {
19218
+ if (!(data instanceof Uint8Array || typeof Buffer !== "undefined" && Buffer.isBuffer(data) || typeof data === "string")) {
19219
+ return null;
19220
+ }
19221
+ const extension = mimeType ? mimeType.split("/")[1] : "bin";
19222
+ const filename = `file.${extension}`;
19223
+ const buffer = typeof data === "string" ? typeof Buffer !== "undefined" ? Buffer.from(data, "base64") : new Uint8Array(
19224
+ atob(data).split("").map((c) => c.charCodeAt(0))
19225
+ ) : typeof Buffer !== "undefined" ? Buffer.from(data) : new Uint8Array(data);
19226
+ const arrayBuffer = buffer instanceof Uint8Array ? buffer.buffer.slice(
19227
+ buffer.byteOffset,
19228
+ buffer.byteOffset + buffer.byteLength
19229
+ ) : buffer;
19230
+ return new Attachment({
19231
+ data: arrayBuffer,
19232
+ filename,
19233
+ contentType: mimeType || "application/octet-stream"
19234
+ });
19235
+ }
18279
19236
  function serializeGenerateContentTools(params) {
18280
19237
  const config = params.config ? tryToDict(params.config) : null;
18281
19238
  const tools = config?.tools;
@@ -18360,6 +19317,33 @@ function extractEmbedContentMetrics(response, startTime) {
18360
19317
  }
18361
19318
  return metrics;
18362
19319
  }
19320
+ function extractInteractionMetrics(response, startTime) {
19321
+ const metrics = {};
19322
+ if (startTime !== void 0) {
19323
+ const end = getCurrentUnixTimestamp();
19324
+ metrics.start = startTime;
19325
+ metrics.end = end;
19326
+ metrics.duration = end - startTime;
19327
+ }
19328
+ if (response?.usage) {
19329
+ populateInteractionUsageMetrics(metrics, response.usage);
19330
+ }
19331
+ return metrics;
19332
+ }
19333
+ function extractInteractionResponseMetadata(response) {
19334
+ const responseDict = tryToDict(response);
19335
+ if (!responseDict) {
19336
+ return void 0;
19337
+ }
19338
+ const metadata = {};
19339
+ if (typeof responseDict.id === "string") {
19340
+ metadata.interaction_id = responseDict.id;
19341
+ }
19342
+ if (typeof responseDict.status === "string") {
19343
+ metadata.status = responseDict.status;
19344
+ }
19345
+ return Object.keys(metadata).length > 0 ? metadata : void 0;
19346
+ }
18363
19347
  function extractEmbedPromptTokenCount(response) {
18364
19348
  if (!response) {
18365
19349
  return void 0;
@@ -18422,6 +19406,23 @@ function populateUsageMetrics(metrics, usage) {
18422
19406
  metrics.completion_reasoning_tokens = usage.thoughtsTokenCount;
18423
19407
  }
18424
19408
  }
19409
+ function populateInteractionUsageMetrics(metrics, usage) {
19410
+ if (typeof usage.total_input_tokens === "number") {
19411
+ metrics.prompt_tokens = usage.total_input_tokens;
19412
+ }
19413
+ if (typeof usage.total_output_tokens === "number") {
19414
+ metrics.completion_tokens = usage.total_output_tokens;
19415
+ }
19416
+ if (typeof usage.total_tokens === "number") {
19417
+ metrics.tokens = usage.total_tokens;
19418
+ }
19419
+ if (typeof usage.total_cached_tokens === "number") {
19420
+ metrics.prompt_cached_tokens = usage.total_cached_tokens;
19421
+ }
19422
+ if (typeof usage.total_thought_tokens === "number") {
19423
+ metrics.completion_reasoning_tokens = usage.total_thought_tokens;
19424
+ }
19425
+ }
18425
19426
  function aggregateGenerateContentChunks(chunks, startTime, firstTokenTime) {
18426
19427
  const end = getCurrentUnixTimestamp();
18427
19428
  const metrics = {
@@ -18519,6 +19520,146 @@ function aggregateGenerateContentChunks(chunks, startTime, firstTokenTime) {
18519
19520
  }
18520
19521
  return { aggregated, metrics };
18521
19522
  }
19523
+ function aggregateInteractionEvents(chunks, startTime) {
19524
+ const end = getCurrentUnixTimestamp();
19525
+ const metrics = {};
19526
+ if (startTime !== void 0) {
19527
+ metrics.start = startTime;
19528
+ metrics.end = end;
19529
+ metrics.duration = end - startTime;
19530
+ }
19531
+ let latestInteraction;
19532
+ let latestUsage;
19533
+ let status;
19534
+ let outputText = "";
19535
+ const steps = /* @__PURE__ */ new Map();
19536
+ for (const chunk of chunks) {
19537
+ const event = tryToDict(chunk);
19538
+ if (!event) {
19539
+ continue;
19540
+ }
19541
+ const usage = extractInteractionUsageFromEvent(event);
19542
+ if (usage) {
19543
+ latestUsage = usage;
19544
+ }
19545
+ const interaction = tryToDict(event.interaction);
19546
+ if (interaction) {
19547
+ latestInteraction = serializeInteractionValue(interaction);
19548
+ if (typeof interaction.status === "string") {
19549
+ status = interaction.status;
19550
+ }
19551
+ }
19552
+ if (typeof event.status === "string") {
19553
+ status = event.status;
19554
+ }
19555
+ const index = typeof event.index === "number" ? event.index : void 0;
19556
+ if (index === void 0) {
19557
+ continue;
19558
+ }
19559
+ if (event.event_type === "step.start") {
19560
+ const compact = compactInteractionStep(event.step);
19561
+ compact.index = index;
19562
+ steps.set(index, compact);
19563
+ continue;
19564
+ }
19565
+ if (event.event_type === "step.delta") {
19566
+ const step = steps.get(index) ?? { index };
19567
+ const textDelta = applyInteractionDelta(step, event.delta);
19568
+ if (textDelta) {
19569
+ outputText += textDelta;
19570
+ }
19571
+ steps.set(index, step);
19572
+ }
19573
+ }
19574
+ if (latestUsage) {
19575
+ populateInteractionUsageMetrics(metrics, latestUsage);
19576
+ }
19577
+ const output = latestInteraction ? { ...latestInteraction } : {};
19578
+ if (status) {
19579
+ output.status = status;
19580
+ }
19581
+ if (outputText) {
19582
+ output.output_text = outputText;
19583
+ }
19584
+ if (latestUsage) {
19585
+ output.usage = serializeInteractionValue(latestUsage);
19586
+ }
19587
+ const compactSteps = Array.from(steps.values()).sort(
19588
+ (left, right) => Number(left.index ?? 0) - Number(right.index ?? 0)
19589
+ );
19590
+ if (compactSteps.length > 0) {
19591
+ output.steps = compactSteps;
19592
+ }
19593
+ const metadata = {};
19594
+ if (typeof output.id === "string") {
19595
+ metadata.interaction_id = output.id;
19596
+ }
19597
+ if (typeof output.status === "string") {
19598
+ metadata.status = output.status;
19599
+ }
19600
+ return {
19601
+ output,
19602
+ metrics: cleanMetrics3(metrics),
19603
+ ...Object.keys(metadata).length > 0 ? { metadata } : {}
19604
+ };
19605
+ }
19606
+ function extractInteractionUsageFromEvent(event) {
19607
+ const metadata = tryToDict(event.metadata);
19608
+ const metadataUsage = tryToDict(metadata?.usage);
19609
+ if (metadataUsage) {
19610
+ return metadataUsage;
19611
+ }
19612
+ const metadataTotalUsage = tryToDict(metadata?.total_usage);
19613
+ if (metadataTotalUsage) {
19614
+ return metadataTotalUsage;
19615
+ }
19616
+ const interaction = tryToDict(event.interaction);
19617
+ const interactionUsage = tryToDict(interaction?.usage);
19618
+ return interactionUsage ? interactionUsage : void 0;
19619
+ }
19620
+ function compactInteractionStep(step) {
19621
+ const stepDict = tryToDict(step);
19622
+ if (!stepDict) {
19623
+ return {};
19624
+ }
19625
+ const compact = {};
19626
+ for (const key of [
19627
+ "type",
19628
+ "content",
19629
+ "name",
19630
+ "server_name",
19631
+ "arguments",
19632
+ "result",
19633
+ "is_error"
19634
+ ]) {
19635
+ if (stepDict[key] !== void 0) {
19636
+ compact[key] = serializeInteractionValue(stepDict[key]);
19637
+ }
19638
+ }
19639
+ return Object.keys(compact).length > 0 ? compact : serializeInteractionValue(stepDict);
19640
+ }
19641
+ function applyInteractionDelta(step, delta) {
19642
+ const deltaDict = tryToDict(delta);
19643
+ if (!deltaDict) {
19644
+ return void 0;
19645
+ }
19646
+ const deltaType = deltaDict.type;
19647
+ if (typeof deltaType === "string" && typeof step.type !== "string") {
19648
+ step.type = deltaType === "text" ? "model_output" : deltaType;
19649
+ }
19650
+ if (deltaType === "text" && typeof deltaDict.text === "string") {
19651
+ step.text = `${typeof step.text === "string" ? step.text : ""}${deltaDict.text}`;
19652
+ return deltaDict.text;
19653
+ }
19654
+ if (deltaType === "arguments_delta" && typeof deltaDict.arguments === "string") {
19655
+ step.arguments = `${typeof step.arguments === "string" ? step.arguments : ""}${deltaDict.arguments}`;
19656
+ return void 0;
19657
+ }
19658
+ const deltas = Array.isArray(step.deltas) ? step.deltas : [];
19659
+ deltas.push(serializeInteractionValue(deltaDict));
19660
+ step.deltas = deltas;
19661
+ return void 0;
19662
+ }
18522
19663
  function cleanMetrics3(metrics) {
18523
19664
  const cleaned = {};
18524
19665
  for (const [key, value] of Object.entries(metrics)) {
@@ -24345,7 +25486,8 @@ var FlueObserveBridge = class {
24345
25486
  metadata
24346
25487
  }
24347
25488
  });
24348
- this.runsById.set(event.runId, { metadata, span });
25489
+ const activeContext = enterCurrentFlueSpan(span);
25490
+ this.runsById.set(event.runId, { activeContext, metadata, span });
24349
25491
  }
24350
25492
  handleRunEnd(event) {
24351
25493
  const state = this.runsById.get(event.runId);
@@ -24363,6 +25505,7 @@ var FlueObserveBridge = class {
24363
25505
  });
24364
25506
  safeEnd(state.span, eventTime(event.timestamp));
24365
25507
  this.runsById.delete(event.runId);
25508
+ restoreCurrentFlueSpan(state.activeContext);
24366
25509
  }
24367
25510
  void flush().catch((error) => {
24368
25511
  logInstrumentationError3("Flue flush", error);
@@ -24489,7 +25632,8 @@ var FlueObserveBridge = class {
24489
25632
  metadata
24490
25633
  }
24491
25634
  });
24492
- this.toolsByKey.set(toolKey(event), { metadata, span });
25635
+ const activeContext = enterCurrentFlueSpan(span);
25636
+ this.toolsByKey.set(toolKey(event), { activeContext, metadata, span });
24493
25637
  }
24494
25638
  handleToolCall(event) {
24495
25639
  if (!event.toolCallId) {
@@ -24512,6 +25656,7 @@ var FlueObserveBridge = class {
24512
25656
  });
24513
25657
  safeEnd(state.span, eventTime(event.timestamp));
24514
25658
  this.toolsByKey.delete(key);
25659
+ restoreCurrentFlueSpan(state.activeContext);
24515
25660
  }
24516
25661
  handleTaskStart(event) {
24517
25662
  if (!event.taskId) {
@@ -24916,6 +26061,34 @@ function stateMatchesRun(state, runId) {
24916
26061
  function startFlueSpan(parent, args) {
24917
26062
  return parent ? withCurrent(parent, () => startSpan(args)) : startSpan(args);
24918
26063
  }
26064
+ function enterCurrentFlueSpan(span) {
26065
+ const contextManager = _internalGetGlobalState()?.contextManager;
26066
+ const store = contextManager ? Reflect.get(contextManager, BRAINTRUST_CURRENT_SPAN_STORE) : void 0;
26067
+ if (!contextManager || !isCurrentSpanStore(store)) {
26068
+ return void 0;
26069
+ }
26070
+ const previous = store.getStore();
26071
+ try {
26072
+ store.enterWith(contextManager.wrapSpanForStore(span));
26073
+ return { previous, store };
26074
+ } catch (error) {
26075
+ logInstrumentationError3("Flue context propagation", error);
26076
+ return void 0;
26077
+ }
26078
+ }
26079
+ function isCurrentSpanStore(value) {
26080
+ return isObjectLike(value) && typeof Reflect.get(value, "enterWith") === "function" && typeof Reflect.get(value, "getStore") === "function";
26081
+ }
26082
+ function restoreCurrentFlueSpan(activeContext) {
26083
+ if (!activeContext) {
26084
+ return;
26085
+ }
26086
+ try {
26087
+ activeContext.store.enterWith(activeContext.previous);
26088
+ } catch (error) {
26089
+ logInstrumentationError3("Flue context restoration", error);
26090
+ }
26091
+ }
24919
26092
  function safeLog3(span, event) {
24920
26093
  try {
24921
26094
  span.log(event);
@@ -25393,6 +26566,890 @@ function isBraintrustHandler(handler) {
25393
26566
  return Reflect.get(handler, "name") === BRAINTRUST_LANGCHAIN_CALLBACK_HANDLER_NAME;
25394
26567
  }
25395
26568
 
26569
+ // src/instrumentation/plugins/pi-coding-agent-channels.ts
26570
+ var piCodingAgentChannels = defineChannels(
26571
+ "@earendil-works/pi-coding-agent",
26572
+ {
26573
+ prompt: channel({
26574
+ channelName: "AgentSession.prompt",
26575
+ kind: "async"
26576
+ })
26577
+ }
26578
+ );
26579
+
26580
+ // src/instrumentation/plugins/pi-coding-agent-plugin.ts
26581
+ var piStreamPatchStates = /* @__PURE__ */ new WeakMap();
26582
+ var piPromptContextStore;
26583
+ var PiCodingAgentPlugin = class extends BasePlugin {
26584
+ activePromptStates = /* @__PURE__ */ new Set();
26585
+ onEnable() {
26586
+ this.subscribeToPrompt();
26587
+ }
26588
+ onDisable() {
26589
+ for (const unsubscribe of this.unsubscribers) {
26590
+ unsubscribe();
26591
+ }
26592
+ this.unsubscribers = [];
26593
+ for (const state of [...this.activePromptStates]) {
26594
+ void finalizePiPromptRun(state).catch((error) => {
26595
+ logInstrumentationError4("Pi Coding Agent disable cleanup", error);
26596
+ });
26597
+ }
26598
+ }
26599
+ subscribeToPrompt() {
26600
+ const channel2 = piCodingAgentChannels.prompt.tracingChannel();
26601
+ const states = /* @__PURE__ */ new WeakMap();
26602
+ const unbindAutoInstrumentationSuppression = bindAutoInstrumentationSuppressionToStart(channel2);
26603
+ const handlers = {
26604
+ start: (event) => {
26605
+ const state = startPiPromptRun(event, (state2) => {
26606
+ this.activePromptStates.delete(state2);
26607
+ });
26608
+ if (state) {
26609
+ this.activePromptStates.add(state);
26610
+ states.set(event, state);
26611
+ }
26612
+ },
26613
+ asyncEnd: async (event) => {
26614
+ const state = states.get(event);
26615
+ if (!state) {
26616
+ return;
26617
+ }
26618
+ states.delete(event);
26619
+ state.promptCallEnded = true;
26620
+ if (!state.finalized && state.deferCompletionUntilTurnEnd && !state.turnEnded) {
26621
+ if (!state.sawStreamFn) {
26622
+ state.queued = true;
26623
+ if (!state.streamPatchState.queuedPromptStates.includes(state)) {
26624
+ state.streamPatchState.queuedPromptStates.push(state);
26625
+ }
26626
+ }
26627
+ return;
26628
+ }
26629
+ await finalizePiPromptRun(state);
26630
+ },
26631
+ error: async (event) => {
26632
+ const state = states.get(event);
26633
+ if (!state) {
26634
+ return;
26635
+ }
26636
+ states.delete(event);
26637
+ await finalizePiPromptRun(state, event.error);
26638
+ }
26639
+ };
26640
+ channel2.subscribe(handlers);
26641
+ this.unsubscribers.push(() => {
26642
+ unbindAutoInstrumentationSuppression?.();
26643
+ channel2.unsubscribe(handlers);
26644
+ });
26645
+ }
26646
+ };
26647
+ function startPiPromptRun(event, onFinalize) {
26648
+ const session = extractSession(event);
26649
+ const agent = session?.agent;
26650
+ if (!session || !isPiAgent(agent)) {
26651
+ return void 0;
26652
+ }
26653
+ const metadata = {
26654
+ ...extractSessionMetadata(session),
26655
+ ...extractPromptOptionsMetadata(event.arguments[1]),
26656
+ "pi_coding_agent.operation": "AgentSession.prompt",
26657
+ provider: session.model?.provider ?? agent.state?.model?.provider ?? "pi",
26658
+ ...session.model?.id || agent.state?.model?.id ? { model: session.model?.id ?? agent.state?.model?.id } : {},
26659
+ ...event.moduleVersion ? { "pi_coding_agent.version": event.moduleVersion } : {}
26660
+ };
26661
+ const span = startSpan({
26662
+ event: {
26663
+ input: extractPromptInput(event.arguments[0], event.arguments[1]),
26664
+ metadata
26665
+ },
26666
+ name: "AgentSession.prompt",
26667
+ spanAttributes: { type: "task" /* TASK */ }
26668
+ });
26669
+ const streamPatchState = installPiStreamPatch(agent);
26670
+ const options = event.arguments[1];
26671
+ const promptText = event.arguments[0];
26672
+ const state = {
26673
+ activeLlmSpans: /* @__PURE__ */ new Set(),
26674
+ activeToolSpans: /* @__PURE__ */ new Map(),
26675
+ agent,
26676
+ collectedLlmUsageMetrics: false,
26677
+ deferCompletionUntilTurnEnd: options?.streamingBehavior === "followUp" || options?.streamingBehavior === "steer",
26678
+ finalized: false,
26679
+ metadata,
26680
+ metrics: {},
26681
+ onFinalize,
26682
+ promptCallEnded: false,
26683
+ ...typeof promptText === "string" ? { promptText } : {},
26684
+ queued: false,
26685
+ span,
26686
+ sawStreamFn: false,
26687
+ startTime: getCurrentUnixTimestamp(),
26688
+ streamPatchState,
26689
+ turnEnded: false
26690
+ };
26691
+ state.restorePromptContext = enterPiPromptContext(state);
26692
+ streamPatchState.activePromptStates.add(state);
26693
+ try {
26694
+ state.unsubscribeAgent = agent.subscribe(async (agentEvent) => {
26695
+ try {
26696
+ await runWithAutoInstrumentationSuppressed(
26697
+ () => handlePiAgentEvent(state, agentEvent)
26698
+ );
26699
+ } catch (error) {
26700
+ logInstrumentationError4("Pi Coding Agent event", error);
26701
+ }
26702
+ });
26703
+ } catch (error) {
26704
+ logInstrumentationError4("Pi Coding Agent event subscription", error);
26705
+ }
26706
+ return state;
26707
+ }
26708
+ function extractSession(event) {
26709
+ const candidate = event.session ?? event.self;
26710
+ return isObject(candidate) && typeof candidate.prompt === "function" ? candidate : void 0;
26711
+ }
26712
+ function isPiAgent(value) {
26713
+ return isObject(value) && typeof value.streamFn === "function" && typeof value.subscribe === "function";
26714
+ }
26715
+ function promptContextStore() {
26716
+ piPromptContextStore ??= isomorph_default.newAsyncLocalStorage();
26717
+ return piPromptContextStore;
26718
+ }
26719
+ function currentPromptContextFrames() {
26720
+ return promptContextStore().getStore()?.frames ?? [];
26721
+ }
26722
+ function currentPiPromptState() {
26723
+ const frames = currentPromptContextFrames();
26724
+ return frames[frames.length - 1]?.state;
26725
+ }
26726
+ function enterPiPromptContext(state) {
26727
+ const frame = {
26728
+ id: /* @__PURE__ */ Symbol("braintrust.pi-coding-agent.prompt"),
26729
+ state
26730
+ };
26731
+ promptContextStore().enterWith({
26732
+ frames: [...currentPromptContextFrames(), frame]
26733
+ });
26734
+ return () => {
26735
+ const frames = currentPromptContextFrames().filter(
26736
+ (candidate) => candidate.id !== frame.id
26737
+ );
26738
+ promptContextStore().enterWith(frames.length > 0 ? { frames } : void 0);
26739
+ };
26740
+ }
26741
+ function installPiStreamPatch(agent) {
26742
+ const existing = piStreamPatchStates.get(agent);
26743
+ if (existing) {
26744
+ if (agent.streamFn !== existing.wrappedStreamFn) {
26745
+ debugLogger.debug(
26746
+ "Pi Coding Agent streamFn changed while Braintrust instrumentation was active; preserving existing patch state."
26747
+ );
26748
+ }
26749
+ return existing;
26750
+ }
26751
+ const patchState = {
26752
+ activePromptStates: /* @__PURE__ */ new Set(),
26753
+ agent,
26754
+ originalStreamFn: agent.streamFn,
26755
+ queuedPromptStates: [],
26756
+ wrappedStreamFn: agent.streamFn
26757
+ };
26758
+ patchState.wrappedStreamFn = makeSharedInstrumentedStreamFn(patchState);
26759
+ agent.streamFn = patchState.wrappedStreamFn;
26760
+ piStreamPatchStates.set(agent, patchState);
26761
+ return patchState;
26762
+ }
26763
+ function resolveStreamPromptState(patchState, context) {
26764
+ let lastUserText;
26765
+ if (Array.isArray(context.messages)) {
26766
+ for (let i = context.messages.length - 1; i >= 0; i--) {
26767
+ const message = context.messages[i];
26768
+ if (isPiUserMessage(message)) {
26769
+ if (typeof message.content === "string") {
26770
+ lastUserText = message.content;
26771
+ } else {
26772
+ lastUserText = message.content.flatMap((part) => part.type === "text" ? [part.text] : []).join("");
26773
+ }
26774
+ break;
26775
+ }
26776
+ }
26777
+ }
26778
+ if (lastUserText !== void 0) {
26779
+ const queuedMatch = patchState.queuedPromptStates.find(
26780
+ (state) => state.promptText === lastUserText
26781
+ );
26782
+ if (queuedMatch) {
26783
+ return queuedMatch;
26784
+ }
26785
+ const matches = [...patchState.activePromptStates].filter(
26786
+ (state) => state.promptText === lastUserText
26787
+ );
26788
+ if (matches.length === 1) {
26789
+ return matches[0];
26790
+ }
26791
+ }
26792
+ const contextState = currentPiPromptState();
26793
+ if (contextState && patchState.activePromptStates.has(contextState) && (!contextState.queued || lastUserText !== void 0 && contextState.promptText === lastUserText)) {
26794
+ return contextState;
26795
+ }
26796
+ if (patchState.activePromptStates.size === 1) {
26797
+ return [...patchState.activePromptStates][0];
26798
+ }
26799
+ return void 0;
26800
+ }
26801
+ function makeSharedInstrumentedStreamFn(patchState) {
26802
+ return async function instrumentedPiStreamFn(model, context, options) {
26803
+ const state = resolveStreamPromptState(patchState, context);
26804
+ if (!state) {
26805
+ const invokeOriginal = () => Reflect.apply(patchState.originalStreamFn, this, [
26806
+ model,
26807
+ context,
26808
+ options
26809
+ ]);
26810
+ return patchState.activePromptStates.size > 0 ? runWithAutoInstrumentationSuppressed(invokeOriginal) : invokeOriginal();
26811
+ }
26812
+ state.sawStreamFn = true;
26813
+ removeQueuedPromptState(state);
26814
+ state.streamPatchState.eventPromptState = state;
26815
+ const llmState = await startPiLlmSpan(state, model, context, options);
26816
+ try {
26817
+ const stream = await runWithAutoInstrumentationSuppressed(
26818
+ () => Reflect.apply(patchState.originalStreamFn, this, [
26819
+ model,
26820
+ context,
26821
+ options
26822
+ ])
26823
+ );
26824
+ return patchAssistantMessageStream(stream, state, llmState);
26825
+ } catch (error) {
26826
+ finishPiLlmSpan(state, llmState, void 0, error);
26827
+ throw error;
26828
+ }
26829
+ };
26830
+ }
26831
+ async function startPiLlmSpan(state, model, context, options) {
26832
+ const metadata = {
26833
+ ...extractModelMetadata2(model),
26834
+ ...extractStreamOptionsMetadata(options),
26835
+ ...extractToolMetadata(context.tools),
26836
+ "pi_coding_agent.operation": "agent.streamFn"
26837
+ };
26838
+ const span = startSpan({
26839
+ event: {
26840
+ input: processInputAttachments(normalizePiContextInput(context)),
26841
+ metadata
26842
+ },
26843
+ name: getLlmSpanName(model),
26844
+ parent: await state.span.export(),
26845
+ spanAttributes: { type: "llm" /* LLM */ }
26846
+ });
26847
+ const llmState = {
26848
+ finalized: false,
26849
+ metadata,
26850
+ metrics: {},
26851
+ span,
26852
+ startTime: getCurrentUnixTimestamp()
26853
+ };
26854
+ state.activeLlmSpans.add(llmState);
26855
+ return llmState;
26856
+ }
26857
+ function patchAssistantMessageStream(stream, promptState, llmState) {
26858
+ if (!isObject(stream)) {
26859
+ return stream;
26860
+ }
26861
+ const streamRecord = stream;
26862
+ const originalResult = stream.result;
26863
+ if (typeof originalResult === "function") {
26864
+ streamRecord.result = function patchedPiResult() {
26865
+ return Promise.resolve(Reflect.apply(originalResult, this, [])).then(
26866
+ (message) => {
26867
+ finishPiLlmSpan(promptState, llmState, message);
26868
+ return message;
26869
+ },
26870
+ (error) => {
26871
+ finishPiLlmSpan(promptState, llmState, void 0, error);
26872
+ throw error;
26873
+ }
26874
+ );
26875
+ };
26876
+ }
26877
+ const originalIterator = stream[Symbol.asyncIterator];
26878
+ if (typeof originalIterator === "function") {
26879
+ streamRecord[Symbol.asyncIterator] = function patchedPiIterator() {
26880
+ const iterator = Reflect.apply(
26881
+ originalIterator,
26882
+ this,
26883
+ []
26884
+ );
26885
+ return {
26886
+ async next() {
26887
+ try {
26888
+ const result = await iterator.next();
26889
+ if (result.done) {
26890
+ finishPiLlmSpan(promptState, llmState);
26891
+ return result;
26892
+ }
26893
+ recordPiAssistantMessageEvent(promptState, llmState, result.value);
26894
+ return result;
26895
+ } catch (error) {
26896
+ finishPiLlmSpan(promptState, llmState, void 0, error);
26897
+ if (typeof iterator.return === "function") {
26898
+ try {
26899
+ await iterator.return();
26900
+ } catch (cleanupError) {
26901
+ logInstrumentationError4(
26902
+ "Pi Coding Agent stream cleanup",
26903
+ cleanupError
26904
+ );
26905
+ }
26906
+ }
26907
+ throw error;
26908
+ }
26909
+ },
26910
+ async return(value) {
26911
+ try {
26912
+ if (typeof iterator.return === "function") {
26913
+ return await iterator.return(value);
26914
+ }
26915
+ return {
26916
+ done: true,
26917
+ value
26918
+ };
26919
+ } catch (error) {
26920
+ finishPiLlmSpan(promptState, llmState, void 0, error);
26921
+ throw error;
26922
+ } finally {
26923
+ finishPiLlmSpan(promptState, llmState);
26924
+ }
26925
+ },
26926
+ async throw(error) {
26927
+ try {
26928
+ if (typeof iterator.throw === "function") {
26929
+ return await iterator.throw(error);
26930
+ }
26931
+ throw error;
26932
+ } catch (thrownError) {
26933
+ finishPiLlmSpan(promptState, llmState, void 0, thrownError);
26934
+ throw thrownError;
26935
+ }
26936
+ },
26937
+ [Symbol.asyncIterator]() {
26938
+ return this;
26939
+ }
26940
+ };
26941
+ };
26942
+ }
26943
+ return stream;
26944
+ }
26945
+ function recordPiAssistantMessageEvent(promptState, llmState, event) {
26946
+ recordFirstTokenMetric(llmState, event);
26947
+ const message = "message" in event ? event.message : void 0;
26948
+ const errorMessage2 = "error" in event ? event.error : void 0;
26949
+ if (event.type === "done" && isPiAssistantMessage(message)) {
26950
+ finishPiLlmSpan(promptState, llmState, message);
26951
+ } else if (event.type === "error" && isPiAssistantMessage(errorMessage2)) {
26952
+ finishPiLlmSpan(promptState, llmState, errorMessage2);
26953
+ }
26954
+ }
26955
+ function recordFirstTokenMetric(state, event) {
26956
+ if (state.metrics.time_to_first_token !== void 0 || event.type === "start") {
26957
+ return;
26958
+ }
26959
+ state.metrics.time_to_first_token = getCurrentUnixTimestamp() - state.startTime;
26960
+ }
26961
+ async function handlePiAgentEvent(state, event) {
26962
+ if (state.finalized) {
26963
+ return;
26964
+ }
26965
+ const eventPromptState = state.streamPatchState.eventPromptState;
26966
+ if (eventPromptState && eventPromptState !== state) {
26967
+ return;
26968
+ }
26969
+ if (!eventPromptState && (state.queued || state.streamPatchState.activePromptStates.size > 1 && currentPiPromptState() !== state)) {
26970
+ return;
26971
+ }
26972
+ switch (event.type) {
26973
+ case "message_end":
26974
+ if (isPiAssistantMessage(event.message)) {
26975
+ state.output = extractAssistantOutput(event.message);
26976
+ }
26977
+ return;
26978
+ case "turn_end":
26979
+ state.turnEnded = true;
26980
+ if (isPiAssistantMessage(event.message)) {
26981
+ state.output = extractAssistantOutput(event.message);
26982
+ if (!state.collectedLlmUsageMetrics) {
26983
+ addMetrics(state.metrics, extractUsageMetrics2(event.message.usage));
26984
+ }
26985
+ }
26986
+ if (state.streamPatchState.eventPromptState === state) {
26987
+ state.streamPatchState.eventPromptState = void 0;
26988
+ }
26989
+ if (state.promptCallEnded && state.deferCompletionUntilTurnEnd) {
26990
+ await finalizePiPromptRun(state);
26991
+ }
26992
+ return;
26993
+ case "tool_execution_start":
26994
+ await startPiToolSpan(state, event);
26995
+ return;
26996
+ case "tool_execution_end":
26997
+ finishPiToolSpan(state, event);
26998
+ return;
26999
+ default:
27000
+ return;
27001
+ }
27002
+ }
27003
+ async function startPiToolSpan(state, event) {
27004
+ if (!event.toolCallId || state.activeToolSpans.has(event.toolCallId)) {
27005
+ return;
27006
+ }
27007
+ const restoreAutoInstrumentation = enterAutoInstrumentationAllowed();
27008
+ const metadata = {
27009
+ "gen_ai.tool.call.id": event.toolCallId,
27010
+ "gen_ai.tool.name": event.toolName,
27011
+ "pi_coding_agent.tool.name": event.toolName
27012
+ };
27013
+ try {
27014
+ const span = startSpan({
27015
+ event: {
27016
+ input: event.args,
27017
+ metadata
27018
+ },
27019
+ name: event.toolName || "tool",
27020
+ parent: await state.span.export(),
27021
+ spanAttributes: { type: "tool" /* TOOL */ }
27022
+ });
27023
+ state.activeToolSpans.set(event.toolCallId, {
27024
+ restoreAutoInstrumentation,
27025
+ span
27026
+ });
27027
+ } catch (error) {
27028
+ restoreAutoInstrumentation();
27029
+ throw error;
27030
+ }
27031
+ }
27032
+ function finishPiToolSpan(state, event) {
27033
+ const toolState = state.activeToolSpans.get(event.toolCallId);
27034
+ if (!toolState) {
27035
+ return;
27036
+ }
27037
+ state.activeToolSpans.delete(event.toolCallId);
27038
+ const metadata = {
27039
+ "gen_ai.tool.call.id": event.toolCallId,
27040
+ "gen_ai.tool.name": event.toolName,
27041
+ "pi_coding_agent.tool.name": event.toolName,
27042
+ "pi_coding_agent.tool.is_error": event.isError
27043
+ };
27044
+ try {
27045
+ safeLog4(toolState.span, {
27046
+ ...event.isError ? { error: stringifyUnknown2(event.result) } : {},
27047
+ metadata,
27048
+ output: event.result
27049
+ });
27050
+ } finally {
27051
+ try {
27052
+ toolState.span.end();
27053
+ } finally {
27054
+ toolState.restoreAutoInstrumentation?.();
27055
+ }
27056
+ }
27057
+ }
27058
+ async function finalizePiPromptRun(state, error) {
27059
+ if (state.finalized) {
27060
+ return;
27061
+ }
27062
+ state.finalized = true;
27063
+ state.onFinalize?.(state);
27064
+ restorePiStreamFn(state);
27065
+ try {
27066
+ state.unsubscribeAgent?.();
27067
+ } catch (unsubscribeError) {
27068
+ logInstrumentationError4("Pi Coding Agent unsubscribe", unsubscribeError);
27069
+ }
27070
+ await finishOpenLlmSpans(state, error);
27071
+ finishOpenToolSpans(state, error);
27072
+ const metadata = {
27073
+ ...state.metadata,
27074
+ ...extractModelMetadata2(state.agent.state?.model)
27075
+ };
27076
+ try {
27077
+ safeLog4(state.span, {
27078
+ ...error ? { error: stringifyUnknown2(error) } : {},
27079
+ metadata,
27080
+ metrics: {
27081
+ ...cleanMetrics5(state.metrics),
27082
+ ...buildDurationMetrics3(state.startTime)
27083
+ },
27084
+ output: state.output
27085
+ });
27086
+ } finally {
27087
+ state.span.end();
27088
+ }
27089
+ }
27090
+ function restorePiStreamFn(state) {
27091
+ const patchState = state.streamPatchState;
27092
+ patchState.activePromptStates.delete(state);
27093
+ removeQueuedPromptState(state);
27094
+ if (patchState.eventPromptState === state) {
27095
+ patchState.eventPromptState = void 0;
27096
+ }
27097
+ state.restorePromptContext?.();
27098
+ if (patchState.activePromptStates.size > 0) {
27099
+ return;
27100
+ }
27101
+ if (patchState.agent.streamFn === patchState.wrappedStreamFn) {
27102
+ patchState.agent.streamFn = patchState.originalStreamFn;
27103
+ }
27104
+ piStreamPatchStates.delete(patchState.agent);
27105
+ }
27106
+ function removeQueuedPromptState(state) {
27107
+ state.queued = false;
27108
+ const queuedPromptStates = state.streamPatchState.queuedPromptStates;
27109
+ const index = queuedPromptStates.indexOf(state);
27110
+ if (index >= 0) {
27111
+ queuedPromptStates.splice(index, 1);
27112
+ }
27113
+ }
27114
+ async function finishOpenLlmSpans(state, error) {
27115
+ for (const llmState of [...state.activeLlmSpans]) {
27116
+ finishPiLlmSpan(state, llmState, void 0, error);
27117
+ }
27118
+ }
27119
+ function finishPiLlmSpan(promptState, llmState, message, error) {
27120
+ if (llmState.finalized) {
27121
+ return;
27122
+ }
27123
+ llmState.finalized = true;
27124
+ promptState.activeLlmSpans.delete(llmState);
27125
+ const messageError = message?.stopReason === "error" && message.errorMessage;
27126
+ const metrics = {
27127
+ ...extractUsageMetrics2(message?.usage),
27128
+ ...cleanMetrics5(llmState.metrics),
27129
+ ...buildDurationMetrics3(llmState.startTime)
27130
+ };
27131
+ const usageMetrics = extractUsageMetrics2(message?.usage);
27132
+ if (Object.keys(usageMetrics).length > 0) {
27133
+ promptState.collectedLlmUsageMetrics = true;
27134
+ addMetrics(promptState.metrics, usageMetrics);
27135
+ }
27136
+ try {
27137
+ safeLog4(llmState.span, {
27138
+ ...error || messageError ? { error: stringifyUnknown2(error ?? messageError) } : {},
27139
+ metadata: {
27140
+ ...llmState.metadata,
27141
+ ...message ? extractAssistantMetadata(message) : {}
27142
+ },
27143
+ metrics,
27144
+ ...message ? { output: extractAssistantOutput(message) } : {}
27145
+ });
27146
+ } finally {
27147
+ llmState.span.end();
27148
+ }
27149
+ }
27150
+ function finishOpenToolSpans(state, error) {
27151
+ for (const [, toolState] of state.activeToolSpans) {
27152
+ try {
27153
+ safeLog4(toolState.span, {
27154
+ error: error ? stringifyUnknown2(error) : "Pi tool did not complete"
27155
+ });
27156
+ toolState.span.end();
27157
+ } finally {
27158
+ toolState.restoreAutoInstrumentation?.();
27159
+ }
27160
+ }
27161
+ state.activeToolSpans.clear();
27162
+ }
27163
+ function normalizePiContextInput(context) {
27164
+ const messages = context.messages.flatMap(
27165
+ (message) => normalizePiMessage(message)
27166
+ );
27167
+ if (context.systemPrompt) {
27168
+ return [{ role: "system", content: context.systemPrompt }, ...messages];
27169
+ }
27170
+ return messages;
27171
+ }
27172
+ function normalizePiMessage(message) {
27173
+ if (isPiUserMessage(message)) {
27174
+ return [
27175
+ {
27176
+ role: "user",
27177
+ content: normalizeUserContent(message.content)
27178
+ }
27179
+ ];
27180
+ }
27181
+ if (isPiAssistantMessage(message)) {
27182
+ return [normalizeAssistantMessage(message)];
27183
+ }
27184
+ if (isPiToolResultMessage(message)) {
27185
+ return [normalizeToolResultMessage(message)];
27186
+ }
27187
+ return [];
27188
+ }
27189
+ function normalizeAssistantMessage(message) {
27190
+ const text = message.content.flatMap((part) => part.type === "text" ? [part.text] : []).join("");
27191
+ const thinking = message.content.flatMap(
27192
+ (part) => part.type === "thinking" && !part.redacted ? [part.thinking] : []
27193
+ ).join("");
27194
+ const toolCalls = message.content.flatMap(
27195
+ (part) => part.type === "toolCall" ? [normalizeToolCall(part)] : []
27196
+ );
27197
+ return {
27198
+ role: "assistant",
27199
+ content: text || (toolCalls.length > 0 ? null : ""),
27200
+ ...thinking ? { reasoning: thinking } : {},
27201
+ ...toolCalls.length > 0 ? { tool_calls: toolCalls } : {}
27202
+ };
27203
+ }
27204
+ function normalizeToolResultMessage(message) {
27205
+ return {
27206
+ role: "tool",
27207
+ tool_call_id: message.toolCallId,
27208
+ content: normalizeUserContent(message.content)
27209
+ };
27210
+ }
27211
+ function normalizeUserContent(content) {
27212
+ if (typeof content === "string") {
27213
+ return content;
27214
+ }
27215
+ return content.map((part) => {
27216
+ if (part.type === "text") {
27217
+ return { type: "text", text: part.text };
27218
+ }
27219
+ if (part.type === "image") {
27220
+ return {
27221
+ type: "image_url",
27222
+ image_url: {
27223
+ url: `data:${part.mimeType};base64,${part.data}`
27224
+ }
27225
+ };
27226
+ }
27227
+ return part;
27228
+ });
27229
+ }
27230
+ function normalizeToolCall(toolCall) {
27231
+ return {
27232
+ id: toolCall.id,
27233
+ type: "function",
27234
+ function: {
27235
+ name: toolCall.name,
27236
+ arguments: stringifyArguments(toolCall.arguments)
27237
+ }
27238
+ };
27239
+ }
27240
+ function extractAssistantOutput(message) {
27241
+ return processInputAttachments([
27242
+ {
27243
+ finish_reason: normalizeStopReason(message.stopReason),
27244
+ index: 0,
27245
+ message: normalizeAssistantMessage(message)
27246
+ }
27247
+ ]);
27248
+ }
27249
+ function isPiUserMessage(message) {
27250
+ return message.role === "user" && "content" in message;
27251
+ }
27252
+ function isPiAssistantMessage(message) {
27253
+ return isObject(message) && message.role === "assistant" && Array.isArray(message.content);
27254
+ }
27255
+ function isPiToolResultMessage(message) {
27256
+ return message.role === "toolResult" && Array.isArray(message.content);
27257
+ }
27258
+ function normalizeStopReason(reason) {
27259
+ switch (reason) {
27260
+ case "toolUse":
27261
+ return "tool_calls";
27262
+ case "length":
27263
+ case "stop":
27264
+ return reason;
27265
+ default:
27266
+ return reason ?? "stop";
27267
+ }
27268
+ }
27269
+ function extractPromptInput(text, options) {
27270
+ const images = options?.images;
27271
+ if (!images || images.length === 0) {
27272
+ return text;
27273
+ }
27274
+ return processInputAttachments([
27275
+ {
27276
+ role: "user",
27277
+ content: [
27278
+ { type: "text", text: text ?? "" },
27279
+ ...images.map((image) => ({
27280
+ type: "image_url",
27281
+ image_url: {
27282
+ url: `data:${image.mimeType};base64,${image.data}`
27283
+ }
27284
+ }))
27285
+ ]
27286
+ }
27287
+ ]);
27288
+ }
27289
+ function extractToolMetadata(tools) {
27290
+ if (!tools || tools.length === 0) {
27291
+ return {};
27292
+ }
27293
+ return {
27294
+ tools: tools.map((tool) => ({
27295
+ type: "function",
27296
+ function: {
27297
+ name: tool.name,
27298
+ ...tool.description ? { description: tool.description } : {},
27299
+ ...tool.parameters ? { parameters: tool.parameters } : {}
27300
+ }
27301
+ }))
27302
+ };
27303
+ }
27304
+ function extractModelMetadata2(model) {
27305
+ if (!model) {
27306
+ return {};
27307
+ }
27308
+ return {
27309
+ ...model.provider ? { provider: model.provider } : {},
27310
+ ...model.id ? { model: model.id, "pi_coding_agent.model": model.id } : {},
27311
+ ...model.api ? { "pi_coding_agent.api": model.api } : {},
27312
+ ...model.name ? { "pi_coding_agent.model_name": model.name } : {}
27313
+ };
27314
+ }
27315
+ function extractAssistantMetadata(message) {
27316
+ return {
27317
+ ...message.provider ? { provider: message.provider } : {},
27318
+ ...message.responseModel || message.model ? { model: message.responseModel ?? message.model } : {},
27319
+ ...message.api ? { "pi_coding_agent.api": message.api } : {},
27320
+ ...message.model ? { "pi_coding_agent.model": message.model } : {},
27321
+ ...message.responseModel ? { "pi_coding_agent.response_model": message.responseModel } : {},
27322
+ ...message.responseId ? { "pi_coding_agent.response_id": message.responseId } : {},
27323
+ ...message.stopReason ? { "pi_coding_agent.stop_reason": message.stopReason } : {}
27324
+ };
27325
+ }
27326
+ function extractSessionMetadata(session) {
27327
+ return {
27328
+ ...extractModelMetadata2(session.model),
27329
+ ...session.sessionId ? { "pi_coding_agent.session_id": session.sessionId } : {},
27330
+ ...session.sessionName ? { "pi_coding_agent.session_name": session.sessionName } : {},
27331
+ ...session.thinkingLevel ? { "pi_coding_agent.thinking_level": session.thinkingLevel } : {},
27332
+ ...typeof session.getActiveToolNames === "function" ? { "pi_coding_agent.active_tools": session.getActiveToolNames() } : {}
27333
+ };
27334
+ }
27335
+ function extractPromptOptionsMetadata(options) {
27336
+ if (!options) {
27337
+ return {};
27338
+ }
27339
+ return {
27340
+ ...options.source ? { "pi_coding_agent.source": options.source } : {},
27341
+ ...options.streamingBehavior ? { "pi_coding_agent.streaming_behavior": options.streamingBehavior } : {},
27342
+ ...options.expandPromptTemplates !== void 0 ? {
27343
+ "pi_coding_agent.expand_prompt_templates": options.expandPromptTemplates
27344
+ } : {}
27345
+ };
27346
+ }
27347
+ function extractStreamOptionsMetadata(options) {
27348
+ if (!options) {
27349
+ return {};
27350
+ }
27351
+ return {
27352
+ ...options.temperature !== void 0 ? { temperature: options.temperature } : {},
27353
+ ...options.maxTokens !== void 0 ? { max_tokens: options.maxTokens } : {},
27354
+ ...options.reasoning ? { "pi_coding_agent.reasoning": options.reasoning } : {},
27355
+ ...options.transport ? { "pi_coding_agent.transport": options.transport } : {},
27356
+ ...options.cacheRetention ? { "pi_coding_agent.cache_retention": options.cacheRetention } : {},
27357
+ ...options.sessionId ? { "pi_coding_agent.session_id": options.sessionId } : {},
27358
+ ...options.timeoutMs !== void 0 ? { "pi_coding_agent.timeout_ms": options.timeoutMs } : {},
27359
+ ...options.maxRetries !== void 0 ? { "pi_coding_agent.max_retries": options.maxRetries } : {},
27360
+ ...options.maxRetryDelayMs !== void 0 ? { "pi_coding_agent.max_retry_delay_ms": options.maxRetryDelayMs } : {},
27361
+ ...options.metadata ? { "pi_coding_agent.metadata": options.metadata } : {}
27362
+ };
27363
+ }
27364
+ function getLlmSpanName(model) {
27365
+ switch (model.api) {
27366
+ case "anthropic-messages":
27367
+ return "anthropic.messages.create";
27368
+ case "openai-completions":
27369
+ return "Chat Completion";
27370
+ case "openai-responses":
27371
+ case "azure-openai-responses":
27372
+ case "openai-codex-responses":
27373
+ return "openai.responses.create";
27374
+ case "google-generative-ai":
27375
+ case "google-vertex":
27376
+ return "generate_content";
27377
+ case "mistral-conversations":
27378
+ return "mistral.chat.stream";
27379
+ case "bedrock-converse-stream":
27380
+ return "bedrock.converse_stream";
27381
+ default:
27382
+ return "pi_ai.streamSimple";
27383
+ }
27384
+ }
27385
+ function extractUsageMetrics2(usage) {
27386
+ if (!usage) {
27387
+ return {};
27388
+ }
27389
+ return cleanMetrics5({
27390
+ completion_tokens: usage.output,
27391
+ prompt_cache_creation_tokens: usage.cacheWrite,
27392
+ prompt_cached_tokens: usage.cacheRead,
27393
+ prompt_tokens: usage.input,
27394
+ tokens: usage.totalTokens ?? usage.tokens
27395
+ });
27396
+ }
27397
+ function addMetrics(target, source) {
27398
+ for (const [key, value] of Object.entries(source)) {
27399
+ target[key] = (target[key] ?? 0) + value;
27400
+ }
27401
+ }
27402
+ function buildDurationMetrics3(startTime) {
27403
+ const end = getCurrentUnixTimestamp();
27404
+ return {
27405
+ duration: end - startTime,
27406
+ end,
27407
+ start: startTime
27408
+ };
27409
+ }
27410
+ function cleanMetrics5(metrics) {
27411
+ const cleaned = {};
27412
+ for (const [key, value] of Object.entries(metrics)) {
27413
+ if (typeof value === "number" && Number.isFinite(value) && value >= 0) {
27414
+ cleaned[key] = value;
27415
+ }
27416
+ }
27417
+ return cleaned;
27418
+ }
27419
+ function stringifyArguments(value) {
27420
+ if (typeof value === "string") {
27421
+ return value;
27422
+ }
27423
+ try {
27424
+ return JSON.stringify(value);
27425
+ } catch {
27426
+ return stringifyUnknown2(value);
27427
+ }
27428
+ }
27429
+ function stringifyUnknown2(value) {
27430
+ if (value instanceof Error) {
27431
+ return value.message;
27432
+ }
27433
+ if (typeof value === "string") {
27434
+ return value;
27435
+ }
27436
+ try {
27437
+ return JSON.stringify(value);
27438
+ } catch {
27439
+ return String(value);
27440
+ }
27441
+ }
27442
+ function safeLog4(span, event) {
27443
+ try {
27444
+ span.log(event);
27445
+ } catch (error) {
27446
+ logInstrumentationError4("Pi Coding Agent span log", error);
27447
+ }
27448
+ }
27449
+ function logInstrumentationError4(context, error) {
27450
+ debugLogger.debug(`${context}:`, error);
27451
+ }
27452
+
25396
27453
  // src/instrumentation/braintrust-plugin.ts
25397
27454
  function getIntegrationConfig(integrations, key) {
25398
27455
  return integrations[key];
@@ -25418,6 +27475,7 @@ var BraintrustPlugin = class extends BasePlugin {
25418
27475
  gitHubCopilotPlugin = null;
25419
27476
  fluePlugin = null;
25420
27477
  langChainPlugin = null;
27478
+ piCodingAgentPlugin = null;
25421
27479
  constructor(config = {}) {
25422
27480
  super();
25423
27481
  this.config = config;
@@ -25492,6 +27550,10 @@ var BraintrustPlugin = class extends BasePlugin {
25492
27550
  this.gitHubCopilotPlugin = new GitHubCopilotPlugin();
25493
27551
  this.gitHubCopilotPlugin.enable();
25494
27552
  }
27553
+ if (integrations.piCodingAgent !== false) {
27554
+ this.piCodingAgentPlugin = new PiCodingAgentPlugin();
27555
+ this.piCodingAgentPlugin.enable();
27556
+ }
25495
27557
  if (getIntegrationConfig(integrations, "flue") !== false) {
25496
27558
  this.fluePlugin = new FluePlugin();
25497
27559
  this.fluePlugin.enable();
@@ -25570,6 +27632,10 @@ var BraintrustPlugin = class extends BasePlugin {
25570
27632
  this.gitHubCopilotPlugin.disable();
25571
27633
  this.gitHubCopilotPlugin = null;
25572
27634
  }
27635
+ if (this.piCodingAgentPlugin) {
27636
+ this.piCodingAgentPlugin.disable();
27637
+ this.piCodingAgentPlugin = null;
27638
+ }
25573
27639
  if (this.fluePlugin) {
25574
27640
  this.fluePlugin.disable();
25575
27641
  this.fluePlugin = null;
@@ -25589,6 +27655,11 @@ var envIntegrationAliases = {
25589
27655
  openaicodexsdk: "openaiCodexSDK",
25590
27656
  codex: "openaiCodexSDK",
25591
27657
  "codex-sdk": "openaiCodexSDK",
27658
+ "pi-coding-agent": "piCodingAgent",
27659
+ "pi-coding-agent-sdk": "piCodingAgent",
27660
+ picodingagent: "piCodingAgent",
27661
+ picodingagentsdk: "piCodingAgent",
27662
+ "@earendil-works/pi-coding-agent": "piCodingAgent",
25592
27663
  anthropic: "anthropic",
25593
27664
  aisdk: "aisdk",
25594
27665
  "ai-sdk": "aisdk",
@@ -25654,7 +27725,8 @@ function getDefaultInstrumentationIntegrations() {
25654
27725
  genkit: true,
25655
27726
  gitHubCopilot: true,
25656
27727
  langchain: true,
25657
- langgraph: true
27728
+ langgraph: true,
27729
+ piCodingAgent: true
25658
27730
  };
25659
27731
  }
25660
27732
  function readDisabledInstrumentationEnvConfig(disabledList) {
@@ -25950,6 +28022,7 @@ __export(exports_exports, {
25950
28022
  _internalIso: () => isomorph_default,
25951
28023
  _internalSetInitialState: () => _internalSetInitialState,
25952
28024
  addAzureBlobHeaders: () => addAzureBlobHeaders,
28025
+ braintrustAISDKTelemetry: () => braintrustAISDKTelemetry,
25953
28026
  braintrustFlueObserver: () => braintrustFlueObserver,
25954
28027
  braintrustStreamChunkSchema: () => braintrustStreamChunkSchema,
25955
28028
  buildLocalSummary: () => buildLocalSummary,
@@ -26042,6 +28115,7 @@ __export(exports_exports, {
26042
28115
  wrapOpenAIv4: () => wrapOpenAIv4,
26043
28116
  wrapOpenRouter: () => wrapOpenRouter,
26044
28117
  wrapOpenRouterAgent: () => wrapOpenRouterAgent,
28118
+ wrapPiCodingAgentSDK: () => wrapPiCodingAgentSDK,
26045
28119
  wrapTraced: () => wrapTraced,
26046
28120
  wrapVitest: () => wrapVitest
26047
28121
  });
@@ -28102,6 +30176,54 @@ function wrapCursorAgent(agent) {
28102
30176
  return proxy;
28103
30177
  }
28104
30178
 
30179
+ // src/wrappers/pi-coding-agent.ts
30180
+ var WRAPPED_PROMPT = /* @__PURE__ */ Symbol.for("braintrust.pi-coding-agent.wrapped-prompt");
30181
+ function wrapPiCodingAgentSDK(sdk) {
30182
+ if (!sdk || typeof sdk !== "object") {
30183
+ return sdk;
30184
+ }
30185
+ const maybeSDK = sdk;
30186
+ if (!maybeSDK.AgentSession || typeof maybeSDK.AgentSession !== "function") {
30187
+ console.warn("Unsupported Pi Coding Agent SDK. Not wrapping.");
30188
+ return sdk;
30189
+ }
30190
+ patchAgentSessionClass(
30191
+ maybeSDK.AgentSession
30192
+ );
30193
+ return sdk;
30194
+ }
30195
+ function patchAgentSessionClass(AgentSession) {
30196
+ const prototype = AgentSession.prototype;
30197
+ if (!prototype || prototype[WRAPPED_PROMPT]) {
30198
+ return;
30199
+ }
30200
+ const descriptor = Object.getOwnPropertyDescriptor(prototype, "prompt");
30201
+ if (!descriptor || typeof descriptor.value !== "function") {
30202
+ console.warn("Unsupported Pi Coding Agent SDK. Not wrapping.");
30203
+ return;
30204
+ }
30205
+ const originalPrompt = descriptor.value;
30206
+ Object.defineProperty(prototype, "prompt", {
30207
+ ...descriptor,
30208
+ value: function wrappedPiCodingAgentPrompt(text, options) {
30209
+ const args = [text, options];
30210
+ return piCodingAgentChannels.prompt.tracePromise(
30211
+ () => Reflect.apply(originalPrompt, this, args),
30212
+ {
30213
+ arguments: args,
30214
+ self: this,
30215
+ session: this
30216
+ }
30217
+ );
30218
+ }
30219
+ });
30220
+ Object.defineProperty(prototype, WRAPPED_PROMPT, {
30221
+ configurable: false,
30222
+ enumerable: false,
30223
+ value: true
30224
+ });
30225
+ }
30226
+
28105
30227
  // src/wrappers/google-genai.ts
28106
30228
  function wrapGoogleGenAI(googleGenAI) {
28107
30229
  if (!googleGenAI || typeof googleGenAI !== "object") {
@@ -28138,12 +30260,25 @@ function wrapGoogleGenAIClass(OriginalGoogleGenAI) {
28138
30260
  }
28139
30261
  function wrapGoogleGenAIInstance(instance) {
28140
30262
  const wrappedModels = wrapModels(instance.models);
30263
+ let originalInteractions;
30264
+ let wrappedInteractions;
28141
30265
  patchGoogleGenAIChats(instance, wrappedModels);
28142
30266
  return new Proxy(instance, {
28143
30267
  get(target, prop, receiver) {
28144
30268
  if (prop === "models") {
28145
30269
  return wrappedModels;
28146
30270
  }
30271
+ if (prop === "interactions") {
30272
+ const interactions = Reflect.get(target, prop, receiver);
30273
+ if (!isObject(interactions) || typeof interactions.create !== "function") {
30274
+ return interactions;
30275
+ }
30276
+ if (interactions !== originalInteractions) {
30277
+ originalInteractions = interactions;
30278
+ wrappedInteractions = wrapInteractions(interactions);
30279
+ }
30280
+ return wrappedInteractions;
30281
+ }
28147
30282
  return Reflect.get(target, prop, receiver);
28148
30283
  }
28149
30284
  });
@@ -28170,6 +30305,16 @@ function wrapModels(models) {
28170
30305
  }
28171
30306
  });
28172
30307
  }
30308
+ function wrapInteractions(interactions) {
30309
+ return new Proxy(interactions, {
30310
+ get(target, prop, receiver) {
30311
+ if (prop === "create") {
30312
+ return wrapInteractionCreate(target.create.bind(target));
30313
+ }
30314
+ return Reflect.get(target, prop, receiver);
30315
+ }
30316
+ });
30317
+ }
28173
30318
  function wrapGenerateContent(original) {
28174
30319
  return function(params) {
28175
30320
  return googleGenAIChannels.generateContent.tracePromise(
@@ -28194,6 +30339,18 @@ function wrapEmbedContent(original) {
28194
30339
  );
28195
30340
  };
28196
30341
  }
30342
+ function wrapInteractionCreate(original) {
30343
+ return function(params, options) {
30344
+ if (params.background === true) {
30345
+ return options === void 0 ? original(params) : original(params, options);
30346
+ }
30347
+ const traceContext = options === void 0 ? { arguments: [params] } : { arguments: [params, options] };
30348
+ return googleGenAIChannels.interactionsCreate.tracePromise(
30349
+ () => options === void 0 ? original(params) : original(params, options),
30350
+ traceContext
30351
+ );
30352
+ };
30353
+ }
28197
30354
 
28198
30355
  // src/wrappers/google-adk.ts
28199
30356
  function wrapGoogleADK(adkModule) {
@@ -31711,6 +33868,13 @@ var EvalResultWithSummary = class {
31711
33868
  };
31712
33869
  }
31713
33870
  };
33871
+ async function getPersistedBaseExperimentId(experiment) {
33872
+ try {
33873
+ return await experiment._getBaseExperimentId();
33874
+ } catch {
33875
+ return void 0;
33876
+ }
33877
+ }
31714
33878
  function makeEvalName(projectName, experimentName) {
31715
33879
  let out = projectName;
31716
33880
  if (experimentName) {
@@ -32093,6 +34257,14 @@ async function runEvaluatorInternal(experiment, evaluator, progressReporter, fil
32093
34257
  return;
32094
34258
  }
32095
34259
  const eventDataset = experiment ? experiment.dataset : Dataset2.isDataset(evaluator.data) ? evaluator.data : void 0;
34260
+ const inlineOrigin = datum.origin === void 0 ? void 0 : ObjectReference.parse(datum.origin);
34261
+ const origin = inlineOrigin ?? (eventDataset && datum.id && datum._xact_id ? {
34262
+ object_type: "dataset",
34263
+ object_id: await eventDataset.id,
34264
+ id: datum.id,
34265
+ created: datum.created,
34266
+ _xact_id: datum._xact_id
34267
+ } : void 0);
32096
34268
  const baseEvent = {
32097
34269
  name: "eval",
32098
34270
  spanAttributes: {
@@ -32102,13 +34274,7 @@ async function runEvaluatorInternal(experiment, evaluator, progressReporter, fil
32102
34274
  input: datum.input,
32103
34275
  expected: "expected" in datum ? datum.expected : void 0,
32104
34276
  tags: datum.tags,
32105
- origin: eventDataset && datum.id && datum._xact_id ? {
32106
- object_type: "dataset",
32107
- object_id: await eventDataset.id,
32108
- id: datum.id,
32109
- created: datum.created,
32110
- _xact_id: datum._xact_id
32111
- } : void 0,
34277
+ origin,
32112
34278
  ...datum.upsert_id ? { id: datum.upsert_id } : {}
32113
34279
  }
32114
34280
  };
@@ -32465,8 +34631,10 @@ async function runEvaluatorInternal(experiment, evaluator, progressReporter, fil
32465
34631
  collectedResults.length = 0;
32466
34632
  }
32467
34633
  }
34634
+ const comparisonExperimentId = experiment ? evaluator.baseExperimentId ?? await getPersistedBaseExperimentId(experiment) : void 0;
32468
34635
  const summary = experiment ? await experiment.summarize({
32469
- summarizeScores: evaluator.summarizeScores
34636
+ summarizeScores: evaluator.summarizeScores,
34637
+ ...comparisonExperimentId !== void 0 ? { comparisonExperimentId } : {}
32470
34638
  }) : buildLocalSummary(
32471
34639
  evaluator,
32472
34640
  collectResults ? collectedResults : [],
@@ -32695,6 +34863,7 @@ var Project2 = class {
32695
34863
  prompts;
32696
34864
  parameters;
32697
34865
  scorers;
34866
+ classifiers;
32698
34867
  _publishableCodeFunctions = [];
32699
34868
  _publishablePrompts = [];
32700
34869
  _publishableParameters = [];
@@ -32706,6 +34875,7 @@ var Project2 = class {
32706
34875
  this.prompts = new PromptBuilder(this);
32707
34876
  this.parameters = new ParametersBuilder(this);
32708
34877
  this.scorers = new ScorerBuilder(this);
34878
+ this.classifiers = new ClassifierBuilder(this);
32709
34879
  }
32710
34880
  addPrompt(prompt) {
32711
34881
  this._publishablePrompts.push(prompt);
@@ -32840,6 +35010,28 @@ var ScorerBuilder = class {
32840
35010
  }
32841
35011
  }
32842
35012
  };
35013
+ var ClassifierBuilder = class {
35014
+ constructor(project) {
35015
+ this.project = project;
35016
+ }
35017
+ taskCounter = 0;
35018
+ create(opts) {
35019
+ this.taskCounter++;
35020
+ let resolvedName = opts.name ?? opts.handler.name;
35021
+ if (!resolvedName || resolvedName.trim().length === 0) {
35022
+ resolvedName = `Classifier ${isomorph_default.basename(currentFilename)} ${this.taskCounter}`;
35023
+ }
35024
+ const slug = opts.slug ?? slugify(resolvedName, { lower: true, strict: true });
35025
+ const classifier = new CodeFunction(this.project, {
35026
+ ...opts,
35027
+ name: resolvedName,
35028
+ slug,
35029
+ type: "classifier"
35030
+ });
35031
+ this.project.addCodeFunction(classifier);
35032
+ return classifier;
35033
+ }
35034
+ };
32843
35035
  var CodeFunction = class {
32844
35036
  constructor(project, opts) {
32845
35037
  this.project = project;
@@ -33189,7 +35381,7 @@ var serializedParametersContainerSchema = import_v313.z.union([
33189
35381
  staticParametersSchema
33190
35382
  ]);
33191
35383
  var evaluatorDefinitionSchema = import_v313.z.object({
33192
- parameters: serializedParametersContainerSchema.optional(),
35384
+ parameters: serializedParametersContainerSchema.nullish(),
33193
35385
  scores: import_v313.z.array(import_v313.z.object({ name: import_v313.z.string() })).optional(),
33194
35386
  classifiers: import_v313.z.array(import_v313.z.object({ name: import_v313.z.string() })).optional()
33195
35387
  });