braintrust 3.16.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 (55) hide show
  1. package/bin/bt +41 -0
  2. package/dev/dist/index.d.mts +13 -0
  3. package/dev/dist/index.d.ts +13 -0
  4. package/dev/dist/index.js +4300 -2199
  5. package/dev/dist/index.mjs +2211 -110
  6. package/dist/apply-auto-instrumentation.js +238 -186
  7. package/dist/apply-auto-instrumentation.mjs +68 -16
  8. package/dist/auto-instrumentations/bundler/esbuild.cjs +90 -15
  9. package/dist/auto-instrumentations/bundler/esbuild.mjs +2 -2
  10. package/dist/auto-instrumentations/bundler/next.cjs +90 -15
  11. package/dist/auto-instrumentations/bundler/next.mjs +3 -3
  12. package/dist/auto-instrumentations/bundler/rollup.cjs +90 -15
  13. package/dist/auto-instrumentations/bundler/rollup.mjs +2 -2
  14. package/dist/auto-instrumentations/bundler/vite.cjs +90 -15
  15. package/dist/auto-instrumentations/bundler/vite.mjs +2 -2
  16. package/dist/auto-instrumentations/bundler/webpack-loader.cjs +89 -14
  17. package/dist/auto-instrumentations/bundler/webpack.cjs +90 -15
  18. package/dist/auto-instrumentations/bundler/webpack.mjs +3 -3
  19. package/dist/auto-instrumentations/{chunk-VXJONZVX.mjs → chunk-GNUEZ2PE.mjs} +13 -3
  20. package/dist/auto-instrumentations/{chunk-CNQ7BUKN.mjs → chunk-MYCHHXOE.mjs} +1 -1
  21. package/dist/auto-instrumentations/{chunk-E5DUYJWK.mjs → chunk-ZYKZEMRT.mjs} +82 -15
  22. package/dist/auto-instrumentations/hook.mjs +102 -15
  23. package/dist/auto-instrumentations/index.cjs +84 -16
  24. package/dist/auto-instrumentations/index.d.mts +3 -1
  25. package/dist/auto-instrumentations/index.d.ts +3 -1
  26. package/dist/auto-instrumentations/index.mjs +5 -3
  27. package/dist/auto-instrumentations/loader/cjs-patch.cjs +1 -1
  28. package/dist/auto-instrumentations/loader/cjs-patch.mjs +1 -1
  29. package/dist/auto-instrumentations/loader/esm-hook.mjs +1 -1
  30. package/dist/browser.d.mts +177 -11
  31. package/dist/browser.d.ts +177 -11
  32. package/dist/browser.js +2296 -104
  33. package/dist/browser.mjs +2455 -263
  34. package/dist/{chunk-VMBQETG3.js → chunk-73IYIIOL.js} +28 -2
  35. package/dist/{chunk-O4ZIWXO3.mjs → chunk-BYFADLEZ.mjs} +27 -1
  36. package/dist/cli.js +2228 -113
  37. package/dist/edge-light.d.mts +1 -1
  38. package/dist/edge-light.d.ts +1 -1
  39. package/dist/edge-light.js +2296 -104
  40. package/dist/edge-light.mjs +2455 -263
  41. package/dist/index.d.mts +177 -11
  42. package/dist/index.d.ts +177 -11
  43. package/dist/index.js +3296 -1128
  44. package/dist/index.mjs +2272 -104
  45. package/dist/instrumentation/index.d.mts +3 -0
  46. package/dist/instrumentation/index.d.ts +3 -0
  47. package/dist/instrumentation/index.js +2171 -105
  48. package/dist/instrumentation/index.mjs +2171 -105
  49. package/dist/workerd.d.mts +1 -1
  50. package/dist/workerd.d.ts +1 -1
  51. package/dist/workerd.js +2296 -104
  52. package/dist/workerd.mjs +2455 -263
  53. package/package.json +19 -5
  54. package/scripts/bt-helper.js +139 -0
  55. package/scripts/install.js +153 -0
package/dist/workerd.js CHANGED
@@ -86,6 +86,7 @@ __export(workerd_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(workerd_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
  });
@@ -5132,14 +5134,18 @@ function useTestBackgroundLogger() {
5132
5134
  function clearTestBackgroundLogger() {
5133
5135
  _internalGetGlobalState()?.setOverrideBgLogger(null);
5134
5136
  }
5135
- function initTestExperiment(experimentName, projectName) {
5137
+ function initTestExperiment(experimentName, projectName, experimentFullInfo = {}) {
5136
5138
  setInitialTestState();
5137
5139
  const state = _internalGetGlobalState();
5138
5140
  const project = projectName ?? experimentName;
5139
5141
  const lazyMetadata = new LazyValue(
5140
5142
  async () => ({
5141
5143
  project: { id: project, name: project, fullInfo: {} },
5142
- experiment: { id: experimentName, name: experimentName, fullInfo: {} }
5144
+ experiment: {
5145
+ id: experimentName,
5146
+ name: experimentName,
5147
+ fullInfo: experimentFullInfo
5148
+ }
5143
5149
  })
5144
5150
  );
5145
5151
  return new Experiment2(state, lazyMetadata);
@@ -8504,6 +8510,10 @@ var Experiment2 = class extends ObjectFetcher {
8504
8510
  return (await this.lazyMetadata.get()).project;
8505
8511
  })();
8506
8512
  }
8513
+ async _getBaseExperimentId() {
8514
+ const baseExperimentId = (await this.lazyMetadata.get()).experiment.fullInfo["base_exp_id"];
8515
+ return typeof baseExperimentId === "string" && baseExperimentId ? baseExperimentId : void 0;
8516
+ }
8507
8517
  parentObjectType() {
8508
8518
  return 1 /* EXPERIMENT */;
8509
8519
  }
@@ -8644,6 +8654,14 @@ var Experiment2 = class extends ObjectFetcher {
8644
8654
  comparisonExperimentId = baseExperiment.id;
8645
8655
  comparisonExperimentName = baseExperiment.name;
8646
8656
  }
8657
+ } else {
8658
+ try {
8659
+ const comparisonExperiment = await state.apiConn().get_json(`v1/experiment/${comparisonExperimentId}`);
8660
+ if (typeof comparisonExperiment["name"] === "string") {
8661
+ comparisonExperimentName = comparisonExperiment["name"];
8662
+ }
8663
+ } catch {
8664
+ }
8647
8665
  }
8648
8666
  try {
8649
8667
  const results = await state.apiConn().get_json(
@@ -10808,6 +10826,64 @@ var BasePlugin = class {
10808
10826
  }
10809
10827
  };
10810
10828
 
10829
+ // src/instrumentation/auto-instrumentation-suppression.ts
10830
+ var autoInstrumentationSuppressionStore;
10831
+ function suppressionStore() {
10832
+ autoInstrumentationSuppressionStore ??= isomorph_default.newAsyncLocalStorage();
10833
+ return autoInstrumentationSuppressionStore;
10834
+ }
10835
+ function currentFrames() {
10836
+ return suppressionStore().getStore()?.frames ?? [];
10837
+ }
10838
+ function isAutoInstrumentationSuppressed() {
10839
+ const frames = currentFrames();
10840
+ return frames[frames.length - 1]?.mode === "suppress";
10841
+ }
10842
+ function runWithAutoInstrumentationSuppressed(callback) {
10843
+ const frame = {
10844
+ id: /* @__PURE__ */ Symbol("braintrust.auto-instrumentation-suppress"),
10845
+ mode: "suppress"
10846
+ };
10847
+ return suppressionStore().run(
10848
+ { frames: [...currentFrames(), frame] },
10849
+ callback
10850
+ );
10851
+ }
10852
+ function bindAutoInstrumentationSuppressionToStart(tracingChannel2) {
10853
+ const startChannel = tracingChannel2.start;
10854
+ if (!startChannel) {
10855
+ return void 0;
10856
+ }
10857
+ const store = suppressionStore();
10858
+ startChannel.bindStore(store, () => ({
10859
+ frames: [
10860
+ ...currentFrames(),
10861
+ {
10862
+ id: /* @__PURE__ */ Symbol("braintrust.auto-instrumentation-suppress"),
10863
+ mode: "suppress"
10864
+ }
10865
+ ]
10866
+ }));
10867
+ return () => {
10868
+ startChannel.unbindStore(store);
10869
+ };
10870
+ }
10871
+ function enterAutoInstrumentationAllowed() {
10872
+ const frame = {
10873
+ id: /* @__PURE__ */ Symbol("braintrust.auto-instrumentation-allow"),
10874
+ mode: "allow"
10875
+ };
10876
+ suppressionStore().enterWith({
10877
+ frames: [...currentFrames(), frame]
10878
+ });
10879
+ return () => {
10880
+ const frames = currentFrames().filter(
10881
+ (candidate) => candidate.id !== frame.id
10882
+ );
10883
+ suppressionStore().enterWith(frames.length > 0 ? { frames } : void 0);
10884
+ };
10885
+ }
10886
+
10811
10887
  // src/instrumentation/core/channel-tracing.ts
10812
10888
  function isSyncStreamLike(value) {
10813
10889
  return !!value && typeof value === "object" && typeof value.on === "function";
@@ -10839,16 +10915,33 @@ function startSpanForEvent(config, event, channelName) {
10839
10915
  metadata: mergeInputMetadata(metadata, spanInfoMetadata)
10840
10916
  });
10841
10917
  } catch (error) {
10842
- console.error(`Error extracting input for ${channelName}:`, error);
10918
+ debugLogger.error(`Error extracting input for ${channelName}:`, error);
10843
10919
  }
10844
10920
  return { span, startTime };
10845
10921
  }
10922
+ function shouldTraceEvent(config, event, channelName) {
10923
+ if (!config.shouldTrace) {
10924
+ return true;
10925
+ }
10926
+ try {
10927
+ return config.shouldTrace(event.arguments, event);
10928
+ } catch (error) {
10929
+ debugLogger.error(
10930
+ `Error checking trace predicate for ${channelName}:`,
10931
+ error
10932
+ );
10933
+ return true;
10934
+ }
10935
+ }
10846
10936
  function ensureSpanStateForEvent(states, config, event, channelName) {
10847
10937
  const key = event;
10848
10938
  const existing = states.get(key);
10849
10939
  if (existing) {
10850
10940
  return existing;
10851
10941
  }
10942
+ if (!shouldTraceEvent(config, event, channelName)) {
10943
+ return void 0;
10944
+ }
10852
10945
  const created = startSpanForEvent(config, event, channelName);
10853
10946
  states.set(key, created);
10854
10947
  return created;
@@ -10864,13 +10957,16 @@ function bindCurrentSpanStoreToStart(tracingChannel2, states, config, channelNam
10864
10957
  startChannel.bindStore(
10865
10958
  currentSpanStore,
10866
10959
  (event) => {
10867
- const span = ensureSpanStateForEvent(
10960
+ if (isAutoInstrumentationSuppressed()) {
10961
+ return currentSpanStore.getStore();
10962
+ }
10963
+ const spanState = ensureSpanStateForEvent(
10868
10964
  states,
10869
10965
  config,
10870
10966
  event,
10871
10967
  channelName
10872
- ).span;
10873
- return contextManager.wrapSpanForStore(span);
10968
+ );
10969
+ return spanState ? contextManager.wrapSpanForStore(spanState.span) : currentSpanStore.getStore();
10874
10970
  }
10875
10971
  );
10876
10972
  return () => {
@@ -10905,7 +11001,10 @@ function runStreamingCompletionHook(args) {
10905
11001
  startTime: args.startTime
10906
11002
  });
10907
11003
  } catch (error) {
10908
- console.error(`Error in onComplete hook for ${args.channelName}:`, error);
11004
+ debugLogger.error(
11005
+ `Error in onComplete hook for ${args.channelName}:`,
11006
+ error
11007
+ );
10909
11008
  }
10910
11009
  }
10911
11010
  function traceAsyncChannel(channel2, config) {
@@ -10920,6 +11019,9 @@ function traceAsyncChannel(channel2, config) {
10920
11019
  );
10921
11020
  const handlers = {
10922
11021
  start: (event) => {
11022
+ if (isAutoInstrumentationSuppressed()) {
11023
+ return;
11024
+ }
10923
11025
  ensureSpanStateForEvent(
10924
11026
  states,
10925
11027
  config,
@@ -10954,7 +11056,7 @@ function traceAsyncChannel(channel2, config) {
10954
11056
  metrics
10955
11057
  });
10956
11058
  } catch (error) {
10957
- console.error(`Error extracting output for ${channelName}:`, error);
11059
+ debugLogger.error(`Error extracting output for ${channelName}:`, error);
10958
11060
  } finally {
10959
11061
  span.end();
10960
11062
  states.delete(event);
@@ -10982,6 +11084,9 @@ function traceStreamingChannel(channel2, config) {
10982
11084
  );
10983
11085
  const handlers = {
10984
11086
  start: (event) => {
11087
+ if (isAutoInstrumentationSuppressed()) {
11088
+ return;
11089
+ }
10985
11090
  ensureSpanStateForEvent(
10986
11091
  states,
10987
11092
  config,
@@ -11053,7 +11158,7 @@ function traceStreamingChannel(channel2, config) {
11053
11158
  metrics
11054
11159
  });
11055
11160
  } catch (error) {
11056
- console.error(
11161
+ debugLogger.error(
11057
11162
  `Error extracting output for ${channelName}:`,
11058
11163
  error
11059
11164
  );
@@ -11113,7 +11218,7 @@ function traceStreamingChannel(channel2, config) {
11113
11218
  metrics
11114
11219
  });
11115
11220
  } catch (error) {
11116
- console.error(`Error extracting output for ${channelName}:`, error);
11221
+ debugLogger.error(`Error extracting output for ${channelName}:`, error);
11117
11222
  } finally {
11118
11223
  span.end();
11119
11224
  states.delete(event);
@@ -11141,6 +11246,9 @@ function traceSyncStreamChannel(channel2, config) {
11141
11246
  );
11142
11247
  const handlers = {
11143
11248
  start: (event) => {
11249
+ if (isAutoInstrumentationSuppressed()) {
11250
+ return;
11251
+ }
11144
11252
  ensureSpanStateForEvent(
11145
11253
  states,
11146
11254
  config,
@@ -11194,7 +11302,7 @@ function traceSyncStreamChannel(channel2, config) {
11194
11302
  });
11195
11303
  }
11196
11304
  } catch (error) {
11197
- console.error(
11305
+ debugLogger.error(
11198
11306
  `Error extracting chatCompletion for ${channelName}:`,
11199
11307
  error
11200
11308
  );
@@ -11218,7 +11326,10 @@ function traceSyncStreamChannel(channel2, config) {
11218
11326
  span.log(extracted);
11219
11327
  }
11220
11328
  } catch (error) {
11221
- console.error(`Error extracting event for ${channelName}:`, error);
11329
+ debugLogger.error(
11330
+ `Error extracting event for ${channelName}:`,
11331
+ error
11332
+ );
11222
11333
  }
11223
11334
  });
11224
11335
  stream.on("end", () => {
@@ -12747,6 +12858,9 @@ var AnthropicPlugin = class extends BasePlugin {
12747
12858
  const states = /* @__PURE__ */ new WeakMap();
12748
12859
  const handlers = {
12749
12860
  start: (event) => {
12861
+ if (isAutoInstrumentationSuppressed()) {
12862
+ return;
12863
+ }
12750
12864
  const params = event.arguments[0] ?? {};
12751
12865
  const span = startSpan({
12752
12866
  name: "anthropic.beta.messages.toolRunner",
@@ -13476,6 +13590,520 @@ function serializeAISDKToolsForLogging(tools) {
13476
13590
  return serialized;
13477
13591
  }
13478
13592
 
13593
+ // src/wrappers/ai-sdk/telemetry.ts
13594
+ function braintrustAISDKTelemetry() {
13595
+ const operations = /* @__PURE__ */ new Map();
13596
+ const modelSpans = /* @__PURE__ */ new Map();
13597
+ const objectSpans = /* @__PURE__ */ new Map();
13598
+ const embedSpans = /* @__PURE__ */ new Map();
13599
+ const rerankSpans = /* @__PURE__ */ new Map();
13600
+ const toolSpans = /* @__PURE__ */ new Map();
13601
+ const runSafely = (name, callback) => {
13602
+ try {
13603
+ callback();
13604
+ } catch (error) {
13605
+ console.error(`Error in Braintrust AI SDK telemetry ${name}:`, error);
13606
+ }
13607
+ };
13608
+ const startChildSpan = (callId, name, type, event) => {
13609
+ const parent = operations.get(callId)?.span;
13610
+ const spanArgs = {
13611
+ name,
13612
+ spanAttributes: { type },
13613
+ ...event ? { event } : {}
13614
+ };
13615
+ const span = parent ? parent.startSpan(spanArgs) : startSpan(spanArgs);
13616
+ const state = operations.get(callId);
13617
+ if (state && type === "llm" /* LLM */) {
13618
+ state.hadModelChild = true;
13619
+ }
13620
+ return span;
13621
+ };
13622
+ return {
13623
+ onStart(event) {
13624
+ runSafely("onStart", () => {
13625
+ const operationName = operationNameFromId(event.operationId);
13626
+ const span = startSpan({
13627
+ name: operationName,
13628
+ spanAttributes: { type: "function" /* FUNCTION */ }
13629
+ });
13630
+ operations.set(event.callId, {
13631
+ hadModelChild: false,
13632
+ operationName,
13633
+ span,
13634
+ startTime: getCurrentUnixTimestamp()
13635
+ });
13636
+ const metadata = metadataFromEvent(event);
13637
+ const logPayload = { metadata };
13638
+ if (shouldRecordInputs(event)) {
13639
+ const { input, outputPromise } = processAISDKCallInput(
13640
+ operationInput(event, operationName)
13641
+ );
13642
+ logPayload.input = input;
13643
+ if (outputPromise && input && typeof input === "object") {
13644
+ outputPromise.then((resolvedData) => {
13645
+ span.log({
13646
+ input: {
13647
+ ...input,
13648
+ ...resolvedData
13649
+ }
13650
+ });
13651
+ }).catch(() => {
13652
+ });
13653
+ }
13654
+ }
13655
+ span.log(logPayload);
13656
+ });
13657
+ },
13658
+ onLanguageModelCallStart(event) {
13659
+ runSafely("onLanguageModelCallStart", () => {
13660
+ const state = operations.get(event.callId);
13661
+ const openSpans = modelSpans.get(event.callId);
13662
+ if (openSpans) {
13663
+ for (const span2 of openSpans) {
13664
+ span2.end();
13665
+ }
13666
+ modelSpans.delete(event.callId);
13667
+ }
13668
+ const span = startChildSpan(
13669
+ event.callId,
13670
+ state?.operationName === "streamText" ? "doStream" : "doGenerate",
13671
+ "llm" /* LLM */,
13672
+ {
13673
+ ...shouldRecordInputs(event) ? {
13674
+ input: processAISDKCallInput(
13675
+ operationInput(
13676
+ event,
13677
+ state?.operationName ?? "generateText"
13678
+ )
13679
+ ).input
13680
+ } : {},
13681
+ metadata: metadataFromEvent(event)
13682
+ }
13683
+ );
13684
+ const spans = modelSpans.get(event.callId) ?? [];
13685
+ spans.push(span);
13686
+ modelSpans.set(event.callId, spans);
13687
+ });
13688
+ },
13689
+ onLanguageModelCallEnd(event) {
13690
+ runSafely("onLanguageModelCallEnd", () => {
13691
+ const span = shiftModelSpan(modelSpans, event.callId);
13692
+ if (!span) {
13693
+ return;
13694
+ }
13695
+ const result = {
13696
+ ...event,
13697
+ response: event.responseId ? { id: event.responseId } : void 0
13698
+ };
13699
+ span.log({
13700
+ ...shouldRecordOutputs(event) ? {
13701
+ output: processAISDKOutput(result, DEFAULT_DENY_OUTPUT_PATHS)
13702
+ } : {},
13703
+ metrics: extractTokenMetrics(result)
13704
+ });
13705
+ span.end();
13706
+ });
13707
+ },
13708
+ onObjectStepStart(event) {
13709
+ runSafely("onObjectStepStart", () => {
13710
+ const state = operations.get(event.callId);
13711
+ const openSpan = objectSpans.get(event.callId);
13712
+ if (openSpan) {
13713
+ openSpan.end();
13714
+ objectSpans.delete(event.callId);
13715
+ }
13716
+ const span = startChildSpan(
13717
+ event.callId,
13718
+ state?.operationName === "streamObject" ? "doStream" : "doGenerate",
13719
+ "llm" /* LLM */,
13720
+ {
13721
+ ...shouldRecordInputs(event) ? {
13722
+ input: {
13723
+ prompt: event.promptMessages
13724
+ }
13725
+ } : {},
13726
+ metadata: metadataFromEvent(event)
13727
+ }
13728
+ );
13729
+ objectSpans.set(event.callId, span);
13730
+ });
13731
+ },
13732
+ onObjectStepFinish(event) {
13733
+ runSafely("onObjectStepFinish", () => {
13734
+ const span = objectSpans.get(event.callId);
13735
+ if (!span) {
13736
+ return;
13737
+ }
13738
+ const result = {
13739
+ ...event,
13740
+ text: event.objectText
13741
+ };
13742
+ span.log({
13743
+ ...shouldRecordOutputs(event) ? {
13744
+ output: processAISDKOutput(result, DEFAULT_DENY_OUTPUT_PATHS)
13745
+ } : {},
13746
+ metrics: extractTokenMetrics(result)
13747
+ });
13748
+ span.end();
13749
+ objectSpans.delete(event.callId);
13750
+ });
13751
+ },
13752
+ onEmbedStart(event) {
13753
+ runSafely("onEmbedStart", () => {
13754
+ const state = operations.get(event.callId);
13755
+ for (const [embedCallId, embedState] of embedSpans) {
13756
+ if (embedState.callId === event.callId && (state?.operationName === "embed" || embedState.values === event.values)) {
13757
+ embedState.span.end();
13758
+ embedSpans.delete(embedCallId);
13759
+ }
13760
+ }
13761
+ const span = startChildSpan(
13762
+ event.callId,
13763
+ "doEmbed",
13764
+ "llm" /* LLM */,
13765
+ {
13766
+ ...shouldRecordInputs(event) ? {
13767
+ input: {
13768
+ values: event.values
13769
+ }
13770
+ } : {},
13771
+ metadata: metadataFromEvent(event)
13772
+ }
13773
+ );
13774
+ embedSpans.set(event.embedCallId, {
13775
+ callId: event.callId,
13776
+ span,
13777
+ values: event.values
13778
+ });
13779
+ });
13780
+ },
13781
+ onEmbedFinish(event) {
13782
+ runSafely("onEmbedFinish", () => {
13783
+ const state = embedSpans.get(event.embedCallId);
13784
+ if (!state) {
13785
+ return;
13786
+ }
13787
+ const result = {
13788
+ ...event,
13789
+ embeddings: event.embeddings
13790
+ };
13791
+ state.span.log({
13792
+ ...shouldRecordOutputs(event) ? {
13793
+ output: processAISDKEmbeddingOutput(
13794
+ result,
13795
+ DEFAULT_DENY_OUTPUT_PATHS
13796
+ )
13797
+ } : {},
13798
+ metrics: extractTokenMetrics(result)
13799
+ });
13800
+ state.span.end();
13801
+ embedSpans.delete(event.embedCallId);
13802
+ });
13803
+ },
13804
+ onRerankStart(event) {
13805
+ runSafely("onRerankStart", () => {
13806
+ const openSpan = rerankSpans.get(event.callId);
13807
+ if (openSpan) {
13808
+ openSpan.end();
13809
+ rerankSpans.delete(event.callId);
13810
+ }
13811
+ const span = startChildSpan(
13812
+ event.callId,
13813
+ "doRerank",
13814
+ "llm" /* LLM */,
13815
+ {
13816
+ ...shouldRecordInputs(event) ? {
13817
+ input: {
13818
+ documents: event.documents,
13819
+ query: event.query,
13820
+ topN: event.topN
13821
+ }
13822
+ } : {},
13823
+ metadata: metadataFromEvent(event)
13824
+ }
13825
+ );
13826
+ rerankSpans.set(event.callId, span);
13827
+ });
13828
+ },
13829
+ onRerankFinish(event) {
13830
+ runSafely("onRerankFinish", () => {
13831
+ const span = rerankSpans.get(event.callId);
13832
+ if (!span) {
13833
+ return;
13834
+ }
13835
+ const result = {
13836
+ ranking: event.ranking?.map((entry) => ({
13837
+ originalIndex: entry.index,
13838
+ score: entry.relevanceScore
13839
+ }))
13840
+ };
13841
+ span.log({
13842
+ ...shouldRecordOutputs(event) ? {
13843
+ output: processAISDKRerankOutput(
13844
+ result,
13845
+ DEFAULT_DENY_OUTPUT_PATHS
13846
+ )
13847
+ } : {}
13848
+ });
13849
+ span.end();
13850
+ rerankSpans.delete(event.callId);
13851
+ });
13852
+ },
13853
+ onToolExecutionStart(event) {
13854
+ runSafely("onToolExecutionStart", () => {
13855
+ const toolCallId = event.toolCall.toolCallId;
13856
+ if (!toolCallId) {
13857
+ return;
13858
+ }
13859
+ const span = startChildSpan(
13860
+ event.callId,
13861
+ event.toolCall.toolName || "tool",
13862
+ "tool" /* TOOL */,
13863
+ {
13864
+ ...shouldRecordInputs(event) ? {
13865
+ input: event.toolCall.input
13866
+ } : {},
13867
+ metadata: {
13868
+ ...createAISDKIntegrationMetadata(),
13869
+ toolCallId,
13870
+ ...typeof event.toolCall.toolName === "string" ? { toolName: event.toolCall.toolName } : {}
13871
+ }
13872
+ }
13873
+ );
13874
+ toolSpans.set(toolCallId, { callId: event.callId, span });
13875
+ });
13876
+ },
13877
+ onToolExecutionEnd(event) {
13878
+ runSafely("onToolExecutionEnd", () => {
13879
+ const toolCallId = event.toolCall.toolCallId;
13880
+ const state = toolCallId ? toolSpans.get(toolCallId) : void 0;
13881
+ if (!toolCallId || !state) {
13882
+ return;
13883
+ }
13884
+ const toolOutput = event.toolOutput;
13885
+ if (toolOutput?.type === "tool-error") {
13886
+ state.span.log({
13887
+ error: toolOutput.error instanceof Error ? toolOutput.error.message : String(toolOutput?.error),
13888
+ metrics: typeof event.durationMs === "number" ? { duration_ms: event.durationMs } : {}
13889
+ });
13890
+ } else {
13891
+ state.span.log({
13892
+ ...shouldRecordOutputs(event) ? { output: toolOutput?.output } : {},
13893
+ metrics: typeof event.durationMs === "number" ? { duration_ms: event.durationMs } : {}
13894
+ });
13895
+ }
13896
+ state.span.end();
13897
+ toolSpans.delete(toolCallId);
13898
+ });
13899
+ },
13900
+ onChunk(event) {
13901
+ runSafely("onChunk", () => {
13902
+ const callId = event.chunk?.callId;
13903
+ if (!callId) {
13904
+ return;
13905
+ }
13906
+ const state = operations.get(callId);
13907
+ if (!state || state.firstChunkTime !== void 0) {
13908
+ return;
13909
+ }
13910
+ state.firstChunkTime = getCurrentUnixTimestamp();
13911
+ });
13912
+ },
13913
+ onFinish(event) {
13914
+ runSafely("onFinish", () => {
13915
+ const state = operations.get(event.callId);
13916
+ if (!state) {
13917
+ return;
13918
+ }
13919
+ const result = finishResult(event, state.operationName);
13920
+ const metrics = state.hadModelChild ? {} : extractTokenMetrics(result);
13921
+ if (state.firstChunkTime !== void 0) {
13922
+ metrics.time_to_first_token = state.firstChunkTime - state.startTime;
13923
+ }
13924
+ state.span.log({
13925
+ ...shouldRecordOutputs(event) ? {
13926
+ output: finishOutput(result, state.operationName)
13927
+ } : {},
13928
+ metrics
13929
+ });
13930
+ state.span.end();
13931
+ operations.delete(event.callId);
13932
+ });
13933
+ },
13934
+ onError(event) {
13935
+ runSafely("onError", () => {
13936
+ const errorEvent = isObject(event) ? event : {};
13937
+ const callId = typeof errorEvent.callId === "string" ? errorEvent.callId : void 0;
13938
+ if (!callId) {
13939
+ return;
13940
+ }
13941
+ const state = operations.get(callId);
13942
+ if (!state) {
13943
+ return;
13944
+ }
13945
+ const error = errorEvent.error ?? event;
13946
+ const openModelSpans = modelSpans.get(callId);
13947
+ if (openModelSpans) {
13948
+ for (const span of openModelSpans) {
13949
+ logError(span, error);
13950
+ span.end();
13951
+ }
13952
+ modelSpans.delete(callId);
13953
+ }
13954
+ const openObjectSpan = objectSpans.get(callId);
13955
+ if (openObjectSpan) {
13956
+ logError(openObjectSpan, error);
13957
+ openObjectSpan.end();
13958
+ objectSpans.delete(callId);
13959
+ }
13960
+ for (const [embedCallId, embedState] of embedSpans) {
13961
+ if (embedState.callId === callId) {
13962
+ logError(embedState.span, error);
13963
+ embedState.span.end();
13964
+ embedSpans.delete(embedCallId);
13965
+ }
13966
+ }
13967
+ const openRerankSpan = rerankSpans.get(callId);
13968
+ if (openRerankSpan) {
13969
+ logError(openRerankSpan, error);
13970
+ openRerankSpan.end();
13971
+ rerankSpans.delete(callId);
13972
+ }
13973
+ for (const [toolCallId, toolState] of toolSpans) {
13974
+ if (toolState.callId === callId) {
13975
+ logError(toolState.span, error);
13976
+ toolState.span.end();
13977
+ toolSpans.delete(toolCallId);
13978
+ }
13979
+ }
13980
+ logError(state.span, error);
13981
+ state.span.end();
13982
+ operations.delete(callId);
13983
+ });
13984
+ },
13985
+ executeTool({ toolCallId, execute }) {
13986
+ const state = toolSpans.get(toolCallId);
13987
+ return state ? withCurrent(state.span, () => execute()) : execute();
13988
+ }
13989
+ };
13990
+ }
13991
+ function shouldRecordInputs(event) {
13992
+ return event.recordInputs !== false;
13993
+ }
13994
+ function shouldRecordOutputs(event) {
13995
+ return event.recordOutputs !== false;
13996
+ }
13997
+ function operationNameFromId(operationId) {
13998
+ return operationId?.startsWith("ai.") ? operationId.slice("ai.".length) : operationId || "ai-sdk";
13999
+ }
14000
+ function modelFromEvent(event) {
14001
+ return event.modelId ? {
14002
+ modelId: event.modelId,
14003
+ ...event.provider ? { provider: event.provider } : {}
14004
+ } : void 0;
14005
+ }
14006
+ function metadataFromEvent(event) {
14007
+ const metadata = createAISDKIntegrationMetadata();
14008
+ const { model, provider } = serializeModelWithProvider(modelFromEvent(event));
14009
+ if (model) {
14010
+ metadata.model = model;
14011
+ }
14012
+ if (provider) {
14013
+ metadata.provider = provider;
14014
+ }
14015
+ if (typeof event.functionId === "string") {
14016
+ metadata.functionId = event.functionId;
14017
+ }
14018
+ return metadata;
14019
+ }
14020
+ function operationInput(event, operationName) {
14021
+ if (operationName === "embed") {
14022
+ return {
14023
+ model: modelFromEvent(event),
14024
+ value: event.value
14025
+ };
14026
+ }
14027
+ if (operationName === "embedMany") {
14028
+ return {
14029
+ model: modelFromEvent(event),
14030
+ values: Array.isArray(event.value) ? event.value ?? [] : void 0
14031
+ };
14032
+ }
14033
+ if (operationName === "rerank") {
14034
+ return {
14035
+ model: modelFromEvent(event),
14036
+ documents: event.documents,
14037
+ query: event.query,
14038
+ topN: event.topN
14039
+ };
14040
+ }
14041
+ return {
14042
+ model: modelFromEvent(event),
14043
+ system: event.system,
14044
+ prompt: event.prompt,
14045
+ messages: event.messages,
14046
+ tools: event.tools,
14047
+ toolChoice: event.toolChoice,
14048
+ activeTools: event.activeTools,
14049
+ output: event.output,
14050
+ schema: event.schema,
14051
+ schemaName: event.schemaName,
14052
+ schemaDescription: event.schemaDescription,
14053
+ maxOutputTokens: event.maxOutputTokens,
14054
+ temperature: event.temperature,
14055
+ topP: event.topP,
14056
+ topK: event.topK,
14057
+ presencePenalty: event.presencePenalty,
14058
+ frequencyPenalty: event.frequencyPenalty,
14059
+ seed: event.seed,
14060
+ maxRetries: event.maxRetries,
14061
+ headers: event.headers,
14062
+ providerOptions: event.providerOptions
14063
+ };
14064
+ }
14065
+ function shiftModelSpan(modelSpans, callId) {
14066
+ const spans = modelSpans.get(callId);
14067
+ const span = spans?.shift();
14068
+ if (spans && spans.length === 0) {
14069
+ modelSpans.delete(callId);
14070
+ }
14071
+ return span;
14072
+ }
14073
+ function finishResult(event, operationName) {
14074
+ if (operationName === "embed") {
14075
+ return {
14076
+ ...event,
14077
+ embedding: event.embedding
14078
+ };
14079
+ }
14080
+ if (operationName === "embedMany") {
14081
+ return {
14082
+ ...event,
14083
+ embeddings: event.embedding
14084
+ };
14085
+ }
14086
+ if (operationName === "rerank") {
14087
+ return event;
14088
+ }
14089
+ return event;
14090
+ }
14091
+ function finishOutput(result, operationName) {
14092
+ if (operationName === "embed" || operationName === "embedMany") {
14093
+ return processAISDKEmbeddingOutput(
14094
+ result,
14095
+ DEFAULT_DENY_OUTPUT_PATHS
14096
+ );
14097
+ }
14098
+ if (operationName === "rerank") {
14099
+ return processAISDKRerankOutput(
14100
+ result,
14101
+ DEFAULT_DENY_OUTPUT_PATHS
14102
+ );
14103
+ }
14104
+ return processAISDKOutput(result, DEFAULT_DENY_OUTPUT_PATHS);
14105
+ }
14106
+
13479
14107
  // src/instrumentation/plugins/ai-sdk-channels.ts
13480
14108
  var aiSDKChannels = defineChannels("ai", {
13481
14109
  generateText: channel({
@@ -13535,6 +14163,10 @@ var aiSDKChannels = defineChannels("ai", {
13535
14163
  toolLoopAgentStream: channel({
13536
14164
  channelName: "ToolLoopAgent.stream",
13537
14165
  kind: "async"
14166
+ }),
14167
+ v7CreateTelemetryDispatcher: channel({
14168
+ channelName: "createTelemetryDispatcher",
14169
+ kind: "sync-stream"
13538
14170
  })
13539
14171
  });
13540
14172
 
@@ -13555,9 +14187,30 @@ var DEFAULT_DENY_OUTPUT_PATHS = [
13555
14187
  ];
13556
14188
  var AUTO_PATCHED_MODEL = /* @__PURE__ */ Symbol.for("braintrust.ai-sdk.auto-patched-model");
13557
14189
  var AUTO_PATCHED_TOOL = /* @__PURE__ */ Symbol.for("braintrust.ai-sdk.auto-patched-tool");
14190
+ var AUTO_PATCHED_V7_TELEMETRY_DISPATCHER = /* @__PURE__ */ Symbol.for(
14191
+ "braintrust.ai-sdk.v7.auto-patched-telemetry-dispatcher"
14192
+ );
13558
14193
  var RUNTIME_DENY_OUTPUT_PATHS = /* @__PURE__ */ Symbol.for(
13559
14194
  "braintrust.ai-sdk.deny-output-paths"
13560
14195
  );
14196
+ var AI_SDK_V7_TELEMETRY_CALLBACKS = [
14197
+ "onStart",
14198
+ "onStepStart",
14199
+ "onLanguageModelCallStart",
14200
+ "onLanguageModelCallEnd",
14201
+ "onToolExecutionStart",
14202
+ "onToolExecutionEnd",
14203
+ "onChunk",
14204
+ "onStepFinish",
14205
+ "onObjectStepStart",
14206
+ "onObjectStepFinish",
14207
+ "onEmbedStart",
14208
+ "onEmbedFinish",
14209
+ "onRerankStart",
14210
+ "onRerankFinish",
14211
+ "onFinish",
14212
+ "onError"
14213
+ ];
13561
14214
  var AISDKPlugin = class extends BasePlugin {
13562
14215
  config;
13563
14216
  constructor(config = {}) {
@@ -13572,6 +14225,7 @@ var AISDKPlugin = class extends BasePlugin {
13572
14225
  }
13573
14226
  subscribeToAISDK() {
13574
14227
  const denyOutputPaths = this.config.denyOutputPaths || DEFAULT_DENY_OUTPUT_PATHS;
14228
+ this.unsubscribers.push(subscribeToAISDKV7TelemetryDispatcher());
13575
14229
  this.unsubscribers.push(
13576
14230
  traceStreamingChannel(aiSDKChannels.generateText, {
13577
14231
  name: "generateText",
@@ -13796,6 +14450,57 @@ var AISDKPlugin = class extends BasePlugin {
13796
14450
  );
13797
14451
  }
13798
14452
  };
14453
+ function subscribeToAISDKV7TelemetryDispatcher() {
14454
+ const channel2 = aiSDKChannels.v7CreateTelemetryDispatcher.tracingChannel();
14455
+ const telemetry = braintrustAISDKTelemetry();
14456
+ const handlers = {
14457
+ end: (event) => {
14458
+ const telemetryOptions = event.arguments?.[0]?.telemetry;
14459
+ if (telemetryOptions?.isEnabled === false) {
14460
+ return;
14461
+ }
14462
+ patchAISDKV7TelemetryDispatcher(event.result, telemetry);
14463
+ }
14464
+ };
14465
+ channel2.subscribe(handlers);
14466
+ return () => {
14467
+ channel2.unsubscribe(handlers);
14468
+ };
14469
+ }
14470
+ function patchAISDKV7TelemetryDispatcher(dispatcher, telemetry) {
14471
+ if (!isObject(dispatcher)) {
14472
+ return;
14473
+ }
14474
+ const dispatcherRecord = dispatcher;
14475
+ if (dispatcherRecord[AUTO_PATCHED_V7_TELEMETRY_DISPATCHER]) {
14476
+ return;
14477
+ }
14478
+ dispatcherRecord[AUTO_PATCHED_V7_TELEMETRY_DISPATCHER] = true;
14479
+ for (const key of AI_SDK_V7_TELEMETRY_CALLBACKS) {
14480
+ const braintrustCallback = telemetry[key];
14481
+ if (typeof braintrustCallback !== "function") {
14482
+ continue;
14483
+ }
14484
+ const existingCallback = dispatcherRecord[key];
14485
+ dispatcherRecord[key] = (event) => {
14486
+ const existingResult = typeof existingCallback === "function" ? existingCallback.call(dispatcher, event) : void 0;
14487
+ const braintrustResult = braintrustCallback.call(telemetry, event);
14488
+ const pending = [existingResult, braintrustResult].filter(isPromiseLike);
14489
+ if (pending.length > 0) {
14490
+ return Promise.allSettled(pending).then(() => void 0);
14491
+ }
14492
+ };
14493
+ }
14494
+ const braintrustExecuteTool = telemetry.executeTool;
14495
+ if (typeof braintrustExecuteTool !== "function") {
14496
+ return;
14497
+ }
14498
+ const existingExecuteTool = dispatcherRecord.executeTool;
14499
+ dispatcherRecord.executeTool = (args) => braintrustExecuteTool.call(telemetry, {
14500
+ ...args,
14501
+ execute: () => typeof existingExecuteTool === "function" ? existingExecuteTool.call(dispatcher, args) : args.execute()
14502
+ });
14503
+ }
13799
14504
  function resolveDenyOutputPaths(event, defaultDenyOutputPaths) {
13800
14505
  if (Array.isArray(event?.denyOutputPaths)) {
13801
14506
  return event.denyOutputPaths;
@@ -14247,11 +14952,11 @@ function prepareAISDKChildTracing(params, self, parentSpan, denyOutputPaths, aiS
14247
14952
  metadata: baseMetadata
14248
14953
  }
14249
14954
  });
14955
+ const streamStartTime = getCurrentUnixTimestamp();
14250
14956
  const result = await withCurrent(
14251
14957
  span,
14252
14958
  () => Reflect.apply(originalDoStream, resolvedModel, [options])
14253
14959
  );
14254
- const streamStartTime = getCurrentUnixTimestamp();
14255
14960
  let firstChunkTime;
14256
14961
  const output = {};
14257
14962
  let text = "";
@@ -14260,7 +14965,7 @@ function prepareAISDKChildTracing(params, self, parentSpan, denyOutputPaths, aiS
14260
14965
  let object = void 0;
14261
14966
  const transformStream = new TransformStream({
14262
14967
  transform(chunk, controller) {
14263
- if (firstChunkTime === void 0) {
14968
+ if (firstChunkTime === void 0 && isAISDKContentStreamChunk(chunk)) {
14264
14969
  firstChunkTime = getCurrentUnixTimestamp();
14265
14970
  }
14266
14971
  switch (chunk.type) {
@@ -14452,6 +15157,78 @@ function finalizeAISDKChildTracing(event) {
14452
15157
  delete event.__braintrust_ai_sdk_cleanup;
14453
15158
  }
14454
15159
  }
15160
+ function extractAISDKStreamPart(chunk) {
15161
+ if (!isObject(chunk) || !isObject(chunk.part)) {
15162
+ return chunk;
15163
+ }
15164
+ return chunk.part;
15165
+ }
15166
+ function stringContent(value) {
15167
+ return typeof value === "string" && value.length > 0 ? value : void 0;
15168
+ }
15169
+ function rawValueHasAISDKContent(value) {
15170
+ if (value === void 0 || value === null) {
15171
+ return false;
15172
+ }
15173
+ if (typeof value === "string") {
15174
+ return value.length > 0;
15175
+ }
15176
+ if (!isObject(value)) {
15177
+ return true;
15178
+ }
15179
+ const delta = value.delta;
15180
+ 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) => {
15181
+ if (!isObject(choice) || !isObject(choice.delta)) {
15182
+ return false;
15183
+ }
15184
+ const choiceDelta = choice.delta;
15185
+ if (stringContent(choiceDelta.content) || stringContent(choiceDelta.text)) {
15186
+ return true;
15187
+ }
15188
+ if (isObject(choiceDelta.function_call) && stringContent(choiceDelta.function_call.arguments)) {
15189
+ return true;
15190
+ }
15191
+ return Array.isArray(choiceDelta.tool_calls) && choiceDelta.tool_calls.some(
15192
+ (toolCall) => isObject(toolCall) && isObject(toolCall.function) && stringContent(toolCall.function.arguments)
15193
+ );
15194
+ })) {
15195
+ return true;
15196
+ }
15197
+ return false;
15198
+ }
15199
+ function isAISDKContentStreamChunk(chunk) {
15200
+ const part = extractAISDKStreamPart(chunk);
15201
+ if (typeof part === "string") {
15202
+ return part.length > 0;
15203
+ }
15204
+ if (!isObject(part) || typeof part.type !== "string") {
15205
+ return false;
15206
+ }
15207
+ switch (part.type) {
15208
+ case "text-delta":
15209
+ return stringContent(part.textDelta) !== void 0 || stringContent(part.delta) !== void 0 || stringContent(part.text) !== void 0 || stringContent(part.content) !== void 0;
15210
+ case "reasoning-delta":
15211
+ return stringContent(part.delta) !== void 0 || stringContent(part.text) !== void 0 || stringContent(part.content) !== void 0;
15212
+ case "tool-call":
15213
+ case "object":
15214
+ case "file":
15215
+ return true;
15216
+ case "tool-input-delta":
15217
+ case "tool-call-delta":
15218
+ 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;
15219
+ case "raw":
15220
+ return rawValueHasAISDKContent(part.rawValue);
15221
+ default:
15222
+ return false;
15223
+ }
15224
+ }
15225
+ function isAISDKContentAsyncIterableChunk(chunk) {
15226
+ if (isAISDKContentStreamChunk(chunk)) {
15227
+ return true;
15228
+ }
15229
+ const part = extractAISDKStreamPart(chunk);
15230
+ return isObject(part) && typeof part.type !== "string";
15231
+ }
14455
15232
  function patchAISDKStreamingResult(args) {
14456
15233
  const { defaultDenyOutputPaths, endEvent, result, span, startTime } = args;
14457
15234
  if (!result || typeof result !== "object") {
@@ -14464,7 +15241,7 @@ function patchAISDKStreamingResult(args) {
14464
15241
  const wrappedBaseStream = resultRecord.baseStream.pipeThrough(
14465
15242
  new TransformStream({
14466
15243
  transform(chunk, controller) {
14467
- if (firstChunkTime2 === void 0) {
15244
+ if (firstChunkTime2 === void 0 && isAISDKContentStreamChunk(chunk)) {
14468
15245
  firstChunkTime2 = getCurrentUnixTimestamp();
14469
15246
  }
14470
15247
  controller.enqueue(chunk);
@@ -14508,8 +15285,8 @@ function patchAISDKStreamingResult(args) {
14508
15285
  }
14509
15286
  let firstChunkTime;
14510
15287
  const wrappedStream = createPatchedAsyncIterable(streamField.stream, {
14511
- onChunk: () => {
14512
- if (firstChunkTime === void 0) {
15288
+ onChunk: (chunk) => {
15289
+ if (firstChunkTime === void 0 && isAISDKContentAsyncIterableChunk(chunk)) {
14513
15290
  firstChunkTime = getCurrentUnixTimestamp();
14514
15291
  }
14515
15292
  },
@@ -15481,15 +16258,17 @@ function collectLocalMcpServerToolHookNames(serverName, serverConfig) {
15481
16258
 
15482
16259
  // src/instrumentation/plugins/claude-agent-sdk-plugin.ts
15483
16260
  var ROOT_LLM_PARENT_KEY = "__root__";
16261
+ var SUB_AGENT_PROMPT_SOURCE_PRIORITY = {
16262
+ delegation: 0,
16263
+ lifecycle: 1,
16264
+ sidechain: 2
16265
+ };
15484
16266
  function llmParentKey(parentToolUseId) {
15485
16267
  return parentToolUseId ?? ROOT_LLM_PARENT_KEY;
15486
16268
  }
15487
16269
  function isSubAgentDelegationToolName(toolName) {
15488
16270
  return toolName === "Agent" || toolName === "Task";
15489
16271
  }
15490
- function shouldParentToolAsTaskSibling(toolName) {
15491
- return toolName === "Agent" || toolName === "Task" || toolName === "Bash";
15492
- }
15493
16272
  function filterSerializableOptions(options) {
15494
16273
  const allowedKeys = [
15495
16274
  "model",
@@ -15626,26 +16405,39 @@ function extractUsageFromMessage(message) {
15626
16405
  }
15627
16406
  return metrics;
15628
16407
  }
15629
- function buildLLMInput(prompt, conversationHistory, capturedPromptMessages) {
15630
- const promptMessages = [];
15631
- if (typeof prompt === "string") {
15632
- promptMessages.push({ content: prompt, role: "user" });
15633
- } else if (capturedPromptMessages && capturedPromptMessages.length > 0) {
15634
- for (const msg of capturedPromptMessages) {
15635
- const role = msg.message?.role;
15636
- const content = msg.message?.content;
15637
- if (role && content !== void 0) {
15638
- promptMessages.push({ content, role });
15639
- }
15640
- }
15641
- }
16408
+ function buildLLMInput(promptMessages, conversationHistory) {
15642
16409
  const inputParts = [...promptMessages, ...conversationHistory];
15643
16410
  return inputParts.length > 0 ? inputParts : void 0;
15644
16411
  }
16412
+ function conversationMessageFromSDKMessage(message) {
16413
+ const role = message.message?.role;
16414
+ const content = message.message?.content;
16415
+ if (role && content !== void 0) {
16416
+ return { content, role };
16417
+ }
16418
+ return void 0;
16419
+ }
16420
+ function messageContentHasBlockType(message, blockType) {
16421
+ const content = message.message?.content;
16422
+ return Array.isArray(content) && content.some(
16423
+ (block) => typeof block === "object" && block !== null && "type" in block && block.type === blockType
16424
+ );
16425
+ }
16426
+ function buildRootPromptMessages(prompt, capturedPromptMessages) {
16427
+ if (typeof prompt === "string") {
16428
+ return [{ content: prompt, role: "user" }];
16429
+ }
16430
+ if (!capturedPromptMessages || capturedPromptMessages.length === 0) {
16431
+ return [];
16432
+ }
16433
+ return capturedPromptMessages.map(conversationMessageFromSDKMessage).filter(
16434
+ (message) => message !== void 0
16435
+ );
16436
+ }
15645
16437
  function formatCapturedMessages(messages) {
15646
16438
  return messages.length > 0 ? messages : [];
15647
16439
  }
15648
- async function createLLMSpanForMessages(messages, prompt, conversationHistory, options, startTime, capturedPromptMessages, parentSpan, existingSpan) {
16440
+ async function createLLMSpanForMessages(messages, promptMessages, conversationHistory, options, startTime, parentSpan, existingSpan) {
15649
16441
  if (messages.length === 0) {
15650
16442
  return void 0;
15651
16443
  }
@@ -15655,11 +16447,7 @@ async function createLLMSpanForMessages(messages, prompt, conversationHistory, o
15655
16447
  }
15656
16448
  const model = lastMessage.message.model || options.model;
15657
16449
  const usage = extractUsageFromMessage(lastMessage);
15658
- const input = buildLLMInput(
15659
- prompt,
15660
- conversationHistory,
15661
- capturedPromptMessages
15662
- );
16450
+ const input = buildLLMInput(promptMessages, conversationHistory);
15663
16451
  const outputs = messages.map(
15664
16452
  (m) => m.message?.content && m.message?.role ? { content: m.message.content, role: m.message.role } : void 0
15665
16453
  ).filter(
@@ -15790,8 +16578,7 @@ function createToolTracingHooks(resolveParentSpan, activeToolSpans, mcpServers,
15790
16578
  },
15791
16579
  name: parsed.displayName,
15792
16580
  parent: await resolveParentSpan(toolUseID, {
15793
- agentId: input.agent_id,
15794
- preferTaskSiblingParent: shouldParentToolAsTaskSibling(parsed.toolName)
16581
+ agentId: input.agent_id
15795
16582
  }),
15796
16583
  spanAttributes: { type: "tool" /* TOOL */ }
15797
16584
  });
@@ -16037,12 +16824,37 @@ function injectTracingHooks(options, resolveParentSpan, activeToolSpans, localTo
16037
16824
  }
16038
16825
  };
16039
16826
  }
16827
+ function setSubAgentPromptMessages(state, parentToolUseId, promptMessages, source) {
16828
+ if (promptMessages.length === 0) {
16829
+ return;
16830
+ }
16831
+ const parentKey = llmParentKey(parentToolUseId);
16832
+ const sourcePriority = SUB_AGENT_PROMPT_SOURCE_PRIORITY[source];
16833
+ const currentPriority = state.promptSourcePriorityByParentKey.get(parentKey) ?? -1;
16834
+ if (sourcePriority > currentPriority) {
16835
+ state.promptMessagesByParentKey.set(parentKey, promptMessages);
16836
+ state.promptSourcePriorityByParentKey.set(parentKey, sourcePriority);
16837
+ }
16838
+ }
16839
+ function getConversationHistory(state, parentKey) {
16840
+ let conversationHistory = state.conversationHistoryByParentKey.get(parentKey);
16841
+ if (!conversationHistory) {
16842
+ conversationHistory = [];
16843
+ state.conversationHistoryByParentKey.set(parentKey, conversationHistory);
16844
+ }
16845
+ return conversationHistory;
16846
+ }
16040
16847
  async function finalizeCurrentMessageGroup(state) {
16041
16848
  if (state.currentMessages.length === 0) {
16042
16849
  return;
16043
16850
  }
16044
16851
  const parentToolUseId = state.currentMessages[0]?.parent_tool_use_id ?? null;
16045
16852
  const parentKey = llmParentKey(parentToolUseId);
16853
+ const conversationHistory = getConversationHistory(state, parentKey);
16854
+ const promptMessages = parentToolUseId ? state.promptMessagesByParentKey.get(parentKey) ?? [] : buildRootPromptMessages(
16855
+ state.originalPrompt,
16856
+ state.capturedPromptMessages
16857
+ );
16046
16858
  let parentSpan = await state.span.export();
16047
16859
  if (parentToolUseId) {
16048
16860
  const subAgentSpan = state.subAgentSpans.get(parentToolUseId);
@@ -16053,11 +16865,10 @@ async function finalizeCurrentMessageGroup(state) {
16053
16865
  const existingLlmSpan = state.activeLlmSpansByParentToolUse.get(parentKey);
16054
16866
  const llmSpanResult = await createLLMSpanForMessages(
16055
16867
  state.currentMessages,
16056
- state.originalPrompt,
16057
- state.finalResults,
16868
+ promptMessages,
16869
+ conversationHistory,
16058
16870
  state.options,
16059
16871
  state.currentMessageStartTime,
16060
- state.capturedPromptMessages,
16061
16872
  parentSpan,
16062
16873
  existingLlmSpan
16063
16874
  );
@@ -16071,6 +16882,7 @@ async function finalizeCurrentMessageGroup(state) {
16071
16882
  state.latestRootLlmParentRef.value = llmSpanResult.spanExport;
16072
16883
  }
16073
16884
  if (llmSpanResult.finalMessage) {
16885
+ conversationHistory.push(llmSpanResult.finalMessage);
16074
16886
  state.finalResults.push(llmSpanResult.finalMessage);
16075
16887
  }
16076
16888
  }
@@ -16098,6 +16910,15 @@ function maybeTrackToolUseContext(state, message) {
16098
16910
  description: getStringProperty(block.input, "description"),
16099
16911
  toolUseId: block.id
16100
16912
  });
16913
+ const prompt = getStringProperty(block.input, "prompt");
16914
+ if (prompt) {
16915
+ setSubAgentPromptMessages(
16916
+ state,
16917
+ block.id,
16918
+ [{ content: prompt, role: "user" }],
16919
+ "delegation"
16920
+ );
16921
+ }
16101
16922
  }
16102
16923
  }
16103
16924
  }
@@ -16216,6 +17037,14 @@ async function maybeHandleTaskLifecycleMessage(state, message) {
16216
17037
  };
16217
17038
  if (message.subtype === "task_started") {
16218
17039
  const prompt = getStringProperty(message, "prompt");
17040
+ if (prompt) {
17041
+ setSubAgentPromptMessages(
17042
+ state,
17043
+ toolUseId,
17044
+ [{ content: prompt, role: "user" }],
17045
+ "lifecycle"
17046
+ );
17047
+ }
16219
17048
  subAgentSpan.log({
16220
17049
  input: prompt,
16221
17050
  metadata
@@ -16266,6 +17095,28 @@ async function handleStreamMessage(state, message) {
16266
17095
  return;
16267
17096
  }
16268
17097
  await maybeStartSubAgentSpan(state, message);
17098
+ const messageParentToolUseId = message.parent_tool_use_id;
17099
+ if (messageParentToolUseId && message.type === "user") {
17100
+ const conversationMessage = conversationMessageFromSDKMessage(message);
17101
+ if (conversationMessage?.role === "user") {
17102
+ await finalizeCurrentMessageGroup(state);
17103
+ const parentKey = llmParentKey(messageParentToolUseId);
17104
+ const conversationHistory = getConversationHistory(state, parentKey);
17105
+ const currentPromptSourcePriority = state.promptSourcePriorityByParentKey.get(parentKey) ?? -1;
17106
+ const canUseAsInitialSidechainPrompt = conversationHistory.length === 0 && currentPromptSourcePriority < SUB_AGENT_PROMPT_SOURCE_PRIORITY.sidechain && !messageContentHasBlockType(message, "tool_result");
17107
+ if (!canUseAsInitialSidechainPrompt) {
17108
+ conversationHistory.push(conversationMessage);
17109
+ return;
17110
+ }
17111
+ setSubAgentPromptMessages(
17112
+ state,
17113
+ messageParentToolUseId,
17114
+ [conversationMessage],
17115
+ "sidechain"
17116
+ );
17117
+ return;
17118
+ }
17119
+ }
16269
17120
  const messageId = message.message?.id;
16270
17121
  if (messageId && messageId !== state.currentMessageId) {
16271
17122
  await finalizeCurrentMessageGroup(state);
@@ -16417,6 +17268,7 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
16417
17268
  }
16418
17269
  const activeToolSpans = /* @__PURE__ */ new Map();
16419
17270
  const activeLlmSpansByParentToolUse = /* @__PURE__ */ new Map();
17271
+ const conversationHistoryByParentKey = /* @__PURE__ */ new Map();
16420
17272
  const subAgentSpans = /* @__PURE__ */ new Map();
16421
17273
  const endedSubAgentSpans = /* @__PURE__ */ new Set();
16422
17274
  const toolUseToParent = /* @__PURE__ */ new Map();
@@ -16426,6 +17278,8 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
16426
17278
  };
16427
17279
  const subAgentDetailsByToolUseId = /* @__PURE__ */ new Map();
16428
17280
  const taskIdToToolUseId = /* @__PURE__ */ new Map();
17281
+ const promptMessagesByParentKey = /* @__PURE__ */ new Map();
17282
+ const promptSourcePriorityByParentKey = /* @__PURE__ */ new Map();
16429
17283
  const localToolContext = createClaudeLocalToolContext();
16430
17284
  const { hasLocalToolHandlers, localToolHookNames } = prepareLocalToolHandlersInMcpServers(options.mcpServers);
16431
17285
  const skipLocalToolHooks = options[CLAUDE_AGENT_SDK_SKIP_LOCAL_TOOL_HOOKS_OPTION] === true || hasLocalToolHandlers;
@@ -16434,38 +17288,19 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
16434
17288
  const parentToolUseId = trackedParentToolUseId ?? (context?.agentId ? taskIdToToolUseId.get(context.agentId) ?? null : null);
16435
17289
  const parentKey = llmParentKey(parentToolUseId);
16436
17290
  const activeLlmSpan = activeLlmSpansByParentToolUse.get(parentKey);
16437
- if (context?.preferTaskSiblingParent) {
16438
- if (!activeLlmSpan) {
16439
- await ensureActiveLlmSpanForParentToolUse(
16440
- span,
16441
- activeLlmSpansByParentToolUse,
16442
- subAgentDetailsByToolUseId,
16443
- activeToolSpans,
16444
- subAgentSpans,
16445
- parentToolUseId,
16446
- getCurrentUnixTimestamp()
16447
- );
16448
- }
16449
- if (parentToolUseId) {
16450
- const subAgentSpan = await ensureSubAgentSpan(
16451
- subAgentDetailsByToolUseId,
16452
- span,
16453
- activeToolSpans,
16454
- subAgentSpans,
16455
- parentToolUseId
16456
- );
16457
- return subAgentSpan.export();
16458
- }
16459
- return span.export();
16460
- }
16461
- if (activeLlmSpan) {
16462
- return activeLlmSpan.export();
17291
+ const latestLlmParent = parentToolUseId ? latestLlmParentBySubAgentToolUse.get(parentToolUseId) : latestRootLlmParentRef.value;
17292
+ if (!activeLlmSpan && !latestLlmParent) {
17293
+ await ensureActiveLlmSpanForParentToolUse(
17294
+ span,
17295
+ activeLlmSpansByParentToolUse,
17296
+ subAgentDetailsByToolUseId,
17297
+ activeToolSpans,
17298
+ subAgentSpans,
17299
+ parentToolUseId,
17300
+ getCurrentUnixTimestamp()
17301
+ );
16463
17302
  }
16464
17303
  if (parentToolUseId) {
16465
- const parentLlm = latestLlmParentBySubAgentToolUse.get(parentToolUseId);
16466
- if (parentLlm) {
16467
- return parentLlm;
16468
- }
16469
17304
  const subAgentSpan = await ensureSubAgentSpan(
16470
17305
  subAgentDetailsByToolUseId,
16471
17306
  span,
@@ -16475,9 +17310,6 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
16475
17310
  );
16476
17311
  return subAgentSpan.export();
16477
17312
  }
16478
- if (latestRootLlmParentRef.value) {
16479
- return latestRootLlmParentRef.value;
16480
- }
16481
17313
  return span.export();
16482
17314
  };
16483
17315
  localToolContext.resolveLocalToolParent = resolveToolUseParentSpan;
@@ -16498,6 +17330,7 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
16498
17330
  accumulatedOutputTokens: 0,
16499
17331
  activeLlmSpansByParentToolUse,
16500
17332
  activeToolSpans,
17333
+ conversationHistoryByParentKey,
16501
17334
  capturedPromptMessages,
16502
17335
  currentMessageId: void 0,
16503
17336
  currentMessageStartTime: startTime,
@@ -16508,7 +17341,9 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
16508
17341
  originalPrompt,
16509
17342
  processing: Promise.resolve(),
16510
17343
  promptDone,
17344
+ promptMessagesByParentKey,
16511
17345
  promptStarted: () => promptStarted,
17346
+ promptSourcePriorityByParentKey,
16512
17347
  span,
16513
17348
  subAgentDetailsByToolUseId,
16514
17349
  subAgentSpans,
@@ -17937,6 +18772,10 @@ var googleGenAIChannels = defineChannels("@google/genai", {
17937
18772
  embedContent: channel({
17938
18773
  channelName: "models.embedContent",
17939
18774
  kind: "async"
18775
+ }),
18776
+ interactionsCreate: channel({
18777
+ channelName: "interactions.create",
18778
+ kind: "async"
17940
18779
  })
17941
18780
  });
17942
18781
 
@@ -17964,6 +18803,7 @@ var GoogleGenAIPlugin = class extends BasePlugin {
17964
18803
  this.subscribeToGenerateContentChannel();
17965
18804
  this.subscribeToGenerateContentStreamChannel();
17966
18805
  this.subscribeToEmbedContentChannel();
18806
+ this.subscribeToInteractionsCreateChannel();
17967
18807
  }
17968
18808
  subscribeToGenerateContentChannel() {
17969
18809
  const tracingChannel2 = googleGenAIChannels.generateContent.tracingChannel();
@@ -18136,7 +18976,30 @@ var GoogleGenAIPlugin = class extends BasePlugin {
18136
18976
  tracingChannel2.unsubscribe(handlers);
18137
18977
  });
18138
18978
  }
18979
+ subscribeToInteractionsCreateChannel() {
18980
+ this.unsubscribers.push(
18981
+ traceStreamingChannel(
18982
+ googleGenAIChannels.interactionsCreate,
18983
+ {
18984
+ name: "create_interaction",
18985
+ shouldTrace: ([params]) => !isBackgroundInteractionCreate(params),
18986
+ type: "llm" /* LLM */,
18987
+ extractInput: ([params]) => ({
18988
+ input: serializeInteractionInput(params),
18989
+ metadata: extractInteractionMetadata(params)
18990
+ }),
18991
+ extractOutput: (result) => serializeInteractionValue(result),
18992
+ extractMetadata: (result) => extractInteractionResponseMetadata(result),
18993
+ extractMetrics: (result, startTime) => cleanMetrics3(extractInteractionMetrics(result, startTime)),
18994
+ aggregateChunks: (chunks, _result, _event, startTime) => aggregateInteractionEvents(chunks, startTime)
18995
+ }
18996
+ )
18997
+ );
18998
+ }
18139
18999
  };
19000
+ function isBackgroundInteractionCreate(params) {
19001
+ return tryToDict(params)?.background === true;
19002
+ }
18140
19003
  function ensureSpanState(states, event, create) {
18141
19004
  const existing = states.get(event);
18142
19005
  if (existing) {
@@ -18344,6 +19207,60 @@ function serializeEmbedContentInput(params) {
18344
19207
  }
18345
19208
  return input;
18346
19209
  }
19210
+ function serializeInteractionInput(params) {
19211
+ const input = {
19212
+ input: serializeInteractionValue(params.input)
19213
+ };
19214
+ for (const key of [
19215
+ "model",
19216
+ "agent",
19217
+ "agent_config",
19218
+ "api_version",
19219
+ "background",
19220
+ "environment",
19221
+ "generation_config",
19222
+ "previous_interaction_id",
19223
+ "response_format",
19224
+ "response_mime_type",
19225
+ "response_modalities",
19226
+ "service_tier",
19227
+ "store",
19228
+ "stream",
19229
+ "system_instruction",
19230
+ "webhook_config"
19231
+ ]) {
19232
+ const value = params[key];
19233
+ if (value !== void 0) {
19234
+ input[key] = serializeInteractionValue(value);
19235
+ }
19236
+ }
19237
+ return input;
19238
+ }
19239
+ function extractInteractionMetadata(params) {
19240
+ const metadata = {};
19241
+ for (const key of [
19242
+ "model",
19243
+ "agent",
19244
+ "agent_config",
19245
+ "generation_config",
19246
+ "system_instruction",
19247
+ "response_format",
19248
+ "response_mime_type",
19249
+ "response_modalities",
19250
+ "service_tier"
19251
+ ]) {
19252
+ const value = params[key];
19253
+ if (value !== void 0) {
19254
+ metadata[key] = serializeInteractionValue(value);
19255
+ }
19256
+ }
19257
+ if (Array.isArray(params.tools)) {
19258
+ metadata.tools = params.tools.map(
19259
+ (tool) => serializeInteractionValue(tool)
19260
+ );
19261
+ }
19262
+ return metadata;
19263
+ }
18347
19264
  function serializeContentCollection(contents) {
18348
19265
  if (contents === null || contents === void 0) {
18349
19266
  return null;
@@ -18374,21 +19291,8 @@ function serializePart(part) {
18374
19291
  }
18375
19292
  if (part.inlineData && part.inlineData.data) {
18376
19293
  const { data, mimeType } = part.inlineData;
18377
- if (data instanceof Uint8Array || typeof Buffer !== "undefined" && Buffer.isBuffer(data) || typeof data === "string") {
18378
- const extension = mimeType ? mimeType.split("/")[1] : "bin";
18379
- const filename = `file.${extension}`;
18380
- const buffer = typeof data === "string" ? typeof Buffer !== "undefined" ? Buffer.from(data, "base64") : new Uint8Array(
18381
- atob(data).split("").map((c) => c.charCodeAt(0))
18382
- ) : typeof Buffer !== "undefined" ? Buffer.from(data) : new Uint8Array(data);
18383
- const arrayBuffer = buffer instanceof Uint8Array ? buffer.buffer.slice(
18384
- buffer.byteOffset,
18385
- buffer.byteOffset + buffer.byteLength
18386
- ) : buffer;
18387
- const attachment = new Attachment({
18388
- data: arrayBuffer,
18389
- filename,
18390
- contentType: mimeType || "application/octet-stream"
18391
- });
19294
+ const attachment = createAttachmentFromInlineData(data, mimeType);
19295
+ if (attachment) {
18392
19296
  return {
18393
19297
  image_url: { url: attachment }
18394
19298
  };
@@ -18396,6 +19300,59 @@ function serializePart(part) {
18396
19300
  }
18397
19301
  return part;
18398
19302
  }
19303
+ function serializeInteractionValue(value, seen = /* @__PURE__ */ new WeakSet()) {
19304
+ if (value === null || value === void 0 || typeof value !== "object") {
19305
+ return value;
19306
+ }
19307
+ if (Array.isArray(value)) {
19308
+ return value.map((item) => serializeInteractionValue(item, seen));
19309
+ }
19310
+ const dict = tryToDict(value);
19311
+ if (dict === null || dict === void 0 || typeof dict !== "object") {
19312
+ return dict;
19313
+ }
19314
+ if (Array.isArray(dict)) {
19315
+ return dict.map((item) => serializeInteractionValue(item, seen));
19316
+ }
19317
+ if (seen.has(dict)) {
19318
+ return "[Circular]";
19319
+ }
19320
+ seen.add(dict);
19321
+ try {
19322
+ const serialized = {};
19323
+ 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;
19324
+ const attachment = mimeType && "data" in dict && dict.data !== void 0 ? createAttachmentFromInlineData(dict.data, mimeType) : null;
19325
+ for (const [key, entry] of Object.entries(dict)) {
19326
+ if (key === "data" && attachment) {
19327
+ serialized[key] = attachment;
19328
+ } else {
19329
+ serialized[key] = serializeInteractionValue(entry, seen);
19330
+ }
19331
+ }
19332
+ return serialized;
19333
+ } finally {
19334
+ seen.delete(dict);
19335
+ }
19336
+ }
19337
+ function createAttachmentFromInlineData(data, mimeType) {
19338
+ if (!(data instanceof Uint8Array || typeof Buffer !== "undefined" && Buffer.isBuffer(data) || typeof data === "string")) {
19339
+ return null;
19340
+ }
19341
+ const extension = mimeType ? mimeType.split("/")[1] : "bin";
19342
+ const filename = `file.${extension}`;
19343
+ const buffer = typeof data === "string" ? typeof Buffer !== "undefined" ? Buffer.from(data, "base64") : new Uint8Array(
19344
+ atob(data).split("").map((c) => c.charCodeAt(0))
19345
+ ) : typeof Buffer !== "undefined" ? Buffer.from(data) : new Uint8Array(data);
19346
+ const arrayBuffer = buffer instanceof Uint8Array ? buffer.buffer.slice(
19347
+ buffer.byteOffset,
19348
+ buffer.byteOffset + buffer.byteLength
19349
+ ) : buffer;
19350
+ return new Attachment({
19351
+ data: arrayBuffer,
19352
+ filename,
19353
+ contentType: mimeType || "application/octet-stream"
19354
+ });
19355
+ }
18399
19356
  function serializeGenerateContentTools(params) {
18400
19357
  const config = params.config ? tryToDict(params.config) : null;
18401
19358
  const tools = config?.tools;
@@ -18480,6 +19437,33 @@ function extractEmbedContentMetrics(response, startTime) {
18480
19437
  }
18481
19438
  return metrics;
18482
19439
  }
19440
+ function extractInteractionMetrics(response, startTime) {
19441
+ const metrics = {};
19442
+ if (startTime !== void 0) {
19443
+ const end = getCurrentUnixTimestamp();
19444
+ metrics.start = startTime;
19445
+ metrics.end = end;
19446
+ metrics.duration = end - startTime;
19447
+ }
19448
+ if (response?.usage) {
19449
+ populateInteractionUsageMetrics(metrics, response.usage);
19450
+ }
19451
+ return metrics;
19452
+ }
19453
+ function extractInteractionResponseMetadata(response) {
19454
+ const responseDict = tryToDict(response);
19455
+ if (!responseDict) {
19456
+ return void 0;
19457
+ }
19458
+ const metadata = {};
19459
+ if (typeof responseDict.id === "string") {
19460
+ metadata.interaction_id = responseDict.id;
19461
+ }
19462
+ if (typeof responseDict.status === "string") {
19463
+ metadata.status = responseDict.status;
19464
+ }
19465
+ return Object.keys(metadata).length > 0 ? metadata : void 0;
19466
+ }
18483
19467
  function extractEmbedPromptTokenCount(response) {
18484
19468
  if (!response) {
18485
19469
  return void 0;
@@ -18542,6 +19526,23 @@ function populateUsageMetrics(metrics, usage) {
18542
19526
  metrics.completion_reasoning_tokens = usage.thoughtsTokenCount;
18543
19527
  }
18544
19528
  }
19529
+ function populateInteractionUsageMetrics(metrics, usage) {
19530
+ if (typeof usage.total_input_tokens === "number") {
19531
+ metrics.prompt_tokens = usage.total_input_tokens;
19532
+ }
19533
+ if (typeof usage.total_output_tokens === "number") {
19534
+ metrics.completion_tokens = usage.total_output_tokens;
19535
+ }
19536
+ if (typeof usage.total_tokens === "number") {
19537
+ metrics.tokens = usage.total_tokens;
19538
+ }
19539
+ if (typeof usage.total_cached_tokens === "number") {
19540
+ metrics.prompt_cached_tokens = usage.total_cached_tokens;
19541
+ }
19542
+ if (typeof usage.total_thought_tokens === "number") {
19543
+ metrics.completion_reasoning_tokens = usage.total_thought_tokens;
19544
+ }
19545
+ }
18545
19546
  function aggregateGenerateContentChunks(chunks, startTime, firstTokenTime) {
18546
19547
  const end = getCurrentUnixTimestamp();
18547
19548
  const metrics = {
@@ -18639,6 +19640,146 @@ function aggregateGenerateContentChunks(chunks, startTime, firstTokenTime) {
18639
19640
  }
18640
19641
  return { aggregated, metrics };
18641
19642
  }
19643
+ function aggregateInteractionEvents(chunks, startTime) {
19644
+ const end = getCurrentUnixTimestamp();
19645
+ const metrics = {};
19646
+ if (startTime !== void 0) {
19647
+ metrics.start = startTime;
19648
+ metrics.end = end;
19649
+ metrics.duration = end - startTime;
19650
+ }
19651
+ let latestInteraction;
19652
+ let latestUsage;
19653
+ let status;
19654
+ let outputText = "";
19655
+ const steps = /* @__PURE__ */ new Map();
19656
+ for (const chunk of chunks) {
19657
+ const event = tryToDict(chunk);
19658
+ if (!event) {
19659
+ continue;
19660
+ }
19661
+ const usage = extractInteractionUsageFromEvent(event);
19662
+ if (usage) {
19663
+ latestUsage = usage;
19664
+ }
19665
+ const interaction = tryToDict(event.interaction);
19666
+ if (interaction) {
19667
+ latestInteraction = serializeInteractionValue(interaction);
19668
+ if (typeof interaction.status === "string") {
19669
+ status = interaction.status;
19670
+ }
19671
+ }
19672
+ if (typeof event.status === "string") {
19673
+ status = event.status;
19674
+ }
19675
+ const index = typeof event.index === "number" ? event.index : void 0;
19676
+ if (index === void 0) {
19677
+ continue;
19678
+ }
19679
+ if (event.event_type === "step.start") {
19680
+ const compact = compactInteractionStep(event.step);
19681
+ compact.index = index;
19682
+ steps.set(index, compact);
19683
+ continue;
19684
+ }
19685
+ if (event.event_type === "step.delta") {
19686
+ const step = steps.get(index) ?? { index };
19687
+ const textDelta = applyInteractionDelta(step, event.delta);
19688
+ if (textDelta) {
19689
+ outputText += textDelta;
19690
+ }
19691
+ steps.set(index, step);
19692
+ }
19693
+ }
19694
+ if (latestUsage) {
19695
+ populateInteractionUsageMetrics(metrics, latestUsage);
19696
+ }
19697
+ const output = latestInteraction ? { ...latestInteraction } : {};
19698
+ if (status) {
19699
+ output.status = status;
19700
+ }
19701
+ if (outputText) {
19702
+ output.output_text = outputText;
19703
+ }
19704
+ if (latestUsage) {
19705
+ output.usage = serializeInteractionValue(latestUsage);
19706
+ }
19707
+ const compactSteps = Array.from(steps.values()).sort(
19708
+ (left, right) => Number(left.index ?? 0) - Number(right.index ?? 0)
19709
+ );
19710
+ if (compactSteps.length > 0) {
19711
+ output.steps = compactSteps;
19712
+ }
19713
+ const metadata = {};
19714
+ if (typeof output.id === "string") {
19715
+ metadata.interaction_id = output.id;
19716
+ }
19717
+ if (typeof output.status === "string") {
19718
+ metadata.status = output.status;
19719
+ }
19720
+ return {
19721
+ output,
19722
+ metrics: cleanMetrics3(metrics),
19723
+ ...Object.keys(metadata).length > 0 ? { metadata } : {}
19724
+ };
19725
+ }
19726
+ function extractInteractionUsageFromEvent(event) {
19727
+ const metadata = tryToDict(event.metadata);
19728
+ const metadataUsage = tryToDict(metadata?.usage);
19729
+ if (metadataUsage) {
19730
+ return metadataUsage;
19731
+ }
19732
+ const metadataTotalUsage = tryToDict(metadata?.total_usage);
19733
+ if (metadataTotalUsage) {
19734
+ return metadataTotalUsage;
19735
+ }
19736
+ const interaction = tryToDict(event.interaction);
19737
+ const interactionUsage = tryToDict(interaction?.usage);
19738
+ return interactionUsage ? interactionUsage : void 0;
19739
+ }
19740
+ function compactInteractionStep(step) {
19741
+ const stepDict = tryToDict(step);
19742
+ if (!stepDict) {
19743
+ return {};
19744
+ }
19745
+ const compact = {};
19746
+ for (const key of [
19747
+ "type",
19748
+ "content",
19749
+ "name",
19750
+ "server_name",
19751
+ "arguments",
19752
+ "result",
19753
+ "is_error"
19754
+ ]) {
19755
+ if (stepDict[key] !== void 0) {
19756
+ compact[key] = serializeInteractionValue(stepDict[key]);
19757
+ }
19758
+ }
19759
+ return Object.keys(compact).length > 0 ? compact : serializeInteractionValue(stepDict);
19760
+ }
19761
+ function applyInteractionDelta(step, delta) {
19762
+ const deltaDict = tryToDict(delta);
19763
+ if (!deltaDict) {
19764
+ return void 0;
19765
+ }
19766
+ const deltaType = deltaDict.type;
19767
+ if (typeof deltaType === "string" && typeof step.type !== "string") {
19768
+ step.type = deltaType === "text" ? "model_output" : deltaType;
19769
+ }
19770
+ if (deltaType === "text" && typeof deltaDict.text === "string") {
19771
+ step.text = `${typeof step.text === "string" ? step.text : ""}${deltaDict.text}`;
19772
+ return deltaDict.text;
19773
+ }
19774
+ if (deltaType === "arguments_delta" && typeof deltaDict.arguments === "string") {
19775
+ step.arguments = `${typeof step.arguments === "string" ? step.arguments : ""}${deltaDict.arguments}`;
19776
+ return void 0;
19777
+ }
19778
+ const deltas = Array.isArray(step.deltas) ? step.deltas : [];
19779
+ deltas.push(serializeInteractionValue(deltaDict));
19780
+ step.deltas = deltas;
19781
+ return void 0;
19782
+ }
18642
19783
  function cleanMetrics3(metrics) {
18643
19784
  const cleaned = {};
18644
19785
  for (const [key, value] of Object.entries(metrics)) {
@@ -24465,7 +25606,8 @@ var FlueObserveBridge = class {
24465
25606
  metadata
24466
25607
  }
24467
25608
  });
24468
- this.runsById.set(event.runId, { metadata, span });
25609
+ const activeContext = enterCurrentFlueSpan(span);
25610
+ this.runsById.set(event.runId, { activeContext, metadata, span });
24469
25611
  }
24470
25612
  handleRunEnd(event) {
24471
25613
  const state = this.runsById.get(event.runId);
@@ -24483,6 +25625,7 @@ var FlueObserveBridge = class {
24483
25625
  });
24484
25626
  safeEnd(state.span, eventTime(event.timestamp));
24485
25627
  this.runsById.delete(event.runId);
25628
+ restoreCurrentFlueSpan(state.activeContext);
24486
25629
  }
24487
25630
  void flush().catch((error) => {
24488
25631
  logInstrumentationError3("Flue flush", error);
@@ -24609,7 +25752,8 @@ var FlueObserveBridge = class {
24609
25752
  metadata
24610
25753
  }
24611
25754
  });
24612
- this.toolsByKey.set(toolKey(event), { metadata, span });
25755
+ const activeContext = enterCurrentFlueSpan(span);
25756
+ this.toolsByKey.set(toolKey(event), { activeContext, metadata, span });
24613
25757
  }
24614
25758
  handleToolCall(event) {
24615
25759
  if (!event.toolCallId) {
@@ -24632,6 +25776,7 @@ var FlueObserveBridge = class {
24632
25776
  });
24633
25777
  safeEnd(state.span, eventTime(event.timestamp));
24634
25778
  this.toolsByKey.delete(key);
25779
+ restoreCurrentFlueSpan(state.activeContext);
24635
25780
  }
24636
25781
  handleTaskStart(event) {
24637
25782
  if (!event.taskId) {
@@ -25036,6 +26181,34 @@ function stateMatchesRun(state, runId) {
25036
26181
  function startFlueSpan(parent, args) {
25037
26182
  return parent ? withCurrent(parent, () => startSpan(args)) : startSpan(args);
25038
26183
  }
26184
+ function enterCurrentFlueSpan(span) {
26185
+ const contextManager = _internalGetGlobalState()?.contextManager;
26186
+ const store = contextManager ? Reflect.get(contextManager, BRAINTRUST_CURRENT_SPAN_STORE) : void 0;
26187
+ if (!contextManager || !isCurrentSpanStore(store)) {
26188
+ return void 0;
26189
+ }
26190
+ const previous = store.getStore();
26191
+ try {
26192
+ store.enterWith(contextManager.wrapSpanForStore(span));
26193
+ return { previous, store };
26194
+ } catch (error) {
26195
+ logInstrumentationError3("Flue context propagation", error);
26196
+ return void 0;
26197
+ }
26198
+ }
26199
+ function isCurrentSpanStore(value) {
26200
+ return isObjectLike(value) && typeof Reflect.get(value, "enterWith") === "function" && typeof Reflect.get(value, "getStore") === "function";
26201
+ }
26202
+ function restoreCurrentFlueSpan(activeContext) {
26203
+ if (!activeContext) {
26204
+ return;
26205
+ }
26206
+ try {
26207
+ activeContext.store.enterWith(activeContext.previous);
26208
+ } catch (error) {
26209
+ logInstrumentationError3("Flue context restoration", error);
26210
+ }
26211
+ }
25039
26212
  function safeLog3(span, event) {
25040
26213
  try {
25041
26214
  span.log(event);
@@ -25513,6 +26686,890 @@ function isBraintrustHandler(handler) {
25513
26686
  return Reflect.get(handler, "name") === BRAINTRUST_LANGCHAIN_CALLBACK_HANDLER_NAME;
25514
26687
  }
25515
26688
 
26689
+ // src/instrumentation/plugins/pi-coding-agent-channels.ts
26690
+ var piCodingAgentChannels = defineChannels(
26691
+ "@earendil-works/pi-coding-agent",
26692
+ {
26693
+ prompt: channel({
26694
+ channelName: "AgentSession.prompt",
26695
+ kind: "async"
26696
+ })
26697
+ }
26698
+ );
26699
+
26700
+ // src/instrumentation/plugins/pi-coding-agent-plugin.ts
26701
+ var piStreamPatchStates = /* @__PURE__ */ new WeakMap();
26702
+ var piPromptContextStore;
26703
+ var PiCodingAgentPlugin = class extends BasePlugin {
26704
+ activePromptStates = /* @__PURE__ */ new Set();
26705
+ onEnable() {
26706
+ this.subscribeToPrompt();
26707
+ }
26708
+ onDisable() {
26709
+ for (const unsubscribe of this.unsubscribers) {
26710
+ unsubscribe();
26711
+ }
26712
+ this.unsubscribers = [];
26713
+ for (const state of [...this.activePromptStates]) {
26714
+ void finalizePiPromptRun(state).catch((error) => {
26715
+ logInstrumentationError4("Pi Coding Agent disable cleanup", error);
26716
+ });
26717
+ }
26718
+ }
26719
+ subscribeToPrompt() {
26720
+ const channel2 = piCodingAgentChannels.prompt.tracingChannel();
26721
+ const states = /* @__PURE__ */ new WeakMap();
26722
+ const unbindAutoInstrumentationSuppression = bindAutoInstrumentationSuppressionToStart(channel2);
26723
+ const handlers = {
26724
+ start: (event) => {
26725
+ const state = startPiPromptRun(event, (state2) => {
26726
+ this.activePromptStates.delete(state2);
26727
+ });
26728
+ if (state) {
26729
+ this.activePromptStates.add(state);
26730
+ states.set(event, state);
26731
+ }
26732
+ },
26733
+ asyncEnd: async (event) => {
26734
+ const state = states.get(event);
26735
+ if (!state) {
26736
+ return;
26737
+ }
26738
+ states.delete(event);
26739
+ state.promptCallEnded = true;
26740
+ if (!state.finalized && state.deferCompletionUntilTurnEnd && !state.turnEnded) {
26741
+ if (!state.sawStreamFn) {
26742
+ state.queued = true;
26743
+ if (!state.streamPatchState.queuedPromptStates.includes(state)) {
26744
+ state.streamPatchState.queuedPromptStates.push(state);
26745
+ }
26746
+ }
26747
+ return;
26748
+ }
26749
+ await finalizePiPromptRun(state);
26750
+ },
26751
+ error: async (event) => {
26752
+ const state = states.get(event);
26753
+ if (!state) {
26754
+ return;
26755
+ }
26756
+ states.delete(event);
26757
+ await finalizePiPromptRun(state, event.error);
26758
+ }
26759
+ };
26760
+ channel2.subscribe(handlers);
26761
+ this.unsubscribers.push(() => {
26762
+ unbindAutoInstrumentationSuppression?.();
26763
+ channel2.unsubscribe(handlers);
26764
+ });
26765
+ }
26766
+ };
26767
+ function startPiPromptRun(event, onFinalize) {
26768
+ const session = extractSession(event);
26769
+ const agent = session?.agent;
26770
+ if (!session || !isPiAgent(agent)) {
26771
+ return void 0;
26772
+ }
26773
+ const metadata = {
26774
+ ...extractSessionMetadata(session),
26775
+ ...extractPromptOptionsMetadata(event.arguments[1]),
26776
+ "pi_coding_agent.operation": "AgentSession.prompt",
26777
+ provider: session.model?.provider ?? agent.state?.model?.provider ?? "pi",
26778
+ ...session.model?.id || agent.state?.model?.id ? { model: session.model?.id ?? agent.state?.model?.id } : {},
26779
+ ...event.moduleVersion ? { "pi_coding_agent.version": event.moduleVersion } : {}
26780
+ };
26781
+ const span = startSpan({
26782
+ event: {
26783
+ input: extractPromptInput(event.arguments[0], event.arguments[1]),
26784
+ metadata
26785
+ },
26786
+ name: "AgentSession.prompt",
26787
+ spanAttributes: { type: "task" /* TASK */ }
26788
+ });
26789
+ const streamPatchState = installPiStreamPatch(agent);
26790
+ const options = event.arguments[1];
26791
+ const promptText = event.arguments[0];
26792
+ const state = {
26793
+ activeLlmSpans: /* @__PURE__ */ new Set(),
26794
+ activeToolSpans: /* @__PURE__ */ new Map(),
26795
+ agent,
26796
+ collectedLlmUsageMetrics: false,
26797
+ deferCompletionUntilTurnEnd: options?.streamingBehavior === "followUp" || options?.streamingBehavior === "steer",
26798
+ finalized: false,
26799
+ metadata,
26800
+ metrics: {},
26801
+ onFinalize,
26802
+ promptCallEnded: false,
26803
+ ...typeof promptText === "string" ? { promptText } : {},
26804
+ queued: false,
26805
+ span,
26806
+ sawStreamFn: false,
26807
+ startTime: getCurrentUnixTimestamp(),
26808
+ streamPatchState,
26809
+ turnEnded: false
26810
+ };
26811
+ state.restorePromptContext = enterPiPromptContext(state);
26812
+ streamPatchState.activePromptStates.add(state);
26813
+ try {
26814
+ state.unsubscribeAgent = agent.subscribe(async (agentEvent) => {
26815
+ try {
26816
+ await runWithAutoInstrumentationSuppressed(
26817
+ () => handlePiAgentEvent(state, agentEvent)
26818
+ );
26819
+ } catch (error) {
26820
+ logInstrumentationError4("Pi Coding Agent event", error);
26821
+ }
26822
+ });
26823
+ } catch (error) {
26824
+ logInstrumentationError4("Pi Coding Agent event subscription", error);
26825
+ }
26826
+ return state;
26827
+ }
26828
+ function extractSession(event) {
26829
+ const candidate = event.session ?? event.self;
26830
+ return isObject(candidate) && typeof candidate.prompt === "function" ? candidate : void 0;
26831
+ }
26832
+ function isPiAgent(value) {
26833
+ return isObject(value) && typeof value.streamFn === "function" && typeof value.subscribe === "function";
26834
+ }
26835
+ function promptContextStore() {
26836
+ piPromptContextStore ??= isomorph_default.newAsyncLocalStorage();
26837
+ return piPromptContextStore;
26838
+ }
26839
+ function currentPromptContextFrames() {
26840
+ return promptContextStore().getStore()?.frames ?? [];
26841
+ }
26842
+ function currentPiPromptState() {
26843
+ const frames = currentPromptContextFrames();
26844
+ return frames[frames.length - 1]?.state;
26845
+ }
26846
+ function enterPiPromptContext(state) {
26847
+ const frame = {
26848
+ id: /* @__PURE__ */ Symbol("braintrust.pi-coding-agent.prompt"),
26849
+ state
26850
+ };
26851
+ promptContextStore().enterWith({
26852
+ frames: [...currentPromptContextFrames(), frame]
26853
+ });
26854
+ return () => {
26855
+ const frames = currentPromptContextFrames().filter(
26856
+ (candidate) => candidate.id !== frame.id
26857
+ );
26858
+ promptContextStore().enterWith(frames.length > 0 ? { frames } : void 0);
26859
+ };
26860
+ }
26861
+ function installPiStreamPatch(agent) {
26862
+ const existing = piStreamPatchStates.get(agent);
26863
+ if (existing) {
26864
+ if (agent.streamFn !== existing.wrappedStreamFn) {
26865
+ debugLogger.debug(
26866
+ "Pi Coding Agent streamFn changed while Braintrust instrumentation was active; preserving existing patch state."
26867
+ );
26868
+ }
26869
+ return existing;
26870
+ }
26871
+ const patchState = {
26872
+ activePromptStates: /* @__PURE__ */ new Set(),
26873
+ agent,
26874
+ originalStreamFn: agent.streamFn,
26875
+ queuedPromptStates: [],
26876
+ wrappedStreamFn: agent.streamFn
26877
+ };
26878
+ patchState.wrappedStreamFn = makeSharedInstrumentedStreamFn(patchState);
26879
+ agent.streamFn = patchState.wrappedStreamFn;
26880
+ piStreamPatchStates.set(agent, patchState);
26881
+ return patchState;
26882
+ }
26883
+ function resolveStreamPromptState(patchState, context) {
26884
+ let lastUserText;
26885
+ if (Array.isArray(context.messages)) {
26886
+ for (let i = context.messages.length - 1; i >= 0; i--) {
26887
+ const message = context.messages[i];
26888
+ if (isPiUserMessage(message)) {
26889
+ if (typeof message.content === "string") {
26890
+ lastUserText = message.content;
26891
+ } else {
26892
+ lastUserText = message.content.flatMap((part) => part.type === "text" ? [part.text] : []).join("");
26893
+ }
26894
+ break;
26895
+ }
26896
+ }
26897
+ }
26898
+ if (lastUserText !== void 0) {
26899
+ const queuedMatch = patchState.queuedPromptStates.find(
26900
+ (state) => state.promptText === lastUserText
26901
+ );
26902
+ if (queuedMatch) {
26903
+ return queuedMatch;
26904
+ }
26905
+ const matches = [...patchState.activePromptStates].filter(
26906
+ (state) => state.promptText === lastUserText
26907
+ );
26908
+ if (matches.length === 1) {
26909
+ return matches[0];
26910
+ }
26911
+ }
26912
+ const contextState = currentPiPromptState();
26913
+ if (contextState && patchState.activePromptStates.has(contextState) && (!contextState.queued || lastUserText !== void 0 && contextState.promptText === lastUserText)) {
26914
+ return contextState;
26915
+ }
26916
+ if (patchState.activePromptStates.size === 1) {
26917
+ return [...patchState.activePromptStates][0];
26918
+ }
26919
+ return void 0;
26920
+ }
26921
+ function makeSharedInstrumentedStreamFn(patchState) {
26922
+ return async function instrumentedPiStreamFn(model, context, options) {
26923
+ const state = resolveStreamPromptState(patchState, context);
26924
+ if (!state) {
26925
+ const invokeOriginal = () => Reflect.apply(patchState.originalStreamFn, this, [
26926
+ model,
26927
+ context,
26928
+ options
26929
+ ]);
26930
+ return patchState.activePromptStates.size > 0 ? runWithAutoInstrumentationSuppressed(invokeOriginal) : invokeOriginal();
26931
+ }
26932
+ state.sawStreamFn = true;
26933
+ removeQueuedPromptState(state);
26934
+ state.streamPatchState.eventPromptState = state;
26935
+ const llmState = await startPiLlmSpan(state, model, context, options);
26936
+ try {
26937
+ const stream = await runWithAutoInstrumentationSuppressed(
26938
+ () => Reflect.apply(patchState.originalStreamFn, this, [
26939
+ model,
26940
+ context,
26941
+ options
26942
+ ])
26943
+ );
26944
+ return patchAssistantMessageStream(stream, state, llmState);
26945
+ } catch (error) {
26946
+ finishPiLlmSpan(state, llmState, void 0, error);
26947
+ throw error;
26948
+ }
26949
+ };
26950
+ }
26951
+ async function startPiLlmSpan(state, model, context, options) {
26952
+ const metadata = {
26953
+ ...extractModelMetadata2(model),
26954
+ ...extractStreamOptionsMetadata(options),
26955
+ ...extractToolMetadata(context.tools),
26956
+ "pi_coding_agent.operation": "agent.streamFn"
26957
+ };
26958
+ const span = startSpan({
26959
+ event: {
26960
+ input: processInputAttachments(normalizePiContextInput(context)),
26961
+ metadata
26962
+ },
26963
+ name: getLlmSpanName(model),
26964
+ parent: await state.span.export(),
26965
+ spanAttributes: { type: "llm" /* LLM */ }
26966
+ });
26967
+ const llmState = {
26968
+ finalized: false,
26969
+ metadata,
26970
+ metrics: {},
26971
+ span,
26972
+ startTime: getCurrentUnixTimestamp()
26973
+ };
26974
+ state.activeLlmSpans.add(llmState);
26975
+ return llmState;
26976
+ }
26977
+ function patchAssistantMessageStream(stream, promptState, llmState) {
26978
+ if (!isObject(stream)) {
26979
+ return stream;
26980
+ }
26981
+ const streamRecord = stream;
26982
+ const originalResult = stream.result;
26983
+ if (typeof originalResult === "function") {
26984
+ streamRecord.result = function patchedPiResult() {
26985
+ return Promise.resolve(Reflect.apply(originalResult, this, [])).then(
26986
+ (message) => {
26987
+ finishPiLlmSpan(promptState, llmState, message);
26988
+ return message;
26989
+ },
26990
+ (error) => {
26991
+ finishPiLlmSpan(promptState, llmState, void 0, error);
26992
+ throw error;
26993
+ }
26994
+ );
26995
+ };
26996
+ }
26997
+ const originalIterator = stream[Symbol.asyncIterator];
26998
+ if (typeof originalIterator === "function") {
26999
+ streamRecord[Symbol.asyncIterator] = function patchedPiIterator() {
27000
+ const iterator = Reflect.apply(
27001
+ originalIterator,
27002
+ this,
27003
+ []
27004
+ );
27005
+ return {
27006
+ async next() {
27007
+ try {
27008
+ const result = await iterator.next();
27009
+ if (result.done) {
27010
+ finishPiLlmSpan(promptState, llmState);
27011
+ return result;
27012
+ }
27013
+ recordPiAssistantMessageEvent(promptState, llmState, result.value);
27014
+ return result;
27015
+ } catch (error) {
27016
+ finishPiLlmSpan(promptState, llmState, void 0, error);
27017
+ if (typeof iterator.return === "function") {
27018
+ try {
27019
+ await iterator.return();
27020
+ } catch (cleanupError) {
27021
+ logInstrumentationError4(
27022
+ "Pi Coding Agent stream cleanup",
27023
+ cleanupError
27024
+ );
27025
+ }
27026
+ }
27027
+ throw error;
27028
+ }
27029
+ },
27030
+ async return(value) {
27031
+ try {
27032
+ if (typeof iterator.return === "function") {
27033
+ return await iterator.return(value);
27034
+ }
27035
+ return {
27036
+ done: true,
27037
+ value
27038
+ };
27039
+ } catch (error) {
27040
+ finishPiLlmSpan(promptState, llmState, void 0, error);
27041
+ throw error;
27042
+ } finally {
27043
+ finishPiLlmSpan(promptState, llmState);
27044
+ }
27045
+ },
27046
+ async throw(error) {
27047
+ try {
27048
+ if (typeof iterator.throw === "function") {
27049
+ return await iterator.throw(error);
27050
+ }
27051
+ throw error;
27052
+ } catch (thrownError) {
27053
+ finishPiLlmSpan(promptState, llmState, void 0, thrownError);
27054
+ throw thrownError;
27055
+ }
27056
+ },
27057
+ [Symbol.asyncIterator]() {
27058
+ return this;
27059
+ }
27060
+ };
27061
+ };
27062
+ }
27063
+ return stream;
27064
+ }
27065
+ function recordPiAssistantMessageEvent(promptState, llmState, event) {
27066
+ recordFirstTokenMetric(llmState, event);
27067
+ const message = "message" in event ? event.message : void 0;
27068
+ const errorMessage2 = "error" in event ? event.error : void 0;
27069
+ if (event.type === "done" && isPiAssistantMessage(message)) {
27070
+ finishPiLlmSpan(promptState, llmState, message);
27071
+ } else if (event.type === "error" && isPiAssistantMessage(errorMessage2)) {
27072
+ finishPiLlmSpan(promptState, llmState, errorMessage2);
27073
+ }
27074
+ }
27075
+ function recordFirstTokenMetric(state, event) {
27076
+ if (state.metrics.time_to_first_token !== void 0 || event.type === "start") {
27077
+ return;
27078
+ }
27079
+ state.metrics.time_to_first_token = getCurrentUnixTimestamp() - state.startTime;
27080
+ }
27081
+ async function handlePiAgentEvent(state, event) {
27082
+ if (state.finalized) {
27083
+ return;
27084
+ }
27085
+ const eventPromptState = state.streamPatchState.eventPromptState;
27086
+ if (eventPromptState && eventPromptState !== state) {
27087
+ return;
27088
+ }
27089
+ if (!eventPromptState && (state.queued || state.streamPatchState.activePromptStates.size > 1 && currentPiPromptState() !== state)) {
27090
+ return;
27091
+ }
27092
+ switch (event.type) {
27093
+ case "message_end":
27094
+ if (isPiAssistantMessage(event.message)) {
27095
+ state.output = extractAssistantOutput(event.message);
27096
+ }
27097
+ return;
27098
+ case "turn_end":
27099
+ state.turnEnded = true;
27100
+ if (isPiAssistantMessage(event.message)) {
27101
+ state.output = extractAssistantOutput(event.message);
27102
+ if (!state.collectedLlmUsageMetrics) {
27103
+ addMetrics(state.metrics, extractUsageMetrics2(event.message.usage));
27104
+ }
27105
+ }
27106
+ if (state.streamPatchState.eventPromptState === state) {
27107
+ state.streamPatchState.eventPromptState = void 0;
27108
+ }
27109
+ if (state.promptCallEnded && state.deferCompletionUntilTurnEnd) {
27110
+ await finalizePiPromptRun(state);
27111
+ }
27112
+ return;
27113
+ case "tool_execution_start":
27114
+ await startPiToolSpan(state, event);
27115
+ return;
27116
+ case "tool_execution_end":
27117
+ finishPiToolSpan(state, event);
27118
+ return;
27119
+ default:
27120
+ return;
27121
+ }
27122
+ }
27123
+ async function startPiToolSpan(state, event) {
27124
+ if (!event.toolCallId || state.activeToolSpans.has(event.toolCallId)) {
27125
+ return;
27126
+ }
27127
+ const restoreAutoInstrumentation = enterAutoInstrumentationAllowed();
27128
+ const metadata = {
27129
+ "gen_ai.tool.call.id": event.toolCallId,
27130
+ "gen_ai.tool.name": event.toolName,
27131
+ "pi_coding_agent.tool.name": event.toolName
27132
+ };
27133
+ try {
27134
+ const span = startSpan({
27135
+ event: {
27136
+ input: event.args,
27137
+ metadata
27138
+ },
27139
+ name: event.toolName || "tool",
27140
+ parent: await state.span.export(),
27141
+ spanAttributes: { type: "tool" /* TOOL */ }
27142
+ });
27143
+ state.activeToolSpans.set(event.toolCallId, {
27144
+ restoreAutoInstrumentation,
27145
+ span
27146
+ });
27147
+ } catch (error) {
27148
+ restoreAutoInstrumentation();
27149
+ throw error;
27150
+ }
27151
+ }
27152
+ function finishPiToolSpan(state, event) {
27153
+ const toolState = state.activeToolSpans.get(event.toolCallId);
27154
+ if (!toolState) {
27155
+ return;
27156
+ }
27157
+ state.activeToolSpans.delete(event.toolCallId);
27158
+ const metadata = {
27159
+ "gen_ai.tool.call.id": event.toolCallId,
27160
+ "gen_ai.tool.name": event.toolName,
27161
+ "pi_coding_agent.tool.name": event.toolName,
27162
+ "pi_coding_agent.tool.is_error": event.isError
27163
+ };
27164
+ try {
27165
+ safeLog4(toolState.span, {
27166
+ ...event.isError ? { error: stringifyUnknown2(event.result) } : {},
27167
+ metadata,
27168
+ output: event.result
27169
+ });
27170
+ } finally {
27171
+ try {
27172
+ toolState.span.end();
27173
+ } finally {
27174
+ toolState.restoreAutoInstrumentation?.();
27175
+ }
27176
+ }
27177
+ }
27178
+ async function finalizePiPromptRun(state, error) {
27179
+ if (state.finalized) {
27180
+ return;
27181
+ }
27182
+ state.finalized = true;
27183
+ state.onFinalize?.(state);
27184
+ restorePiStreamFn(state);
27185
+ try {
27186
+ state.unsubscribeAgent?.();
27187
+ } catch (unsubscribeError) {
27188
+ logInstrumentationError4("Pi Coding Agent unsubscribe", unsubscribeError);
27189
+ }
27190
+ await finishOpenLlmSpans(state, error);
27191
+ finishOpenToolSpans(state, error);
27192
+ const metadata = {
27193
+ ...state.metadata,
27194
+ ...extractModelMetadata2(state.agent.state?.model)
27195
+ };
27196
+ try {
27197
+ safeLog4(state.span, {
27198
+ ...error ? { error: stringifyUnknown2(error) } : {},
27199
+ metadata,
27200
+ metrics: {
27201
+ ...cleanMetrics5(state.metrics),
27202
+ ...buildDurationMetrics3(state.startTime)
27203
+ },
27204
+ output: state.output
27205
+ });
27206
+ } finally {
27207
+ state.span.end();
27208
+ }
27209
+ }
27210
+ function restorePiStreamFn(state) {
27211
+ const patchState = state.streamPatchState;
27212
+ patchState.activePromptStates.delete(state);
27213
+ removeQueuedPromptState(state);
27214
+ if (patchState.eventPromptState === state) {
27215
+ patchState.eventPromptState = void 0;
27216
+ }
27217
+ state.restorePromptContext?.();
27218
+ if (patchState.activePromptStates.size > 0) {
27219
+ return;
27220
+ }
27221
+ if (patchState.agent.streamFn === patchState.wrappedStreamFn) {
27222
+ patchState.agent.streamFn = patchState.originalStreamFn;
27223
+ }
27224
+ piStreamPatchStates.delete(patchState.agent);
27225
+ }
27226
+ function removeQueuedPromptState(state) {
27227
+ state.queued = false;
27228
+ const queuedPromptStates = state.streamPatchState.queuedPromptStates;
27229
+ const index = queuedPromptStates.indexOf(state);
27230
+ if (index >= 0) {
27231
+ queuedPromptStates.splice(index, 1);
27232
+ }
27233
+ }
27234
+ async function finishOpenLlmSpans(state, error) {
27235
+ for (const llmState of [...state.activeLlmSpans]) {
27236
+ finishPiLlmSpan(state, llmState, void 0, error);
27237
+ }
27238
+ }
27239
+ function finishPiLlmSpan(promptState, llmState, message, error) {
27240
+ if (llmState.finalized) {
27241
+ return;
27242
+ }
27243
+ llmState.finalized = true;
27244
+ promptState.activeLlmSpans.delete(llmState);
27245
+ const messageError = message?.stopReason === "error" && message.errorMessage;
27246
+ const metrics = {
27247
+ ...extractUsageMetrics2(message?.usage),
27248
+ ...cleanMetrics5(llmState.metrics),
27249
+ ...buildDurationMetrics3(llmState.startTime)
27250
+ };
27251
+ const usageMetrics = extractUsageMetrics2(message?.usage);
27252
+ if (Object.keys(usageMetrics).length > 0) {
27253
+ promptState.collectedLlmUsageMetrics = true;
27254
+ addMetrics(promptState.metrics, usageMetrics);
27255
+ }
27256
+ try {
27257
+ safeLog4(llmState.span, {
27258
+ ...error || messageError ? { error: stringifyUnknown2(error ?? messageError) } : {},
27259
+ metadata: {
27260
+ ...llmState.metadata,
27261
+ ...message ? extractAssistantMetadata(message) : {}
27262
+ },
27263
+ metrics,
27264
+ ...message ? { output: extractAssistantOutput(message) } : {}
27265
+ });
27266
+ } finally {
27267
+ llmState.span.end();
27268
+ }
27269
+ }
27270
+ function finishOpenToolSpans(state, error) {
27271
+ for (const [, toolState] of state.activeToolSpans) {
27272
+ try {
27273
+ safeLog4(toolState.span, {
27274
+ error: error ? stringifyUnknown2(error) : "Pi tool did not complete"
27275
+ });
27276
+ toolState.span.end();
27277
+ } finally {
27278
+ toolState.restoreAutoInstrumentation?.();
27279
+ }
27280
+ }
27281
+ state.activeToolSpans.clear();
27282
+ }
27283
+ function normalizePiContextInput(context) {
27284
+ const messages = context.messages.flatMap(
27285
+ (message) => normalizePiMessage(message)
27286
+ );
27287
+ if (context.systemPrompt) {
27288
+ return [{ role: "system", content: context.systemPrompt }, ...messages];
27289
+ }
27290
+ return messages;
27291
+ }
27292
+ function normalizePiMessage(message) {
27293
+ if (isPiUserMessage(message)) {
27294
+ return [
27295
+ {
27296
+ role: "user",
27297
+ content: normalizeUserContent(message.content)
27298
+ }
27299
+ ];
27300
+ }
27301
+ if (isPiAssistantMessage(message)) {
27302
+ return [normalizeAssistantMessage(message)];
27303
+ }
27304
+ if (isPiToolResultMessage(message)) {
27305
+ return [normalizeToolResultMessage(message)];
27306
+ }
27307
+ return [];
27308
+ }
27309
+ function normalizeAssistantMessage(message) {
27310
+ const text = message.content.flatMap((part) => part.type === "text" ? [part.text] : []).join("");
27311
+ const thinking = message.content.flatMap(
27312
+ (part) => part.type === "thinking" && !part.redacted ? [part.thinking] : []
27313
+ ).join("");
27314
+ const toolCalls = message.content.flatMap(
27315
+ (part) => part.type === "toolCall" ? [normalizeToolCall(part)] : []
27316
+ );
27317
+ return {
27318
+ role: "assistant",
27319
+ content: text || (toolCalls.length > 0 ? null : ""),
27320
+ ...thinking ? { reasoning: thinking } : {},
27321
+ ...toolCalls.length > 0 ? { tool_calls: toolCalls } : {}
27322
+ };
27323
+ }
27324
+ function normalizeToolResultMessage(message) {
27325
+ return {
27326
+ role: "tool",
27327
+ tool_call_id: message.toolCallId,
27328
+ content: normalizeUserContent(message.content)
27329
+ };
27330
+ }
27331
+ function normalizeUserContent(content) {
27332
+ if (typeof content === "string") {
27333
+ return content;
27334
+ }
27335
+ return content.map((part) => {
27336
+ if (part.type === "text") {
27337
+ return { type: "text", text: part.text };
27338
+ }
27339
+ if (part.type === "image") {
27340
+ return {
27341
+ type: "image_url",
27342
+ image_url: {
27343
+ url: `data:${part.mimeType};base64,${part.data}`
27344
+ }
27345
+ };
27346
+ }
27347
+ return part;
27348
+ });
27349
+ }
27350
+ function normalizeToolCall(toolCall) {
27351
+ return {
27352
+ id: toolCall.id,
27353
+ type: "function",
27354
+ function: {
27355
+ name: toolCall.name,
27356
+ arguments: stringifyArguments(toolCall.arguments)
27357
+ }
27358
+ };
27359
+ }
27360
+ function extractAssistantOutput(message) {
27361
+ return processInputAttachments([
27362
+ {
27363
+ finish_reason: normalizeStopReason(message.stopReason),
27364
+ index: 0,
27365
+ message: normalizeAssistantMessage(message)
27366
+ }
27367
+ ]);
27368
+ }
27369
+ function isPiUserMessage(message) {
27370
+ return message.role === "user" && "content" in message;
27371
+ }
27372
+ function isPiAssistantMessage(message) {
27373
+ return isObject(message) && message.role === "assistant" && Array.isArray(message.content);
27374
+ }
27375
+ function isPiToolResultMessage(message) {
27376
+ return message.role === "toolResult" && Array.isArray(message.content);
27377
+ }
27378
+ function normalizeStopReason(reason) {
27379
+ switch (reason) {
27380
+ case "toolUse":
27381
+ return "tool_calls";
27382
+ case "length":
27383
+ case "stop":
27384
+ return reason;
27385
+ default:
27386
+ return reason ?? "stop";
27387
+ }
27388
+ }
27389
+ function extractPromptInput(text, options) {
27390
+ const images = options?.images;
27391
+ if (!images || images.length === 0) {
27392
+ return text;
27393
+ }
27394
+ return processInputAttachments([
27395
+ {
27396
+ role: "user",
27397
+ content: [
27398
+ { type: "text", text: text ?? "" },
27399
+ ...images.map((image) => ({
27400
+ type: "image_url",
27401
+ image_url: {
27402
+ url: `data:${image.mimeType};base64,${image.data}`
27403
+ }
27404
+ }))
27405
+ ]
27406
+ }
27407
+ ]);
27408
+ }
27409
+ function extractToolMetadata(tools) {
27410
+ if (!tools || tools.length === 0) {
27411
+ return {};
27412
+ }
27413
+ return {
27414
+ tools: tools.map((tool) => ({
27415
+ type: "function",
27416
+ function: {
27417
+ name: tool.name,
27418
+ ...tool.description ? { description: tool.description } : {},
27419
+ ...tool.parameters ? { parameters: tool.parameters } : {}
27420
+ }
27421
+ }))
27422
+ };
27423
+ }
27424
+ function extractModelMetadata2(model) {
27425
+ if (!model) {
27426
+ return {};
27427
+ }
27428
+ return {
27429
+ ...model.provider ? { provider: model.provider } : {},
27430
+ ...model.id ? { model: model.id, "pi_coding_agent.model": model.id } : {},
27431
+ ...model.api ? { "pi_coding_agent.api": model.api } : {},
27432
+ ...model.name ? { "pi_coding_agent.model_name": model.name } : {}
27433
+ };
27434
+ }
27435
+ function extractAssistantMetadata(message) {
27436
+ return {
27437
+ ...message.provider ? { provider: message.provider } : {},
27438
+ ...message.responseModel || message.model ? { model: message.responseModel ?? message.model } : {},
27439
+ ...message.api ? { "pi_coding_agent.api": message.api } : {},
27440
+ ...message.model ? { "pi_coding_agent.model": message.model } : {},
27441
+ ...message.responseModel ? { "pi_coding_agent.response_model": message.responseModel } : {},
27442
+ ...message.responseId ? { "pi_coding_agent.response_id": message.responseId } : {},
27443
+ ...message.stopReason ? { "pi_coding_agent.stop_reason": message.stopReason } : {}
27444
+ };
27445
+ }
27446
+ function extractSessionMetadata(session) {
27447
+ return {
27448
+ ...extractModelMetadata2(session.model),
27449
+ ...session.sessionId ? { "pi_coding_agent.session_id": session.sessionId } : {},
27450
+ ...session.sessionName ? { "pi_coding_agent.session_name": session.sessionName } : {},
27451
+ ...session.thinkingLevel ? { "pi_coding_agent.thinking_level": session.thinkingLevel } : {},
27452
+ ...typeof session.getActiveToolNames === "function" ? { "pi_coding_agent.active_tools": session.getActiveToolNames() } : {}
27453
+ };
27454
+ }
27455
+ function extractPromptOptionsMetadata(options) {
27456
+ if (!options) {
27457
+ return {};
27458
+ }
27459
+ return {
27460
+ ...options.source ? { "pi_coding_agent.source": options.source } : {},
27461
+ ...options.streamingBehavior ? { "pi_coding_agent.streaming_behavior": options.streamingBehavior } : {},
27462
+ ...options.expandPromptTemplates !== void 0 ? {
27463
+ "pi_coding_agent.expand_prompt_templates": options.expandPromptTemplates
27464
+ } : {}
27465
+ };
27466
+ }
27467
+ function extractStreamOptionsMetadata(options) {
27468
+ if (!options) {
27469
+ return {};
27470
+ }
27471
+ return {
27472
+ ...options.temperature !== void 0 ? { temperature: options.temperature } : {},
27473
+ ...options.maxTokens !== void 0 ? { max_tokens: options.maxTokens } : {},
27474
+ ...options.reasoning ? { "pi_coding_agent.reasoning": options.reasoning } : {},
27475
+ ...options.transport ? { "pi_coding_agent.transport": options.transport } : {},
27476
+ ...options.cacheRetention ? { "pi_coding_agent.cache_retention": options.cacheRetention } : {},
27477
+ ...options.sessionId ? { "pi_coding_agent.session_id": options.sessionId } : {},
27478
+ ...options.timeoutMs !== void 0 ? { "pi_coding_agent.timeout_ms": options.timeoutMs } : {},
27479
+ ...options.maxRetries !== void 0 ? { "pi_coding_agent.max_retries": options.maxRetries } : {},
27480
+ ...options.maxRetryDelayMs !== void 0 ? { "pi_coding_agent.max_retry_delay_ms": options.maxRetryDelayMs } : {},
27481
+ ...options.metadata ? { "pi_coding_agent.metadata": options.metadata } : {}
27482
+ };
27483
+ }
27484
+ function getLlmSpanName(model) {
27485
+ switch (model.api) {
27486
+ case "anthropic-messages":
27487
+ return "anthropic.messages.create";
27488
+ case "openai-completions":
27489
+ return "Chat Completion";
27490
+ case "openai-responses":
27491
+ case "azure-openai-responses":
27492
+ case "openai-codex-responses":
27493
+ return "openai.responses.create";
27494
+ case "google-generative-ai":
27495
+ case "google-vertex":
27496
+ return "generate_content";
27497
+ case "mistral-conversations":
27498
+ return "mistral.chat.stream";
27499
+ case "bedrock-converse-stream":
27500
+ return "bedrock.converse_stream";
27501
+ default:
27502
+ return "pi_ai.streamSimple";
27503
+ }
27504
+ }
27505
+ function extractUsageMetrics2(usage) {
27506
+ if (!usage) {
27507
+ return {};
27508
+ }
27509
+ return cleanMetrics5({
27510
+ completion_tokens: usage.output,
27511
+ prompt_cache_creation_tokens: usage.cacheWrite,
27512
+ prompt_cached_tokens: usage.cacheRead,
27513
+ prompt_tokens: usage.input,
27514
+ tokens: usage.totalTokens ?? usage.tokens
27515
+ });
27516
+ }
27517
+ function addMetrics(target, source) {
27518
+ for (const [key, value] of Object.entries(source)) {
27519
+ target[key] = (target[key] ?? 0) + value;
27520
+ }
27521
+ }
27522
+ function buildDurationMetrics3(startTime) {
27523
+ const end = getCurrentUnixTimestamp();
27524
+ return {
27525
+ duration: end - startTime,
27526
+ end,
27527
+ start: startTime
27528
+ };
27529
+ }
27530
+ function cleanMetrics5(metrics) {
27531
+ const cleaned = {};
27532
+ for (const [key, value] of Object.entries(metrics)) {
27533
+ if (typeof value === "number" && Number.isFinite(value) && value >= 0) {
27534
+ cleaned[key] = value;
27535
+ }
27536
+ }
27537
+ return cleaned;
27538
+ }
27539
+ function stringifyArguments(value) {
27540
+ if (typeof value === "string") {
27541
+ return value;
27542
+ }
27543
+ try {
27544
+ return JSON.stringify(value);
27545
+ } catch {
27546
+ return stringifyUnknown2(value);
27547
+ }
27548
+ }
27549
+ function stringifyUnknown2(value) {
27550
+ if (value instanceof Error) {
27551
+ return value.message;
27552
+ }
27553
+ if (typeof value === "string") {
27554
+ return value;
27555
+ }
27556
+ try {
27557
+ return JSON.stringify(value);
27558
+ } catch {
27559
+ return String(value);
27560
+ }
27561
+ }
27562
+ function safeLog4(span, event) {
27563
+ try {
27564
+ span.log(event);
27565
+ } catch (error) {
27566
+ logInstrumentationError4("Pi Coding Agent span log", error);
27567
+ }
27568
+ }
27569
+ function logInstrumentationError4(context, error) {
27570
+ debugLogger.debug(`${context}:`, error);
27571
+ }
27572
+
25516
27573
  // src/instrumentation/braintrust-plugin.ts
25517
27574
  function getIntegrationConfig(integrations, key) {
25518
27575
  return integrations[key];
@@ -25538,6 +27595,7 @@ var BraintrustPlugin = class extends BasePlugin {
25538
27595
  gitHubCopilotPlugin = null;
25539
27596
  fluePlugin = null;
25540
27597
  langChainPlugin = null;
27598
+ piCodingAgentPlugin = null;
25541
27599
  constructor(config = {}) {
25542
27600
  super();
25543
27601
  this.config = config;
@@ -25612,6 +27670,10 @@ var BraintrustPlugin = class extends BasePlugin {
25612
27670
  this.gitHubCopilotPlugin = new GitHubCopilotPlugin();
25613
27671
  this.gitHubCopilotPlugin.enable();
25614
27672
  }
27673
+ if (integrations.piCodingAgent !== false) {
27674
+ this.piCodingAgentPlugin = new PiCodingAgentPlugin();
27675
+ this.piCodingAgentPlugin.enable();
27676
+ }
25615
27677
  if (getIntegrationConfig(integrations, "flue") !== false) {
25616
27678
  this.fluePlugin = new FluePlugin();
25617
27679
  this.fluePlugin.enable();
@@ -25690,6 +27752,10 @@ var BraintrustPlugin = class extends BasePlugin {
25690
27752
  this.gitHubCopilotPlugin.disable();
25691
27753
  this.gitHubCopilotPlugin = null;
25692
27754
  }
27755
+ if (this.piCodingAgentPlugin) {
27756
+ this.piCodingAgentPlugin.disable();
27757
+ this.piCodingAgentPlugin = null;
27758
+ }
25693
27759
  if (this.fluePlugin) {
25694
27760
  this.fluePlugin.disable();
25695
27761
  this.fluePlugin = null;
@@ -25709,6 +27775,11 @@ var envIntegrationAliases = {
25709
27775
  openaicodexsdk: "openaiCodexSDK",
25710
27776
  codex: "openaiCodexSDK",
25711
27777
  "codex-sdk": "openaiCodexSDK",
27778
+ "pi-coding-agent": "piCodingAgent",
27779
+ "pi-coding-agent-sdk": "piCodingAgent",
27780
+ picodingagent: "piCodingAgent",
27781
+ picodingagentsdk: "piCodingAgent",
27782
+ "@earendil-works/pi-coding-agent": "piCodingAgent",
25712
27783
  anthropic: "anthropic",
25713
27784
  aisdk: "aisdk",
25714
27785
  "ai-sdk": "aisdk",
@@ -25774,7 +27845,8 @@ function getDefaultInstrumentationIntegrations() {
25774
27845
  genkit: true,
25775
27846
  gitHubCopilot: true,
25776
27847
  langchain: true,
25777
- langgraph: true
27848
+ langgraph: true,
27849
+ piCodingAgent: true
25778
27850
  };
25779
27851
  }
25780
27852
  function readDisabledInstrumentationEnvConfig(disabledList) {
@@ -25985,6 +28057,7 @@ __export(exports_exports, {
25985
28057
  _internalIso: () => isomorph_default,
25986
28058
  _internalSetInitialState: () => _internalSetInitialState,
25987
28059
  addAzureBlobHeaders: () => addAzureBlobHeaders,
28060
+ braintrustAISDKTelemetry: () => braintrustAISDKTelemetry,
25988
28061
  braintrustFlueObserver: () => braintrustFlueObserver,
25989
28062
  braintrustStreamChunkSchema: () => braintrustStreamChunkSchema,
25990
28063
  buildLocalSummary: () => buildLocalSummary,
@@ -26077,6 +28150,7 @@ __export(exports_exports, {
26077
28150
  wrapOpenAIv4: () => wrapOpenAIv4,
26078
28151
  wrapOpenRouter: () => wrapOpenRouter,
26079
28152
  wrapOpenRouterAgent: () => wrapOpenRouterAgent,
28153
+ wrapPiCodingAgentSDK: () => wrapPiCodingAgentSDK,
26080
28154
  wrapTraced: () => wrapTraced,
26081
28155
  wrapVitest: () => wrapVitest
26082
28156
  });
@@ -28137,6 +30211,54 @@ function wrapCursorAgent(agent) {
28137
30211
  return proxy;
28138
30212
  }
28139
30213
 
30214
+ // src/wrappers/pi-coding-agent.ts
30215
+ var WRAPPED_PROMPT = /* @__PURE__ */ Symbol.for("braintrust.pi-coding-agent.wrapped-prompt");
30216
+ function wrapPiCodingAgentSDK(sdk) {
30217
+ if (!sdk || typeof sdk !== "object") {
30218
+ return sdk;
30219
+ }
30220
+ const maybeSDK = sdk;
30221
+ if (!maybeSDK.AgentSession || typeof maybeSDK.AgentSession !== "function") {
30222
+ console.warn("Unsupported Pi Coding Agent SDK. Not wrapping.");
30223
+ return sdk;
30224
+ }
30225
+ patchAgentSessionClass(
30226
+ maybeSDK.AgentSession
30227
+ );
30228
+ return sdk;
30229
+ }
30230
+ function patchAgentSessionClass(AgentSession) {
30231
+ const prototype = AgentSession.prototype;
30232
+ if (!prototype || prototype[WRAPPED_PROMPT]) {
30233
+ return;
30234
+ }
30235
+ const descriptor = Object.getOwnPropertyDescriptor(prototype, "prompt");
30236
+ if (!descriptor || typeof descriptor.value !== "function") {
30237
+ console.warn("Unsupported Pi Coding Agent SDK. Not wrapping.");
30238
+ return;
30239
+ }
30240
+ const originalPrompt = descriptor.value;
30241
+ Object.defineProperty(prototype, "prompt", {
30242
+ ...descriptor,
30243
+ value: function wrappedPiCodingAgentPrompt(text, options) {
30244
+ const args = [text, options];
30245
+ return piCodingAgentChannels.prompt.tracePromise(
30246
+ () => Reflect.apply(originalPrompt, this, args),
30247
+ {
30248
+ arguments: args,
30249
+ self: this,
30250
+ session: this
30251
+ }
30252
+ );
30253
+ }
30254
+ });
30255
+ Object.defineProperty(prototype, WRAPPED_PROMPT, {
30256
+ configurable: false,
30257
+ enumerable: false,
30258
+ value: true
30259
+ });
30260
+ }
30261
+
28140
30262
  // src/wrappers/google-genai.ts
28141
30263
  function wrapGoogleGenAI(googleGenAI) {
28142
30264
  if (!googleGenAI || typeof googleGenAI !== "object") {
@@ -28173,12 +30295,25 @@ function wrapGoogleGenAIClass(OriginalGoogleGenAI) {
28173
30295
  }
28174
30296
  function wrapGoogleGenAIInstance(instance) {
28175
30297
  const wrappedModels = wrapModels(instance.models);
30298
+ let originalInteractions;
30299
+ let wrappedInteractions;
28176
30300
  patchGoogleGenAIChats(instance, wrappedModels);
28177
30301
  return new Proxy(instance, {
28178
30302
  get(target, prop, receiver) {
28179
30303
  if (prop === "models") {
28180
30304
  return wrappedModels;
28181
30305
  }
30306
+ if (prop === "interactions") {
30307
+ const interactions = Reflect.get(target, prop, receiver);
30308
+ if (!isObject(interactions) || typeof interactions.create !== "function") {
30309
+ return interactions;
30310
+ }
30311
+ if (interactions !== originalInteractions) {
30312
+ originalInteractions = interactions;
30313
+ wrappedInteractions = wrapInteractions(interactions);
30314
+ }
30315
+ return wrappedInteractions;
30316
+ }
28182
30317
  return Reflect.get(target, prop, receiver);
28183
30318
  }
28184
30319
  });
@@ -28205,6 +30340,16 @@ function wrapModels(models) {
28205
30340
  }
28206
30341
  });
28207
30342
  }
30343
+ function wrapInteractions(interactions) {
30344
+ return new Proxy(interactions, {
30345
+ get(target, prop, receiver) {
30346
+ if (prop === "create") {
30347
+ return wrapInteractionCreate(target.create.bind(target));
30348
+ }
30349
+ return Reflect.get(target, prop, receiver);
30350
+ }
30351
+ });
30352
+ }
28208
30353
  function wrapGenerateContent(original) {
28209
30354
  return function(params) {
28210
30355
  return googleGenAIChannels.generateContent.tracePromise(
@@ -28229,6 +30374,18 @@ function wrapEmbedContent(original) {
28229
30374
  );
28230
30375
  };
28231
30376
  }
30377
+ function wrapInteractionCreate(original) {
30378
+ return function(params, options) {
30379
+ if (params.background === true) {
30380
+ return options === void 0 ? original(params) : original(params, options);
30381
+ }
30382
+ const traceContext = options === void 0 ? { arguments: [params] } : { arguments: [params, options] };
30383
+ return googleGenAIChannels.interactionsCreate.tracePromise(
30384
+ () => options === void 0 ? original(params) : original(params, options),
30385
+ traceContext
30386
+ );
30387
+ };
30388
+ }
28232
30389
 
28233
30390
  // src/wrappers/google-adk.ts
28234
30391
  function wrapGoogleADK(adkModule) {
@@ -31746,6 +33903,13 @@ var EvalResultWithSummary = class {
31746
33903
  };
31747
33904
  }
31748
33905
  };
33906
+ async function getPersistedBaseExperimentId(experiment) {
33907
+ try {
33908
+ return await experiment._getBaseExperimentId();
33909
+ } catch {
33910
+ return void 0;
33911
+ }
33912
+ }
31749
33913
  function makeEvalName(projectName, experimentName) {
31750
33914
  let out = projectName;
31751
33915
  if (experimentName) {
@@ -32128,6 +34292,14 @@ async function runEvaluatorInternal(experiment, evaluator, progressReporter, fil
32128
34292
  return;
32129
34293
  }
32130
34294
  const eventDataset = experiment ? experiment.dataset : Dataset2.isDataset(evaluator.data) ? evaluator.data : void 0;
34295
+ const inlineOrigin = datum.origin === void 0 ? void 0 : ObjectReference.parse(datum.origin);
34296
+ const origin = inlineOrigin ?? (eventDataset && datum.id && datum._xact_id ? {
34297
+ object_type: "dataset",
34298
+ object_id: await eventDataset.id,
34299
+ id: datum.id,
34300
+ created: datum.created,
34301
+ _xact_id: datum._xact_id
34302
+ } : void 0);
32131
34303
  const baseEvent = {
32132
34304
  name: "eval",
32133
34305
  spanAttributes: {
@@ -32137,13 +34309,7 @@ async function runEvaluatorInternal(experiment, evaluator, progressReporter, fil
32137
34309
  input: datum.input,
32138
34310
  expected: "expected" in datum ? datum.expected : void 0,
32139
34311
  tags: datum.tags,
32140
- origin: eventDataset && datum.id && datum._xact_id ? {
32141
- object_type: "dataset",
32142
- object_id: await eventDataset.id,
32143
- id: datum.id,
32144
- created: datum.created,
32145
- _xact_id: datum._xact_id
32146
- } : void 0,
34312
+ origin,
32147
34313
  ...datum.upsert_id ? { id: datum.upsert_id } : {}
32148
34314
  }
32149
34315
  };
@@ -32500,8 +34666,10 @@ async function runEvaluatorInternal(experiment, evaluator, progressReporter, fil
32500
34666
  collectedResults.length = 0;
32501
34667
  }
32502
34668
  }
34669
+ const comparisonExperimentId = experiment ? evaluator.baseExperimentId ?? await getPersistedBaseExperimentId(experiment) : void 0;
32503
34670
  const summary = experiment ? await experiment.summarize({
32504
- summarizeScores: evaluator.summarizeScores
34671
+ summarizeScores: evaluator.summarizeScores,
34672
+ ...comparisonExperimentId !== void 0 ? { comparisonExperimentId } : {}
32505
34673
  }) : buildLocalSummary(
32506
34674
  evaluator,
32507
34675
  collectResults ? collectedResults : [],
@@ -32730,6 +34898,7 @@ var Project2 = class {
32730
34898
  prompts;
32731
34899
  parameters;
32732
34900
  scorers;
34901
+ classifiers;
32733
34902
  _publishableCodeFunctions = [];
32734
34903
  _publishablePrompts = [];
32735
34904
  _publishableParameters = [];
@@ -32741,6 +34910,7 @@ var Project2 = class {
32741
34910
  this.prompts = new PromptBuilder(this);
32742
34911
  this.parameters = new ParametersBuilder(this);
32743
34912
  this.scorers = new ScorerBuilder(this);
34913
+ this.classifiers = new ClassifierBuilder(this);
32744
34914
  }
32745
34915
  addPrompt(prompt) {
32746
34916
  this._publishablePrompts.push(prompt);
@@ -32875,6 +35045,28 @@ var ScorerBuilder = class {
32875
35045
  }
32876
35046
  }
32877
35047
  };
35048
+ var ClassifierBuilder = class {
35049
+ constructor(project) {
35050
+ this.project = project;
35051
+ }
35052
+ taskCounter = 0;
35053
+ create(opts) {
35054
+ this.taskCounter++;
35055
+ let resolvedName = opts.name ?? opts.handler.name;
35056
+ if (!resolvedName || resolvedName.trim().length === 0) {
35057
+ resolvedName = `Classifier ${isomorph_default.basename(currentFilename)} ${this.taskCounter}`;
35058
+ }
35059
+ const slug = opts.slug ?? slugify(resolvedName, { lower: true, strict: true });
35060
+ const classifier = new CodeFunction(this.project, {
35061
+ ...opts,
35062
+ name: resolvedName,
35063
+ slug,
35064
+ type: "classifier"
35065
+ });
35066
+ this.project.addCodeFunction(classifier);
35067
+ return classifier;
35068
+ }
35069
+ };
32878
35070
  var CodeFunction = class {
32879
35071
  constructor(project, opts) {
32880
35072
  this.project = project;
@@ -33224,7 +35416,7 @@ var serializedParametersContainerSchema = import_v313.z.union([
33224
35416
  staticParametersSchema
33225
35417
  ]);
33226
35418
  var evaluatorDefinitionSchema = import_v313.z.object({
33227
- parameters: serializedParametersContainerSchema.optional(),
35419
+ parameters: serializedParametersContainerSchema.nullish(),
33228
35420
  scores: import_v313.z.array(import_v313.z.object({ name: import_v313.z.string() })).optional(),
33229
35421
  classifiers: import_v313.z.array(import_v313.z.object({ name: import_v313.z.string() })).optional()
33230
35422
  });