braintrust 3.17.0 → 3.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/dev/dist/index.d.mts +13 -0
  2. package/dev/dist/index.d.ts +13 -0
  3. package/dev/dist/index.js +4300 -2199
  4. package/dev/dist/index.mjs +2211 -110
  5. package/dist/apply-auto-instrumentation.js +238 -186
  6. package/dist/apply-auto-instrumentation.mjs +68 -16
  7. package/dist/auto-instrumentations/bundler/esbuild.cjs +90 -15
  8. package/dist/auto-instrumentations/bundler/esbuild.mjs +2 -2
  9. package/dist/auto-instrumentations/bundler/next.cjs +90 -15
  10. package/dist/auto-instrumentations/bundler/next.mjs +3 -3
  11. package/dist/auto-instrumentations/bundler/rollup.cjs +90 -15
  12. package/dist/auto-instrumentations/bundler/rollup.mjs +2 -2
  13. package/dist/auto-instrumentations/bundler/vite.cjs +90 -15
  14. package/dist/auto-instrumentations/bundler/vite.mjs +2 -2
  15. package/dist/auto-instrumentations/bundler/webpack-loader.cjs +89 -14
  16. package/dist/auto-instrumentations/bundler/webpack.cjs +90 -15
  17. package/dist/auto-instrumentations/bundler/webpack.mjs +3 -3
  18. package/dist/auto-instrumentations/{chunk-VXJONZVX.mjs → chunk-GNUEZ2PE.mjs} +13 -3
  19. package/dist/auto-instrumentations/{chunk-CNQ7BUKN.mjs → chunk-MYCHHXOE.mjs} +1 -1
  20. package/dist/auto-instrumentations/{chunk-E5DUYJWK.mjs → chunk-ZYKZEMRT.mjs} +82 -15
  21. package/dist/auto-instrumentations/hook.mjs +102 -15
  22. package/dist/auto-instrumentations/index.cjs +84 -16
  23. package/dist/auto-instrumentations/index.d.mts +3 -1
  24. package/dist/auto-instrumentations/index.d.ts +3 -1
  25. package/dist/auto-instrumentations/index.mjs +5 -3
  26. package/dist/auto-instrumentations/loader/cjs-patch.cjs +1 -1
  27. package/dist/auto-instrumentations/loader/cjs-patch.mjs +1 -1
  28. package/dist/auto-instrumentations/loader/esm-hook.mjs +1 -1
  29. package/dist/browser.d.mts +177 -11
  30. package/dist/browser.d.ts +177 -11
  31. package/dist/browser.js +2296 -104
  32. package/dist/browser.mjs +2455 -263
  33. package/dist/{chunk-VMBQETG3.js → chunk-73IYIIOL.js} +28 -2
  34. package/dist/{chunk-O4ZIWXO3.mjs → chunk-BYFADLEZ.mjs} +27 -1
  35. package/dist/cli.js +2219 -118
  36. package/dist/edge-light.d.mts +1 -1
  37. package/dist/edge-light.d.ts +1 -1
  38. package/dist/edge-light.js +2296 -104
  39. package/dist/edge-light.mjs +2455 -263
  40. package/dist/index.d.mts +177 -11
  41. package/dist/index.d.ts +177 -11
  42. package/dist/index.js +3296 -1128
  43. package/dist/index.mjs +2272 -104
  44. package/dist/instrumentation/index.d.mts +3 -0
  45. package/dist/instrumentation/index.d.ts +3 -0
  46. package/dist/instrumentation/index.js +2171 -105
  47. package/dist/instrumentation/index.mjs +2171 -105
  48. package/dist/workerd.d.mts +1 -1
  49. package/dist/workerd.d.ts +1 -1
  50. package/dist/workerd.js +2296 -104
  51. package/dist/workerd.mjs +2455 -263
  52. package/package.json +10 -10
package/dist/index.mjs CHANGED
@@ -25,8 +25,9 @@ import {
25
25
  openRouterAgentChannels,
26
26
  openRouterChannels,
27
27
  patchTracingChannel,
28
+ piCodingAgentChannels,
28
29
  readDisabledInstrumentationEnvConfig
29
- } from "./chunk-O4ZIWXO3.mjs";
30
+ } from "./chunk-BYFADLEZ.mjs";
30
31
 
31
32
  // src/node/config.ts
32
33
  import { AsyncLocalStorage } from "node:async_hooks";
@@ -5106,14 +5107,18 @@ function useTestBackgroundLogger() {
5106
5107
  function clearTestBackgroundLogger() {
5107
5108
  _internalGetGlobalState()?.setOverrideBgLogger(null);
5108
5109
  }
5109
- function initTestExperiment(experimentName, projectName) {
5110
+ function initTestExperiment(experimentName, projectName, experimentFullInfo = {}) {
5110
5111
  setInitialTestState();
5111
5112
  const state = _internalGetGlobalState();
5112
5113
  const project = projectName ?? experimentName;
5113
5114
  const lazyMetadata = new LazyValue(
5114
5115
  async () => ({
5115
5116
  project: { id: project, name: project, fullInfo: {} },
5116
- experiment: { id: experimentName, name: experimentName, fullInfo: {} }
5117
+ experiment: {
5118
+ id: experimentName,
5119
+ name: experimentName,
5120
+ fullInfo: experimentFullInfo
5121
+ }
5117
5122
  })
5118
5123
  );
5119
5124
  return new Experiment2(state, lazyMetadata);
@@ -8478,6 +8483,10 @@ var Experiment2 = class extends ObjectFetcher {
8478
8483
  return (await this.lazyMetadata.get()).project;
8479
8484
  })();
8480
8485
  }
8486
+ async _getBaseExperimentId() {
8487
+ const baseExperimentId = (await this.lazyMetadata.get()).experiment.fullInfo["base_exp_id"];
8488
+ return typeof baseExperimentId === "string" && baseExperimentId ? baseExperimentId : void 0;
8489
+ }
8481
8490
  parentObjectType() {
8482
8491
  return 1 /* EXPERIMENT */;
8483
8492
  }
@@ -8618,6 +8627,14 @@ var Experiment2 = class extends ObjectFetcher {
8618
8627
  comparisonExperimentId = baseExperiment.id;
8619
8628
  comparisonExperimentName = baseExperiment.name;
8620
8629
  }
8630
+ } else {
8631
+ try {
8632
+ const comparisonExperiment = await state.apiConn().get_json(`v1/experiment/${comparisonExperimentId}`);
8633
+ if (typeof comparisonExperiment["name"] === "string") {
8634
+ comparisonExperimentName = comparisonExperiment["name"];
8635
+ }
8636
+ } catch {
8637
+ }
8621
8638
  }
8622
8639
  try {
8623
8640
  const results = await state.apiConn().get_json(
@@ -10659,6 +10676,64 @@ var BasePlugin = class {
10659
10676
  }
10660
10677
  };
10661
10678
 
10679
+ // src/instrumentation/auto-instrumentation-suppression.ts
10680
+ var autoInstrumentationSuppressionStore;
10681
+ function suppressionStore() {
10682
+ autoInstrumentationSuppressionStore ??= isomorph_default.newAsyncLocalStorage();
10683
+ return autoInstrumentationSuppressionStore;
10684
+ }
10685
+ function currentFrames() {
10686
+ return suppressionStore().getStore()?.frames ?? [];
10687
+ }
10688
+ function isAutoInstrumentationSuppressed() {
10689
+ const frames = currentFrames();
10690
+ return frames[frames.length - 1]?.mode === "suppress";
10691
+ }
10692
+ function runWithAutoInstrumentationSuppressed(callback) {
10693
+ const frame = {
10694
+ id: /* @__PURE__ */ Symbol("braintrust.auto-instrumentation-suppress"),
10695
+ mode: "suppress"
10696
+ };
10697
+ return suppressionStore().run(
10698
+ { frames: [...currentFrames(), frame] },
10699
+ callback
10700
+ );
10701
+ }
10702
+ function bindAutoInstrumentationSuppressionToStart(tracingChannel2) {
10703
+ const startChannel = tracingChannel2.start;
10704
+ if (!startChannel) {
10705
+ return void 0;
10706
+ }
10707
+ const store = suppressionStore();
10708
+ startChannel.bindStore(store, () => ({
10709
+ frames: [
10710
+ ...currentFrames(),
10711
+ {
10712
+ id: /* @__PURE__ */ Symbol("braintrust.auto-instrumentation-suppress"),
10713
+ mode: "suppress"
10714
+ }
10715
+ ]
10716
+ }));
10717
+ return () => {
10718
+ startChannel.unbindStore(store);
10719
+ };
10720
+ }
10721
+ function enterAutoInstrumentationAllowed() {
10722
+ const frame = {
10723
+ id: /* @__PURE__ */ Symbol("braintrust.auto-instrumentation-allow"),
10724
+ mode: "allow"
10725
+ };
10726
+ suppressionStore().enterWith({
10727
+ frames: [...currentFrames(), frame]
10728
+ });
10729
+ return () => {
10730
+ const frames = currentFrames().filter(
10731
+ (candidate) => candidate.id !== frame.id
10732
+ );
10733
+ suppressionStore().enterWith(frames.length > 0 ? { frames } : void 0);
10734
+ };
10735
+ }
10736
+
10662
10737
  // src/instrumentation/core/channel-tracing.ts
10663
10738
  function isSyncStreamLike(value) {
10664
10739
  return !!value && typeof value === "object" && typeof value.on === "function";
@@ -10690,16 +10765,33 @@ function startSpanForEvent(config, event, channelName) {
10690
10765
  metadata: mergeInputMetadata(metadata, spanInfoMetadata)
10691
10766
  });
10692
10767
  } catch (error) {
10693
- console.error(`Error extracting input for ${channelName}:`, error);
10768
+ debugLogger.error(`Error extracting input for ${channelName}:`, error);
10694
10769
  }
10695
10770
  return { span, startTime };
10696
10771
  }
10772
+ function shouldTraceEvent(config, event, channelName) {
10773
+ if (!config.shouldTrace) {
10774
+ return true;
10775
+ }
10776
+ try {
10777
+ return config.shouldTrace(event.arguments, event);
10778
+ } catch (error) {
10779
+ debugLogger.error(
10780
+ `Error checking trace predicate for ${channelName}:`,
10781
+ error
10782
+ );
10783
+ return true;
10784
+ }
10785
+ }
10697
10786
  function ensureSpanStateForEvent(states, config, event, channelName) {
10698
10787
  const key = event;
10699
10788
  const existing = states.get(key);
10700
10789
  if (existing) {
10701
10790
  return existing;
10702
10791
  }
10792
+ if (!shouldTraceEvent(config, event, channelName)) {
10793
+ return void 0;
10794
+ }
10703
10795
  const created = startSpanForEvent(config, event, channelName);
10704
10796
  states.set(key, created);
10705
10797
  return created;
@@ -10715,13 +10807,16 @@ function bindCurrentSpanStoreToStart(tracingChannel2, states, config, channelNam
10715
10807
  startChannel.bindStore(
10716
10808
  currentSpanStore,
10717
10809
  (event) => {
10718
- const span = ensureSpanStateForEvent(
10810
+ if (isAutoInstrumentationSuppressed()) {
10811
+ return currentSpanStore.getStore();
10812
+ }
10813
+ const spanState = ensureSpanStateForEvent(
10719
10814
  states,
10720
10815
  config,
10721
10816
  event,
10722
10817
  channelName
10723
- ).span;
10724
- return contextManager.wrapSpanForStore(span);
10818
+ );
10819
+ return spanState ? contextManager.wrapSpanForStore(spanState.span) : currentSpanStore.getStore();
10725
10820
  }
10726
10821
  );
10727
10822
  return () => {
@@ -10756,7 +10851,10 @@ function runStreamingCompletionHook(args) {
10756
10851
  startTime: args.startTime
10757
10852
  });
10758
10853
  } catch (error) {
10759
- console.error(`Error in onComplete hook for ${args.channelName}:`, error);
10854
+ debugLogger.error(
10855
+ `Error in onComplete hook for ${args.channelName}:`,
10856
+ error
10857
+ );
10760
10858
  }
10761
10859
  }
10762
10860
  function traceAsyncChannel(channel, config) {
@@ -10771,6 +10869,9 @@ function traceAsyncChannel(channel, config) {
10771
10869
  );
10772
10870
  const handlers = {
10773
10871
  start: (event) => {
10872
+ if (isAutoInstrumentationSuppressed()) {
10873
+ return;
10874
+ }
10774
10875
  ensureSpanStateForEvent(
10775
10876
  states,
10776
10877
  config,
@@ -10805,7 +10906,7 @@ function traceAsyncChannel(channel, config) {
10805
10906
  metrics
10806
10907
  });
10807
10908
  } catch (error) {
10808
- console.error(`Error extracting output for ${channelName}:`, error);
10909
+ debugLogger.error(`Error extracting output for ${channelName}:`, error);
10809
10910
  } finally {
10810
10911
  span.end();
10811
10912
  states.delete(event);
@@ -10833,6 +10934,9 @@ function traceStreamingChannel(channel, config) {
10833
10934
  );
10834
10935
  const handlers = {
10835
10936
  start: (event) => {
10937
+ if (isAutoInstrumentationSuppressed()) {
10938
+ return;
10939
+ }
10836
10940
  ensureSpanStateForEvent(
10837
10941
  states,
10838
10942
  config,
@@ -10904,7 +11008,7 @@ function traceStreamingChannel(channel, config) {
10904
11008
  metrics
10905
11009
  });
10906
11010
  } catch (error) {
10907
- console.error(
11011
+ debugLogger.error(
10908
11012
  `Error extracting output for ${channelName}:`,
10909
11013
  error
10910
11014
  );
@@ -10964,7 +11068,7 @@ function traceStreamingChannel(channel, config) {
10964
11068
  metrics
10965
11069
  });
10966
11070
  } catch (error) {
10967
- console.error(`Error extracting output for ${channelName}:`, error);
11071
+ debugLogger.error(`Error extracting output for ${channelName}:`, error);
10968
11072
  } finally {
10969
11073
  span.end();
10970
11074
  states.delete(event);
@@ -10992,6 +11096,9 @@ function traceSyncStreamChannel(channel, config) {
10992
11096
  );
10993
11097
  const handlers = {
10994
11098
  start: (event) => {
11099
+ if (isAutoInstrumentationSuppressed()) {
11100
+ return;
11101
+ }
10995
11102
  ensureSpanStateForEvent(
10996
11103
  states,
10997
11104
  config,
@@ -11045,7 +11152,7 @@ function traceSyncStreamChannel(channel, config) {
11045
11152
  });
11046
11153
  }
11047
11154
  } catch (error) {
11048
- console.error(
11155
+ debugLogger.error(
11049
11156
  `Error extracting chatCompletion for ${channelName}:`,
11050
11157
  error
11051
11158
  );
@@ -11069,7 +11176,10 @@ function traceSyncStreamChannel(channel, config) {
11069
11176
  span.log(extracted);
11070
11177
  }
11071
11178
  } catch (error) {
11072
- console.error(`Error extracting event for ${channelName}:`, error);
11179
+ debugLogger.error(
11180
+ `Error extracting event for ${channelName}:`,
11181
+ error
11182
+ );
11073
11183
  }
11074
11184
  });
11075
11185
  stream.on("end", () => {
@@ -12484,6 +12594,9 @@ var AnthropicPlugin = class extends BasePlugin {
12484
12594
  const states = /* @__PURE__ */ new WeakMap();
12485
12595
  const handlers = {
12486
12596
  start: (event) => {
12597
+ if (isAutoInstrumentationSuppressed()) {
12598
+ return;
12599
+ }
12487
12600
  const params = event.arguments[0] ?? {};
12488
12601
  const span = startSpan({
12489
12602
  name: "anthropic.beta.messages.toolRunner",
@@ -13213,6 +13326,520 @@ function serializeAISDKToolsForLogging(tools) {
13213
13326
  return serialized;
13214
13327
  }
13215
13328
 
13329
+ // src/wrappers/ai-sdk/telemetry.ts
13330
+ function braintrustAISDKTelemetry() {
13331
+ const operations = /* @__PURE__ */ new Map();
13332
+ const modelSpans = /* @__PURE__ */ new Map();
13333
+ const objectSpans = /* @__PURE__ */ new Map();
13334
+ const embedSpans = /* @__PURE__ */ new Map();
13335
+ const rerankSpans = /* @__PURE__ */ new Map();
13336
+ const toolSpans = /* @__PURE__ */ new Map();
13337
+ const runSafely = (name, callback) => {
13338
+ try {
13339
+ callback();
13340
+ } catch (error) {
13341
+ console.error(`Error in Braintrust AI SDK telemetry ${name}:`, error);
13342
+ }
13343
+ };
13344
+ const startChildSpan = (callId, name, type, event) => {
13345
+ const parent = operations.get(callId)?.span;
13346
+ const spanArgs = {
13347
+ name,
13348
+ spanAttributes: { type },
13349
+ ...event ? { event } : {}
13350
+ };
13351
+ const span = parent ? parent.startSpan(spanArgs) : startSpan(spanArgs);
13352
+ const state = operations.get(callId);
13353
+ if (state && type === "llm" /* LLM */) {
13354
+ state.hadModelChild = true;
13355
+ }
13356
+ return span;
13357
+ };
13358
+ return {
13359
+ onStart(event) {
13360
+ runSafely("onStart", () => {
13361
+ const operationName = operationNameFromId(event.operationId);
13362
+ const span = startSpan({
13363
+ name: operationName,
13364
+ spanAttributes: { type: "function" /* FUNCTION */ }
13365
+ });
13366
+ operations.set(event.callId, {
13367
+ hadModelChild: false,
13368
+ operationName,
13369
+ span,
13370
+ startTime: getCurrentUnixTimestamp()
13371
+ });
13372
+ const metadata = metadataFromEvent(event);
13373
+ const logPayload = { metadata };
13374
+ if (shouldRecordInputs(event)) {
13375
+ const { input, outputPromise } = processAISDKCallInput(
13376
+ operationInput(event, operationName)
13377
+ );
13378
+ logPayload.input = input;
13379
+ if (outputPromise && input && typeof input === "object") {
13380
+ outputPromise.then((resolvedData) => {
13381
+ span.log({
13382
+ input: {
13383
+ ...input,
13384
+ ...resolvedData
13385
+ }
13386
+ });
13387
+ }).catch(() => {
13388
+ });
13389
+ }
13390
+ }
13391
+ span.log(logPayload);
13392
+ });
13393
+ },
13394
+ onLanguageModelCallStart(event) {
13395
+ runSafely("onLanguageModelCallStart", () => {
13396
+ const state = operations.get(event.callId);
13397
+ const openSpans = modelSpans.get(event.callId);
13398
+ if (openSpans) {
13399
+ for (const span2 of openSpans) {
13400
+ span2.end();
13401
+ }
13402
+ modelSpans.delete(event.callId);
13403
+ }
13404
+ const span = startChildSpan(
13405
+ event.callId,
13406
+ state?.operationName === "streamText" ? "doStream" : "doGenerate",
13407
+ "llm" /* LLM */,
13408
+ {
13409
+ ...shouldRecordInputs(event) ? {
13410
+ input: processAISDKCallInput(
13411
+ operationInput(
13412
+ event,
13413
+ state?.operationName ?? "generateText"
13414
+ )
13415
+ ).input
13416
+ } : {},
13417
+ metadata: metadataFromEvent(event)
13418
+ }
13419
+ );
13420
+ const spans = modelSpans.get(event.callId) ?? [];
13421
+ spans.push(span);
13422
+ modelSpans.set(event.callId, spans);
13423
+ });
13424
+ },
13425
+ onLanguageModelCallEnd(event) {
13426
+ runSafely("onLanguageModelCallEnd", () => {
13427
+ const span = shiftModelSpan(modelSpans, event.callId);
13428
+ if (!span) {
13429
+ return;
13430
+ }
13431
+ const result = {
13432
+ ...event,
13433
+ response: event.responseId ? { id: event.responseId } : void 0
13434
+ };
13435
+ span.log({
13436
+ ...shouldRecordOutputs(event) ? {
13437
+ output: processAISDKOutput(result, DEFAULT_DENY_OUTPUT_PATHS)
13438
+ } : {},
13439
+ metrics: extractTokenMetrics(result)
13440
+ });
13441
+ span.end();
13442
+ });
13443
+ },
13444
+ onObjectStepStart(event) {
13445
+ runSafely("onObjectStepStart", () => {
13446
+ const state = operations.get(event.callId);
13447
+ const openSpan = objectSpans.get(event.callId);
13448
+ if (openSpan) {
13449
+ openSpan.end();
13450
+ objectSpans.delete(event.callId);
13451
+ }
13452
+ const span = startChildSpan(
13453
+ event.callId,
13454
+ state?.operationName === "streamObject" ? "doStream" : "doGenerate",
13455
+ "llm" /* LLM */,
13456
+ {
13457
+ ...shouldRecordInputs(event) ? {
13458
+ input: {
13459
+ prompt: event.promptMessages
13460
+ }
13461
+ } : {},
13462
+ metadata: metadataFromEvent(event)
13463
+ }
13464
+ );
13465
+ objectSpans.set(event.callId, span);
13466
+ });
13467
+ },
13468
+ onObjectStepFinish(event) {
13469
+ runSafely("onObjectStepFinish", () => {
13470
+ const span = objectSpans.get(event.callId);
13471
+ if (!span) {
13472
+ return;
13473
+ }
13474
+ const result = {
13475
+ ...event,
13476
+ text: event.objectText
13477
+ };
13478
+ span.log({
13479
+ ...shouldRecordOutputs(event) ? {
13480
+ output: processAISDKOutput(result, DEFAULT_DENY_OUTPUT_PATHS)
13481
+ } : {},
13482
+ metrics: extractTokenMetrics(result)
13483
+ });
13484
+ span.end();
13485
+ objectSpans.delete(event.callId);
13486
+ });
13487
+ },
13488
+ onEmbedStart(event) {
13489
+ runSafely("onEmbedStart", () => {
13490
+ const state = operations.get(event.callId);
13491
+ for (const [embedCallId, embedState] of embedSpans) {
13492
+ if (embedState.callId === event.callId && (state?.operationName === "embed" || embedState.values === event.values)) {
13493
+ embedState.span.end();
13494
+ embedSpans.delete(embedCallId);
13495
+ }
13496
+ }
13497
+ const span = startChildSpan(
13498
+ event.callId,
13499
+ "doEmbed",
13500
+ "llm" /* LLM */,
13501
+ {
13502
+ ...shouldRecordInputs(event) ? {
13503
+ input: {
13504
+ values: event.values
13505
+ }
13506
+ } : {},
13507
+ metadata: metadataFromEvent(event)
13508
+ }
13509
+ );
13510
+ embedSpans.set(event.embedCallId, {
13511
+ callId: event.callId,
13512
+ span,
13513
+ values: event.values
13514
+ });
13515
+ });
13516
+ },
13517
+ onEmbedFinish(event) {
13518
+ runSafely("onEmbedFinish", () => {
13519
+ const state = embedSpans.get(event.embedCallId);
13520
+ if (!state) {
13521
+ return;
13522
+ }
13523
+ const result = {
13524
+ ...event,
13525
+ embeddings: event.embeddings
13526
+ };
13527
+ state.span.log({
13528
+ ...shouldRecordOutputs(event) ? {
13529
+ output: processAISDKEmbeddingOutput(
13530
+ result,
13531
+ DEFAULT_DENY_OUTPUT_PATHS
13532
+ )
13533
+ } : {},
13534
+ metrics: extractTokenMetrics(result)
13535
+ });
13536
+ state.span.end();
13537
+ embedSpans.delete(event.embedCallId);
13538
+ });
13539
+ },
13540
+ onRerankStart(event) {
13541
+ runSafely("onRerankStart", () => {
13542
+ const openSpan = rerankSpans.get(event.callId);
13543
+ if (openSpan) {
13544
+ openSpan.end();
13545
+ rerankSpans.delete(event.callId);
13546
+ }
13547
+ const span = startChildSpan(
13548
+ event.callId,
13549
+ "doRerank",
13550
+ "llm" /* LLM */,
13551
+ {
13552
+ ...shouldRecordInputs(event) ? {
13553
+ input: {
13554
+ documents: event.documents,
13555
+ query: event.query,
13556
+ topN: event.topN
13557
+ }
13558
+ } : {},
13559
+ metadata: metadataFromEvent(event)
13560
+ }
13561
+ );
13562
+ rerankSpans.set(event.callId, span);
13563
+ });
13564
+ },
13565
+ onRerankFinish(event) {
13566
+ runSafely("onRerankFinish", () => {
13567
+ const span = rerankSpans.get(event.callId);
13568
+ if (!span) {
13569
+ return;
13570
+ }
13571
+ const result = {
13572
+ ranking: event.ranking?.map((entry) => ({
13573
+ originalIndex: entry.index,
13574
+ score: entry.relevanceScore
13575
+ }))
13576
+ };
13577
+ span.log({
13578
+ ...shouldRecordOutputs(event) ? {
13579
+ output: processAISDKRerankOutput(
13580
+ result,
13581
+ DEFAULT_DENY_OUTPUT_PATHS
13582
+ )
13583
+ } : {}
13584
+ });
13585
+ span.end();
13586
+ rerankSpans.delete(event.callId);
13587
+ });
13588
+ },
13589
+ onToolExecutionStart(event) {
13590
+ runSafely("onToolExecutionStart", () => {
13591
+ const toolCallId = event.toolCall.toolCallId;
13592
+ if (!toolCallId) {
13593
+ return;
13594
+ }
13595
+ const span = startChildSpan(
13596
+ event.callId,
13597
+ event.toolCall.toolName || "tool",
13598
+ "tool" /* TOOL */,
13599
+ {
13600
+ ...shouldRecordInputs(event) ? {
13601
+ input: event.toolCall.input
13602
+ } : {},
13603
+ metadata: {
13604
+ ...createAISDKIntegrationMetadata(),
13605
+ toolCallId,
13606
+ ...typeof event.toolCall.toolName === "string" ? { toolName: event.toolCall.toolName } : {}
13607
+ }
13608
+ }
13609
+ );
13610
+ toolSpans.set(toolCallId, { callId: event.callId, span });
13611
+ });
13612
+ },
13613
+ onToolExecutionEnd(event) {
13614
+ runSafely("onToolExecutionEnd", () => {
13615
+ const toolCallId = event.toolCall.toolCallId;
13616
+ const state = toolCallId ? toolSpans.get(toolCallId) : void 0;
13617
+ if (!toolCallId || !state) {
13618
+ return;
13619
+ }
13620
+ const toolOutput = event.toolOutput;
13621
+ if (toolOutput?.type === "tool-error") {
13622
+ state.span.log({
13623
+ error: toolOutput.error instanceof Error ? toolOutput.error.message : String(toolOutput?.error),
13624
+ metrics: typeof event.durationMs === "number" ? { duration_ms: event.durationMs } : {}
13625
+ });
13626
+ } else {
13627
+ state.span.log({
13628
+ ...shouldRecordOutputs(event) ? { output: toolOutput?.output } : {},
13629
+ metrics: typeof event.durationMs === "number" ? { duration_ms: event.durationMs } : {}
13630
+ });
13631
+ }
13632
+ state.span.end();
13633
+ toolSpans.delete(toolCallId);
13634
+ });
13635
+ },
13636
+ onChunk(event) {
13637
+ runSafely("onChunk", () => {
13638
+ const callId = event.chunk?.callId;
13639
+ if (!callId) {
13640
+ return;
13641
+ }
13642
+ const state = operations.get(callId);
13643
+ if (!state || state.firstChunkTime !== void 0) {
13644
+ return;
13645
+ }
13646
+ state.firstChunkTime = getCurrentUnixTimestamp();
13647
+ });
13648
+ },
13649
+ onFinish(event) {
13650
+ runSafely("onFinish", () => {
13651
+ const state = operations.get(event.callId);
13652
+ if (!state) {
13653
+ return;
13654
+ }
13655
+ const result = finishResult(event, state.operationName);
13656
+ const metrics = state.hadModelChild ? {} : extractTokenMetrics(result);
13657
+ if (state.firstChunkTime !== void 0) {
13658
+ metrics.time_to_first_token = state.firstChunkTime - state.startTime;
13659
+ }
13660
+ state.span.log({
13661
+ ...shouldRecordOutputs(event) ? {
13662
+ output: finishOutput(result, state.operationName)
13663
+ } : {},
13664
+ metrics
13665
+ });
13666
+ state.span.end();
13667
+ operations.delete(event.callId);
13668
+ });
13669
+ },
13670
+ onError(event) {
13671
+ runSafely("onError", () => {
13672
+ const errorEvent = isObject(event) ? event : {};
13673
+ const callId = typeof errorEvent.callId === "string" ? errorEvent.callId : void 0;
13674
+ if (!callId) {
13675
+ return;
13676
+ }
13677
+ const state = operations.get(callId);
13678
+ if (!state) {
13679
+ return;
13680
+ }
13681
+ const error = errorEvent.error ?? event;
13682
+ const openModelSpans = modelSpans.get(callId);
13683
+ if (openModelSpans) {
13684
+ for (const span of openModelSpans) {
13685
+ logError(span, error);
13686
+ span.end();
13687
+ }
13688
+ modelSpans.delete(callId);
13689
+ }
13690
+ const openObjectSpan = objectSpans.get(callId);
13691
+ if (openObjectSpan) {
13692
+ logError(openObjectSpan, error);
13693
+ openObjectSpan.end();
13694
+ objectSpans.delete(callId);
13695
+ }
13696
+ for (const [embedCallId, embedState] of embedSpans) {
13697
+ if (embedState.callId === callId) {
13698
+ logError(embedState.span, error);
13699
+ embedState.span.end();
13700
+ embedSpans.delete(embedCallId);
13701
+ }
13702
+ }
13703
+ const openRerankSpan = rerankSpans.get(callId);
13704
+ if (openRerankSpan) {
13705
+ logError(openRerankSpan, error);
13706
+ openRerankSpan.end();
13707
+ rerankSpans.delete(callId);
13708
+ }
13709
+ for (const [toolCallId, toolState] of toolSpans) {
13710
+ if (toolState.callId === callId) {
13711
+ logError(toolState.span, error);
13712
+ toolState.span.end();
13713
+ toolSpans.delete(toolCallId);
13714
+ }
13715
+ }
13716
+ logError(state.span, error);
13717
+ state.span.end();
13718
+ operations.delete(callId);
13719
+ });
13720
+ },
13721
+ executeTool({ toolCallId, execute }) {
13722
+ const state = toolSpans.get(toolCallId);
13723
+ return state ? withCurrent(state.span, () => execute()) : execute();
13724
+ }
13725
+ };
13726
+ }
13727
+ function shouldRecordInputs(event) {
13728
+ return event.recordInputs !== false;
13729
+ }
13730
+ function shouldRecordOutputs(event) {
13731
+ return event.recordOutputs !== false;
13732
+ }
13733
+ function operationNameFromId(operationId) {
13734
+ return operationId?.startsWith("ai.") ? operationId.slice("ai.".length) : operationId || "ai-sdk";
13735
+ }
13736
+ function modelFromEvent(event) {
13737
+ return event.modelId ? {
13738
+ modelId: event.modelId,
13739
+ ...event.provider ? { provider: event.provider } : {}
13740
+ } : void 0;
13741
+ }
13742
+ function metadataFromEvent(event) {
13743
+ const metadata = createAISDKIntegrationMetadata();
13744
+ const { model, provider } = serializeModelWithProvider(modelFromEvent(event));
13745
+ if (model) {
13746
+ metadata.model = model;
13747
+ }
13748
+ if (provider) {
13749
+ metadata.provider = provider;
13750
+ }
13751
+ if (typeof event.functionId === "string") {
13752
+ metadata.functionId = event.functionId;
13753
+ }
13754
+ return metadata;
13755
+ }
13756
+ function operationInput(event, operationName) {
13757
+ if (operationName === "embed") {
13758
+ return {
13759
+ model: modelFromEvent(event),
13760
+ value: event.value
13761
+ };
13762
+ }
13763
+ if (operationName === "embedMany") {
13764
+ return {
13765
+ model: modelFromEvent(event),
13766
+ values: Array.isArray(event.value) ? event.value ?? [] : void 0
13767
+ };
13768
+ }
13769
+ if (operationName === "rerank") {
13770
+ return {
13771
+ model: modelFromEvent(event),
13772
+ documents: event.documents,
13773
+ query: event.query,
13774
+ topN: event.topN
13775
+ };
13776
+ }
13777
+ return {
13778
+ model: modelFromEvent(event),
13779
+ system: event.system,
13780
+ prompt: event.prompt,
13781
+ messages: event.messages,
13782
+ tools: event.tools,
13783
+ toolChoice: event.toolChoice,
13784
+ activeTools: event.activeTools,
13785
+ output: event.output,
13786
+ schema: event.schema,
13787
+ schemaName: event.schemaName,
13788
+ schemaDescription: event.schemaDescription,
13789
+ maxOutputTokens: event.maxOutputTokens,
13790
+ temperature: event.temperature,
13791
+ topP: event.topP,
13792
+ topK: event.topK,
13793
+ presencePenalty: event.presencePenalty,
13794
+ frequencyPenalty: event.frequencyPenalty,
13795
+ seed: event.seed,
13796
+ maxRetries: event.maxRetries,
13797
+ headers: event.headers,
13798
+ providerOptions: event.providerOptions
13799
+ };
13800
+ }
13801
+ function shiftModelSpan(modelSpans, callId) {
13802
+ const spans = modelSpans.get(callId);
13803
+ const span = spans?.shift();
13804
+ if (spans && spans.length === 0) {
13805
+ modelSpans.delete(callId);
13806
+ }
13807
+ return span;
13808
+ }
13809
+ function finishResult(event, operationName) {
13810
+ if (operationName === "embed") {
13811
+ return {
13812
+ ...event,
13813
+ embedding: event.embedding
13814
+ };
13815
+ }
13816
+ if (operationName === "embedMany") {
13817
+ return {
13818
+ ...event,
13819
+ embeddings: event.embedding
13820
+ };
13821
+ }
13822
+ if (operationName === "rerank") {
13823
+ return event;
13824
+ }
13825
+ return event;
13826
+ }
13827
+ function finishOutput(result, operationName) {
13828
+ if (operationName === "embed" || operationName === "embedMany") {
13829
+ return processAISDKEmbeddingOutput(
13830
+ result,
13831
+ DEFAULT_DENY_OUTPUT_PATHS
13832
+ );
13833
+ }
13834
+ if (operationName === "rerank") {
13835
+ return processAISDKRerankOutput(
13836
+ result,
13837
+ DEFAULT_DENY_OUTPUT_PATHS
13838
+ );
13839
+ }
13840
+ return processAISDKOutput(result, DEFAULT_DENY_OUTPUT_PATHS);
13841
+ }
13842
+
13216
13843
  // src/instrumentation/plugins/ai-sdk-plugin.ts
13217
13844
  var DEFAULT_DENY_OUTPUT_PATHS = [
13218
13845
  // v3
@@ -13230,9 +13857,30 @@ var DEFAULT_DENY_OUTPUT_PATHS = [
13230
13857
  ];
13231
13858
  var AUTO_PATCHED_MODEL = /* @__PURE__ */ Symbol.for("braintrust.ai-sdk.auto-patched-model");
13232
13859
  var AUTO_PATCHED_TOOL = /* @__PURE__ */ Symbol.for("braintrust.ai-sdk.auto-patched-tool");
13860
+ var AUTO_PATCHED_V7_TELEMETRY_DISPATCHER = /* @__PURE__ */ Symbol.for(
13861
+ "braintrust.ai-sdk.v7.auto-patched-telemetry-dispatcher"
13862
+ );
13233
13863
  var RUNTIME_DENY_OUTPUT_PATHS = /* @__PURE__ */ Symbol.for(
13234
13864
  "braintrust.ai-sdk.deny-output-paths"
13235
13865
  );
13866
+ var AI_SDK_V7_TELEMETRY_CALLBACKS = [
13867
+ "onStart",
13868
+ "onStepStart",
13869
+ "onLanguageModelCallStart",
13870
+ "onLanguageModelCallEnd",
13871
+ "onToolExecutionStart",
13872
+ "onToolExecutionEnd",
13873
+ "onChunk",
13874
+ "onStepFinish",
13875
+ "onObjectStepStart",
13876
+ "onObjectStepFinish",
13877
+ "onEmbedStart",
13878
+ "onEmbedFinish",
13879
+ "onRerankStart",
13880
+ "onRerankFinish",
13881
+ "onFinish",
13882
+ "onError"
13883
+ ];
13236
13884
  var AISDKPlugin = class extends BasePlugin {
13237
13885
  config;
13238
13886
  constructor(config = {}) {
@@ -13247,6 +13895,7 @@ var AISDKPlugin = class extends BasePlugin {
13247
13895
  }
13248
13896
  subscribeToAISDK() {
13249
13897
  const denyOutputPaths = this.config.denyOutputPaths || DEFAULT_DENY_OUTPUT_PATHS;
13898
+ this.unsubscribers.push(subscribeToAISDKV7TelemetryDispatcher());
13250
13899
  this.unsubscribers.push(
13251
13900
  traceStreamingChannel(aiSDKChannels.generateText, {
13252
13901
  name: "generateText",
@@ -13471,6 +14120,57 @@ var AISDKPlugin = class extends BasePlugin {
13471
14120
  );
13472
14121
  }
13473
14122
  };
14123
+ function subscribeToAISDKV7TelemetryDispatcher() {
14124
+ const channel = aiSDKChannels.v7CreateTelemetryDispatcher.tracingChannel();
14125
+ const telemetry = braintrustAISDKTelemetry();
14126
+ const handlers = {
14127
+ end: (event) => {
14128
+ const telemetryOptions = event.arguments?.[0]?.telemetry;
14129
+ if (telemetryOptions?.isEnabled === false) {
14130
+ return;
14131
+ }
14132
+ patchAISDKV7TelemetryDispatcher(event.result, telemetry);
14133
+ }
14134
+ };
14135
+ channel.subscribe(handlers);
14136
+ return () => {
14137
+ channel.unsubscribe(handlers);
14138
+ };
14139
+ }
14140
+ function patchAISDKV7TelemetryDispatcher(dispatcher, telemetry) {
14141
+ if (!isObject(dispatcher)) {
14142
+ return;
14143
+ }
14144
+ const dispatcherRecord = dispatcher;
14145
+ if (dispatcherRecord[AUTO_PATCHED_V7_TELEMETRY_DISPATCHER]) {
14146
+ return;
14147
+ }
14148
+ dispatcherRecord[AUTO_PATCHED_V7_TELEMETRY_DISPATCHER] = true;
14149
+ for (const key of AI_SDK_V7_TELEMETRY_CALLBACKS) {
14150
+ const braintrustCallback = telemetry[key];
14151
+ if (typeof braintrustCallback !== "function") {
14152
+ continue;
14153
+ }
14154
+ const existingCallback = dispatcherRecord[key];
14155
+ dispatcherRecord[key] = (event) => {
14156
+ const existingResult = typeof existingCallback === "function" ? existingCallback.call(dispatcher, event) : void 0;
14157
+ const braintrustResult = braintrustCallback.call(telemetry, event);
14158
+ const pending = [existingResult, braintrustResult].filter(isPromiseLike);
14159
+ if (pending.length > 0) {
14160
+ return Promise.allSettled(pending).then(() => void 0);
14161
+ }
14162
+ };
14163
+ }
14164
+ const braintrustExecuteTool = telemetry.executeTool;
14165
+ if (typeof braintrustExecuteTool !== "function") {
14166
+ return;
14167
+ }
14168
+ const existingExecuteTool = dispatcherRecord.executeTool;
14169
+ dispatcherRecord.executeTool = (args) => braintrustExecuteTool.call(telemetry, {
14170
+ ...args,
14171
+ execute: () => typeof existingExecuteTool === "function" ? existingExecuteTool.call(dispatcher, args) : args.execute()
14172
+ });
14173
+ }
13474
14174
  function resolveDenyOutputPaths(event, defaultDenyOutputPaths) {
13475
14175
  if (Array.isArray(event?.denyOutputPaths)) {
13476
14176
  return event.denyOutputPaths;
@@ -13922,11 +14622,11 @@ function prepareAISDKChildTracing(params, self, parentSpan, denyOutputPaths, aiS
13922
14622
  metadata: baseMetadata
13923
14623
  }
13924
14624
  });
14625
+ const streamStartTime = getCurrentUnixTimestamp();
13925
14626
  const result = await withCurrent(
13926
14627
  span,
13927
14628
  () => Reflect.apply(originalDoStream, resolvedModel, [options])
13928
14629
  );
13929
- const streamStartTime = getCurrentUnixTimestamp();
13930
14630
  let firstChunkTime;
13931
14631
  const output = {};
13932
14632
  let text = "";
@@ -13935,7 +14635,7 @@ function prepareAISDKChildTracing(params, self, parentSpan, denyOutputPaths, aiS
13935
14635
  let object = void 0;
13936
14636
  const transformStream = new TransformStream({
13937
14637
  transform(chunk, controller) {
13938
- if (firstChunkTime === void 0) {
14638
+ if (firstChunkTime === void 0 && isAISDKContentStreamChunk(chunk)) {
13939
14639
  firstChunkTime = getCurrentUnixTimestamp();
13940
14640
  }
13941
14641
  switch (chunk.type) {
@@ -14127,6 +14827,78 @@ function finalizeAISDKChildTracing(event) {
14127
14827
  delete event.__braintrust_ai_sdk_cleanup;
14128
14828
  }
14129
14829
  }
14830
+ function extractAISDKStreamPart(chunk) {
14831
+ if (!isObject(chunk) || !isObject(chunk.part)) {
14832
+ return chunk;
14833
+ }
14834
+ return chunk.part;
14835
+ }
14836
+ function stringContent(value) {
14837
+ return typeof value === "string" && value.length > 0 ? value : void 0;
14838
+ }
14839
+ function rawValueHasAISDKContent(value) {
14840
+ if (value === void 0 || value === null) {
14841
+ return false;
14842
+ }
14843
+ if (typeof value === "string") {
14844
+ return value.length > 0;
14845
+ }
14846
+ if (!isObject(value)) {
14847
+ return true;
14848
+ }
14849
+ const delta = value.delta;
14850
+ 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) => {
14851
+ if (!isObject(choice) || !isObject(choice.delta)) {
14852
+ return false;
14853
+ }
14854
+ const choiceDelta = choice.delta;
14855
+ if (stringContent(choiceDelta.content) || stringContent(choiceDelta.text)) {
14856
+ return true;
14857
+ }
14858
+ if (isObject(choiceDelta.function_call) && stringContent(choiceDelta.function_call.arguments)) {
14859
+ return true;
14860
+ }
14861
+ return Array.isArray(choiceDelta.tool_calls) && choiceDelta.tool_calls.some(
14862
+ (toolCall) => isObject(toolCall) && isObject(toolCall.function) && stringContent(toolCall.function.arguments)
14863
+ );
14864
+ })) {
14865
+ return true;
14866
+ }
14867
+ return false;
14868
+ }
14869
+ function isAISDKContentStreamChunk(chunk) {
14870
+ const part = extractAISDKStreamPart(chunk);
14871
+ if (typeof part === "string") {
14872
+ return part.length > 0;
14873
+ }
14874
+ if (!isObject(part) || typeof part.type !== "string") {
14875
+ return false;
14876
+ }
14877
+ switch (part.type) {
14878
+ case "text-delta":
14879
+ return stringContent(part.textDelta) !== void 0 || stringContent(part.delta) !== void 0 || stringContent(part.text) !== void 0 || stringContent(part.content) !== void 0;
14880
+ case "reasoning-delta":
14881
+ return stringContent(part.delta) !== void 0 || stringContent(part.text) !== void 0 || stringContent(part.content) !== void 0;
14882
+ case "tool-call":
14883
+ case "object":
14884
+ case "file":
14885
+ return true;
14886
+ case "tool-input-delta":
14887
+ case "tool-call-delta":
14888
+ 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;
14889
+ case "raw":
14890
+ return rawValueHasAISDKContent(part.rawValue);
14891
+ default:
14892
+ return false;
14893
+ }
14894
+ }
14895
+ function isAISDKContentAsyncIterableChunk(chunk) {
14896
+ if (isAISDKContentStreamChunk(chunk)) {
14897
+ return true;
14898
+ }
14899
+ const part = extractAISDKStreamPart(chunk);
14900
+ return isObject(part) && typeof part.type !== "string";
14901
+ }
14130
14902
  function patchAISDKStreamingResult(args) {
14131
14903
  const { defaultDenyOutputPaths, endEvent, result, span, startTime } = args;
14132
14904
  if (!result || typeof result !== "object") {
@@ -14139,7 +14911,7 @@ function patchAISDKStreamingResult(args) {
14139
14911
  const wrappedBaseStream = resultRecord.baseStream.pipeThrough(
14140
14912
  new TransformStream({
14141
14913
  transform(chunk, controller) {
14142
- if (firstChunkTime2 === void 0) {
14914
+ if (firstChunkTime2 === void 0 && isAISDKContentStreamChunk(chunk)) {
14143
14915
  firstChunkTime2 = getCurrentUnixTimestamp();
14144
14916
  }
14145
14917
  controller.enqueue(chunk);
@@ -14183,8 +14955,8 @@ function patchAISDKStreamingResult(args) {
14183
14955
  }
14184
14956
  let firstChunkTime;
14185
14957
  const wrappedStream = createPatchedAsyncIterable(streamField.stream, {
14186
- onChunk: () => {
14187
- if (firstChunkTime === void 0) {
14958
+ onChunk: (chunk) => {
14959
+ if (firstChunkTime === void 0 && isAISDKContentAsyncIterableChunk(chunk)) {
14188
14960
  firstChunkTime = getCurrentUnixTimestamp();
14189
14961
  }
14190
14962
  },
@@ -15145,15 +15917,17 @@ function collectLocalMcpServerToolHookNames(serverName, serverConfig) {
15145
15917
 
15146
15918
  // src/instrumentation/plugins/claude-agent-sdk-plugin.ts
15147
15919
  var ROOT_LLM_PARENT_KEY = "__root__";
15920
+ var SUB_AGENT_PROMPT_SOURCE_PRIORITY = {
15921
+ delegation: 0,
15922
+ lifecycle: 1,
15923
+ sidechain: 2
15924
+ };
15148
15925
  function llmParentKey(parentToolUseId) {
15149
15926
  return parentToolUseId ?? ROOT_LLM_PARENT_KEY;
15150
15927
  }
15151
15928
  function isSubAgentDelegationToolName(toolName) {
15152
15929
  return toolName === "Agent" || toolName === "Task";
15153
15930
  }
15154
- function shouldParentToolAsTaskSibling(toolName) {
15155
- return toolName === "Agent" || toolName === "Task" || toolName === "Bash";
15156
- }
15157
15931
  function filterSerializableOptions(options) {
15158
15932
  const allowedKeys = [
15159
15933
  "model",
@@ -15290,26 +16064,39 @@ function extractUsageFromMessage(message) {
15290
16064
  }
15291
16065
  return metrics;
15292
16066
  }
15293
- function buildLLMInput(prompt, conversationHistory, capturedPromptMessages) {
15294
- const promptMessages = [];
15295
- if (typeof prompt === "string") {
15296
- promptMessages.push({ content: prompt, role: "user" });
15297
- } else if (capturedPromptMessages && capturedPromptMessages.length > 0) {
15298
- for (const msg of capturedPromptMessages) {
15299
- const role = msg.message?.role;
15300
- const content = msg.message?.content;
15301
- if (role && content !== void 0) {
15302
- promptMessages.push({ content, role });
15303
- }
15304
- }
15305
- }
16067
+ function buildLLMInput(promptMessages, conversationHistory) {
15306
16068
  const inputParts = [...promptMessages, ...conversationHistory];
15307
16069
  return inputParts.length > 0 ? inputParts : void 0;
15308
16070
  }
16071
+ function conversationMessageFromSDKMessage(message) {
16072
+ const role = message.message?.role;
16073
+ const content = message.message?.content;
16074
+ if (role && content !== void 0) {
16075
+ return { content, role };
16076
+ }
16077
+ return void 0;
16078
+ }
16079
+ function messageContentHasBlockType(message, blockType) {
16080
+ const content = message.message?.content;
16081
+ return Array.isArray(content) && content.some(
16082
+ (block) => typeof block === "object" && block !== null && "type" in block && block.type === blockType
16083
+ );
16084
+ }
16085
+ function buildRootPromptMessages(prompt, capturedPromptMessages) {
16086
+ if (typeof prompt === "string") {
16087
+ return [{ content: prompt, role: "user" }];
16088
+ }
16089
+ if (!capturedPromptMessages || capturedPromptMessages.length === 0) {
16090
+ return [];
16091
+ }
16092
+ return capturedPromptMessages.map(conversationMessageFromSDKMessage).filter(
16093
+ (message) => message !== void 0
16094
+ );
16095
+ }
15309
16096
  function formatCapturedMessages(messages) {
15310
16097
  return messages.length > 0 ? messages : [];
15311
16098
  }
15312
- async function createLLMSpanForMessages(messages, prompt, conversationHistory, options, startTime, capturedPromptMessages, parentSpan, existingSpan) {
16099
+ async function createLLMSpanForMessages(messages, promptMessages, conversationHistory, options, startTime, parentSpan, existingSpan) {
15313
16100
  if (messages.length === 0) {
15314
16101
  return void 0;
15315
16102
  }
@@ -15319,11 +16106,7 @@ async function createLLMSpanForMessages(messages, prompt, conversationHistory, o
15319
16106
  }
15320
16107
  const model = lastMessage.message.model || options.model;
15321
16108
  const usage = extractUsageFromMessage(lastMessage);
15322
- const input = buildLLMInput(
15323
- prompt,
15324
- conversationHistory,
15325
- capturedPromptMessages
15326
- );
16109
+ const input = buildLLMInput(promptMessages, conversationHistory);
15327
16110
  const outputs = messages.map(
15328
16111
  (m) => m.message?.content && m.message?.role ? { content: m.message.content, role: m.message.role } : void 0
15329
16112
  ).filter(
@@ -15454,8 +16237,7 @@ function createToolTracingHooks(resolveParentSpan, activeToolSpans, mcpServers,
15454
16237
  },
15455
16238
  name: parsed.displayName,
15456
16239
  parent: await resolveParentSpan(toolUseID, {
15457
- agentId: input.agent_id,
15458
- preferTaskSiblingParent: shouldParentToolAsTaskSibling(parsed.toolName)
16240
+ agentId: input.agent_id
15459
16241
  }),
15460
16242
  spanAttributes: { type: "tool" /* TOOL */ }
15461
16243
  });
@@ -15701,12 +16483,37 @@ function injectTracingHooks(options, resolveParentSpan, activeToolSpans, localTo
15701
16483
  }
15702
16484
  };
15703
16485
  }
16486
+ function setSubAgentPromptMessages(state, parentToolUseId, promptMessages, source) {
16487
+ if (promptMessages.length === 0) {
16488
+ return;
16489
+ }
16490
+ const parentKey = llmParentKey(parentToolUseId);
16491
+ const sourcePriority = SUB_AGENT_PROMPT_SOURCE_PRIORITY[source];
16492
+ const currentPriority = state.promptSourcePriorityByParentKey.get(parentKey) ?? -1;
16493
+ if (sourcePriority > currentPriority) {
16494
+ state.promptMessagesByParentKey.set(parentKey, promptMessages);
16495
+ state.promptSourcePriorityByParentKey.set(parentKey, sourcePriority);
16496
+ }
16497
+ }
16498
+ function getConversationHistory(state, parentKey) {
16499
+ let conversationHistory = state.conversationHistoryByParentKey.get(parentKey);
16500
+ if (!conversationHistory) {
16501
+ conversationHistory = [];
16502
+ state.conversationHistoryByParentKey.set(parentKey, conversationHistory);
16503
+ }
16504
+ return conversationHistory;
16505
+ }
15704
16506
  async function finalizeCurrentMessageGroup(state) {
15705
16507
  if (state.currentMessages.length === 0) {
15706
16508
  return;
15707
16509
  }
15708
16510
  const parentToolUseId = state.currentMessages[0]?.parent_tool_use_id ?? null;
15709
16511
  const parentKey = llmParentKey(parentToolUseId);
16512
+ const conversationHistory = getConversationHistory(state, parentKey);
16513
+ const promptMessages = parentToolUseId ? state.promptMessagesByParentKey.get(parentKey) ?? [] : buildRootPromptMessages(
16514
+ state.originalPrompt,
16515
+ state.capturedPromptMessages
16516
+ );
15710
16517
  let parentSpan = await state.span.export();
15711
16518
  if (parentToolUseId) {
15712
16519
  const subAgentSpan = state.subAgentSpans.get(parentToolUseId);
@@ -15717,11 +16524,10 @@ async function finalizeCurrentMessageGroup(state) {
15717
16524
  const existingLlmSpan = state.activeLlmSpansByParentToolUse.get(parentKey);
15718
16525
  const llmSpanResult = await createLLMSpanForMessages(
15719
16526
  state.currentMessages,
15720
- state.originalPrompt,
15721
- state.finalResults,
16527
+ promptMessages,
16528
+ conversationHistory,
15722
16529
  state.options,
15723
16530
  state.currentMessageStartTime,
15724
- state.capturedPromptMessages,
15725
16531
  parentSpan,
15726
16532
  existingLlmSpan
15727
16533
  );
@@ -15735,6 +16541,7 @@ async function finalizeCurrentMessageGroup(state) {
15735
16541
  state.latestRootLlmParentRef.value = llmSpanResult.spanExport;
15736
16542
  }
15737
16543
  if (llmSpanResult.finalMessage) {
16544
+ conversationHistory.push(llmSpanResult.finalMessage);
15738
16545
  state.finalResults.push(llmSpanResult.finalMessage);
15739
16546
  }
15740
16547
  }
@@ -15762,6 +16569,15 @@ function maybeTrackToolUseContext(state, message) {
15762
16569
  description: getStringProperty(block.input, "description"),
15763
16570
  toolUseId: block.id
15764
16571
  });
16572
+ const prompt = getStringProperty(block.input, "prompt");
16573
+ if (prompt) {
16574
+ setSubAgentPromptMessages(
16575
+ state,
16576
+ block.id,
16577
+ [{ content: prompt, role: "user" }],
16578
+ "delegation"
16579
+ );
16580
+ }
15765
16581
  }
15766
16582
  }
15767
16583
  }
@@ -15880,6 +16696,14 @@ async function maybeHandleTaskLifecycleMessage(state, message) {
15880
16696
  };
15881
16697
  if (message.subtype === "task_started") {
15882
16698
  const prompt = getStringProperty(message, "prompt");
16699
+ if (prompt) {
16700
+ setSubAgentPromptMessages(
16701
+ state,
16702
+ toolUseId,
16703
+ [{ content: prompt, role: "user" }],
16704
+ "lifecycle"
16705
+ );
16706
+ }
15883
16707
  subAgentSpan.log({
15884
16708
  input: prompt,
15885
16709
  metadata
@@ -15930,6 +16754,28 @@ async function handleStreamMessage(state, message) {
15930
16754
  return;
15931
16755
  }
15932
16756
  await maybeStartSubAgentSpan(state, message);
16757
+ const messageParentToolUseId = message.parent_tool_use_id;
16758
+ if (messageParentToolUseId && message.type === "user") {
16759
+ const conversationMessage = conversationMessageFromSDKMessage(message);
16760
+ if (conversationMessage?.role === "user") {
16761
+ await finalizeCurrentMessageGroup(state);
16762
+ const parentKey = llmParentKey(messageParentToolUseId);
16763
+ const conversationHistory = getConversationHistory(state, parentKey);
16764
+ const currentPromptSourcePriority = state.promptSourcePriorityByParentKey.get(parentKey) ?? -1;
16765
+ const canUseAsInitialSidechainPrompt = conversationHistory.length === 0 && currentPromptSourcePriority < SUB_AGENT_PROMPT_SOURCE_PRIORITY.sidechain && !messageContentHasBlockType(message, "tool_result");
16766
+ if (!canUseAsInitialSidechainPrompt) {
16767
+ conversationHistory.push(conversationMessage);
16768
+ return;
16769
+ }
16770
+ setSubAgentPromptMessages(
16771
+ state,
16772
+ messageParentToolUseId,
16773
+ [conversationMessage],
16774
+ "sidechain"
16775
+ );
16776
+ return;
16777
+ }
16778
+ }
15933
16779
  const messageId = message.message?.id;
15934
16780
  if (messageId && messageId !== state.currentMessageId) {
15935
16781
  await finalizeCurrentMessageGroup(state);
@@ -16081,6 +16927,7 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
16081
16927
  }
16082
16928
  const activeToolSpans = /* @__PURE__ */ new Map();
16083
16929
  const activeLlmSpansByParentToolUse = /* @__PURE__ */ new Map();
16930
+ const conversationHistoryByParentKey = /* @__PURE__ */ new Map();
16084
16931
  const subAgentSpans = /* @__PURE__ */ new Map();
16085
16932
  const endedSubAgentSpans = /* @__PURE__ */ new Set();
16086
16933
  const toolUseToParent = /* @__PURE__ */ new Map();
@@ -16090,6 +16937,8 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
16090
16937
  };
16091
16938
  const subAgentDetailsByToolUseId = /* @__PURE__ */ new Map();
16092
16939
  const taskIdToToolUseId = /* @__PURE__ */ new Map();
16940
+ const promptMessagesByParentKey = /* @__PURE__ */ new Map();
16941
+ const promptSourcePriorityByParentKey = /* @__PURE__ */ new Map();
16093
16942
  const localToolContext = createClaudeLocalToolContext();
16094
16943
  const { hasLocalToolHandlers, localToolHookNames } = prepareLocalToolHandlersInMcpServers(options.mcpServers);
16095
16944
  const skipLocalToolHooks = options[CLAUDE_AGENT_SDK_SKIP_LOCAL_TOOL_HOOKS_OPTION] === true || hasLocalToolHandlers;
@@ -16098,38 +16947,19 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
16098
16947
  const parentToolUseId = trackedParentToolUseId ?? (context?.agentId ? taskIdToToolUseId.get(context.agentId) ?? null : null);
16099
16948
  const parentKey = llmParentKey(parentToolUseId);
16100
16949
  const activeLlmSpan = activeLlmSpansByParentToolUse.get(parentKey);
16101
- if (context?.preferTaskSiblingParent) {
16102
- if (!activeLlmSpan) {
16103
- await ensureActiveLlmSpanForParentToolUse(
16104
- span,
16105
- activeLlmSpansByParentToolUse,
16106
- subAgentDetailsByToolUseId,
16107
- activeToolSpans,
16108
- subAgentSpans,
16109
- parentToolUseId,
16110
- getCurrentUnixTimestamp()
16111
- );
16112
- }
16113
- if (parentToolUseId) {
16114
- const subAgentSpan = await ensureSubAgentSpan(
16115
- subAgentDetailsByToolUseId,
16116
- span,
16117
- activeToolSpans,
16118
- subAgentSpans,
16119
- parentToolUseId
16120
- );
16121
- return subAgentSpan.export();
16122
- }
16123
- return span.export();
16124
- }
16125
- if (activeLlmSpan) {
16126
- return activeLlmSpan.export();
16950
+ const latestLlmParent = parentToolUseId ? latestLlmParentBySubAgentToolUse.get(parentToolUseId) : latestRootLlmParentRef.value;
16951
+ if (!activeLlmSpan && !latestLlmParent) {
16952
+ await ensureActiveLlmSpanForParentToolUse(
16953
+ span,
16954
+ activeLlmSpansByParentToolUse,
16955
+ subAgentDetailsByToolUseId,
16956
+ activeToolSpans,
16957
+ subAgentSpans,
16958
+ parentToolUseId,
16959
+ getCurrentUnixTimestamp()
16960
+ );
16127
16961
  }
16128
16962
  if (parentToolUseId) {
16129
- const parentLlm = latestLlmParentBySubAgentToolUse.get(parentToolUseId);
16130
- if (parentLlm) {
16131
- return parentLlm;
16132
- }
16133
16963
  const subAgentSpan = await ensureSubAgentSpan(
16134
16964
  subAgentDetailsByToolUseId,
16135
16965
  span,
@@ -16139,9 +16969,6 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
16139
16969
  );
16140
16970
  return subAgentSpan.export();
16141
16971
  }
16142
- if (latestRootLlmParentRef.value) {
16143
- return latestRootLlmParentRef.value;
16144
- }
16145
16972
  return span.export();
16146
16973
  };
16147
16974
  localToolContext.resolveLocalToolParent = resolveToolUseParentSpan;
@@ -16162,6 +16989,7 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
16162
16989
  accumulatedOutputTokens: 0,
16163
16990
  activeLlmSpansByParentToolUse,
16164
16991
  activeToolSpans,
16992
+ conversationHistoryByParentKey,
16165
16993
  capturedPromptMessages,
16166
16994
  currentMessageId: void 0,
16167
16995
  currentMessageStartTime: startTime,
@@ -16172,7 +17000,9 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
16172
17000
  originalPrompt,
16173
17001
  processing: Promise.resolve(),
16174
17002
  promptDone,
17003
+ promptMessagesByParentKey,
16175
17004
  promptStarted: () => promptStarted,
17005
+ promptSourcePriorityByParentKey,
16176
17006
  span,
16177
17007
  subAgentDetailsByToolUseId,
16178
17008
  subAgentSpans,
@@ -17572,6 +18402,7 @@ var GoogleGenAIPlugin = class extends BasePlugin {
17572
18402
  this.subscribeToGenerateContentChannel();
17573
18403
  this.subscribeToGenerateContentStreamChannel();
17574
18404
  this.subscribeToEmbedContentChannel();
18405
+ this.subscribeToInteractionsCreateChannel();
17575
18406
  }
17576
18407
  subscribeToGenerateContentChannel() {
17577
18408
  const tracingChannel2 = googleGenAIChannels.generateContent.tracingChannel();
@@ -17744,7 +18575,30 @@ var GoogleGenAIPlugin = class extends BasePlugin {
17744
18575
  tracingChannel2.unsubscribe(handlers);
17745
18576
  });
17746
18577
  }
18578
+ subscribeToInteractionsCreateChannel() {
18579
+ this.unsubscribers.push(
18580
+ traceStreamingChannel(
18581
+ googleGenAIChannels.interactionsCreate,
18582
+ {
18583
+ name: "create_interaction",
18584
+ shouldTrace: ([params]) => !isBackgroundInteractionCreate(params),
18585
+ type: "llm" /* LLM */,
18586
+ extractInput: ([params]) => ({
18587
+ input: serializeInteractionInput(params),
18588
+ metadata: extractInteractionMetadata(params)
18589
+ }),
18590
+ extractOutput: (result) => serializeInteractionValue(result),
18591
+ extractMetadata: (result) => extractInteractionResponseMetadata(result),
18592
+ extractMetrics: (result, startTime) => cleanMetrics3(extractInteractionMetrics(result, startTime)),
18593
+ aggregateChunks: (chunks, _result, _event, startTime) => aggregateInteractionEvents(chunks, startTime)
18594
+ }
18595
+ )
18596
+ );
18597
+ }
17747
18598
  };
18599
+ function isBackgroundInteractionCreate(params) {
18600
+ return tryToDict(params)?.background === true;
18601
+ }
17748
18602
  function ensureSpanState(states, event, create) {
17749
18603
  const existing = states.get(event);
17750
18604
  if (existing) {
@@ -17952,6 +18806,60 @@ function serializeEmbedContentInput(params) {
17952
18806
  }
17953
18807
  return input;
17954
18808
  }
18809
+ function serializeInteractionInput(params) {
18810
+ const input = {
18811
+ input: serializeInteractionValue(params.input)
18812
+ };
18813
+ for (const key of [
18814
+ "model",
18815
+ "agent",
18816
+ "agent_config",
18817
+ "api_version",
18818
+ "background",
18819
+ "environment",
18820
+ "generation_config",
18821
+ "previous_interaction_id",
18822
+ "response_format",
18823
+ "response_mime_type",
18824
+ "response_modalities",
18825
+ "service_tier",
18826
+ "store",
18827
+ "stream",
18828
+ "system_instruction",
18829
+ "webhook_config"
18830
+ ]) {
18831
+ const value = params[key];
18832
+ if (value !== void 0) {
18833
+ input[key] = serializeInteractionValue(value);
18834
+ }
18835
+ }
18836
+ return input;
18837
+ }
18838
+ function extractInteractionMetadata(params) {
18839
+ const metadata = {};
18840
+ for (const key of [
18841
+ "model",
18842
+ "agent",
18843
+ "agent_config",
18844
+ "generation_config",
18845
+ "system_instruction",
18846
+ "response_format",
18847
+ "response_mime_type",
18848
+ "response_modalities",
18849
+ "service_tier"
18850
+ ]) {
18851
+ const value = params[key];
18852
+ if (value !== void 0) {
18853
+ metadata[key] = serializeInteractionValue(value);
18854
+ }
18855
+ }
18856
+ if (Array.isArray(params.tools)) {
18857
+ metadata.tools = params.tools.map(
18858
+ (tool) => serializeInteractionValue(tool)
18859
+ );
18860
+ }
18861
+ return metadata;
18862
+ }
17955
18863
  function serializeContentCollection(contents) {
17956
18864
  if (contents === null || contents === void 0) {
17957
18865
  return null;
@@ -17982,21 +18890,8 @@ function serializePart(part) {
17982
18890
  }
17983
18891
  if (part.inlineData && part.inlineData.data) {
17984
18892
  const { data, mimeType } = part.inlineData;
17985
- if (data instanceof Uint8Array || typeof Buffer !== "undefined" && Buffer.isBuffer(data) || typeof data === "string") {
17986
- const extension = mimeType ? mimeType.split("/")[1] : "bin";
17987
- const filename = `file.${extension}`;
17988
- const buffer = typeof data === "string" ? typeof Buffer !== "undefined" ? Buffer.from(data, "base64") : new Uint8Array(
17989
- atob(data).split("").map((c) => c.charCodeAt(0))
17990
- ) : typeof Buffer !== "undefined" ? Buffer.from(data) : new Uint8Array(data);
17991
- const arrayBuffer = buffer instanceof Uint8Array ? buffer.buffer.slice(
17992
- buffer.byteOffset,
17993
- buffer.byteOffset + buffer.byteLength
17994
- ) : buffer;
17995
- const attachment = new Attachment({
17996
- data: arrayBuffer,
17997
- filename,
17998
- contentType: mimeType || "application/octet-stream"
17999
- });
18893
+ const attachment = createAttachmentFromInlineData(data, mimeType);
18894
+ if (attachment) {
18000
18895
  return {
18001
18896
  image_url: { url: attachment }
18002
18897
  };
@@ -18004,6 +18899,59 @@ function serializePart(part) {
18004
18899
  }
18005
18900
  return part;
18006
18901
  }
18902
+ function serializeInteractionValue(value, seen = /* @__PURE__ */ new WeakSet()) {
18903
+ if (value === null || value === void 0 || typeof value !== "object") {
18904
+ return value;
18905
+ }
18906
+ if (Array.isArray(value)) {
18907
+ return value.map((item) => serializeInteractionValue(item, seen));
18908
+ }
18909
+ const dict = tryToDict(value);
18910
+ if (dict === null || dict === void 0 || typeof dict !== "object") {
18911
+ return dict;
18912
+ }
18913
+ if (Array.isArray(dict)) {
18914
+ return dict.map((item) => serializeInteractionValue(item, seen));
18915
+ }
18916
+ if (seen.has(dict)) {
18917
+ return "[Circular]";
18918
+ }
18919
+ seen.add(dict);
18920
+ try {
18921
+ const serialized = {};
18922
+ 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;
18923
+ const attachment = mimeType && "data" in dict && dict.data !== void 0 ? createAttachmentFromInlineData(dict.data, mimeType) : null;
18924
+ for (const [key, entry] of Object.entries(dict)) {
18925
+ if (key === "data" && attachment) {
18926
+ serialized[key] = attachment;
18927
+ } else {
18928
+ serialized[key] = serializeInteractionValue(entry, seen);
18929
+ }
18930
+ }
18931
+ return serialized;
18932
+ } finally {
18933
+ seen.delete(dict);
18934
+ }
18935
+ }
18936
+ function createAttachmentFromInlineData(data, mimeType) {
18937
+ if (!(data instanceof Uint8Array || typeof Buffer !== "undefined" && Buffer.isBuffer(data) || typeof data === "string")) {
18938
+ return null;
18939
+ }
18940
+ const extension = mimeType ? mimeType.split("/")[1] : "bin";
18941
+ const filename = `file.${extension}`;
18942
+ const buffer = typeof data === "string" ? typeof Buffer !== "undefined" ? Buffer.from(data, "base64") : new Uint8Array(
18943
+ atob(data).split("").map((c) => c.charCodeAt(0))
18944
+ ) : typeof Buffer !== "undefined" ? Buffer.from(data) : new Uint8Array(data);
18945
+ const arrayBuffer = buffer instanceof Uint8Array ? buffer.buffer.slice(
18946
+ buffer.byteOffset,
18947
+ buffer.byteOffset + buffer.byteLength
18948
+ ) : buffer;
18949
+ return new Attachment({
18950
+ data: arrayBuffer,
18951
+ filename,
18952
+ contentType: mimeType || "application/octet-stream"
18953
+ });
18954
+ }
18007
18955
  function serializeGenerateContentTools(params) {
18008
18956
  const config = params.config ? tryToDict(params.config) : null;
18009
18957
  const tools = config?.tools;
@@ -18088,6 +19036,33 @@ function extractEmbedContentMetrics(response, startTime) {
18088
19036
  }
18089
19037
  return metrics;
18090
19038
  }
19039
+ function extractInteractionMetrics(response, startTime) {
19040
+ const metrics = {};
19041
+ if (startTime !== void 0) {
19042
+ const end = getCurrentUnixTimestamp();
19043
+ metrics.start = startTime;
19044
+ metrics.end = end;
19045
+ metrics.duration = end - startTime;
19046
+ }
19047
+ if (response?.usage) {
19048
+ populateInteractionUsageMetrics(metrics, response.usage);
19049
+ }
19050
+ return metrics;
19051
+ }
19052
+ function extractInteractionResponseMetadata(response) {
19053
+ const responseDict = tryToDict(response);
19054
+ if (!responseDict) {
19055
+ return void 0;
19056
+ }
19057
+ const metadata = {};
19058
+ if (typeof responseDict.id === "string") {
19059
+ metadata.interaction_id = responseDict.id;
19060
+ }
19061
+ if (typeof responseDict.status === "string") {
19062
+ metadata.status = responseDict.status;
19063
+ }
19064
+ return Object.keys(metadata).length > 0 ? metadata : void 0;
19065
+ }
18091
19066
  function extractEmbedPromptTokenCount(response) {
18092
19067
  if (!response) {
18093
19068
  return void 0;
@@ -18150,6 +19125,23 @@ function populateUsageMetrics(metrics, usage) {
18150
19125
  metrics.completion_reasoning_tokens = usage.thoughtsTokenCount;
18151
19126
  }
18152
19127
  }
19128
+ function populateInteractionUsageMetrics(metrics, usage) {
19129
+ if (typeof usage.total_input_tokens === "number") {
19130
+ metrics.prompt_tokens = usage.total_input_tokens;
19131
+ }
19132
+ if (typeof usage.total_output_tokens === "number") {
19133
+ metrics.completion_tokens = usage.total_output_tokens;
19134
+ }
19135
+ if (typeof usage.total_tokens === "number") {
19136
+ metrics.tokens = usage.total_tokens;
19137
+ }
19138
+ if (typeof usage.total_cached_tokens === "number") {
19139
+ metrics.prompt_cached_tokens = usage.total_cached_tokens;
19140
+ }
19141
+ if (typeof usage.total_thought_tokens === "number") {
19142
+ metrics.completion_reasoning_tokens = usage.total_thought_tokens;
19143
+ }
19144
+ }
18153
19145
  function aggregateGenerateContentChunks(chunks, startTime, firstTokenTime) {
18154
19146
  const end = getCurrentUnixTimestamp();
18155
19147
  const metrics = {
@@ -18247,6 +19239,146 @@ function aggregateGenerateContentChunks(chunks, startTime, firstTokenTime) {
18247
19239
  }
18248
19240
  return { aggregated, metrics };
18249
19241
  }
19242
+ function aggregateInteractionEvents(chunks, startTime) {
19243
+ const end = getCurrentUnixTimestamp();
19244
+ const metrics = {};
19245
+ if (startTime !== void 0) {
19246
+ metrics.start = startTime;
19247
+ metrics.end = end;
19248
+ metrics.duration = end - startTime;
19249
+ }
19250
+ let latestInteraction;
19251
+ let latestUsage;
19252
+ let status;
19253
+ let outputText = "";
19254
+ const steps = /* @__PURE__ */ new Map();
19255
+ for (const chunk of chunks) {
19256
+ const event = tryToDict(chunk);
19257
+ if (!event) {
19258
+ continue;
19259
+ }
19260
+ const usage = extractInteractionUsageFromEvent(event);
19261
+ if (usage) {
19262
+ latestUsage = usage;
19263
+ }
19264
+ const interaction = tryToDict(event.interaction);
19265
+ if (interaction) {
19266
+ latestInteraction = serializeInteractionValue(interaction);
19267
+ if (typeof interaction.status === "string") {
19268
+ status = interaction.status;
19269
+ }
19270
+ }
19271
+ if (typeof event.status === "string") {
19272
+ status = event.status;
19273
+ }
19274
+ const index = typeof event.index === "number" ? event.index : void 0;
19275
+ if (index === void 0) {
19276
+ continue;
19277
+ }
19278
+ if (event.event_type === "step.start") {
19279
+ const compact = compactInteractionStep(event.step);
19280
+ compact.index = index;
19281
+ steps.set(index, compact);
19282
+ continue;
19283
+ }
19284
+ if (event.event_type === "step.delta") {
19285
+ const step = steps.get(index) ?? { index };
19286
+ const textDelta = applyInteractionDelta(step, event.delta);
19287
+ if (textDelta) {
19288
+ outputText += textDelta;
19289
+ }
19290
+ steps.set(index, step);
19291
+ }
19292
+ }
19293
+ if (latestUsage) {
19294
+ populateInteractionUsageMetrics(metrics, latestUsage);
19295
+ }
19296
+ const output = latestInteraction ? { ...latestInteraction } : {};
19297
+ if (status) {
19298
+ output.status = status;
19299
+ }
19300
+ if (outputText) {
19301
+ output.output_text = outputText;
19302
+ }
19303
+ if (latestUsage) {
19304
+ output.usage = serializeInteractionValue(latestUsage);
19305
+ }
19306
+ const compactSteps = Array.from(steps.values()).sort(
19307
+ (left, right) => Number(left.index ?? 0) - Number(right.index ?? 0)
19308
+ );
19309
+ if (compactSteps.length > 0) {
19310
+ output.steps = compactSteps;
19311
+ }
19312
+ const metadata = {};
19313
+ if (typeof output.id === "string") {
19314
+ metadata.interaction_id = output.id;
19315
+ }
19316
+ if (typeof output.status === "string") {
19317
+ metadata.status = output.status;
19318
+ }
19319
+ return {
19320
+ output,
19321
+ metrics: cleanMetrics3(metrics),
19322
+ ...Object.keys(metadata).length > 0 ? { metadata } : {}
19323
+ };
19324
+ }
19325
+ function extractInteractionUsageFromEvent(event) {
19326
+ const metadata = tryToDict(event.metadata);
19327
+ const metadataUsage = tryToDict(metadata?.usage);
19328
+ if (metadataUsage) {
19329
+ return metadataUsage;
19330
+ }
19331
+ const metadataTotalUsage = tryToDict(metadata?.total_usage);
19332
+ if (metadataTotalUsage) {
19333
+ return metadataTotalUsage;
19334
+ }
19335
+ const interaction = tryToDict(event.interaction);
19336
+ const interactionUsage = tryToDict(interaction?.usage);
19337
+ return interactionUsage ? interactionUsage : void 0;
19338
+ }
19339
+ function compactInteractionStep(step) {
19340
+ const stepDict = tryToDict(step);
19341
+ if (!stepDict) {
19342
+ return {};
19343
+ }
19344
+ const compact = {};
19345
+ for (const key of [
19346
+ "type",
19347
+ "content",
19348
+ "name",
19349
+ "server_name",
19350
+ "arguments",
19351
+ "result",
19352
+ "is_error"
19353
+ ]) {
19354
+ if (stepDict[key] !== void 0) {
19355
+ compact[key] = serializeInteractionValue(stepDict[key]);
19356
+ }
19357
+ }
19358
+ return Object.keys(compact).length > 0 ? compact : serializeInteractionValue(stepDict);
19359
+ }
19360
+ function applyInteractionDelta(step, delta) {
19361
+ const deltaDict = tryToDict(delta);
19362
+ if (!deltaDict) {
19363
+ return void 0;
19364
+ }
19365
+ const deltaType = deltaDict.type;
19366
+ if (typeof deltaType === "string" && typeof step.type !== "string") {
19367
+ step.type = deltaType === "text" ? "model_output" : deltaType;
19368
+ }
19369
+ if (deltaType === "text" && typeof deltaDict.text === "string") {
19370
+ step.text = `${typeof step.text === "string" ? step.text : ""}${deltaDict.text}`;
19371
+ return deltaDict.text;
19372
+ }
19373
+ if (deltaType === "arguments_delta" && typeof deltaDict.arguments === "string") {
19374
+ step.arguments = `${typeof step.arguments === "string" ? step.arguments : ""}${deltaDict.arguments}`;
19375
+ return void 0;
19376
+ }
19377
+ const deltas = Array.isArray(step.deltas) ? step.deltas : [];
19378
+ deltas.push(serializeInteractionValue(deltaDict));
19379
+ step.deltas = deltas;
19380
+ return void 0;
19381
+ }
18250
19382
  function cleanMetrics3(metrics) {
18251
19383
  const cleaned = {};
18252
19384
  for (const [key, value] of Object.entries(metrics)) {
@@ -23843,7 +24975,8 @@ var FlueObserveBridge = class {
23843
24975
  metadata
23844
24976
  }
23845
24977
  });
23846
- this.runsById.set(event.runId, { metadata, span });
24978
+ const activeContext = enterCurrentFlueSpan(span);
24979
+ this.runsById.set(event.runId, { activeContext, metadata, span });
23847
24980
  }
23848
24981
  handleRunEnd(event) {
23849
24982
  const state = this.runsById.get(event.runId);
@@ -23861,6 +24994,7 @@ var FlueObserveBridge = class {
23861
24994
  });
23862
24995
  safeEnd(state.span, eventTime(event.timestamp));
23863
24996
  this.runsById.delete(event.runId);
24997
+ restoreCurrentFlueSpan(state.activeContext);
23864
24998
  }
23865
24999
  void flush().catch((error) => {
23866
25000
  logInstrumentationError3("Flue flush", error);
@@ -23987,7 +25121,8 @@ var FlueObserveBridge = class {
23987
25121
  metadata
23988
25122
  }
23989
25123
  });
23990
- this.toolsByKey.set(toolKey(event), { metadata, span });
25124
+ const activeContext = enterCurrentFlueSpan(span);
25125
+ this.toolsByKey.set(toolKey(event), { activeContext, metadata, span });
23991
25126
  }
23992
25127
  handleToolCall(event) {
23993
25128
  if (!event.toolCallId) {
@@ -24010,6 +25145,7 @@ var FlueObserveBridge = class {
24010
25145
  });
24011
25146
  safeEnd(state.span, eventTime(event.timestamp));
24012
25147
  this.toolsByKey.delete(key);
25148
+ restoreCurrentFlueSpan(state.activeContext);
24013
25149
  }
24014
25150
  handleTaskStart(event) {
24015
25151
  if (!event.taskId) {
@@ -24414,6 +25550,34 @@ function stateMatchesRun(state, runId) {
24414
25550
  function startFlueSpan(parent, args) {
24415
25551
  return parent ? withCurrent(parent, () => startSpan(args)) : startSpan(args);
24416
25552
  }
25553
+ function enterCurrentFlueSpan(span) {
25554
+ const contextManager = _internalGetGlobalState()?.contextManager;
25555
+ const store = contextManager ? Reflect.get(contextManager, BRAINTRUST_CURRENT_SPAN_STORE) : void 0;
25556
+ if (!contextManager || !isCurrentSpanStore(store)) {
25557
+ return void 0;
25558
+ }
25559
+ const previous = store.getStore();
25560
+ try {
25561
+ store.enterWith(contextManager.wrapSpanForStore(span));
25562
+ return { previous, store };
25563
+ } catch (error) {
25564
+ logInstrumentationError3("Flue context propagation", error);
25565
+ return void 0;
25566
+ }
25567
+ }
25568
+ function isCurrentSpanStore(value) {
25569
+ return isObjectLike(value) && typeof Reflect.get(value, "enterWith") === "function" && typeof Reflect.get(value, "getStore") === "function";
25570
+ }
25571
+ function restoreCurrentFlueSpan(activeContext) {
25572
+ if (!activeContext) {
25573
+ return;
25574
+ }
25575
+ try {
25576
+ activeContext.store.enterWith(activeContext.previous);
25577
+ } catch (error) {
25578
+ logInstrumentationError3("Flue context restoration", error);
25579
+ }
25580
+ }
24417
25581
  function safeLog3(span, event) {
24418
25582
  try {
24419
25583
  span.log(event);
@@ -24879,6 +26043,879 @@ function isBraintrustHandler(handler) {
24879
26043
  return Reflect.get(handler, "name") === BRAINTRUST_LANGCHAIN_CALLBACK_HANDLER_NAME;
24880
26044
  }
24881
26045
 
26046
+ // src/instrumentation/plugins/pi-coding-agent-plugin.ts
26047
+ var piStreamPatchStates = /* @__PURE__ */ new WeakMap();
26048
+ var piPromptContextStore;
26049
+ var PiCodingAgentPlugin = class extends BasePlugin {
26050
+ activePromptStates = /* @__PURE__ */ new Set();
26051
+ onEnable() {
26052
+ this.subscribeToPrompt();
26053
+ }
26054
+ onDisable() {
26055
+ for (const unsubscribe of this.unsubscribers) {
26056
+ unsubscribe();
26057
+ }
26058
+ this.unsubscribers = [];
26059
+ for (const state of [...this.activePromptStates]) {
26060
+ void finalizePiPromptRun(state).catch((error) => {
26061
+ logInstrumentationError4("Pi Coding Agent disable cleanup", error);
26062
+ });
26063
+ }
26064
+ }
26065
+ subscribeToPrompt() {
26066
+ const channel = piCodingAgentChannels.prompt.tracingChannel();
26067
+ const states = /* @__PURE__ */ new WeakMap();
26068
+ const unbindAutoInstrumentationSuppression = bindAutoInstrumentationSuppressionToStart(channel);
26069
+ const handlers = {
26070
+ start: (event) => {
26071
+ const state = startPiPromptRun(event, (state2) => {
26072
+ this.activePromptStates.delete(state2);
26073
+ });
26074
+ if (state) {
26075
+ this.activePromptStates.add(state);
26076
+ states.set(event, state);
26077
+ }
26078
+ },
26079
+ asyncEnd: async (event) => {
26080
+ const state = states.get(event);
26081
+ if (!state) {
26082
+ return;
26083
+ }
26084
+ states.delete(event);
26085
+ state.promptCallEnded = true;
26086
+ if (!state.finalized && state.deferCompletionUntilTurnEnd && !state.turnEnded) {
26087
+ if (!state.sawStreamFn) {
26088
+ state.queued = true;
26089
+ if (!state.streamPatchState.queuedPromptStates.includes(state)) {
26090
+ state.streamPatchState.queuedPromptStates.push(state);
26091
+ }
26092
+ }
26093
+ return;
26094
+ }
26095
+ await finalizePiPromptRun(state);
26096
+ },
26097
+ error: async (event) => {
26098
+ const state = states.get(event);
26099
+ if (!state) {
26100
+ return;
26101
+ }
26102
+ states.delete(event);
26103
+ await finalizePiPromptRun(state, event.error);
26104
+ }
26105
+ };
26106
+ channel.subscribe(handlers);
26107
+ this.unsubscribers.push(() => {
26108
+ unbindAutoInstrumentationSuppression?.();
26109
+ channel.unsubscribe(handlers);
26110
+ });
26111
+ }
26112
+ };
26113
+ function startPiPromptRun(event, onFinalize) {
26114
+ const session = extractSession(event);
26115
+ const agent = session?.agent;
26116
+ if (!session || !isPiAgent(agent)) {
26117
+ return void 0;
26118
+ }
26119
+ const metadata = {
26120
+ ...extractSessionMetadata(session),
26121
+ ...extractPromptOptionsMetadata(event.arguments[1]),
26122
+ "pi_coding_agent.operation": "AgentSession.prompt",
26123
+ provider: session.model?.provider ?? agent.state?.model?.provider ?? "pi",
26124
+ ...session.model?.id || agent.state?.model?.id ? { model: session.model?.id ?? agent.state?.model?.id } : {},
26125
+ ...event.moduleVersion ? { "pi_coding_agent.version": event.moduleVersion } : {}
26126
+ };
26127
+ const span = startSpan({
26128
+ event: {
26129
+ input: extractPromptInput(event.arguments[0], event.arguments[1]),
26130
+ metadata
26131
+ },
26132
+ name: "AgentSession.prompt",
26133
+ spanAttributes: { type: "task" /* TASK */ }
26134
+ });
26135
+ const streamPatchState = installPiStreamPatch(agent);
26136
+ const options = event.arguments[1];
26137
+ const promptText = event.arguments[0];
26138
+ const state = {
26139
+ activeLlmSpans: /* @__PURE__ */ new Set(),
26140
+ activeToolSpans: /* @__PURE__ */ new Map(),
26141
+ agent,
26142
+ collectedLlmUsageMetrics: false,
26143
+ deferCompletionUntilTurnEnd: options?.streamingBehavior === "followUp" || options?.streamingBehavior === "steer",
26144
+ finalized: false,
26145
+ metadata,
26146
+ metrics: {},
26147
+ onFinalize,
26148
+ promptCallEnded: false,
26149
+ ...typeof promptText === "string" ? { promptText } : {},
26150
+ queued: false,
26151
+ span,
26152
+ sawStreamFn: false,
26153
+ startTime: getCurrentUnixTimestamp(),
26154
+ streamPatchState,
26155
+ turnEnded: false
26156
+ };
26157
+ state.restorePromptContext = enterPiPromptContext(state);
26158
+ streamPatchState.activePromptStates.add(state);
26159
+ try {
26160
+ state.unsubscribeAgent = agent.subscribe(async (agentEvent) => {
26161
+ try {
26162
+ await runWithAutoInstrumentationSuppressed(
26163
+ () => handlePiAgentEvent(state, agentEvent)
26164
+ );
26165
+ } catch (error) {
26166
+ logInstrumentationError4("Pi Coding Agent event", error);
26167
+ }
26168
+ });
26169
+ } catch (error) {
26170
+ logInstrumentationError4("Pi Coding Agent event subscription", error);
26171
+ }
26172
+ return state;
26173
+ }
26174
+ function extractSession(event) {
26175
+ const candidate = event.session ?? event.self;
26176
+ return isObject(candidate) && typeof candidate.prompt === "function" ? candidate : void 0;
26177
+ }
26178
+ function isPiAgent(value) {
26179
+ return isObject(value) && typeof value.streamFn === "function" && typeof value.subscribe === "function";
26180
+ }
26181
+ function promptContextStore() {
26182
+ piPromptContextStore ??= isomorph_default.newAsyncLocalStorage();
26183
+ return piPromptContextStore;
26184
+ }
26185
+ function currentPromptContextFrames() {
26186
+ return promptContextStore().getStore()?.frames ?? [];
26187
+ }
26188
+ function currentPiPromptState() {
26189
+ const frames = currentPromptContextFrames();
26190
+ return frames[frames.length - 1]?.state;
26191
+ }
26192
+ function enterPiPromptContext(state) {
26193
+ const frame = {
26194
+ id: /* @__PURE__ */ Symbol("braintrust.pi-coding-agent.prompt"),
26195
+ state
26196
+ };
26197
+ promptContextStore().enterWith({
26198
+ frames: [...currentPromptContextFrames(), frame]
26199
+ });
26200
+ return () => {
26201
+ const frames = currentPromptContextFrames().filter(
26202
+ (candidate) => candidate.id !== frame.id
26203
+ );
26204
+ promptContextStore().enterWith(frames.length > 0 ? { frames } : void 0);
26205
+ };
26206
+ }
26207
+ function installPiStreamPatch(agent) {
26208
+ const existing = piStreamPatchStates.get(agent);
26209
+ if (existing) {
26210
+ if (agent.streamFn !== existing.wrappedStreamFn) {
26211
+ debugLogger.debug(
26212
+ "Pi Coding Agent streamFn changed while Braintrust instrumentation was active; preserving existing patch state."
26213
+ );
26214
+ }
26215
+ return existing;
26216
+ }
26217
+ const patchState = {
26218
+ activePromptStates: /* @__PURE__ */ new Set(),
26219
+ agent,
26220
+ originalStreamFn: agent.streamFn,
26221
+ queuedPromptStates: [],
26222
+ wrappedStreamFn: agent.streamFn
26223
+ };
26224
+ patchState.wrappedStreamFn = makeSharedInstrumentedStreamFn(patchState);
26225
+ agent.streamFn = patchState.wrappedStreamFn;
26226
+ piStreamPatchStates.set(agent, patchState);
26227
+ return patchState;
26228
+ }
26229
+ function resolveStreamPromptState(patchState, context) {
26230
+ let lastUserText;
26231
+ if (Array.isArray(context.messages)) {
26232
+ for (let i = context.messages.length - 1; i >= 0; i--) {
26233
+ const message = context.messages[i];
26234
+ if (isPiUserMessage(message)) {
26235
+ if (typeof message.content === "string") {
26236
+ lastUserText = message.content;
26237
+ } else {
26238
+ lastUserText = message.content.flatMap((part) => part.type === "text" ? [part.text] : []).join("");
26239
+ }
26240
+ break;
26241
+ }
26242
+ }
26243
+ }
26244
+ if (lastUserText !== void 0) {
26245
+ const queuedMatch = patchState.queuedPromptStates.find(
26246
+ (state) => state.promptText === lastUserText
26247
+ );
26248
+ if (queuedMatch) {
26249
+ return queuedMatch;
26250
+ }
26251
+ const matches = [...patchState.activePromptStates].filter(
26252
+ (state) => state.promptText === lastUserText
26253
+ );
26254
+ if (matches.length === 1) {
26255
+ return matches[0];
26256
+ }
26257
+ }
26258
+ const contextState = currentPiPromptState();
26259
+ if (contextState && patchState.activePromptStates.has(contextState) && (!contextState.queued || lastUserText !== void 0 && contextState.promptText === lastUserText)) {
26260
+ return contextState;
26261
+ }
26262
+ if (patchState.activePromptStates.size === 1) {
26263
+ return [...patchState.activePromptStates][0];
26264
+ }
26265
+ return void 0;
26266
+ }
26267
+ function makeSharedInstrumentedStreamFn(patchState) {
26268
+ return async function instrumentedPiStreamFn(model, context, options) {
26269
+ const state = resolveStreamPromptState(patchState, context);
26270
+ if (!state) {
26271
+ const invokeOriginal = () => Reflect.apply(patchState.originalStreamFn, this, [
26272
+ model,
26273
+ context,
26274
+ options
26275
+ ]);
26276
+ return patchState.activePromptStates.size > 0 ? runWithAutoInstrumentationSuppressed(invokeOriginal) : invokeOriginal();
26277
+ }
26278
+ state.sawStreamFn = true;
26279
+ removeQueuedPromptState(state);
26280
+ state.streamPatchState.eventPromptState = state;
26281
+ const llmState = await startPiLlmSpan(state, model, context, options);
26282
+ try {
26283
+ const stream = await runWithAutoInstrumentationSuppressed(
26284
+ () => Reflect.apply(patchState.originalStreamFn, this, [
26285
+ model,
26286
+ context,
26287
+ options
26288
+ ])
26289
+ );
26290
+ return patchAssistantMessageStream(stream, state, llmState);
26291
+ } catch (error) {
26292
+ finishPiLlmSpan(state, llmState, void 0, error);
26293
+ throw error;
26294
+ }
26295
+ };
26296
+ }
26297
+ async function startPiLlmSpan(state, model, context, options) {
26298
+ const metadata = {
26299
+ ...extractModelMetadata2(model),
26300
+ ...extractStreamOptionsMetadata(options),
26301
+ ...extractToolMetadata(context.tools),
26302
+ "pi_coding_agent.operation": "agent.streamFn"
26303
+ };
26304
+ const span = startSpan({
26305
+ event: {
26306
+ input: processInputAttachments(normalizePiContextInput(context)),
26307
+ metadata
26308
+ },
26309
+ name: getLlmSpanName(model),
26310
+ parent: await state.span.export(),
26311
+ spanAttributes: { type: "llm" /* LLM */ }
26312
+ });
26313
+ const llmState = {
26314
+ finalized: false,
26315
+ metadata,
26316
+ metrics: {},
26317
+ span,
26318
+ startTime: getCurrentUnixTimestamp()
26319
+ };
26320
+ state.activeLlmSpans.add(llmState);
26321
+ return llmState;
26322
+ }
26323
+ function patchAssistantMessageStream(stream, promptState, llmState) {
26324
+ if (!isObject(stream)) {
26325
+ return stream;
26326
+ }
26327
+ const streamRecord = stream;
26328
+ const originalResult = stream.result;
26329
+ if (typeof originalResult === "function") {
26330
+ streamRecord.result = function patchedPiResult() {
26331
+ return Promise.resolve(Reflect.apply(originalResult, this, [])).then(
26332
+ (message) => {
26333
+ finishPiLlmSpan(promptState, llmState, message);
26334
+ return message;
26335
+ },
26336
+ (error) => {
26337
+ finishPiLlmSpan(promptState, llmState, void 0, error);
26338
+ throw error;
26339
+ }
26340
+ );
26341
+ };
26342
+ }
26343
+ const originalIterator = stream[Symbol.asyncIterator];
26344
+ if (typeof originalIterator === "function") {
26345
+ streamRecord[Symbol.asyncIterator] = function patchedPiIterator() {
26346
+ const iterator = Reflect.apply(
26347
+ originalIterator,
26348
+ this,
26349
+ []
26350
+ );
26351
+ return {
26352
+ async next() {
26353
+ try {
26354
+ const result = await iterator.next();
26355
+ if (result.done) {
26356
+ finishPiLlmSpan(promptState, llmState);
26357
+ return result;
26358
+ }
26359
+ recordPiAssistantMessageEvent(promptState, llmState, result.value);
26360
+ return result;
26361
+ } catch (error) {
26362
+ finishPiLlmSpan(promptState, llmState, void 0, error);
26363
+ if (typeof iterator.return === "function") {
26364
+ try {
26365
+ await iterator.return();
26366
+ } catch (cleanupError) {
26367
+ logInstrumentationError4(
26368
+ "Pi Coding Agent stream cleanup",
26369
+ cleanupError
26370
+ );
26371
+ }
26372
+ }
26373
+ throw error;
26374
+ }
26375
+ },
26376
+ async return(value) {
26377
+ try {
26378
+ if (typeof iterator.return === "function") {
26379
+ return await iterator.return(value);
26380
+ }
26381
+ return {
26382
+ done: true,
26383
+ value
26384
+ };
26385
+ } catch (error) {
26386
+ finishPiLlmSpan(promptState, llmState, void 0, error);
26387
+ throw error;
26388
+ } finally {
26389
+ finishPiLlmSpan(promptState, llmState);
26390
+ }
26391
+ },
26392
+ async throw(error) {
26393
+ try {
26394
+ if (typeof iterator.throw === "function") {
26395
+ return await iterator.throw(error);
26396
+ }
26397
+ throw error;
26398
+ } catch (thrownError) {
26399
+ finishPiLlmSpan(promptState, llmState, void 0, thrownError);
26400
+ throw thrownError;
26401
+ }
26402
+ },
26403
+ [Symbol.asyncIterator]() {
26404
+ return this;
26405
+ }
26406
+ };
26407
+ };
26408
+ }
26409
+ return stream;
26410
+ }
26411
+ function recordPiAssistantMessageEvent(promptState, llmState, event) {
26412
+ recordFirstTokenMetric(llmState, event);
26413
+ const message = "message" in event ? event.message : void 0;
26414
+ const errorMessage2 = "error" in event ? event.error : void 0;
26415
+ if (event.type === "done" && isPiAssistantMessage(message)) {
26416
+ finishPiLlmSpan(promptState, llmState, message);
26417
+ } else if (event.type === "error" && isPiAssistantMessage(errorMessage2)) {
26418
+ finishPiLlmSpan(promptState, llmState, errorMessage2);
26419
+ }
26420
+ }
26421
+ function recordFirstTokenMetric(state, event) {
26422
+ if (state.metrics.time_to_first_token !== void 0 || event.type === "start") {
26423
+ return;
26424
+ }
26425
+ state.metrics.time_to_first_token = getCurrentUnixTimestamp() - state.startTime;
26426
+ }
26427
+ async function handlePiAgentEvent(state, event) {
26428
+ if (state.finalized) {
26429
+ return;
26430
+ }
26431
+ const eventPromptState = state.streamPatchState.eventPromptState;
26432
+ if (eventPromptState && eventPromptState !== state) {
26433
+ return;
26434
+ }
26435
+ if (!eventPromptState && (state.queued || state.streamPatchState.activePromptStates.size > 1 && currentPiPromptState() !== state)) {
26436
+ return;
26437
+ }
26438
+ switch (event.type) {
26439
+ case "message_end":
26440
+ if (isPiAssistantMessage(event.message)) {
26441
+ state.output = extractAssistantOutput(event.message);
26442
+ }
26443
+ return;
26444
+ case "turn_end":
26445
+ state.turnEnded = true;
26446
+ if (isPiAssistantMessage(event.message)) {
26447
+ state.output = extractAssistantOutput(event.message);
26448
+ if (!state.collectedLlmUsageMetrics) {
26449
+ addMetrics(state.metrics, extractUsageMetrics2(event.message.usage));
26450
+ }
26451
+ }
26452
+ if (state.streamPatchState.eventPromptState === state) {
26453
+ state.streamPatchState.eventPromptState = void 0;
26454
+ }
26455
+ if (state.promptCallEnded && state.deferCompletionUntilTurnEnd) {
26456
+ await finalizePiPromptRun(state);
26457
+ }
26458
+ return;
26459
+ case "tool_execution_start":
26460
+ await startPiToolSpan(state, event);
26461
+ return;
26462
+ case "tool_execution_end":
26463
+ finishPiToolSpan(state, event);
26464
+ return;
26465
+ default:
26466
+ return;
26467
+ }
26468
+ }
26469
+ async function startPiToolSpan(state, event) {
26470
+ if (!event.toolCallId || state.activeToolSpans.has(event.toolCallId)) {
26471
+ return;
26472
+ }
26473
+ const restoreAutoInstrumentation = enterAutoInstrumentationAllowed();
26474
+ const metadata = {
26475
+ "gen_ai.tool.call.id": event.toolCallId,
26476
+ "gen_ai.tool.name": event.toolName,
26477
+ "pi_coding_agent.tool.name": event.toolName
26478
+ };
26479
+ try {
26480
+ const span = startSpan({
26481
+ event: {
26482
+ input: event.args,
26483
+ metadata
26484
+ },
26485
+ name: event.toolName || "tool",
26486
+ parent: await state.span.export(),
26487
+ spanAttributes: { type: "tool" /* TOOL */ }
26488
+ });
26489
+ state.activeToolSpans.set(event.toolCallId, {
26490
+ restoreAutoInstrumentation,
26491
+ span
26492
+ });
26493
+ } catch (error) {
26494
+ restoreAutoInstrumentation();
26495
+ throw error;
26496
+ }
26497
+ }
26498
+ function finishPiToolSpan(state, event) {
26499
+ const toolState = state.activeToolSpans.get(event.toolCallId);
26500
+ if (!toolState) {
26501
+ return;
26502
+ }
26503
+ state.activeToolSpans.delete(event.toolCallId);
26504
+ const metadata = {
26505
+ "gen_ai.tool.call.id": event.toolCallId,
26506
+ "gen_ai.tool.name": event.toolName,
26507
+ "pi_coding_agent.tool.name": event.toolName,
26508
+ "pi_coding_agent.tool.is_error": event.isError
26509
+ };
26510
+ try {
26511
+ safeLog4(toolState.span, {
26512
+ ...event.isError ? { error: stringifyUnknown2(event.result) } : {},
26513
+ metadata,
26514
+ output: event.result
26515
+ });
26516
+ } finally {
26517
+ try {
26518
+ toolState.span.end();
26519
+ } finally {
26520
+ toolState.restoreAutoInstrumentation?.();
26521
+ }
26522
+ }
26523
+ }
26524
+ async function finalizePiPromptRun(state, error) {
26525
+ if (state.finalized) {
26526
+ return;
26527
+ }
26528
+ state.finalized = true;
26529
+ state.onFinalize?.(state);
26530
+ restorePiStreamFn(state);
26531
+ try {
26532
+ state.unsubscribeAgent?.();
26533
+ } catch (unsubscribeError) {
26534
+ logInstrumentationError4("Pi Coding Agent unsubscribe", unsubscribeError);
26535
+ }
26536
+ await finishOpenLlmSpans(state, error);
26537
+ finishOpenToolSpans(state, error);
26538
+ const metadata = {
26539
+ ...state.metadata,
26540
+ ...extractModelMetadata2(state.agent.state?.model)
26541
+ };
26542
+ try {
26543
+ safeLog4(state.span, {
26544
+ ...error ? { error: stringifyUnknown2(error) } : {},
26545
+ metadata,
26546
+ metrics: {
26547
+ ...cleanMetrics5(state.metrics),
26548
+ ...buildDurationMetrics3(state.startTime)
26549
+ },
26550
+ output: state.output
26551
+ });
26552
+ } finally {
26553
+ state.span.end();
26554
+ }
26555
+ }
26556
+ function restorePiStreamFn(state) {
26557
+ const patchState = state.streamPatchState;
26558
+ patchState.activePromptStates.delete(state);
26559
+ removeQueuedPromptState(state);
26560
+ if (patchState.eventPromptState === state) {
26561
+ patchState.eventPromptState = void 0;
26562
+ }
26563
+ state.restorePromptContext?.();
26564
+ if (patchState.activePromptStates.size > 0) {
26565
+ return;
26566
+ }
26567
+ if (patchState.agent.streamFn === patchState.wrappedStreamFn) {
26568
+ patchState.agent.streamFn = patchState.originalStreamFn;
26569
+ }
26570
+ piStreamPatchStates.delete(patchState.agent);
26571
+ }
26572
+ function removeQueuedPromptState(state) {
26573
+ state.queued = false;
26574
+ const queuedPromptStates = state.streamPatchState.queuedPromptStates;
26575
+ const index = queuedPromptStates.indexOf(state);
26576
+ if (index >= 0) {
26577
+ queuedPromptStates.splice(index, 1);
26578
+ }
26579
+ }
26580
+ async function finishOpenLlmSpans(state, error) {
26581
+ for (const llmState of [...state.activeLlmSpans]) {
26582
+ finishPiLlmSpan(state, llmState, void 0, error);
26583
+ }
26584
+ }
26585
+ function finishPiLlmSpan(promptState, llmState, message, error) {
26586
+ if (llmState.finalized) {
26587
+ return;
26588
+ }
26589
+ llmState.finalized = true;
26590
+ promptState.activeLlmSpans.delete(llmState);
26591
+ const messageError = message?.stopReason === "error" && message.errorMessage;
26592
+ const metrics = {
26593
+ ...extractUsageMetrics2(message?.usage),
26594
+ ...cleanMetrics5(llmState.metrics),
26595
+ ...buildDurationMetrics3(llmState.startTime)
26596
+ };
26597
+ const usageMetrics = extractUsageMetrics2(message?.usage);
26598
+ if (Object.keys(usageMetrics).length > 0) {
26599
+ promptState.collectedLlmUsageMetrics = true;
26600
+ addMetrics(promptState.metrics, usageMetrics);
26601
+ }
26602
+ try {
26603
+ safeLog4(llmState.span, {
26604
+ ...error || messageError ? { error: stringifyUnknown2(error ?? messageError) } : {},
26605
+ metadata: {
26606
+ ...llmState.metadata,
26607
+ ...message ? extractAssistantMetadata(message) : {}
26608
+ },
26609
+ metrics,
26610
+ ...message ? { output: extractAssistantOutput(message) } : {}
26611
+ });
26612
+ } finally {
26613
+ llmState.span.end();
26614
+ }
26615
+ }
26616
+ function finishOpenToolSpans(state, error) {
26617
+ for (const [, toolState] of state.activeToolSpans) {
26618
+ try {
26619
+ safeLog4(toolState.span, {
26620
+ error: error ? stringifyUnknown2(error) : "Pi tool did not complete"
26621
+ });
26622
+ toolState.span.end();
26623
+ } finally {
26624
+ toolState.restoreAutoInstrumentation?.();
26625
+ }
26626
+ }
26627
+ state.activeToolSpans.clear();
26628
+ }
26629
+ function normalizePiContextInput(context) {
26630
+ const messages = context.messages.flatMap(
26631
+ (message) => normalizePiMessage(message)
26632
+ );
26633
+ if (context.systemPrompt) {
26634
+ return [{ role: "system", content: context.systemPrompt }, ...messages];
26635
+ }
26636
+ return messages;
26637
+ }
26638
+ function normalizePiMessage(message) {
26639
+ if (isPiUserMessage(message)) {
26640
+ return [
26641
+ {
26642
+ role: "user",
26643
+ content: normalizeUserContent(message.content)
26644
+ }
26645
+ ];
26646
+ }
26647
+ if (isPiAssistantMessage(message)) {
26648
+ return [normalizeAssistantMessage(message)];
26649
+ }
26650
+ if (isPiToolResultMessage(message)) {
26651
+ return [normalizeToolResultMessage(message)];
26652
+ }
26653
+ return [];
26654
+ }
26655
+ function normalizeAssistantMessage(message) {
26656
+ const text = message.content.flatMap((part) => part.type === "text" ? [part.text] : []).join("");
26657
+ const thinking = message.content.flatMap(
26658
+ (part) => part.type === "thinking" && !part.redacted ? [part.thinking] : []
26659
+ ).join("");
26660
+ const toolCalls = message.content.flatMap(
26661
+ (part) => part.type === "toolCall" ? [normalizeToolCall(part)] : []
26662
+ );
26663
+ return {
26664
+ role: "assistant",
26665
+ content: text || (toolCalls.length > 0 ? null : ""),
26666
+ ...thinking ? { reasoning: thinking } : {},
26667
+ ...toolCalls.length > 0 ? { tool_calls: toolCalls } : {}
26668
+ };
26669
+ }
26670
+ function normalizeToolResultMessage(message) {
26671
+ return {
26672
+ role: "tool",
26673
+ tool_call_id: message.toolCallId,
26674
+ content: normalizeUserContent(message.content)
26675
+ };
26676
+ }
26677
+ function normalizeUserContent(content) {
26678
+ if (typeof content === "string") {
26679
+ return content;
26680
+ }
26681
+ return content.map((part) => {
26682
+ if (part.type === "text") {
26683
+ return { type: "text", text: part.text };
26684
+ }
26685
+ if (part.type === "image") {
26686
+ return {
26687
+ type: "image_url",
26688
+ image_url: {
26689
+ url: `data:${part.mimeType};base64,${part.data}`
26690
+ }
26691
+ };
26692
+ }
26693
+ return part;
26694
+ });
26695
+ }
26696
+ function normalizeToolCall(toolCall) {
26697
+ return {
26698
+ id: toolCall.id,
26699
+ type: "function",
26700
+ function: {
26701
+ name: toolCall.name,
26702
+ arguments: stringifyArguments(toolCall.arguments)
26703
+ }
26704
+ };
26705
+ }
26706
+ function extractAssistantOutput(message) {
26707
+ return processInputAttachments([
26708
+ {
26709
+ finish_reason: normalizeStopReason(message.stopReason),
26710
+ index: 0,
26711
+ message: normalizeAssistantMessage(message)
26712
+ }
26713
+ ]);
26714
+ }
26715
+ function isPiUserMessage(message) {
26716
+ return message.role === "user" && "content" in message;
26717
+ }
26718
+ function isPiAssistantMessage(message) {
26719
+ return isObject(message) && message.role === "assistant" && Array.isArray(message.content);
26720
+ }
26721
+ function isPiToolResultMessage(message) {
26722
+ return message.role === "toolResult" && Array.isArray(message.content);
26723
+ }
26724
+ function normalizeStopReason(reason) {
26725
+ switch (reason) {
26726
+ case "toolUse":
26727
+ return "tool_calls";
26728
+ case "length":
26729
+ case "stop":
26730
+ return reason;
26731
+ default:
26732
+ return reason ?? "stop";
26733
+ }
26734
+ }
26735
+ function extractPromptInput(text, options) {
26736
+ const images = options?.images;
26737
+ if (!images || images.length === 0) {
26738
+ return text;
26739
+ }
26740
+ return processInputAttachments([
26741
+ {
26742
+ role: "user",
26743
+ content: [
26744
+ { type: "text", text: text ?? "" },
26745
+ ...images.map((image) => ({
26746
+ type: "image_url",
26747
+ image_url: {
26748
+ url: `data:${image.mimeType};base64,${image.data}`
26749
+ }
26750
+ }))
26751
+ ]
26752
+ }
26753
+ ]);
26754
+ }
26755
+ function extractToolMetadata(tools) {
26756
+ if (!tools || tools.length === 0) {
26757
+ return {};
26758
+ }
26759
+ return {
26760
+ tools: tools.map((tool) => ({
26761
+ type: "function",
26762
+ function: {
26763
+ name: tool.name,
26764
+ ...tool.description ? { description: tool.description } : {},
26765
+ ...tool.parameters ? { parameters: tool.parameters } : {}
26766
+ }
26767
+ }))
26768
+ };
26769
+ }
26770
+ function extractModelMetadata2(model) {
26771
+ if (!model) {
26772
+ return {};
26773
+ }
26774
+ return {
26775
+ ...model.provider ? { provider: model.provider } : {},
26776
+ ...model.id ? { model: model.id, "pi_coding_agent.model": model.id } : {},
26777
+ ...model.api ? { "pi_coding_agent.api": model.api } : {},
26778
+ ...model.name ? { "pi_coding_agent.model_name": model.name } : {}
26779
+ };
26780
+ }
26781
+ function extractAssistantMetadata(message) {
26782
+ return {
26783
+ ...message.provider ? { provider: message.provider } : {},
26784
+ ...message.responseModel || message.model ? { model: message.responseModel ?? message.model } : {},
26785
+ ...message.api ? { "pi_coding_agent.api": message.api } : {},
26786
+ ...message.model ? { "pi_coding_agent.model": message.model } : {},
26787
+ ...message.responseModel ? { "pi_coding_agent.response_model": message.responseModel } : {},
26788
+ ...message.responseId ? { "pi_coding_agent.response_id": message.responseId } : {},
26789
+ ...message.stopReason ? { "pi_coding_agent.stop_reason": message.stopReason } : {}
26790
+ };
26791
+ }
26792
+ function extractSessionMetadata(session) {
26793
+ return {
26794
+ ...extractModelMetadata2(session.model),
26795
+ ...session.sessionId ? { "pi_coding_agent.session_id": session.sessionId } : {},
26796
+ ...session.sessionName ? { "pi_coding_agent.session_name": session.sessionName } : {},
26797
+ ...session.thinkingLevel ? { "pi_coding_agent.thinking_level": session.thinkingLevel } : {},
26798
+ ...typeof session.getActiveToolNames === "function" ? { "pi_coding_agent.active_tools": session.getActiveToolNames() } : {}
26799
+ };
26800
+ }
26801
+ function extractPromptOptionsMetadata(options) {
26802
+ if (!options) {
26803
+ return {};
26804
+ }
26805
+ return {
26806
+ ...options.source ? { "pi_coding_agent.source": options.source } : {},
26807
+ ...options.streamingBehavior ? { "pi_coding_agent.streaming_behavior": options.streamingBehavior } : {},
26808
+ ...options.expandPromptTemplates !== void 0 ? {
26809
+ "pi_coding_agent.expand_prompt_templates": options.expandPromptTemplates
26810
+ } : {}
26811
+ };
26812
+ }
26813
+ function extractStreamOptionsMetadata(options) {
26814
+ if (!options) {
26815
+ return {};
26816
+ }
26817
+ return {
26818
+ ...options.temperature !== void 0 ? { temperature: options.temperature } : {},
26819
+ ...options.maxTokens !== void 0 ? { max_tokens: options.maxTokens } : {},
26820
+ ...options.reasoning ? { "pi_coding_agent.reasoning": options.reasoning } : {},
26821
+ ...options.transport ? { "pi_coding_agent.transport": options.transport } : {},
26822
+ ...options.cacheRetention ? { "pi_coding_agent.cache_retention": options.cacheRetention } : {},
26823
+ ...options.sessionId ? { "pi_coding_agent.session_id": options.sessionId } : {},
26824
+ ...options.timeoutMs !== void 0 ? { "pi_coding_agent.timeout_ms": options.timeoutMs } : {},
26825
+ ...options.maxRetries !== void 0 ? { "pi_coding_agent.max_retries": options.maxRetries } : {},
26826
+ ...options.maxRetryDelayMs !== void 0 ? { "pi_coding_agent.max_retry_delay_ms": options.maxRetryDelayMs } : {},
26827
+ ...options.metadata ? { "pi_coding_agent.metadata": options.metadata } : {}
26828
+ };
26829
+ }
26830
+ function getLlmSpanName(model) {
26831
+ switch (model.api) {
26832
+ case "anthropic-messages":
26833
+ return "anthropic.messages.create";
26834
+ case "openai-completions":
26835
+ return "Chat Completion";
26836
+ case "openai-responses":
26837
+ case "azure-openai-responses":
26838
+ case "openai-codex-responses":
26839
+ return "openai.responses.create";
26840
+ case "google-generative-ai":
26841
+ case "google-vertex":
26842
+ return "generate_content";
26843
+ case "mistral-conversations":
26844
+ return "mistral.chat.stream";
26845
+ case "bedrock-converse-stream":
26846
+ return "bedrock.converse_stream";
26847
+ default:
26848
+ return "pi_ai.streamSimple";
26849
+ }
26850
+ }
26851
+ function extractUsageMetrics2(usage) {
26852
+ if (!usage) {
26853
+ return {};
26854
+ }
26855
+ return cleanMetrics5({
26856
+ completion_tokens: usage.output,
26857
+ prompt_cache_creation_tokens: usage.cacheWrite,
26858
+ prompt_cached_tokens: usage.cacheRead,
26859
+ prompt_tokens: usage.input,
26860
+ tokens: usage.totalTokens ?? usage.tokens
26861
+ });
26862
+ }
26863
+ function addMetrics(target, source) {
26864
+ for (const [key, value] of Object.entries(source)) {
26865
+ target[key] = (target[key] ?? 0) + value;
26866
+ }
26867
+ }
26868
+ function buildDurationMetrics3(startTime) {
26869
+ const end = getCurrentUnixTimestamp();
26870
+ return {
26871
+ duration: end - startTime,
26872
+ end,
26873
+ start: startTime
26874
+ };
26875
+ }
26876
+ function cleanMetrics5(metrics) {
26877
+ const cleaned = {};
26878
+ for (const [key, value] of Object.entries(metrics)) {
26879
+ if (typeof value === "number" && Number.isFinite(value) && value >= 0) {
26880
+ cleaned[key] = value;
26881
+ }
26882
+ }
26883
+ return cleaned;
26884
+ }
26885
+ function stringifyArguments(value) {
26886
+ if (typeof value === "string") {
26887
+ return value;
26888
+ }
26889
+ try {
26890
+ return JSON.stringify(value);
26891
+ } catch {
26892
+ return stringifyUnknown2(value);
26893
+ }
26894
+ }
26895
+ function stringifyUnknown2(value) {
26896
+ if (value instanceof Error) {
26897
+ return value.message;
26898
+ }
26899
+ if (typeof value === "string") {
26900
+ return value;
26901
+ }
26902
+ try {
26903
+ return JSON.stringify(value);
26904
+ } catch {
26905
+ return String(value);
26906
+ }
26907
+ }
26908
+ function safeLog4(span, event) {
26909
+ try {
26910
+ span.log(event);
26911
+ } catch (error) {
26912
+ logInstrumentationError4("Pi Coding Agent span log", error);
26913
+ }
26914
+ }
26915
+ function logInstrumentationError4(context, error) {
26916
+ debugLogger.debug(`${context}:`, error);
26917
+ }
26918
+
24882
26919
  // src/instrumentation/braintrust-plugin.ts
24883
26920
  function getIntegrationConfig(integrations, key) {
24884
26921
  return integrations[key];
@@ -24904,6 +26941,7 @@ var BraintrustPlugin = class extends BasePlugin {
24904
26941
  gitHubCopilotPlugin = null;
24905
26942
  fluePlugin = null;
24906
26943
  langChainPlugin = null;
26944
+ piCodingAgentPlugin = null;
24907
26945
  constructor(config = {}) {
24908
26946
  super();
24909
26947
  this.config = config;
@@ -24978,6 +27016,10 @@ var BraintrustPlugin = class extends BasePlugin {
24978
27016
  this.gitHubCopilotPlugin = new GitHubCopilotPlugin();
24979
27017
  this.gitHubCopilotPlugin.enable();
24980
27018
  }
27019
+ if (integrations.piCodingAgent !== false) {
27020
+ this.piCodingAgentPlugin = new PiCodingAgentPlugin();
27021
+ this.piCodingAgentPlugin.enable();
27022
+ }
24981
27023
  if (getIntegrationConfig(integrations, "flue") !== false) {
24982
27024
  this.fluePlugin = new FluePlugin();
24983
27025
  this.fluePlugin.enable();
@@ -25056,6 +27098,10 @@ var BraintrustPlugin = class extends BasePlugin {
25056
27098
  this.gitHubCopilotPlugin.disable();
25057
27099
  this.gitHubCopilotPlugin = null;
25058
27100
  }
27101
+ if (this.piCodingAgentPlugin) {
27102
+ this.piCodingAgentPlugin.disable();
27103
+ this.piCodingAgentPlugin = null;
27104
+ }
25059
27105
  if (this.fluePlugin) {
25060
27106
  this.fluePlugin.disable();
25061
27107
  this.fluePlugin = null;
@@ -25510,6 +27556,7 @@ __export(exports_exports, {
25510
27556
  _internalIso: () => isomorph_default,
25511
27557
  _internalSetInitialState: () => _internalSetInitialState,
25512
27558
  addAzureBlobHeaders: () => addAzureBlobHeaders,
27559
+ braintrustAISDKTelemetry: () => braintrustAISDKTelemetry,
25513
27560
  braintrustFlueObserver: () => braintrustFlueObserver,
25514
27561
  braintrustStreamChunkSchema: () => braintrustStreamChunkSchema,
25515
27562
  buildLocalSummary: () => buildLocalSummary,
@@ -25602,6 +27649,7 @@ __export(exports_exports, {
25602
27649
  wrapOpenAIv4: () => wrapOpenAIv4,
25603
27650
  wrapOpenRouter: () => wrapOpenRouter,
25604
27651
  wrapOpenRouterAgent: () => wrapOpenRouterAgent,
27652
+ wrapPiCodingAgentSDK: () => wrapPiCodingAgentSDK,
25605
27653
  wrapTraced: () => wrapTraced,
25606
27654
  wrapVitest: () => wrapVitest
25607
27655
  });
@@ -27467,6 +29515,54 @@ function wrapCursorAgent(agent) {
27467
29515
  return proxy;
27468
29516
  }
27469
29517
 
29518
+ // src/wrappers/pi-coding-agent.ts
29519
+ var WRAPPED_PROMPT = /* @__PURE__ */ Symbol.for("braintrust.pi-coding-agent.wrapped-prompt");
29520
+ function wrapPiCodingAgentSDK(sdk) {
29521
+ if (!sdk || typeof sdk !== "object") {
29522
+ return sdk;
29523
+ }
29524
+ const maybeSDK = sdk;
29525
+ if (!maybeSDK.AgentSession || typeof maybeSDK.AgentSession !== "function") {
29526
+ console.warn("Unsupported Pi Coding Agent SDK. Not wrapping.");
29527
+ return sdk;
29528
+ }
29529
+ patchAgentSessionClass(
29530
+ maybeSDK.AgentSession
29531
+ );
29532
+ return sdk;
29533
+ }
29534
+ function patchAgentSessionClass(AgentSession) {
29535
+ const prototype = AgentSession.prototype;
29536
+ if (!prototype || prototype[WRAPPED_PROMPT]) {
29537
+ return;
29538
+ }
29539
+ const descriptor = Object.getOwnPropertyDescriptor(prototype, "prompt");
29540
+ if (!descriptor || typeof descriptor.value !== "function") {
29541
+ console.warn("Unsupported Pi Coding Agent SDK. Not wrapping.");
29542
+ return;
29543
+ }
29544
+ const originalPrompt = descriptor.value;
29545
+ Object.defineProperty(prototype, "prompt", {
29546
+ ...descriptor,
29547
+ value: function wrappedPiCodingAgentPrompt(text, options) {
29548
+ const args = [text, options];
29549
+ return piCodingAgentChannels.prompt.tracePromise(
29550
+ () => Reflect.apply(originalPrompt, this, args),
29551
+ {
29552
+ arguments: args,
29553
+ self: this,
29554
+ session: this
29555
+ }
29556
+ );
29557
+ }
29558
+ });
29559
+ Object.defineProperty(prototype, WRAPPED_PROMPT, {
29560
+ configurable: false,
29561
+ enumerable: false,
29562
+ value: true
29563
+ });
29564
+ }
29565
+
27470
29566
  // src/wrappers/google-genai.ts
27471
29567
  function wrapGoogleGenAI(googleGenAI) {
27472
29568
  if (!googleGenAI || typeof googleGenAI !== "object") {
@@ -27503,12 +29599,25 @@ function wrapGoogleGenAIClass(OriginalGoogleGenAI) {
27503
29599
  }
27504
29600
  function wrapGoogleGenAIInstance(instance) {
27505
29601
  const wrappedModels = wrapModels(instance.models);
29602
+ let originalInteractions;
29603
+ let wrappedInteractions;
27506
29604
  patchGoogleGenAIChats(instance, wrappedModels);
27507
29605
  return new Proxy(instance, {
27508
29606
  get(target, prop, receiver) {
27509
29607
  if (prop === "models") {
27510
29608
  return wrappedModels;
27511
29609
  }
29610
+ if (prop === "interactions") {
29611
+ const interactions = Reflect.get(target, prop, receiver);
29612
+ if (!isObject(interactions) || typeof interactions.create !== "function") {
29613
+ return interactions;
29614
+ }
29615
+ if (interactions !== originalInteractions) {
29616
+ originalInteractions = interactions;
29617
+ wrappedInteractions = wrapInteractions(interactions);
29618
+ }
29619
+ return wrappedInteractions;
29620
+ }
27512
29621
  return Reflect.get(target, prop, receiver);
27513
29622
  }
27514
29623
  });
@@ -27535,6 +29644,16 @@ function wrapModels(models) {
27535
29644
  }
27536
29645
  });
27537
29646
  }
29647
+ function wrapInteractions(interactions) {
29648
+ return new Proxy(interactions, {
29649
+ get(target, prop, receiver) {
29650
+ if (prop === "create") {
29651
+ return wrapInteractionCreate(target.create.bind(target));
29652
+ }
29653
+ return Reflect.get(target, prop, receiver);
29654
+ }
29655
+ });
29656
+ }
27538
29657
  function wrapGenerateContent(original) {
27539
29658
  return function(params) {
27540
29659
  return googleGenAIChannels.generateContent.tracePromise(
@@ -27559,6 +29678,18 @@ function wrapEmbedContent(original) {
27559
29678
  );
27560
29679
  };
27561
29680
  }
29681
+ function wrapInteractionCreate(original) {
29682
+ return function(params, options) {
29683
+ if (params.background === true) {
29684
+ return options === void 0 ? original(params) : original(params, options);
29685
+ }
29686
+ const traceContext = options === void 0 ? { arguments: [params] } : { arguments: [params, options] };
29687
+ return googleGenAIChannels.interactionsCreate.tracePromise(
29688
+ () => options === void 0 ? original(params) : original(params, options),
29689
+ traceContext
29690
+ );
29691
+ };
29692
+ }
27562
29693
 
27563
29694
  // src/wrappers/google-adk.ts
27564
29695
  function wrapGoogleADK(adkModule) {
@@ -31076,6 +33207,13 @@ var EvalResultWithSummary = class {
31076
33207
  };
31077
33208
  }
31078
33209
  };
33210
+ async function getPersistedBaseExperimentId(experiment) {
33211
+ try {
33212
+ return await experiment._getBaseExperimentId();
33213
+ } catch {
33214
+ return void 0;
33215
+ }
33216
+ }
31079
33217
  function makeEvalName(projectName, experimentName) {
31080
33218
  let out = projectName;
31081
33219
  if (experimentName) {
@@ -31458,6 +33596,14 @@ async function runEvaluatorInternal(experiment, evaluator, progressReporter, fil
31458
33596
  return;
31459
33597
  }
31460
33598
  const eventDataset = experiment ? experiment.dataset : Dataset2.isDataset(evaluator.data) ? evaluator.data : void 0;
33599
+ const inlineOrigin = datum.origin === void 0 ? void 0 : ObjectReference.parse(datum.origin);
33600
+ const origin = inlineOrigin ?? (eventDataset && datum.id && datum._xact_id ? {
33601
+ object_type: "dataset",
33602
+ object_id: await eventDataset.id,
33603
+ id: datum.id,
33604
+ created: datum.created,
33605
+ _xact_id: datum._xact_id
33606
+ } : void 0);
31461
33607
  const baseEvent = {
31462
33608
  name: "eval",
31463
33609
  spanAttributes: {
@@ -31467,13 +33613,7 @@ async function runEvaluatorInternal(experiment, evaluator, progressReporter, fil
31467
33613
  input: datum.input,
31468
33614
  expected: "expected" in datum ? datum.expected : void 0,
31469
33615
  tags: datum.tags,
31470
- origin: eventDataset && datum.id && datum._xact_id ? {
31471
- object_type: "dataset",
31472
- object_id: await eventDataset.id,
31473
- id: datum.id,
31474
- created: datum.created,
31475
- _xact_id: datum._xact_id
31476
- } : void 0,
33616
+ origin,
31477
33617
  ...datum.upsert_id ? { id: datum.upsert_id } : {}
31478
33618
  }
31479
33619
  };
@@ -31830,8 +33970,10 @@ async function runEvaluatorInternal(experiment, evaluator, progressReporter, fil
31830
33970
  collectedResults.length = 0;
31831
33971
  }
31832
33972
  }
33973
+ const comparisonExperimentId = experiment ? evaluator.baseExperimentId ?? await getPersistedBaseExperimentId(experiment) : void 0;
31833
33974
  const summary = experiment ? await experiment.summarize({
31834
- summarizeScores: evaluator.summarizeScores
33975
+ summarizeScores: evaluator.summarizeScores,
33976
+ ...comparisonExperimentId !== void 0 ? { comparisonExperimentId } : {}
31835
33977
  }) : buildLocalSummary(
31836
33978
  evaluator,
31837
33979
  collectResults ? collectedResults : [],
@@ -32060,6 +34202,7 @@ var Project2 = class {
32060
34202
  prompts;
32061
34203
  parameters;
32062
34204
  scorers;
34205
+ classifiers;
32063
34206
  _publishableCodeFunctions = [];
32064
34207
  _publishablePrompts = [];
32065
34208
  _publishableParameters = [];
@@ -32071,6 +34214,7 @@ var Project2 = class {
32071
34214
  this.prompts = new PromptBuilder(this);
32072
34215
  this.parameters = new ParametersBuilder(this);
32073
34216
  this.scorers = new ScorerBuilder(this);
34217
+ this.classifiers = new ClassifierBuilder(this);
32074
34218
  }
32075
34219
  addPrompt(prompt) {
32076
34220
  this._publishablePrompts.push(prompt);
@@ -32205,6 +34349,28 @@ var ScorerBuilder = class {
32205
34349
  }
32206
34350
  }
32207
34351
  };
34352
+ var ClassifierBuilder = class {
34353
+ constructor(project) {
34354
+ this.project = project;
34355
+ }
34356
+ taskCounter = 0;
34357
+ create(opts) {
34358
+ this.taskCounter++;
34359
+ let resolvedName = opts.name ?? opts.handler.name;
34360
+ if (!resolvedName || resolvedName.trim().length === 0) {
34361
+ resolvedName = `Classifier ${isomorph_default.basename(currentFilename)} ${this.taskCounter}`;
34362
+ }
34363
+ const slug = opts.slug ?? slugify(resolvedName, { lower: true, strict: true });
34364
+ const classifier = new CodeFunction(this.project, {
34365
+ ...opts,
34366
+ name: resolvedName,
34367
+ slug,
34368
+ type: "classifier"
34369
+ });
34370
+ this.project.addCodeFunction(classifier);
34371
+ return classifier;
34372
+ }
34373
+ };
32208
34374
  var CodeFunction = class {
32209
34375
  constructor(project, opts) {
32210
34376
  this.project = project;
@@ -32554,7 +34720,7 @@ var serializedParametersContainerSchema = z13.union([
32554
34720
  staticParametersSchema
32555
34721
  ]);
32556
34722
  var evaluatorDefinitionSchema = z13.object({
32557
- parameters: serializedParametersContainerSchema.optional(),
34723
+ parameters: serializedParametersContainerSchema.nullish(),
32558
34724
  scores: z13.array(z13.object({ name: z13.string() })).optional(),
32559
34725
  classifiers: z13.array(z13.object({ name: z13.string() })).optional()
32560
34726
  });
@@ -32622,6 +34788,7 @@ export {
32622
34788
  isomorph_default as _internalIso,
32623
34789
  _internalSetInitialState,
32624
34790
  addAzureBlobHeaders,
34791
+ braintrustAISDKTelemetry,
32625
34792
  braintrustFlueObserver,
32626
34793
  braintrustStreamChunkSchema,
32627
34794
  buildLocalSummary,
@@ -32715,6 +34882,7 @@ export {
32715
34882
  wrapOpenAIv4,
32716
34883
  wrapOpenRouter,
32717
34884
  wrapOpenRouterAgent,
34885
+ wrapPiCodingAgentSDK,
32718
34886
  wrapTraced,
32719
34887
  wrapVitest
32720
34888
  };