braintrust 3.16.0 → 3.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/bin/bt +41 -0
  2. package/dev/dist/index.d.mts +13 -0
  3. package/dev/dist/index.d.ts +13 -0
  4. package/dev/dist/index.js +4300 -2199
  5. package/dev/dist/index.mjs +2211 -110
  6. package/dist/apply-auto-instrumentation.js +238 -186
  7. package/dist/apply-auto-instrumentation.mjs +68 -16
  8. package/dist/auto-instrumentations/bundler/esbuild.cjs +90 -15
  9. package/dist/auto-instrumentations/bundler/esbuild.mjs +2 -2
  10. package/dist/auto-instrumentations/bundler/next.cjs +90 -15
  11. package/dist/auto-instrumentations/bundler/next.mjs +3 -3
  12. package/dist/auto-instrumentations/bundler/rollup.cjs +90 -15
  13. package/dist/auto-instrumentations/bundler/rollup.mjs +2 -2
  14. package/dist/auto-instrumentations/bundler/vite.cjs +90 -15
  15. package/dist/auto-instrumentations/bundler/vite.mjs +2 -2
  16. package/dist/auto-instrumentations/bundler/webpack-loader.cjs +89 -14
  17. package/dist/auto-instrumentations/bundler/webpack.cjs +90 -15
  18. package/dist/auto-instrumentations/bundler/webpack.mjs +3 -3
  19. package/dist/auto-instrumentations/{chunk-VXJONZVX.mjs → chunk-GNUEZ2PE.mjs} +13 -3
  20. package/dist/auto-instrumentations/{chunk-CNQ7BUKN.mjs → chunk-MYCHHXOE.mjs} +1 -1
  21. package/dist/auto-instrumentations/{chunk-E5DUYJWK.mjs → chunk-ZYKZEMRT.mjs} +82 -15
  22. package/dist/auto-instrumentations/hook.mjs +102 -15
  23. package/dist/auto-instrumentations/index.cjs +84 -16
  24. package/dist/auto-instrumentations/index.d.mts +3 -1
  25. package/dist/auto-instrumentations/index.d.ts +3 -1
  26. package/dist/auto-instrumentations/index.mjs +5 -3
  27. package/dist/auto-instrumentations/loader/cjs-patch.cjs +1 -1
  28. package/dist/auto-instrumentations/loader/cjs-patch.mjs +1 -1
  29. package/dist/auto-instrumentations/loader/esm-hook.mjs +1 -1
  30. package/dist/browser.d.mts +177 -11
  31. package/dist/browser.d.ts +177 -11
  32. package/dist/browser.js +2296 -104
  33. package/dist/browser.mjs +2455 -263
  34. package/dist/{chunk-VMBQETG3.js → chunk-73IYIIOL.js} +28 -2
  35. package/dist/{chunk-O4ZIWXO3.mjs → chunk-BYFADLEZ.mjs} +27 -1
  36. package/dist/cli.js +2228 -113
  37. package/dist/edge-light.d.mts +1 -1
  38. package/dist/edge-light.d.ts +1 -1
  39. package/dist/edge-light.js +2296 -104
  40. package/dist/edge-light.mjs +2455 -263
  41. package/dist/index.d.mts +177 -11
  42. package/dist/index.d.ts +177 -11
  43. package/dist/index.js +3296 -1128
  44. package/dist/index.mjs +2272 -104
  45. package/dist/instrumentation/index.d.mts +3 -0
  46. package/dist/instrumentation/index.d.ts +3 -0
  47. package/dist/instrumentation/index.js +2171 -105
  48. package/dist/instrumentation/index.mjs +2171 -105
  49. package/dist/workerd.d.mts +1 -1
  50. package/dist/workerd.d.ts +1 -1
  51. package/dist/workerd.js +2296 -104
  52. package/dist/workerd.mjs +2455 -263
  53. package/package.json +19 -5
  54. package/scripts/bt-helper.js +139 -0
  55. package/scripts/install.js +153 -0
package/dist/workerd.mjs CHANGED
@@ -4954,14 +4954,18 @@ function useTestBackgroundLogger() {
4954
4954
  function clearTestBackgroundLogger() {
4955
4955
  _internalGetGlobalState()?.setOverrideBgLogger(null);
4956
4956
  }
4957
- function initTestExperiment(experimentName, projectName) {
4957
+ function initTestExperiment(experimentName, projectName, experimentFullInfo = {}) {
4958
4958
  setInitialTestState();
4959
4959
  const state = _internalGetGlobalState();
4960
4960
  const project = projectName ?? experimentName;
4961
4961
  const lazyMetadata = new LazyValue(
4962
4962
  async () => ({
4963
4963
  project: { id: project, name: project, fullInfo: {} },
4964
- experiment: { id: experimentName, name: experimentName, fullInfo: {} }
4964
+ experiment: {
4965
+ id: experimentName,
4966
+ name: experimentName,
4967
+ fullInfo: experimentFullInfo
4968
+ }
4965
4969
  })
4966
4970
  );
4967
4971
  return new Experiment2(state, lazyMetadata);
@@ -8326,6 +8330,10 @@ var Experiment2 = class extends ObjectFetcher {
8326
8330
  return (await this.lazyMetadata.get()).project;
8327
8331
  })();
8328
8332
  }
8333
+ async _getBaseExperimentId() {
8334
+ const baseExperimentId = (await this.lazyMetadata.get()).experiment.fullInfo["base_exp_id"];
8335
+ return typeof baseExperimentId === "string" && baseExperimentId ? baseExperimentId : void 0;
8336
+ }
8329
8337
  parentObjectType() {
8330
8338
  return 1 /* EXPERIMENT */;
8331
8339
  }
@@ -8466,6 +8474,14 @@ var Experiment2 = class extends ObjectFetcher {
8466
8474
  comparisonExperimentId = baseExperiment.id;
8467
8475
  comparisonExperimentName = baseExperiment.name;
8468
8476
  }
8477
+ } else {
8478
+ try {
8479
+ const comparisonExperiment = await state.apiConn().get_json(`v1/experiment/${comparisonExperimentId}`);
8480
+ if (typeof comparisonExperiment["name"] === "string") {
8481
+ comparisonExperimentName = comparisonExperiment["name"];
8482
+ }
8483
+ } catch {
8484
+ }
8469
8485
  }
8470
8486
  try {
8471
8487
  const results = await state.apiConn().get_json(
@@ -10630,6 +10646,64 @@ var BasePlugin = class {
10630
10646
  }
10631
10647
  };
10632
10648
 
10649
+ // src/instrumentation/auto-instrumentation-suppression.ts
10650
+ var autoInstrumentationSuppressionStore;
10651
+ function suppressionStore() {
10652
+ autoInstrumentationSuppressionStore ??= isomorph_default.newAsyncLocalStorage();
10653
+ return autoInstrumentationSuppressionStore;
10654
+ }
10655
+ function currentFrames() {
10656
+ return suppressionStore().getStore()?.frames ?? [];
10657
+ }
10658
+ function isAutoInstrumentationSuppressed() {
10659
+ const frames = currentFrames();
10660
+ return frames[frames.length - 1]?.mode === "suppress";
10661
+ }
10662
+ function runWithAutoInstrumentationSuppressed(callback) {
10663
+ const frame = {
10664
+ id: /* @__PURE__ */ Symbol("braintrust.auto-instrumentation-suppress"),
10665
+ mode: "suppress"
10666
+ };
10667
+ return suppressionStore().run(
10668
+ { frames: [...currentFrames(), frame] },
10669
+ callback
10670
+ );
10671
+ }
10672
+ function bindAutoInstrumentationSuppressionToStart(tracingChannel2) {
10673
+ const startChannel = tracingChannel2.start;
10674
+ if (!startChannel) {
10675
+ return void 0;
10676
+ }
10677
+ const store = suppressionStore();
10678
+ startChannel.bindStore(store, () => ({
10679
+ frames: [
10680
+ ...currentFrames(),
10681
+ {
10682
+ id: /* @__PURE__ */ Symbol("braintrust.auto-instrumentation-suppress"),
10683
+ mode: "suppress"
10684
+ }
10685
+ ]
10686
+ }));
10687
+ return () => {
10688
+ startChannel.unbindStore(store);
10689
+ };
10690
+ }
10691
+ function enterAutoInstrumentationAllowed() {
10692
+ const frame = {
10693
+ id: /* @__PURE__ */ Symbol("braintrust.auto-instrumentation-allow"),
10694
+ mode: "allow"
10695
+ };
10696
+ suppressionStore().enterWith({
10697
+ frames: [...currentFrames(), frame]
10698
+ });
10699
+ return () => {
10700
+ const frames = currentFrames().filter(
10701
+ (candidate) => candidate.id !== frame.id
10702
+ );
10703
+ suppressionStore().enterWith(frames.length > 0 ? { frames } : void 0);
10704
+ };
10705
+ }
10706
+
10633
10707
  // src/instrumentation/core/channel-tracing.ts
10634
10708
  function isSyncStreamLike(value) {
10635
10709
  return !!value && typeof value === "object" && typeof value.on === "function";
@@ -10661,16 +10735,33 @@ function startSpanForEvent(config, event, channelName) {
10661
10735
  metadata: mergeInputMetadata(metadata, spanInfoMetadata)
10662
10736
  });
10663
10737
  } catch (error) {
10664
- console.error(`Error extracting input for ${channelName}:`, error);
10738
+ debugLogger.error(`Error extracting input for ${channelName}:`, error);
10665
10739
  }
10666
10740
  return { span, startTime };
10667
10741
  }
10742
+ function shouldTraceEvent(config, event, channelName) {
10743
+ if (!config.shouldTrace) {
10744
+ return true;
10745
+ }
10746
+ try {
10747
+ return config.shouldTrace(event.arguments, event);
10748
+ } catch (error) {
10749
+ debugLogger.error(
10750
+ `Error checking trace predicate for ${channelName}:`,
10751
+ error
10752
+ );
10753
+ return true;
10754
+ }
10755
+ }
10668
10756
  function ensureSpanStateForEvent(states, config, event, channelName) {
10669
10757
  const key = event;
10670
10758
  const existing = states.get(key);
10671
10759
  if (existing) {
10672
10760
  return existing;
10673
10761
  }
10762
+ if (!shouldTraceEvent(config, event, channelName)) {
10763
+ return void 0;
10764
+ }
10674
10765
  const created = startSpanForEvent(config, event, channelName);
10675
10766
  states.set(key, created);
10676
10767
  return created;
@@ -10686,13 +10777,16 @@ function bindCurrentSpanStoreToStart(tracingChannel2, states, config, channelNam
10686
10777
  startChannel.bindStore(
10687
10778
  currentSpanStore,
10688
10779
  (event) => {
10689
- const span = ensureSpanStateForEvent(
10780
+ if (isAutoInstrumentationSuppressed()) {
10781
+ return currentSpanStore.getStore();
10782
+ }
10783
+ const spanState = ensureSpanStateForEvent(
10690
10784
  states,
10691
10785
  config,
10692
10786
  event,
10693
10787
  channelName
10694
- ).span;
10695
- return contextManager.wrapSpanForStore(span);
10788
+ );
10789
+ return spanState ? contextManager.wrapSpanForStore(spanState.span) : currentSpanStore.getStore();
10696
10790
  }
10697
10791
  );
10698
10792
  return () => {
@@ -10727,7 +10821,10 @@ function runStreamingCompletionHook(args) {
10727
10821
  startTime: args.startTime
10728
10822
  });
10729
10823
  } catch (error) {
10730
- console.error(`Error in onComplete hook for ${args.channelName}:`, error);
10824
+ debugLogger.error(
10825
+ `Error in onComplete hook for ${args.channelName}:`,
10826
+ error
10827
+ );
10731
10828
  }
10732
10829
  }
10733
10830
  function traceAsyncChannel(channel2, config) {
@@ -10742,6 +10839,9 @@ function traceAsyncChannel(channel2, config) {
10742
10839
  );
10743
10840
  const handlers = {
10744
10841
  start: (event) => {
10842
+ if (isAutoInstrumentationSuppressed()) {
10843
+ return;
10844
+ }
10745
10845
  ensureSpanStateForEvent(
10746
10846
  states,
10747
10847
  config,
@@ -10776,7 +10876,7 @@ function traceAsyncChannel(channel2, config) {
10776
10876
  metrics
10777
10877
  });
10778
10878
  } catch (error) {
10779
- console.error(`Error extracting output for ${channelName}:`, error);
10879
+ debugLogger.error(`Error extracting output for ${channelName}:`, error);
10780
10880
  } finally {
10781
10881
  span.end();
10782
10882
  states.delete(event);
@@ -10804,6 +10904,9 @@ function traceStreamingChannel(channel2, config) {
10804
10904
  );
10805
10905
  const handlers = {
10806
10906
  start: (event) => {
10907
+ if (isAutoInstrumentationSuppressed()) {
10908
+ return;
10909
+ }
10807
10910
  ensureSpanStateForEvent(
10808
10911
  states,
10809
10912
  config,
@@ -10875,7 +10978,7 @@ function traceStreamingChannel(channel2, config) {
10875
10978
  metrics
10876
10979
  });
10877
10980
  } catch (error) {
10878
- console.error(
10981
+ debugLogger.error(
10879
10982
  `Error extracting output for ${channelName}:`,
10880
10983
  error
10881
10984
  );
@@ -10935,7 +11038,7 @@ function traceStreamingChannel(channel2, config) {
10935
11038
  metrics
10936
11039
  });
10937
11040
  } catch (error) {
10938
- console.error(`Error extracting output for ${channelName}:`, error);
11041
+ debugLogger.error(`Error extracting output for ${channelName}:`, error);
10939
11042
  } finally {
10940
11043
  span.end();
10941
11044
  states.delete(event);
@@ -10963,6 +11066,9 @@ function traceSyncStreamChannel(channel2, config) {
10963
11066
  );
10964
11067
  const handlers = {
10965
11068
  start: (event) => {
11069
+ if (isAutoInstrumentationSuppressed()) {
11070
+ return;
11071
+ }
10966
11072
  ensureSpanStateForEvent(
10967
11073
  states,
10968
11074
  config,
@@ -11016,7 +11122,7 @@ function traceSyncStreamChannel(channel2, config) {
11016
11122
  });
11017
11123
  }
11018
11124
  } catch (error) {
11019
- console.error(
11125
+ debugLogger.error(
11020
11126
  `Error extracting chatCompletion for ${channelName}:`,
11021
11127
  error
11022
11128
  );
@@ -11040,7 +11146,10 @@ function traceSyncStreamChannel(channel2, config) {
11040
11146
  span.log(extracted);
11041
11147
  }
11042
11148
  } catch (error) {
11043
- console.error(`Error extracting event for ${channelName}:`, error);
11149
+ debugLogger.error(
11150
+ `Error extracting event for ${channelName}:`,
11151
+ error
11152
+ );
11044
11153
  }
11045
11154
  });
11046
11155
  stream.on("end", () => {
@@ -12569,6 +12678,9 @@ var AnthropicPlugin = class extends BasePlugin {
12569
12678
  const states = /* @__PURE__ */ new WeakMap();
12570
12679
  const handlers = {
12571
12680
  start: (event) => {
12681
+ if (isAutoInstrumentationSuppressed()) {
12682
+ return;
12683
+ }
12572
12684
  const params = event.arguments[0] ?? {};
12573
12685
  const span = startSpan({
12574
12686
  name: "anthropic.beta.messages.toolRunner",
@@ -13298,6 +13410,520 @@ function serializeAISDKToolsForLogging(tools) {
13298
13410
  return serialized;
13299
13411
  }
13300
13412
 
13413
+ // src/wrappers/ai-sdk/telemetry.ts
13414
+ function braintrustAISDKTelemetry() {
13415
+ const operations = /* @__PURE__ */ new Map();
13416
+ const modelSpans = /* @__PURE__ */ new Map();
13417
+ const objectSpans = /* @__PURE__ */ new Map();
13418
+ const embedSpans = /* @__PURE__ */ new Map();
13419
+ const rerankSpans = /* @__PURE__ */ new Map();
13420
+ const toolSpans = /* @__PURE__ */ new Map();
13421
+ const runSafely = (name, callback) => {
13422
+ try {
13423
+ callback();
13424
+ } catch (error) {
13425
+ console.error(`Error in Braintrust AI SDK telemetry ${name}:`, error);
13426
+ }
13427
+ };
13428
+ const startChildSpan = (callId, name, type, event) => {
13429
+ const parent = operations.get(callId)?.span;
13430
+ const spanArgs = {
13431
+ name,
13432
+ spanAttributes: { type },
13433
+ ...event ? { event } : {}
13434
+ };
13435
+ const span = parent ? parent.startSpan(spanArgs) : startSpan(spanArgs);
13436
+ const state = operations.get(callId);
13437
+ if (state && type === "llm" /* LLM */) {
13438
+ state.hadModelChild = true;
13439
+ }
13440
+ return span;
13441
+ };
13442
+ return {
13443
+ onStart(event) {
13444
+ runSafely("onStart", () => {
13445
+ const operationName = operationNameFromId(event.operationId);
13446
+ const span = startSpan({
13447
+ name: operationName,
13448
+ spanAttributes: { type: "function" /* FUNCTION */ }
13449
+ });
13450
+ operations.set(event.callId, {
13451
+ hadModelChild: false,
13452
+ operationName,
13453
+ span,
13454
+ startTime: getCurrentUnixTimestamp()
13455
+ });
13456
+ const metadata = metadataFromEvent(event);
13457
+ const logPayload = { metadata };
13458
+ if (shouldRecordInputs(event)) {
13459
+ const { input, outputPromise } = processAISDKCallInput(
13460
+ operationInput(event, operationName)
13461
+ );
13462
+ logPayload.input = input;
13463
+ if (outputPromise && input && typeof input === "object") {
13464
+ outputPromise.then((resolvedData) => {
13465
+ span.log({
13466
+ input: {
13467
+ ...input,
13468
+ ...resolvedData
13469
+ }
13470
+ });
13471
+ }).catch(() => {
13472
+ });
13473
+ }
13474
+ }
13475
+ span.log(logPayload);
13476
+ });
13477
+ },
13478
+ onLanguageModelCallStart(event) {
13479
+ runSafely("onLanguageModelCallStart", () => {
13480
+ const state = operations.get(event.callId);
13481
+ const openSpans = modelSpans.get(event.callId);
13482
+ if (openSpans) {
13483
+ for (const span2 of openSpans) {
13484
+ span2.end();
13485
+ }
13486
+ modelSpans.delete(event.callId);
13487
+ }
13488
+ const span = startChildSpan(
13489
+ event.callId,
13490
+ state?.operationName === "streamText" ? "doStream" : "doGenerate",
13491
+ "llm" /* LLM */,
13492
+ {
13493
+ ...shouldRecordInputs(event) ? {
13494
+ input: processAISDKCallInput(
13495
+ operationInput(
13496
+ event,
13497
+ state?.operationName ?? "generateText"
13498
+ )
13499
+ ).input
13500
+ } : {},
13501
+ metadata: metadataFromEvent(event)
13502
+ }
13503
+ );
13504
+ const spans = modelSpans.get(event.callId) ?? [];
13505
+ spans.push(span);
13506
+ modelSpans.set(event.callId, spans);
13507
+ });
13508
+ },
13509
+ onLanguageModelCallEnd(event) {
13510
+ runSafely("onLanguageModelCallEnd", () => {
13511
+ const span = shiftModelSpan(modelSpans, event.callId);
13512
+ if (!span) {
13513
+ return;
13514
+ }
13515
+ const result = {
13516
+ ...event,
13517
+ response: event.responseId ? { id: event.responseId } : void 0
13518
+ };
13519
+ span.log({
13520
+ ...shouldRecordOutputs(event) ? {
13521
+ output: processAISDKOutput(result, DEFAULT_DENY_OUTPUT_PATHS)
13522
+ } : {},
13523
+ metrics: extractTokenMetrics(result)
13524
+ });
13525
+ span.end();
13526
+ });
13527
+ },
13528
+ onObjectStepStart(event) {
13529
+ runSafely("onObjectStepStart", () => {
13530
+ const state = operations.get(event.callId);
13531
+ const openSpan = objectSpans.get(event.callId);
13532
+ if (openSpan) {
13533
+ openSpan.end();
13534
+ objectSpans.delete(event.callId);
13535
+ }
13536
+ const span = startChildSpan(
13537
+ event.callId,
13538
+ state?.operationName === "streamObject" ? "doStream" : "doGenerate",
13539
+ "llm" /* LLM */,
13540
+ {
13541
+ ...shouldRecordInputs(event) ? {
13542
+ input: {
13543
+ prompt: event.promptMessages
13544
+ }
13545
+ } : {},
13546
+ metadata: metadataFromEvent(event)
13547
+ }
13548
+ );
13549
+ objectSpans.set(event.callId, span);
13550
+ });
13551
+ },
13552
+ onObjectStepFinish(event) {
13553
+ runSafely("onObjectStepFinish", () => {
13554
+ const span = objectSpans.get(event.callId);
13555
+ if (!span) {
13556
+ return;
13557
+ }
13558
+ const result = {
13559
+ ...event,
13560
+ text: event.objectText
13561
+ };
13562
+ span.log({
13563
+ ...shouldRecordOutputs(event) ? {
13564
+ output: processAISDKOutput(result, DEFAULT_DENY_OUTPUT_PATHS)
13565
+ } : {},
13566
+ metrics: extractTokenMetrics(result)
13567
+ });
13568
+ span.end();
13569
+ objectSpans.delete(event.callId);
13570
+ });
13571
+ },
13572
+ onEmbedStart(event) {
13573
+ runSafely("onEmbedStart", () => {
13574
+ const state = operations.get(event.callId);
13575
+ for (const [embedCallId, embedState] of embedSpans) {
13576
+ if (embedState.callId === event.callId && (state?.operationName === "embed" || embedState.values === event.values)) {
13577
+ embedState.span.end();
13578
+ embedSpans.delete(embedCallId);
13579
+ }
13580
+ }
13581
+ const span = startChildSpan(
13582
+ event.callId,
13583
+ "doEmbed",
13584
+ "llm" /* LLM */,
13585
+ {
13586
+ ...shouldRecordInputs(event) ? {
13587
+ input: {
13588
+ values: event.values
13589
+ }
13590
+ } : {},
13591
+ metadata: metadataFromEvent(event)
13592
+ }
13593
+ );
13594
+ embedSpans.set(event.embedCallId, {
13595
+ callId: event.callId,
13596
+ span,
13597
+ values: event.values
13598
+ });
13599
+ });
13600
+ },
13601
+ onEmbedFinish(event) {
13602
+ runSafely("onEmbedFinish", () => {
13603
+ const state = embedSpans.get(event.embedCallId);
13604
+ if (!state) {
13605
+ return;
13606
+ }
13607
+ const result = {
13608
+ ...event,
13609
+ embeddings: event.embeddings
13610
+ };
13611
+ state.span.log({
13612
+ ...shouldRecordOutputs(event) ? {
13613
+ output: processAISDKEmbeddingOutput(
13614
+ result,
13615
+ DEFAULT_DENY_OUTPUT_PATHS
13616
+ )
13617
+ } : {},
13618
+ metrics: extractTokenMetrics(result)
13619
+ });
13620
+ state.span.end();
13621
+ embedSpans.delete(event.embedCallId);
13622
+ });
13623
+ },
13624
+ onRerankStart(event) {
13625
+ runSafely("onRerankStart", () => {
13626
+ const openSpan = rerankSpans.get(event.callId);
13627
+ if (openSpan) {
13628
+ openSpan.end();
13629
+ rerankSpans.delete(event.callId);
13630
+ }
13631
+ const span = startChildSpan(
13632
+ event.callId,
13633
+ "doRerank",
13634
+ "llm" /* LLM */,
13635
+ {
13636
+ ...shouldRecordInputs(event) ? {
13637
+ input: {
13638
+ documents: event.documents,
13639
+ query: event.query,
13640
+ topN: event.topN
13641
+ }
13642
+ } : {},
13643
+ metadata: metadataFromEvent(event)
13644
+ }
13645
+ );
13646
+ rerankSpans.set(event.callId, span);
13647
+ });
13648
+ },
13649
+ onRerankFinish(event) {
13650
+ runSafely("onRerankFinish", () => {
13651
+ const span = rerankSpans.get(event.callId);
13652
+ if (!span) {
13653
+ return;
13654
+ }
13655
+ const result = {
13656
+ ranking: event.ranking?.map((entry) => ({
13657
+ originalIndex: entry.index,
13658
+ score: entry.relevanceScore
13659
+ }))
13660
+ };
13661
+ span.log({
13662
+ ...shouldRecordOutputs(event) ? {
13663
+ output: processAISDKRerankOutput(
13664
+ result,
13665
+ DEFAULT_DENY_OUTPUT_PATHS
13666
+ )
13667
+ } : {}
13668
+ });
13669
+ span.end();
13670
+ rerankSpans.delete(event.callId);
13671
+ });
13672
+ },
13673
+ onToolExecutionStart(event) {
13674
+ runSafely("onToolExecutionStart", () => {
13675
+ const toolCallId = event.toolCall.toolCallId;
13676
+ if (!toolCallId) {
13677
+ return;
13678
+ }
13679
+ const span = startChildSpan(
13680
+ event.callId,
13681
+ event.toolCall.toolName || "tool",
13682
+ "tool" /* TOOL */,
13683
+ {
13684
+ ...shouldRecordInputs(event) ? {
13685
+ input: event.toolCall.input
13686
+ } : {},
13687
+ metadata: {
13688
+ ...createAISDKIntegrationMetadata(),
13689
+ toolCallId,
13690
+ ...typeof event.toolCall.toolName === "string" ? { toolName: event.toolCall.toolName } : {}
13691
+ }
13692
+ }
13693
+ );
13694
+ toolSpans.set(toolCallId, { callId: event.callId, span });
13695
+ });
13696
+ },
13697
+ onToolExecutionEnd(event) {
13698
+ runSafely("onToolExecutionEnd", () => {
13699
+ const toolCallId = event.toolCall.toolCallId;
13700
+ const state = toolCallId ? toolSpans.get(toolCallId) : void 0;
13701
+ if (!toolCallId || !state) {
13702
+ return;
13703
+ }
13704
+ const toolOutput = event.toolOutput;
13705
+ if (toolOutput?.type === "tool-error") {
13706
+ state.span.log({
13707
+ error: toolOutput.error instanceof Error ? toolOutput.error.message : String(toolOutput?.error),
13708
+ metrics: typeof event.durationMs === "number" ? { duration_ms: event.durationMs } : {}
13709
+ });
13710
+ } else {
13711
+ state.span.log({
13712
+ ...shouldRecordOutputs(event) ? { output: toolOutput?.output } : {},
13713
+ metrics: typeof event.durationMs === "number" ? { duration_ms: event.durationMs } : {}
13714
+ });
13715
+ }
13716
+ state.span.end();
13717
+ toolSpans.delete(toolCallId);
13718
+ });
13719
+ },
13720
+ onChunk(event) {
13721
+ runSafely("onChunk", () => {
13722
+ const callId = event.chunk?.callId;
13723
+ if (!callId) {
13724
+ return;
13725
+ }
13726
+ const state = operations.get(callId);
13727
+ if (!state || state.firstChunkTime !== void 0) {
13728
+ return;
13729
+ }
13730
+ state.firstChunkTime = getCurrentUnixTimestamp();
13731
+ });
13732
+ },
13733
+ onFinish(event) {
13734
+ runSafely("onFinish", () => {
13735
+ const state = operations.get(event.callId);
13736
+ if (!state) {
13737
+ return;
13738
+ }
13739
+ const result = finishResult(event, state.operationName);
13740
+ const metrics = state.hadModelChild ? {} : extractTokenMetrics(result);
13741
+ if (state.firstChunkTime !== void 0) {
13742
+ metrics.time_to_first_token = state.firstChunkTime - state.startTime;
13743
+ }
13744
+ state.span.log({
13745
+ ...shouldRecordOutputs(event) ? {
13746
+ output: finishOutput(result, state.operationName)
13747
+ } : {},
13748
+ metrics
13749
+ });
13750
+ state.span.end();
13751
+ operations.delete(event.callId);
13752
+ });
13753
+ },
13754
+ onError(event) {
13755
+ runSafely("onError", () => {
13756
+ const errorEvent = isObject(event) ? event : {};
13757
+ const callId = typeof errorEvent.callId === "string" ? errorEvent.callId : void 0;
13758
+ if (!callId) {
13759
+ return;
13760
+ }
13761
+ const state = operations.get(callId);
13762
+ if (!state) {
13763
+ return;
13764
+ }
13765
+ const error = errorEvent.error ?? event;
13766
+ const openModelSpans = modelSpans.get(callId);
13767
+ if (openModelSpans) {
13768
+ for (const span of openModelSpans) {
13769
+ logError(span, error);
13770
+ span.end();
13771
+ }
13772
+ modelSpans.delete(callId);
13773
+ }
13774
+ const openObjectSpan = objectSpans.get(callId);
13775
+ if (openObjectSpan) {
13776
+ logError(openObjectSpan, error);
13777
+ openObjectSpan.end();
13778
+ objectSpans.delete(callId);
13779
+ }
13780
+ for (const [embedCallId, embedState] of embedSpans) {
13781
+ if (embedState.callId === callId) {
13782
+ logError(embedState.span, error);
13783
+ embedState.span.end();
13784
+ embedSpans.delete(embedCallId);
13785
+ }
13786
+ }
13787
+ const openRerankSpan = rerankSpans.get(callId);
13788
+ if (openRerankSpan) {
13789
+ logError(openRerankSpan, error);
13790
+ openRerankSpan.end();
13791
+ rerankSpans.delete(callId);
13792
+ }
13793
+ for (const [toolCallId, toolState] of toolSpans) {
13794
+ if (toolState.callId === callId) {
13795
+ logError(toolState.span, error);
13796
+ toolState.span.end();
13797
+ toolSpans.delete(toolCallId);
13798
+ }
13799
+ }
13800
+ logError(state.span, error);
13801
+ state.span.end();
13802
+ operations.delete(callId);
13803
+ });
13804
+ },
13805
+ executeTool({ toolCallId, execute }) {
13806
+ const state = toolSpans.get(toolCallId);
13807
+ return state ? withCurrent(state.span, () => execute()) : execute();
13808
+ }
13809
+ };
13810
+ }
13811
+ function shouldRecordInputs(event) {
13812
+ return event.recordInputs !== false;
13813
+ }
13814
+ function shouldRecordOutputs(event) {
13815
+ return event.recordOutputs !== false;
13816
+ }
13817
+ function operationNameFromId(operationId) {
13818
+ return operationId?.startsWith("ai.") ? operationId.slice("ai.".length) : operationId || "ai-sdk";
13819
+ }
13820
+ function modelFromEvent(event) {
13821
+ return event.modelId ? {
13822
+ modelId: event.modelId,
13823
+ ...event.provider ? { provider: event.provider } : {}
13824
+ } : void 0;
13825
+ }
13826
+ function metadataFromEvent(event) {
13827
+ const metadata = createAISDKIntegrationMetadata();
13828
+ const { model, provider } = serializeModelWithProvider(modelFromEvent(event));
13829
+ if (model) {
13830
+ metadata.model = model;
13831
+ }
13832
+ if (provider) {
13833
+ metadata.provider = provider;
13834
+ }
13835
+ if (typeof event.functionId === "string") {
13836
+ metadata.functionId = event.functionId;
13837
+ }
13838
+ return metadata;
13839
+ }
13840
+ function operationInput(event, operationName) {
13841
+ if (operationName === "embed") {
13842
+ return {
13843
+ model: modelFromEvent(event),
13844
+ value: event.value
13845
+ };
13846
+ }
13847
+ if (operationName === "embedMany") {
13848
+ return {
13849
+ model: modelFromEvent(event),
13850
+ values: Array.isArray(event.value) ? event.value ?? [] : void 0
13851
+ };
13852
+ }
13853
+ if (operationName === "rerank") {
13854
+ return {
13855
+ model: modelFromEvent(event),
13856
+ documents: event.documents,
13857
+ query: event.query,
13858
+ topN: event.topN
13859
+ };
13860
+ }
13861
+ return {
13862
+ model: modelFromEvent(event),
13863
+ system: event.system,
13864
+ prompt: event.prompt,
13865
+ messages: event.messages,
13866
+ tools: event.tools,
13867
+ toolChoice: event.toolChoice,
13868
+ activeTools: event.activeTools,
13869
+ output: event.output,
13870
+ schema: event.schema,
13871
+ schemaName: event.schemaName,
13872
+ schemaDescription: event.schemaDescription,
13873
+ maxOutputTokens: event.maxOutputTokens,
13874
+ temperature: event.temperature,
13875
+ topP: event.topP,
13876
+ topK: event.topK,
13877
+ presencePenalty: event.presencePenalty,
13878
+ frequencyPenalty: event.frequencyPenalty,
13879
+ seed: event.seed,
13880
+ maxRetries: event.maxRetries,
13881
+ headers: event.headers,
13882
+ providerOptions: event.providerOptions
13883
+ };
13884
+ }
13885
+ function shiftModelSpan(modelSpans, callId) {
13886
+ const spans = modelSpans.get(callId);
13887
+ const span = spans?.shift();
13888
+ if (spans && spans.length === 0) {
13889
+ modelSpans.delete(callId);
13890
+ }
13891
+ return span;
13892
+ }
13893
+ function finishResult(event, operationName) {
13894
+ if (operationName === "embed") {
13895
+ return {
13896
+ ...event,
13897
+ embedding: event.embedding
13898
+ };
13899
+ }
13900
+ if (operationName === "embedMany") {
13901
+ return {
13902
+ ...event,
13903
+ embeddings: event.embedding
13904
+ };
13905
+ }
13906
+ if (operationName === "rerank") {
13907
+ return event;
13908
+ }
13909
+ return event;
13910
+ }
13911
+ function finishOutput(result, operationName) {
13912
+ if (operationName === "embed" || operationName === "embedMany") {
13913
+ return processAISDKEmbeddingOutput(
13914
+ result,
13915
+ DEFAULT_DENY_OUTPUT_PATHS
13916
+ );
13917
+ }
13918
+ if (operationName === "rerank") {
13919
+ return processAISDKRerankOutput(
13920
+ result,
13921
+ DEFAULT_DENY_OUTPUT_PATHS
13922
+ );
13923
+ }
13924
+ return processAISDKOutput(result, DEFAULT_DENY_OUTPUT_PATHS);
13925
+ }
13926
+
13301
13927
  // src/instrumentation/plugins/ai-sdk-channels.ts
13302
13928
  var aiSDKChannels = defineChannels("ai", {
13303
13929
  generateText: channel({
@@ -13357,6 +13983,10 @@ var aiSDKChannels = defineChannels("ai", {
13357
13983
  toolLoopAgentStream: channel({
13358
13984
  channelName: "ToolLoopAgent.stream",
13359
13985
  kind: "async"
13986
+ }),
13987
+ v7CreateTelemetryDispatcher: channel({
13988
+ channelName: "createTelemetryDispatcher",
13989
+ kind: "sync-stream"
13360
13990
  })
13361
13991
  });
13362
13992
 
@@ -13377,9 +14007,30 @@ var DEFAULT_DENY_OUTPUT_PATHS = [
13377
14007
  ];
13378
14008
  var AUTO_PATCHED_MODEL = /* @__PURE__ */ Symbol.for("braintrust.ai-sdk.auto-patched-model");
13379
14009
  var AUTO_PATCHED_TOOL = /* @__PURE__ */ Symbol.for("braintrust.ai-sdk.auto-patched-tool");
14010
+ var AUTO_PATCHED_V7_TELEMETRY_DISPATCHER = /* @__PURE__ */ Symbol.for(
14011
+ "braintrust.ai-sdk.v7.auto-patched-telemetry-dispatcher"
14012
+ );
13380
14013
  var RUNTIME_DENY_OUTPUT_PATHS = /* @__PURE__ */ Symbol.for(
13381
14014
  "braintrust.ai-sdk.deny-output-paths"
13382
14015
  );
14016
+ var AI_SDK_V7_TELEMETRY_CALLBACKS = [
14017
+ "onStart",
14018
+ "onStepStart",
14019
+ "onLanguageModelCallStart",
14020
+ "onLanguageModelCallEnd",
14021
+ "onToolExecutionStart",
14022
+ "onToolExecutionEnd",
14023
+ "onChunk",
14024
+ "onStepFinish",
14025
+ "onObjectStepStart",
14026
+ "onObjectStepFinish",
14027
+ "onEmbedStart",
14028
+ "onEmbedFinish",
14029
+ "onRerankStart",
14030
+ "onRerankFinish",
14031
+ "onFinish",
14032
+ "onError"
14033
+ ];
13383
14034
  var AISDKPlugin = class extends BasePlugin {
13384
14035
  config;
13385
14036
  constructor(config = {}) {
@@ -13394,6 +14045,7 @@ var AISDKPlugin = class extends BasePlugin {
13394
14045
  }
13395
14046
  subscribeToAISDK() {
13396
14047
  const denyOutputPaths = this.config.denyOutputPaths || DEFAULT_DENY_OUTPUT_PATHS;
14048
+ this.unsubscribers.push(subscribeToAISDKV7TelemetryDispatcher());
13397
14049
  this.unsubscribers.push(
13398
14050
  traceStreamingChannel(aiSDKChannels.generateText, {
13399
14051
  name: "generateText",
@@ -13618,18 +14270,69 @@ var AISDKPlugin = class extends BasePlugin {
13618
14270
  );
13619
14271
  }
13620
14272
  };
13621
- function resolveDenyOutputPaths(event, defaultDenyOutputPaths) {
13622
- if (Array.isArray(event?.denyOutputPaths)) {
13623
- return event.denyOutputPaths;
13624
- }
13625
- const firstArgument2 = event?.arguments && event.arguments.length > 0 ? event.arguments[0] : void 0;
13626
- if (!firstArgument2 || typeof firstArgument2 !== "object") {
13627
- return defaultDenyOutputPaths;
13628
- }
13629
- const runtimeDenyOutputPaths = firstArgument2[RUNTIME_DENY_OUTPUT_PATHS];
13630
- if (Array.isArray(runtimeDenyOutputPaths) && runtimeDenyOutputPaths.every((path) => typeof path === "string")) {
13631
- return runtimeDenyOutputPaths;
13632
- }
14273
+ function subscribeToAISDKV7TelemetryDispatcher() {
14274
+ const channel2 = aiSDKChannels.v7CreateTelemetryDispatcher.tracingChannel();
14275
+ const telemetry = braintrustAISDKTelemetry();
14276
+ const handlers = {
14277
+ end: (event) => {
14278
+ const telemetryOptions = event.arguments?.[0]?.telemetry;
14279
+ if (telemetryOptions?.isEnabled === false) {
14280
+ return;
14281
+ }
14282
+ patchAISDKV7TelemetryDispatcher(event.result, telemetry);
14283
+ }
14284
+ };
14285
+ channel2.subscribe(handlers);
14286
+ return () => {
14287
+ channel2.unsubscribe(handlers);
14288
+ };
14289
+ }
14290
+ function patchAISDKV7TelemetryDispatcher(dispatcher, telemetry) {
14291
+ if (!isObject(dispatcher)) {
14292
+ return;
14293
+ }
14294
+ const dispatcherRecord = dispatcher;
14295
+ if (dispatcherRecord[AUTO_PATCHED_V7_TELEMETRY_DISPATCHER]) {
14296
+ return;
14297
+ }
14298
+ dispatcherRecord[AUTO_PATCHED_V7_TELEMETRY_DISPATCHER] = true;
14299
+ for (const key of AI_SDK_V7_TELEMETRY_CALLBACKS) {
14300
+ const braintrustCallback = telemetry[key];
14301
+ if (typeof braintrustCallback !== "function") {
14302
+ continue;
14303
+ }
14304
+ const existingCallback = dispatcherRecord[key];
14305
+ dispatcherRecord[key] = (event) => {
14306
+ const existingResult = typeof existingCallback === "function" ? existingCallback.call(dispatcher, event) : void 0;
14307
+ const braintrustResult = braintrustCallback.call(telemetry, event);
14308
+ const pending = [existingResult, braintrustResult].filter(isPromiseLike);
14309
+ if (pending.length > 0) {
14310
+ return Promise.allSettled(pending).then(() => void 0);
14311
+ }
14312
+ };
14313
+ }
14314
+ const braintrustExecuteTool = telemetry.executeTool;
14315
+ if (typeof braintrustExecuteTool !== "function") {
14316
+ return;
14317
+ }
14318
+ const existingExecuteTool = dispatcherRecord.executeTool;
14319
+ dispatcherRecord.executeTool = (args) => braintrustExecuteTool.call(telemetry, {
14320
+ ...args,
14321
+ execute: () => typeof existingExecuteTool === "function" ? existingExecuteTool.call(dispatcher, args) : args.execute()
14322
+ });
14323
+ }
14324
+ function resolveDenyOutputPaths(event, defaultDenyOutputPaths) {
14325
+ if (Array.isArray(event?.denyOutputPaths)) {
14326
+ return event.denyOutputPaths;
14327
+ }
14328
+ const firstArgument2 = event?.arguments && event.arguments.length > 0 ? event.arguments[0] : void 0;
14329
+ if (!firstArgument2 || typeof firstArgument2 !== "object") {
14330
+ return defaultDenyOutputPaths;
14331
+ }
14332
+ const runtimeDenyOutputPaths = firstArgument2[RUNTIME_DENY_OUTPUT_PATHS];
14333
+ if (Array.isArray(runtimeDenyOutputPaths) && runtimeDenyOutputPaths.every((path) => typeof path === "string")) {
14334
+ return runtimeDenyOutputPaths;
14335
+ }
13633
14336
  return defaultDenyOutputPaths;
13634
14337
  }
13635
14338
  var isZodSchema2 = (value) => {
@@ -14069,11 +14772,11 @@ function prepareAISDKChildTracing(params, self, parentSpan, denyOutputPaths, aiS
14069
14772
  metadata: baseMetadata
14070
14773
  }
14071
14774
  });
14775
+ const streamStartTime = getCurrentUnixTimestamp();
14072
14776
  const result = await withCurrent(
14073
14777
  span,
14074
14778
  () => Reflect.apply(originalDoStream, resolvedModel, [options])
14075
14779
  );
14076
- const streamStartTime = getCurrentUnixTimestamp();
14077
14780
  let firstChunkTime;
14078
14781
  const output = {};
14079
14782
  let text = "";
@@ -14082,7 +14785,7 @@ function prepareAISDKChildTracing(params, self, parentSpan, denyOutputPaths, aiS
14082
14785
  let object = void 0;
14083
14786
  const transformStream = new TransformStream({
14084
14787
  transform(chunk, controller) {
14085
- if (firstChunkTime === void 0) {
14788
+ if (firstChunkTime === void 0 && isAISDKContentStreamChunk(chunk)) {
14086
14789
  firstChunkTime = getCurrentUnixTimestamp();
14087
14790
  }
14088
14791
  switch (chunk.type) {
@@ -14274,6 +14977,78 @@ function finalizeAISDKChildTracing(event) {
14274
14977
  delete event.__braintrust_ai_sdk_cleanup;
14275
14978
  }
14276
14979
  }
14980
+ function extractAISDKStreamPart(chunk) {
14981
+ if (!isObject(chunk) || !isObject(chunk.part)) {
14982
+ return chunk;
14983
+ }
14984
+ return chunk.part;
14985
+ }
14986
+ function stringContent(value) {
14987
+ return typeof value === "string" && value.length > 0 ? value : void 0;
14988
+ }
14989
+ function rawValueHasAISDKContent(value) {
14990
+ if (value === void 0 || value === null) {
14991
+ return false;
14992
+ }
14993
+ if (typeof value === "string") {
14994
+ return value.length > 0;
14995
+ }
14996
+ if (!isObject(value)) {
14997
+ return true;
14998
+ }
14999
+ const delta = value.delta;
15000
+ 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) => {
15001
+ if (!isObject(choice) || !isObject(choice.delta)) {
15002
+ return false;
15003
+ }
15004
+ const choiceDelta = choice.delta;
15005
+ if (stringContent(choiceDelta.content) || stringContent(choiceDelta.text)) {
15006
+ return true;
15007
+ }
15008
+ if (isObject(choiceDelta.function_call) && stringContent(choiceDelta.function_call.arguments)) {
15009
+ return true;
15010
+ }
15011
+ return Array.isArray(choiceDelta.tool_calls) && choiceDelta.tool_calls.some(
15012
+ (toolCall) => isObject(toolCall) && isObject(toolCall.function) && stringContent(toolCall.function.arguments)
15013
+ );
15014
+ })) {
15015
+ return true;
15016
+ }
15017
+ return false;
15018
+ }
15019
+ function isAISDKContentStreamChunk(chunk) {
15020
+ const part = extractAISDKStreamPart(chunk);
15021
+ if (typeof part === "string") {
15022
+ return part.length > 0;
15023
+ }
15024
+ if (!isObject(part) || typeof part.type !== "string") {
15025
+ return false;
15026
+ }
15027
+ switch (part.type) {
15028
+ case "text-delta":
15029
+ return stringContent(part.textDelta) !== void 0 || stringContent(part.delta) !== void 0 || stringContent(part.text) !== void 0 || stringContent(part.content) !== void 0;
15030
+ case "reasoning-delta":
15031
+ return stringContent(part.delta) !== void 0 || stringContent(part.text) !== void 0 || stringContent(part.content) !== void 0;
15032
+ case "tool-call":
15033
+ case "object":
15034
+ case "file":
15035
+ return true;
15036
+ case "tool-input-delta":
15037
+ case "tool-call-delta":
15038
+ 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;
15039
+ case "raw":
15040
+ return rawValueHasAISDKContent(part.rawValue);
15041
+ default:
15042
+ return false;
15043
+ }
15044
+ }
15045
+ function isAISDKContentAsyncIterableChunk(chunk) {
15046
+ if (isAISDKContentStreamChunk(chunk)) {
15047
+ return true;
15048
+ }
15049
+ const part = extractAISDKStreamPart(chunk);
15050
+ return isObject(part) && typeof part.type !== "string";
15051
+ }
14277
15052
  function patchAISDKStreamingResult(args) {
14278
15053
  const { defaultDenyOutputPaths, endEvent, result, span, startTime } = args;
14279
15054
  if (!result || typeof result !== "object") {
@@ -14286,7 +15061,7 @@ function patchAISDKStreamingResult(args) {
14286
15061
  const wrappedBaseStream = resultRecord.baseStream.pipeThrough(
14287
15062
  new TransformStream({
14288
15063
  transform(chunk, controller) {
14289
- if (firstChunkTime2 === void 0) {
15064
+ if (firstChunkTime2 === void 0 && isAISDKContentStreamChunk(chunk)) {
14290
15065
  firstChunkTime2 = getCurrentUnixTimestamp();
14291
15066
  }
14292
15067
  controller.enqueue(chunk);
@@ -14330,8 +15105,8 @@ function patchAISDKStreamingResult(args) {
14330
15105
  }
14331
15106
  let firstChunkTime;
14332
15107
  const wrappedStream = createPatchedAsyncIterable(streamField.stream, {
14333
- onChunk: () => {
14334
- if (firstChunkTime === void 0) {
15108
+ onChunk: (chunk) => {
15109
+ if (firstChunkTime === void 0 && isAISDKContentAsyncIterableChunk(chunk)) {
14335
15110
  firstChunkTime = getCurrentUnixTimestamp();
14336
15111
  }
14337
15112
  },
@@ -15303,15 +16078,17 @@ function collectLocalMcpServerToolHookNames(serverName, serverConfig) {
15303
16078
 
15304
16079
  // src/instrumentation/plugins/claude-agent-sdk-plugin.ts
15305
16080
  var ROOT_LLM_PARENT_KEY = "__root__";
16081
+ var SUB_AGENT_PROMPT_SOURCE_PRIORITY = {
16082
+ delegation: 0,
16083
+ lifecycle: 1,
16084
+ sidechain: 2
16085
+ };
15306
16086
  function llmParentKey(parentToolUseId) {
15307
16087
  return parentToolUseId ?? ROOT_LLM_PARENT_KEY;
15308
16088
  }
15309
16089
  function isSubAgentDelegationToolName(toolName) {
15310
16090
  return toolName === "Agent" || toolName === "Task";
15311
16091
  }
15312
- function shouldParentToolAsTaskSibling(toolName) {
15313
- return toolName === "Agent" || toolName === "Task" || toolName === "Bash";
15314
- }
15315
16092
  function filterSerializableOptions(options) {
15316
16093
  const allowedKeys = [
15317
16094
  "model",
@@ -15448,26 +16225,39 @@ function extractUsageFromMessage(message) {
15448
16225
  }
15449
16226
  return metrics;
15450
16227
  }
15451
- function buildLLMInput(prompt, conversationHistory, capturedPromptMessages) {
15452
- const promptMessages = [];
15453
- if (typeof prompt === "string") {
15454
- promptMessages.push({ content: prompt, role: "user" });
15455
- } else if (capturedPromptMessages && capturedPromptMessages.length > 0) {
15456
- for (const msg of capturedPromptMessages) {
15457
- const role = msg.message?.role;
15458
- const content = msg.message?.content;
15459
- if (role && content !== void 0) {
15460
- promptMessages.push({ content, role });
15461
- }
15462
- }
15463
- }
16228
+ function buildLLMInput(promptMessages, conversationHistory) {
15464
16229
  const inputParts = [...promptMessages, ...conversationHistory];
15465
16230
  return inputParts.length > 0 ? inputParts : void 0;
15466
16231
  }
16232
+ function conversationMessageFromSDKMessage(message) {
16233
+ const role = message.message?.role;
16234
+ const content = message.message?.content;
16235
+ if (role && content !== void 0) {
16236
+ return { content, role };
16237
+ }
16238
+ return void 0;
16239
+ }
16240
+ function messageContentHasBlockType(message, blockType) {
16241
+ const content = message.message?.content;
16242
+ return Array.isArray(content) && content.some(
16243
+ (block) => typeof block === "object" && block !== null && "type" in block && block.type === blockType
16244
+ );
16245
+ }
16246
+ function buildRootPromptMessages(prompt, capturedPromptMessages) {
16247
+ if (typeof prompt === "string") {
16248
+ return [{ content: prompt, role: "user" }];
16249
+ }
16250
+ if (!capturedPromptMessages || capturedPromptMessages.length === 0) {
16251
+ return [];
16252
+ }
16253
+ return capturedPromptMessages.map(conversationMessageFromSDKMessage).filter(
16254
+ (message) => message !== void 0
16255
+ );
16256
+ }
15467
16257
  function formatCapturedMessages(messages) {
15468
16258
  return messages.length > 0 ? messages : [];
15469
16259
  }
15470
- async function createLLMSpanForMessages(messages, prompt, conversationHistory, options, startTime, capturedPromptMessages, parentSpan, existingSpan) {
16260
+ async function createLLMSpanForMessages(messages, promptMessages, conversationHistory, options, startTime, parentSpan, existingSpan) {
15471
16261
  if (messages.length === 0) {
15472
16262
  return void 0;
15473
16263
  }
@@ -15477,11 +16267,7 @@ async function createLLMSpanForMessages(messages, prompt, conversationHistory, o
15477
16267
  }
15478
16268
  const model = lastMessage.message.model || options.model;
15479
16269
  const usage = extractUsageFromMessage(lastMessage);
15480
- const input = buildLLMInput(
15481
- prompt,
15482
- conversationHistory,
15483
- capturedPromptMessages
15484
- );
16270
+ const input = buildLLMInput(promptMessages, conversationHistory);
15485
16271
  const outputs = messages.map(
15486
16272
  (m) => m.message?.content && m.message?.role ? { content: m.message.content, role: m.message.role } : void 0
15487
16273
  ).filter(
@@ -15612,8 +16398,7 @@ function createToolTracingHooks(resolveParentSpan, activeToolSpans, mcpServers,
15612
16398
  },
15613
16399
  name: parsed.displayName,
15614
16400
  parent: await resolveParentSpan(toolUseID, {
15615
- agentId: input.agent_id,
15616
- preferTaskSiblingParent: shouldParentToolAsTaskSibling(parsed.toolName)
16401
+ agentId: input.agent_id
15617
16402
  }),
15618
16403
  spanAttributes: { type: "tool" /* TOOL */ }
15619
16404
  });
@@ -15859,12 +16644,37 @@ function injectTracingHooks(options, resolveParentSpan, activeToolSpans, localTo
15859
16644
  }
15860
16645
  };
15861
16646
  }
16647
+ function setSubAgentPromptMessages(state, parentToolUseId, promptMessages, source) {
16648
+ if (promptMessages.length === 0) {
16649
+ return;
16650
+ }
16651
+ const parentKey = llmParentKey(parentToolUseId);
16652
+ const sourcePriority = SUB_AGENT_PROMPT_SOURCE_PRIORITY[source];
16653
+ const currentPriority = state.promptSourcePriorityByParentKey.get(parentKey) ?? -1;
16654
+ if (sourcePriority > currentPriority) {
16655
+ state.promptMessagesByParentKey.set(parentKey, promptMessages);
16656
+ state.promptSourcePriorityByParentKey.set(parentKey, sourcePriority);
16657
+ }
16658
+ }
16659
+ function getConversationHistory(state, parentKey) {
16660
+ let conversationHistory = state.conversationHistoryByParentKey.get(parentKey);
16661
+ if (!conversationHistory) {
16662
+ conversationHistory = [];
16663
+ state.conversationHistoryByParentKey.set(parentKey, conversationHistory);
16664
+ }
16665
+ return conversationHistory;
16666
+ }
15862
16667
  async function finalizeCurrentMessageGroup(state) {
15863
16668
  if (state.currentMessages.length === 0) {
15864
16669
  return;
15865
16670
  }
15866
16671
  const parentToolUseId = state.currentMessages[0]?.parent_tool_use_id ?? null;
15867
16672
  const parentKey = llmParentKey(parentToolUseId);
16673
+ const conversationHistory = getConversationHistory(state, parentKey);
16674
+ const promptMessages = parentToolUseId ? state.promptMessagesByParentKey.get(parentKey) ?? [] : buildRootPromptMessages(
16675
+ state.originalPrompt,
16676
+ state.capturedPromptMessages
16677
+ );
15868
16678
  let parentSpan = await state.span.export();
15869
16679
  if (parentToolUseId) {
15870
16680
  const subAgentSpan = state.subAgentSpans.get(parentToolUseId);
@@ -15875,11 +16685,10 @@ async function finalizeCurrentMessageGroup(state) {
15875
16685
  const existingLlmSpan = state.activeLlmSpansByParentToolUse.get(parentKey);
15876
16686
  const llmSpanResult = await createLLMSpanForMessages(
15877
16687
  state.currentMessages,
15878
- state.originalPrompt,
15879
- state.finalResults,
16688
+ promptMessages,
16689
+ conversationHistory,
15880
16690
  state.options,
15881
16691
  state.currentMessageStartTime,
15882
- state.capturedPromptMessages,
15883
16692
  parentSpan,
15884
16693
  existingLlmSpan
15885
16694
  );
@@ -15893,6 +16702,7 @@ async function finalizeCurrentMessageGroup(state) {
15893
16702
  state.latestRootLlmParentRef.value = llmSpanResult.spanExport;
15894
16703
  }
15895
16704
  if (llmSpanResult.finalMessage) {
16705
+ conversationHistory.push(llmSpanResult.finalMessage);
15896
16706
  state.finalResults.push(llmSpanResult.finalMessage);
15897
16707
  }
15898
16708
  }
@@ -15920,6 +16730,15 @@ function maybeTrackToolUseContext(state, message) {
15920
16730
  description: getStringProperty(block.input, "description"),
15921
16731
  toolUseId: block.id
15922
16732
  });
16733
+ const prompt = getStringProperty(block.input, "prompt");
16734
+ if (prompt) {
16735
+ setSubAgentPromptMessages(
16736
+ state,
16737
+ block.id,
16738
+ [{ content: prompt, role: "user" }],
16739
+ "delegation"
16740
+ );
16741
+ }
15923
16742
  }
15924
16743
  }
15925
16744
  }
@@ -16038,6 +16857,14 @@ async function maybeHandleTaskLifecycleMessage(state, message) {
16038
16857
  };
16039
16858
  if (message.subtype === "task_started") {
16040
16859
  const prompt = getStringProperty(message, "prompt");
16860
+ if (prompt) {
16861
+ setSubAgentPromptMessages(
16862
+ state,
16863
+ toolUseId,
16864
+ [{ content: prompt, role: "user" }],
16865
+ "lifecycle"
16866
+ );
16867
+ }
16041
16868
  subAgentSpan.log({
16042
16869
  input: prompt,
16043
16870
  metadata
@@ -16088,6 +16915,28 @@ async function handleStreamMessage(state, message) {
16088
16915
  return;
16089
16916
  }
16090
16917
  await maybeStartSubAgentSpan(state, message);
16918
+ const messageParentToolUseId = message.parent_tool_use_id;
16919
+ if (messageParentToolUseId && message.type === "user") {
16920
+ const conversationMessage = conversationMessageFromSDKMessage(message);
16921
+ if (conversationMessage?.role === "user") {
16922
+ await finalizeCurrentMessageGroup(state);
16923
+ const parentKey = llmParentKey(messageParentToolUseId);
16924
+ const conversationHistory = getConversationHistory(state, parentKey);
16925
+ const currentPromptSourcePriority = state.promptSourcePriorityByParentKey.get(parentKey) ?? -1;
16926
+ const canUseAsInitialSidechainPrompt = conversationHistory.length === 0 && currentPromptSourcePriority < SUB_AGENT_PROMPT_SOURCE_PRIORITY.sidechain && !messageContentHasBlockType(message, "tool_result");
16927
+ if (!canUseAsInitialSidechainPrompt) {
16928
+ conversationHistory.push(conversationMessage);
16929
+ return;
16930
+ }
16931
+ setSubAgentPromptMessages(
16932
+ state,
16933
+ messageParentToolUseId,
16934
+ [conversationMessage],
16935
+ "sidechain"
16936
+ );
16937
+ return;
16938
+ }
16939
+ }
16091
16940
  const messageId = message.message?.id;
16092
16941
  if (messageId && messageId !== state.currentMessageId) {
16093
16942
  await finalizeCurrentMessageGroup(state);
@@ -16239,6 +17088,7 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
16239
17088
  }
16240
17089
  const activeToolSpans = /* @__PURE__ */ new Map();
16241
17090
  const activeLlmSpansByParentToolUse = /* @__PURE__ */ new Map();
17091
+ const conversationHistoryByParentKey = /* @__PURE__ */ new Map();
16242
17092
  const subAgentSpans = /* @__PURE__ */ new Map();
16243
17093
  const endedSubAgentSpans = /* @__PURE__ */ new Set();
16244
17094
  const toolUseToParent = /* @__PURE__ */ new Map();
@@ -16248,6 +17098,8 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
16248
17098
  };
16249
17099
  const subAgentDetailsByToolUseId = /* @__PURE__ */ new Map();
16250
17100
  const taskIdToToolUseId = /* @__PURE__ */ new Map();
17101
+ const promptMessagesByParentKey = /* @__PURE__ */ new Map();
17102
+ const promptSourcePriorityByParentKey = /* @__PURE__ */ new Map();
16251
17103
  const localToolContext = createClaudeLocalToolContext();
16252
17104
  const { hasLocalToolHandlers, localToolHookNames } = prepareLocalToolHandlersInMcpServers(options.mcpServers);
16253
17105
  const skipLocalToolHooks = options[CLAUDE_AGENT_SDK_SKIP_LOCAL_TOOL_HOOKS_OPTION] === true || hasLocalToolHandlers;
@@ -16256,38 +17108,19 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
16256
17108
  const parentToolUseId = trackedParentToolUseId ?? (context?.agentId ? taskIdToToolUseId.get(context.agentId) ?? null : null);
16257
17109
  const parentKey = llmParentKey(parentToolUseId);
16258
17110
  const activeLlmSpan = activeLlmSpansByParentToolUse.get(parentKey);
16259
- if (context?.preferTaskSiblingParent) {
16260
- if (!activeLlmSpan) {
16261
- await ensureActiveLlmSpanForParentToolUse(
16262
- span,
16263
- activeLlmSpansByParentToolUse,
16264
- subAgentDetailsByToolUseId,
16265
- activeToolSpans,
16266
- subAgentSpans,
16267
- parentToolUseId,
16268
- getCurrentUnixTimestamp()
16269
- );
16270
- }
16271
- if (parentToolUseId) {
16272
- const subAgentSpan = await ensureSubAgentSpan(
16273
- subAgentDetailsByToolUseId,
16274
- span,
16275
- activeToolSpans,
16276
- subAgentSpans,
16277
- parentToolUseId
16278
- );
16279
- return subAgentSpan.export();
16280
- }
16281
- return span.export();
16282
- }
16283
- if (activeLlmSpan) {
16284
- return activeLlmSpan.export();
17111
+ const latestLlmParent = parentToolUseId ? latestLlmParentBySubAgentToolUse.get(parentToolUseId) : latestRootLlmParentRef.value;
17112
+ if (!activeLlmSpan && !latestLlmParent) {
17113
+ await ensureActiveLlmSpanForParentToolUse(
17114
+ span,
17115
+ activeLlmSpansByParentToolUse,
17116
+ subAgentDetailsByToolUseId,
17117
+ activeToolSpans,
17118
+ subAgentSpans,
17119
+ parentToolUseId,
17120
+ getCurrentUnixTimestamp()
17121
+ );
16285
17122
  }
16286
17123
  if (parentToolUseId) {
16287
- const parentLlm = latestLlmParentBySubAgentToolUse.get(parentToolUseId);
16288
- if (parentLlm) {
16289
- return parentLlm;
16290
- }
16291
17124
  const subAgentSpan = await ensureSubAgentSpan(
16292
17125
  subAgentDetailsByToolUseId,
16293
17126
  span,
@@ -16297,9 +17130,6 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
16297
17130
  );
16298
17131
  return subAgentSpan.export();
16299
17132
  }
16300
- if (latestRootLlmParentRef.value) {
16301
- return latestRootLlmParentRef.value;
16302
- }
16303
17133
  return span.export();
16304
17134
  };
16305
17135
  localToolContext.resolveLocalToolParent = resolveToolUseParentSpan;
@@ -16320,6 +17150,7 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
16320
17150
  accumulatedOutputTokens: 0,
16321
17151
  activeLlmSpansByParentToolUse,
16322
17152
  activeToolSpans,
17153
+ conversationHistoryByParentKey,
16323
17154
  capturedPromptMessages,
16324
17155
  currentMessageId: void 0,
16325
17156
  currentMessageStartTime: startTime,
@@ -16330,7 +17161,9 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
16330
17161
  originalPrompt,
16331
17162
  processing: Promise.resolve(),
16332
17163
  promptDone,
17164
+ promptMessagesByParentKey,
16333
17165
  promptStarted: () => promptStarted,
17166
+ promptSourcePriorityByParentKey,
16334
17167
  span,
16335
17168
  subAgentDetailsByToolUseId,
16336
17169
  subAgentSpans,
@@ -17759,6 +18592,10 @@ var googleGenAIChannels = defineChannels("@google/genai", {
17759
18592
  embedContent: channel({
17760
18593
  channelName: "models.embedContent",
17761
18594
  kind: "async"
18595
+ }),
18596
+ interactionsCreate: channel({
18597
+ channelName: "interactions.create",
18598
+ kind: "async"
17762
18599
  })
17763
18600
  });
17764
18601
 
@@ -17786,6 +18623,7 @@ var GoogleGenAIPlugin = class extends BasePlugin {
17786
18623
  this.subscribeToGenerateContentChannel();
17787
18624
  this.subscribeToGenerateContentStreamChannel();
17788
18625
  this.subscribeToEmbedContentChannel();
18626
+ this.subscribeToInteractionsCreateChannel();
17789
18627
  }
17790
18628
  subscribeToGenerateContentChannel() {
17791
18629
  const tracingChannel2 = googleGenAIChannels.generateContent.tracingChannel();
@@ -17958,7 +18796,30 @@ var GoogleGenAIPlugin = class extends BasePlugin {
17958
18796
  tracingChannel2.unsubscribe(handlers);
17959
18797
  });
17960
18798
  }
18799
+ subscribeToInteractionsCreateChannel() {
18800
+ this.unsubscribers.push(
18801
+ traceStreamingChannel(
18802
+ googleGenAIChannels.interactionsCreate,
18803
+ {
18804
+ name: "create_interaction",
18805
+ shouldTrace: ([params]) => !isBackgroundInteractionCreate(params),
18806
+ type: "llm" /* LLM */,
18807
+ extractInput: ([params]) => ({
18808
+ input: serializeInteractionInput(params),
18809
+ metadata: extractInteractionMetadata(params)
18810
+ }),
18811
+ extractOutput: (result) => serializeInteractionValue(result),
18812
+ extractMetadata: (result) => extractInteractionResponseMetadata(result),
18813
+ extractMetrics: (result, startTime) => cleanMetrics3(extractInteractionMetrics(result, startTime)),
18814
+ aggregateChunks: (chunks, _result, _event, startTime) => aggregateInteractionEvents(chunks, startTime)
18815
+ }
18816
+ )
18817
+ );
18818
+ }
17961
18819
  };
18820
+ function isBackgroundInteractionCreate(params) {
18821
+ return tryToDict(params)?.background === true;
18822
+ }
17962
18823
  function ensureSpanState(states, event, create) {
17963
18824
  const existing = states.get(event);
17964
18825
  if (existing) {
@@ -18166,6 +19027,60 @@ function serializeEmbedContentInput(params) {
18166
19027
  }
18167
19028
  return input;
18168
19029
  }
19030
+ function serializeInteractionInput(params) {
19031
+ const input = {
19032
+ input: serializeInteractionValue(params.input)
19033
+ };
19034
+ for (const key of [
19035
+ "model",
19036
+ "agent",
19037
+ "agent_config",
19038
+ "api_version",
19039
+ "background",
19040
+ "environment",
19041
+ "generation_config",
19042
+ "previous_interaction_id",
19043
+ "response_format",
19044
+ "response_mime_type",
19045
+ "response_modalities",
19046
+ "service_tier",
19047
+ "store",
19048
+ "stream",
19049
+ "system_instruction",
19050
+ "webhook_config"
19051
+ ]) {
19052
+ const value = params[key];
19053
+ if (value !== void 0) {
19054
+ input[key] = serializeInteractionValue(value);
19055
+ }
19056
+ }
19057
+ return input;
19058
+ }
19059
+ function extractInteractionMetadata(params) {
19060
+ const metadata = {};
19061
+ for (const key of [
19062
+ "model",
19063
+ "agent",
19064
+ "agent_config",
19065
+ "generation_config",
19066
+ "system_instruction",
19067
+ "response_format",
19068
+ "response_mime_type",
19069
+ "response_modalities",
19070
+ "service_tier"
19071
+ ]) {
19072
+ const value = params[key];
19073
+ if (value !== void 0) {
19074
+ metadata[key] = serializeInteractionValue(value);
19075
+ }
19076
+ }
19077
+ if (Array.isArray(params.tools)) {
19078
+ metadata.tools = params.tools.map(
19079
+ (tool) => serializeInteractionValue(tool)
19080
+ );
19081
+ }
19082
+ return metadata;
19083
+ }
18169
19084
  function serializeContentCollection(contents) {
18170
19085
  if (contents === null || contents === void 0) {
18171
19086
  return null;
@@ -18196,21 +19111,8 @@ function serializePart(part) {
18196
19111
  }
18197
19112
  if (part.inlineData && part.inlineData.data) {
18198
19113
  const { data, mimeType } = part.inlineData;
18199
- if (data instanceof Uint8Array || typeof Buffer !== "undefined" && Buffer.isBuffer(data) || typeof data === "string") {
18200
- const extension = mimeType ? mimeType.split("/")[1] : "bin";
18201
- const filename = `file.${extension}`;
18202
- const buffer = typeof data === "string" ? typeof Buffer !== "undefined" ? Buffer.from(data, "base64") : new Uint8Array(
18203
- atob(data).split("").map((c) => c.charCodeAt(0))
18204
- ) : typeof Buffer !== "undefined" ? Buffer.from(data) : new Uint8Array(data);
18205
- const arrayBuffer = buffer instanceof Uint8Array ? buffer.buffer.slice(
18206
- buffer.byteOffset,
18207
- buffer.byteOffset + buffer.byteLength
18208
- ) : buffer;
18209
- const attachment = new Attachment({
18210
- data: arrayBuffer,
18211
- filename,
18212
- contentType: mimeType || "application/octet-stream"
18213
- });
19114
+ const attachment = createAttachmentFromInlineData(data, mimeType);
19115
+ if (attachment) {
18214
19116
  return {
18215
19117
  image_url: { url: attachment }
18216
19118
  };
@@ -18218,6 +19120,59 @@ function serializePart(part) {
18218
19120
  }
18219
19121
  return part;
18220
19122
  }
19123
+ function serializeInteractionValue(value, seen = /* @__PURE__ */ new WeakSet()) {
19124
+ if (value === null || value === void 0 || typeof value !== "object") {
19125
+ return value;
19126
+ }
19127
+ if (Array.isArray(value)) {
19128
+ return value.map((item) => serializeInteractionValue(item, seen));
19129
+ }
19130
+ const dict = tryToDict(value);
19131
+ if (dict === null || dict === void 0 || typeof dict !== "object") {
19132
+ return dict;
19133
+ }
19134
+ if (Array.isArray(dict)) {
19135
+ return dict.map((item) => serializeInteractionValue(item, seen));
19136
+ }
19137
+ if (seen.has(dict)) {
19138
+ return "[Circular]";
19139
+ }
19140
+ seen.add(dict);
19141
+ try {
19142
+ const serialized = {};
19143
+ 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;
19144
+ const attachment = mimeType && "data" in dict && dict.data !== void 0 ? createAttachmentFromInlineData(dict.data, mimeType) : null;
19145
+ for (const [key, entry] of Object.entries(dict)) {
19146
+ if (key === "data" && attachment) {
19147
+ serialized[key] = attachment;
19148
+ } else {
19149
+ serialized[key] = serializeInteractionValue(entry, seen);
19150
+ }
19151
+ }
19152
+ return serialized;
19153
+ } finally {
19154
+ seen.delete(dict);
19155
+ }
19156
+ }
19157
+ function createAttachmentFromInlineData(data, mimeType) {
19158
+ if (!(data instanceof Uint8Array || typeof Buffer !== "undefined" && Buffer.isBuffer(data) || typeof data === "string")) {
19159
+ return null;
19160
+ }
19161
+ const extension = mimeType ? mimeType.split("/")[1] : "bin";
19162
+ const filename = `file.${extension}`;
19163
+ const buffer = typeof data === "string" ? typeof Buffer !== "undefined" ? Buffer.from(data, "base64") : new Uint8Array(
19164
+ atob(data).split("").map((c) => c.charCodeAt(0))
19165
+ ) : typeof Buffer !== "undefined" ? Buffer.from(data) : new Uint8Array(data);
19166
+ const arrayBuffer = buffer instanceof Uint8Array ? buffer.buffer.slice(
19167
+ buffer.byteOffset,
19168
+ buffer.byteOffset + buffer.byteLength
19169
+ ) : buffer;
19170
+ return new Attachment({
19171
+ data: arrayBuffer,
19172
+ filename,
19173
+ contentType: mimeType || "application/octet-stream"
19174
+ });
19175
+ }
18221
19176
  function serializeGenerateContentTools(params) {
18222
19177
  const config = params.config ? tryToDict(params.config) : null;
18223
19178
  const tools = config?.tools;
@@ -18302,6 +19257,33 @@ function extractEmbedContentMetrics(response, startTime) {
18302
19257
  }
18303
19258
  return metrics;
18304
19259
  }
19260
+ function extractInteractionMetrics(response, startTime) {
19261
+ const metrics = {};
19262
+ if (startTime !== void 0) {
19263
+ const end = getCurrentUnixTimestamp();
19264
+ metrics.start = startTime;
19265
+ metrics.end = end;
19266
+ metrics.duration = end - startTime;
19267
+ }
19268
+ if (response?.usage) {
19269
+ populateInteractionUsageMetrics(metrics, response.usage);
19270
+ }
19271
+ return metrics;
19272
+ }
19273
+ function extractInteractionResponseMetadata(response) {
19274
+ const responseDict = tryToDict(response);
19275
+ if (!responseDict) {
19276
+ return void 0;
19277
+ }
19278
+ const metadata = {};
19279
+ if (typeof responseDict.id === "string") {
19280
+ metadata.interaction_id = responseDict.id;
19281
+ }
19282
+ if (typeof responseDict.status === "string") {
19283
+ metadata.status = responseDict.status;
19284
+ }
19285
+ return Object.keys(metadata).length > 0 ? metadata : void 0;
19286
+ }
18305
19287
  function extractEmbedPromptTokenCount(response) {
18306
19288
  if (!response) {
18307
19289
  return void 0;
@@ -18364,6 +19346,23 @@ function populateUsageMetrics(metrics, usage) {
18364
19346
  metrics.completion_reasoning_tokens = usage.thoughtsTokenCount;
18365
19347
  }
18366
19348
  }
19349
+ function populateInteractionUsageMetrics(metrics, usage) {
19350
+ if (typeof usage.total_input_tokens === "number") {
19351
+ metrics.prompt_tokens = usage.total_input_tokens;
19352
+ }
19353
+ if (typeof usage.total_output_tokens === "number") {
19354
+ metrics.completion_tokens = usage.total_output_tokens;
19355
+ }
19356
+ if (typeof usage.total_tokens === "number") {
19357
+ metrics.tokens = usage.total_tokens;
19358
+ }
19359
+ if (typeof usage.total_cached_tokens === "number") {
19360
+ metrics.prompt_cached_tokens = usage.total_cached_tokens;
19361
+ }
19362
+ if (typeof usage.total_thought_tokens === "number") {
19363
+ metrics.completion_reasoning_tokens = usage.total_thought_tokens;
19364
+ }
19365
+ }
18367
19366
  function aggregateGenerateContentChunks(chunks, startTime, firstTokenTime) {
18368
19367
  const end = getCurrentUnixTimestamp();
18369
19368
  const metrics = {
@@ -18461,41 +19460,181 @@ function aggregateGenerateContentChunks(chunks, startTime, firstTokenTime) {
18461
19460
  }
18462
19461
  return { aggregated, metrics };
18463
19462
  }
18464
- function cleanMetrics3(metrics) {
18465
- const cleaned = {};
18466
- for (const [key, value] of Object.entries(metrics)) {
18467
- if (value !== null && value !== void 0) {
18468
- cleaned[key] = value;
18469
- }
18470
- }
18471
- return cleaned;
18472
- }
18473
- function extractResponseMetadata(response) {
18474
- const responseDict = tryToDict(response);
18475
- if (!responseDict) {
18476
- return void 0;
19463
+ function aggregateInteractionEvents(chunks, startTime) {
19464
+ const end = getCurrentUnixTimestamp();
19465
+ const metrics = {};
19466
+ if (startTime !== void 0) {
19467
+ metrics.start = startTime;
19468
+ metrics.end = end;
19469
+ metrics.duration = end - startTime;
18477
19470
  }
18478
- const metadata = {};
18479
- const responseGroundingMetadata = responseDict.groundingMetadata;
18480
- const candidateGroundingMetadata = [];
18481
- if (Array.isArray(responseDict.candidates)) {
18482
- for (const candidate of responseDict.candidates) {
18483
- const candidateDict = tryToDict(candidate);
18484
- if (candidateDict?.groundingMetadata !== void 0) {
18485
- candidateGroundingMetadata.push(candidateDict.groundingMetadata);
19471
+ let latestInteraction;
19472
+ let latestUsage;
19473
+ let status;
19474
+ let outputText = "";
19475
+ const steps = /* @__PURE__ */ new Map();
19476
+ for (const chunk of chunks) {
19477
+ const event = tryToDict(chunk);
19478
+ if (!event) {
19479
+ continue;
19480
+ }
19481
+ const usage = extractInteractionUsageFromEvent(event);
19482
+ if (usage) {
19483
+ latestUsage = usage;
19484
+ }
19485
+ const interaction = tryToDict(event.interaction);
19486
+ if (interaction) {
19487
+ latestInteraction = serializeInteractionValue(interaction);
19488
+ if (typeof interaction.status === "string") {
19489
+ status = interaction.status;
18486
19490
  }
18487
19491
  }
19492
+ if (typeof event.status === "string") {
19493
+ status = event.status;
19494
+ }
19495
+ const index = typeof event.index === "number" ? event.index : void 0;
19496
+ if (index === void 0) {
19497
+ continue;
19498
+ }
19499
+ if (event.event_type === "step.start") {
19500
+ const compact = compactInteractionStep(event.step);
19501
+ compact.index = index;
19502
+ steps.set(index, compact);
19503
+ continue;
19504
+ }
19505
+ if (event.event_type === "step.delta") {
19506
+ const step = steps.get(index) ?? { index };
19507
+ const textDelta = applyInteractionDelta(step, event.delta);
19508
+ if (textDelta) {
19509
+ outputText += textDelta;
19510
+ }
19511
+ steps.set(index, step);
19512
+ }
18488
19513
  }
18489
- if (responseGroundingMetadata !== void 0) {
18490
- metadata.groundingMetadata = responseGroundingMetadata;
18491
- } else if (candidateGroundingMetadata.length === 1) {
18492
- [metadata.groundingMetadata] = candidateGroundingMetadata;
18493
- } else if (candidateGroundingMetadata.length > 1) {
18494
- metadata.groundingMetadata = candidateGroundingMetadata;
19514
+ if (latestUsage) {
19515
+ populateInteractionUsageMetrics(metrics, latestUsage);
18495
19516
  }
18496
- return Object.keys(metadata).length > 0 ? metadata : void 0;
18497
- }
18498
- function tryToDict(obj) {
19517
+ const output = latestInteraction ? { ...latestInteraction } : {};
19518
+ if (status) {
19519
+ output.status = status;
19520
+ }
19521
+ if (outputText) {
19522
+ output.output_text = outputText;
19523
+ }
19524
+ if (latestUsage) {
19525
+ output.usage = serializeInteractionValue(latestUsage);
19526
+ }
19527
+ const compactSteps = Array.from(steps.values()).sort(
19528
+ (left, right) => Number(left.index ?? 0) - Number(right.index ?? 0)
19529
+ );
19530
+ if (compactSteps.length > 0) {
19531
+ output.steps = compactSteps;
19532
+ }
19533
+ const metadata = {};
19534
+ if (typeof output.id === "string") {
19535
+ metadata.interaction_id = output.id;
19536
+ }
19537
+ if (typeof output.status === "string") {
19538
+ metadata.status = output.status;
19539
+ }
19540
+ return {
19541
+ output,
19542
+ metrics: cleanMetrics3(metrics),
19543
+ ...Object.keys(metadata).length > 0 ? { metadata } : {}
19544
+ };
19545
+ }
19546
+ function extractInteractionUsageFromEvent(event) {
19547
+ const metadata = tryToDict(event.metadata);
19548
+ const metadataUsage = tryToDict(metadata?.usage);
19549
+ if (metadataUsage) {
19550
+ return metadataUsage;
19551
+ }
19552
+ const metadataTotalUsage = tryToDict(metadata?.total_usage);
19553
+ if (metadataTotalUsage) {
19554
+ return metadataTotalUsage;
19555
+ }
19556
+ const interaction = tryToDict(event.interaction);
19557
+ const interactionUsage = tryToDict(interaction?.usage);
19558
+ return interactionUsage ? interactionUsage : void 0;
19559
+ }
19560
+ function compactInteractionStep(step) {
19561
+ const stepDict = tryToDict(step);
19562
+ if (!stepDict) {
19563
+ return {};
19564
+ }
19565
+ const compact = {};
19566
+ for (const key of [
19567
+ "type",
19568
+ "content",
19569
+ "name",
19570
+ "server_name",
19571
+ "arguments",
19572
+ "result",
19573
+ "is_error"
19574
+ ]) {
19575
+ if (stepDict[key] !== void 0) {
19576
+ compact[key] = serializeInteractionValue(stepDict[key]);
19577
+ }
19578
+ }
19579
+ return Object.keys(compact).length > 0 ? compact : serializeInteractionValue(stepDict);
19580
+ }
19581
+ function applyInteractionDelta(step, delta) {
19582
+ const deltaDict = tryToDict(delta);
19583
+ if (!deltaDict) {
19584
+ return void 0;
19585
+ }
19586
+ const deltaType = deltaDict.type;
19587
+ if (typeof deltaType === "string" && typeof step.type !== "string") {
19588
+ step.type = deltaType === "text" ? "model_output" : deltaType;
19589
+ }
19590
+ if (deltaType === "text" && typeof deltaDict.text === "string") {
19591
+ step.text = `${typeof step.text === "string" ? step.text : ""}${deltaDict.text}`;
19592
+ return deltaDict.text;
19593
+ }
19594
+ if (deltaType === "arguments_delta" && typeof deltaDict.arguments === "string") {
19595
+ step.arguments = `${typeof step.arguments === "string" ? step.arguments : ""}${deltaDict.arguments}`;
19596
+ return void 0;
19597
+ }
19598
+ const deltas = Array.isArray(step.deltas) ? step.deltas : [];
19599
+ deltas.push(serializeInteractionValue(deltaDict));
19600
+ step.deltas = deltas;
19601
+ return void 0;
19602
+ }
19603
+ function cleanMetrics3(metrics) {
19604
+ const cleaned = {};
19605
+ for (const [key, value] of Object.entries(metrics)) {
19606
+ if (value !== null && value !== void 0) {
19607
+ cleaned[key] = value;
19608
+ }
19609
+ }
19610
+ return cleaned;
19611
+ }
19612
+ function extractResponseMetadata(response) {
19613
+ const responseDict = tryToDict(response);
19614
+ if (!responseDict) {
19615
+ return void 0;
19616
+ }
19617
+ const metadata = {};
19618
+ const responseGroundingMetadata = responseDict.groundingMetadata;
19619
+ const candidateGroundingMetadata = [];
19620
+ if (Array.isArray(responseDict.candidates)) {
19621
+ for (const candidate of responseDict.candidates) {
19622
+ const candidateDict = tryToDict(candidate);
19623
+ if (candidateDict?.groundingMetadata !== void 0) {
19624
+ candidateGroundingMetadata.push(candidateDict.groundingMetadata);
19625
+ }
19626
+ }
19627
+ }
19628
+ if (responseGroundingMetadata !== void 0) {
19629
+ metadata.groundingMetadata = responseGroundingMetadata;
19630
+ } else if (candidateGroundingMetadata.length === 1) {
19631
+ [metadata.groundingMetadata] = candidateGroundingMetadata;
19632
+ } else if (candidateGroundingMetadata.length > 1) {
19633
+ metadata.groundingMetadata = candidateGroundingMetadata;
19634
+ }
19635
+ return Object.keys(metadata).length > 0 ? metadata : void 0;
19636
+ }
19637
+ function tryToDict(obj) {
18499
19638
  if (obj === null || obj === void 0) {
18500
19639
  return null;
18501
19640
  }
@@ -24287,7 +25426,8 @@ var FlueObserveBridge = class {
24287
25426
  metadata
24288
25427
  }
24289
25428
  });
24290
- this.runsById.set(event.runId, { metadata, span });
25429
+ const activeContext = enterCurrentFlueSpan(span);
25430
+ this.runsById.set(event.runId, { activeContext, metadata, span });
24291
25431
  }
24292
25432
  handleRunEnd(event) {
24293
25433
  const state = this.runsById.get(event.runId);
@@ -24305,6 +25445,7 @@ var FlueObserveBridge = class {
24305
25445
  });
24306
25446
  safeEnd(state.span, eventTime(event.timestamp));
24307
25447
  this.runsById.delete(event.runId);
25448
+ restoreCurrentFlueSpan(state.activeContext);
24308
25449
  }
24309
25450
  void flush().catch((error) => {
24310
25451
  logInstrumentationError3("Flue flush", error);
@@ -24431,7 +25572,8 @@ var FlueObserveBridge = class {
24431
25572
  metadata
24432
25573
  }
24433
25574
  });
24434
- this.toolsByKey.set(toolKey(event), { metadata, span });
25575
+ const activeContext = enterCurrentFlueSpan(span);
25576
+ this.toolsByKey.set(toolKey(event), { activeContext, metadata, span });
24435
25577
  }
24436
25578
  handleToolCall(event) {
24437
25579
  if (!event.toolCallId) {
@@ -24454,6 +25596,7 @@ var FlueObserveBridge = class {
24454
25596
  });
24455
25597
  safeEnd(state.span, eventTime(event.timestamp));
24456
25598
  this.toolsByKey.delete(key);
25599
+ restoreCurrentFlueSpan(state.activeContext);
24457
25600
  }
24458
25601
  handleTaskStart(event) {
24459
25602
  if (!event.taskId) {
@@ -24858,6 +26001,34 @@ function stateMatchesRun(state, runId) {
24858
26001
  function startFlueSpan(parent, args) {
24859
26002
  return parent ? withCurrent(parent, () => startSpan(args)) : startSpan(args);
24860
26003
  }
26004
+ function enterCurrentFlueSpan(span) {
26005
+ const contextManager = _internalGetGlobalState()?.contextManager;
26006
+ const store = contextManager ? Reflect.get(contextManager, BRAINTRUST_CURRENT_SPAN_STORE) : void 0;
26007
+ if (!contextManager || !isCurrentSpanStore(store)) {
26008
+ return void 0;
26009
+ }
26010
+ const previous = store.getStore();
26011
+ try {
26012
+ store.enterWith(contextManager.wrapSpanForStore(span));
26013
+ return { previous, store };
26014
+ } catch (error) {
26015
+ logInstrumentationError3("Flue context propagation", error);
26016
+ return void 0;
26017
+ }
26018
+ }
26019
+ function isCurrentSpanStore(value) {
26020
+ return isObjectLike(value) && typeof Reflect.get(value, "enterWith") === "function" && typeof Reflect.get(value, "getStore") === "function";
26021
+ }
26022
+ function restoreCurrentFlueSpan(activeContext) {
26023
+ if (!activeContext) {
26024
+ return;
26025
+ }
26026
+ try {
26027
+ activeContext.store.enterWith(activeContext.previous);
26028
+ } catch (error) {
26029
+ logInstrumentationError3("Flue context restoration", error);
26030
+ }
26031
+ }
24861
26032
  function safeLog3(span, event) {
24862
26033
  try {
24863
26034
  span.log(event);
@@ -25196,143 +26367,1027 @@ function getModelNameFromResponse(response) {
25196
26367
  return modelName3;
25197
26368
  }
25198
26369
  }
25199
- const llmOutput = response.llmOutput || {};
25200
- const modelName2 = llmOutput.model_name ?? llmOutput.model;
25201
- return typeof modelName2 === "string" ? modelName2 : void 0;
26370
+ const llmOutput = response.llmOutput || {};
26371
+ const modelName2 = llmOutput.model_name ?? llmOutput.model;
26372
+ return typeof modelName2 === "string" ? modelName2 : void 0;
26373
+ }
26374
+ function getMetricsFromResponse(response) {
26375
+ for (const generation of walkGenerations(response)) {
26376
+ const message = generation.message;
26377
+ if (!isRecord(message)) {
26378
+ continue;
26379
+ }
26380
+ const usageMetadata = message.usage_metadata;
26381
+ if (!isRecord(usageMetadata)) {
26382
+ continue;
26383
+ }
26384
+ const inputTokenDetails = usageMetadata.input_token_details;
26385
+ return cleanObject({
26386
+ total_tokens: usageMetadata.total_tokens,
26387
+ prompt_tokens: usageMetadata.input_tokens,
26388
+ completion_tokens: usageMetadata.output_tokens,
26389
+ prompt_cache_creation_tokens: isRecord(inputTokenDetails) ? inputTokenDetails.cache_creation : void 0,
26390
+ prompt_cached_tokens: isRecord(inputTokenDetails) ? inputTokenDetails.cache_read : void 0
26391
+ });
26392
+ }
26393
+ const llmOutput = response.llmOutput || {};
26394
+ const tokenUsage = isRecord(llmOutput.tokenUsage) ? llmOutput.tokenUsage : isRecord(llmOutput.estimatedTokens) ? llmOutput.estimatedTokens : {};
26395
+ return cleanObject({
26396
+ total_tokens: tokenUsage.totalTokens,
26397
+ prompt_tokens: tokenUsage.promptTokens,
26398
+ completion_tokens: tokenUsage.completionTokens
26399
+ });
26400
+ }
26401
+ function safeJsonParse(input) {
26402
+ try {
26403
+ return JSON.parse(input);
26404
+ } catch {
26405
+ return input;
26406
+ }
26407
+ }
26408
+ function isRecord(value) {
26409
+ return typeof value === "object" && value !== null && !Array.isArray(value);
26410
+ }
26411
+
26412
+ // src/instrumentation/plugins/langchain-channels.ts
26413
+ var langChainChannels = defineChannels("@langchain/core", {
26414
+ configure: channel({
26415
+ channelName: "CallbackManager.configure",
26416
+ kind: "sync-stream"
26417
+ }),
26418
+ configureSync: channel({
26419
+ channelName: "CallbackManager._configureSync",
26420
+ kind: "sync-stream"
26421
+ })
26422
+ });
26423
+
26424
+ // src/instrumentation/plugins/langchain-plugin.ts
26425
+ var LangChainPlugin = class extends BasePlugin {
26426
+ injectedManagers = /* @__PURE__ */ new WeakSet();
26427
+ onEnable() {
26428
+ this.subscribeToConfigure(langChainChannels.configure);
26429
+ this.subscribeToConfigure(langChainChannels.configureSync);
26430
+ }
26431
+ onDisable() {
26432
+ for (const unsubscribe of this.unsubscribers) {
26433
+ unsubscribe();
26434
+ }
26435
+ this.unsubscribers = [];
26436
+ this.injectedManagers = /* @__PURE__ */ new WeakSet();
26437
+ }
26438
+ subscribeToConfigure(channel2) {
26439
+ const tracingChannel2 = channel2.tracingChannel();
26440
+ const handlers = {
26441
+ start: (event) => {
26442
+ injectHandlerIntoArguments(event.arguments);
26443
+ },
26444
+ end: (event) => {
26445
+ this.injectHandler(event.result);
26446
+ }
26447
+ };
26448
+ tracingChannel2.subscribe(handlers);
26449
+ this.unsubscribers.push(() => {
26450
+ tracingChannel2.unsubscribe(handlers);
26451
+ });
26452
+ }
26453
+ injectHandler(result) {
26454
+ if (!isCallbackManager(result)) {
26455
+ return;
26456
+ }
26457
+ if (this.injectedManagers.has(result) || hasBraintrustHandler(result)) {
26458
+ return;
26459
+ }
26460
+ try {
26461
+ result.addHandler(new BraintrustLangChainCallbackHandler(), true);
26462
+ this.injectedManagers.add(result);
26463
+ } catch {
26464
+ }
26465
+ }
26466
+ };
26467
+ function isCallbackManager(value) {
26468
+ if (typeof value !== "object" || value === null) {
26469
+ return false;
26470
+ }
26471
+ const maybeManager = value;
26472
+ return typeof maybeManager.addHandler === "function";
26473
+ }
26474
+ function hasBraintrustHandler(manager) {
26475
+ return manager.handlers?.some((handler) => {
26476
+ if (typeof handler !== "object" || handler === null) {
26477
+ return false;
26478
+ }
26479
+ const name = Reflect.get(handler, "name");
26480
+ return name === BRAINTRUST_LANGCHAIN_CALLBACK_HANDLER_NAME;
26481
+ }) ?? false;
26482
+ }
26483
+ function injectHandlerIntoArguments(args) {
26484
+ if (!isWritableArgumentsObject(args)) {
26485
+ return;
26486
+ }
26487
+ const inheritedHandlers = Reflect.get(args, "0");
26488
+ const handler = new BraintrustLangChainCallbackHandler();
26489
+ if (inheritedHandlers === void 0 || inheritedHandlers === null) {
26490
+ Reflect.set(args, "0", [handler]);
26491
+ return;
26492
+ }
26493
+ if (Array.isArray(inheritedHandlers)) {
26494
+ if (!inheritedHandlers.some(isBraintrustHandler)) {
26495
+ inheritedHandlers.push(handler);
26496
+ }
26497
+ }
26498
+ }
26499
+ function isWritableArgumentsObject(args) {
26500
+ return typeof args === "object" && args !== null;
26501
+ }
26502
+ function isBraintrustHandler(handler) {
26503
+ if (typeof handler !== "object" || handler === null) {
26504
+ return false;
26505
+ }
26506
+ return Reflect.get(handler, "name") === BRAINTRUST_LANGCHAIN_CALLBACK_HANDLER_NAME;
26507
+ }
26508
+
26509
+ // src/instrumentation/plugins/pi-coding-agent-channels.ts
26510
+ var piCodingAgentChannels = defineChannels(
26511
+ "@earendil-works/pi-coding-agent",
26512
+ {
26513
+ prompt: channel({
26514
+ channelName: "AgentSession.prompt",
26515
+ kind: "async"
26516
+ })
26517
+ }
26518
+ );
26519
+
26520
+ // src/instrumentation/plugins/pi-coding-agent-plugin.ts
26521
+ var piStreamPatchStates = /* @__PURE__ */ new WeakMap();
26522
+ var piPromptContextStore;
26523
+ var PiCodingAgentPlugin = class extends BasePlugin {
26524
+ activePromptStates = /* @__PURE__ */ new Set();
26525
+ onEnable() {
26526
+ this.subscribeToPrompt();
26527
+ }
26528
+ onDisable() {
26529
+ for (const unsubscribe of this.unsubscribers) {
26530
+ unsubscribe();
26531
+ }
26532
+ this.unsubscribers = [];
26533
+ for (const state of [...this.activePromptStates]) {
26534
+ void finalizePiPromptRun(state).catch((error) => {
26535
+ logInstrumentationError4("Pi Coding Agent disable cleanup", error);
26536
+ });
26537
+ }
26538
+ }
26539
+ subscribeToPrompt() {
26540
+ const channel2 = piCodingAgentChannels.prompt.tracingChannel();
26541
+ const states = /* @__PURE__ */ new WeakMap();
26542
+ const unbindAutoInstrumentationSuppression = bindAutoInstrumentationSuppressionToStart(channel2);
26543
+ const handlers = {
26544
+ start: (event) => {
26545
+ const state = startPiPromptRun(event, (state2) => {
26546
+ this.activePromptStates.delete(state2);
26547
+ });
26548
+ if (state) {
26549
+ this.activePromptStates.add(state);
26550
+ states.set(event, state);
26551
+ }
26552
+ },
26553
+ asyncEnd: async (event) => {
26554
+ const state = states.get(event);
26555
+ if (!state) {
26556
+ return;
26557
+ }
26558
+ states.delete(event);
26559
+ state.promptCallEnded = true;
26560
+ if (!state.finalized && state.deferCompletionUntilTurnEnd && !state.turnEnded) {
26561
+ if (!state.sawStreamFn) {
26562
+ state.queued = true;
26563
+ if (!state.streamPatchState.queuedPromptStates.includes(state)) {
26564
+ state.streamPatchState.queuedPromptStates.push(state);
26565
+ }
26566
+ }
26567
+ return;
26568
+ }
26569
+ await finalizePiPromptRun(state);
26570
+ },
26571
+ error: async (event) => {
26572
+ const state = states.get(event);
26573
+ if (!state) {
26574
+ return;
26575
+ }
26576
+ states.delete(event);
26577
+ await finalizePiPromptRun(state, event.error);
26578
+ }
26579
+ };
26580
+ channel2.subscribe(handlers);
26581
+ this.unsubscribers.push(() => {
26582
+ unbindAutoInstrumentationSuppression?.();
26583
+ channel2.unsubscribe(handlers);
26584
+ });
26585
+ }
26586
+ };
26587
+ function startPiPromptRun(event, onFinalize) {
26588
+ const session = extractSession(event);
26589
+ const agent = session?.agent;
26590
+ if (!session || !isPiAgent(agent)) {
26591
+ return void 0;
26592
+ }
26593
+ const metadata = {
26594
+ ...extractSessionMetadata(session),
26595
+ ...extractPromptOptionsMetadata(event.arguments[1]),
26596
+ "pi_coding_agent.operation": "AgentSession.prompt",
26597
+ provider: session.model?.provider ?? agent.state?.model?.provider ?? "pi",
26598
+ ...session.model?.id || agent.state?.model?.id ? { model: session.model?.id ?? agent.state?.model?.id } : {},
26599
+ ...event.moduleVersion ? { "pi_coding_agent.version": event.moduleVersion } : {}
26600
+ };
26601
+ const span = startSpan({
26602
+ event: {
26603
+ input: extractPromptInput(event.arguments[0], event.arguments[1]),
26604
+ metadata
26605
+ },
26606
+ name: "AgentSession.prompt",
26607
+ spanAttributes: { type: "task" /* TASK */ }
26608
+ });
26609
+ const streamPatchState = installPiStreamPatch(agent);
26610
+ const options = event.arguments[1];
26611
+ const promptText = event.arguments[0];
26612
+ const state = {
26613
+ activeLlmSpans: /* @__PURE__ */ new Set(),
26614
+ activeToolSpans: /* @__PURE__ */ new Map(),
26615
+ agent,
26616
+ collectedLlmUsageMetrics: false,
26617
+ deferCompletionUntilTurnEnd: options?.streamingBehavior === "followUp" || options?.streamingBehavior === "steer",
26618
+ finalized: false,
26619
+ metadata,
26620
+ metrics: {},
26621
+ onFinalize,
26622
+ promptCallEnded: false,
26623
+ ...typeof promptText === "string" ? { promptText } : {},
26624
+ queued: false,
26625
+ span,
26626
+ sawStreamFn: false,
26627
+ startTime: getCurrentUnixTimestamp(),
26628
+ streamPatchState,
26629
+ turnEnded: false
26630
+ };
26631
+ state.restorePromptContext = enterPiPromptContext(state);
26632
+ streamPatchState.activePromptStates.add(state);
26633
+ try {
26634
+ state.unsubscribeAgent = agent.subscribe(async (agentEvent) => {
26635
+ try {
26636
+ await runWithAutoInstrumentationSuppressed(
26637
+ () => handlePiAgentEvent(state, agentEvent)
26638
+ );
26639
+ } catch (error) {
26640
+ logInstrumentationError4("Pi Coding Agent event", error);
26641
+ }
26642
+ });
26643
+ } catch (error) {
26644
+ logInstrumentationError4("Pi Coding Agent event subscription", error);
26645
+ }
26646
+ return state;
26647
+ }
26648
+ function extractSession(event) {
26649
+ const candidate = event.session ?? event.self;
26650
+ return isObject(candidate) && typeof candidate.prompt === "function" ? candidate : void 0;
26651
+ }
26652
+ function isPiAgent(value) {
26653
+ return isObject(value) && typeof value.streamFn === "function" && typeof value.subscribe === "function";
26654
+ }
26655
+ function promptContextStore() {
26656
+ piPromptContextStore ??= isomorph_default.newAsyncLocalStorage();
26657
+ return piPromptContextStore;
26658
+ }
26659
+ function currentPromptContextFrames() {
26660
+ return promptContextStore().getStore()?.frames ?? [];
26661
+ }
26662
+ function currentPiPromptState() {
26663
+ const frames = currentPromptContextFrames();
26664
+ return frames[frames.length - 1]?.state;
26665
+ }
26666
+ function enterPiPromptContext(state) {
26667
+ const frame = {
26668
+ id: /* @__PURE__ */ Symbol("braintrust.pi-coding-agent.prompt"),
26669
+ state
26670
+ };
26671
+ promptContextStore().enterWith({
26672
+ frames: [...currentPromptContextFrames(), frame]
26673
+ });
26674
+ return () => {
26675
+ const frames = currentPromptContextFrames().filter(
26676
+ (candidate) => candidate.id !== frame.id
26677
+ );
26678
+ promptContextStore().enterWith(frames.length > 0 ? { frames } : void 0);
26679
+ };
26680
+ }
26681
+ function installPiStreamPatch(agent) {
26682
+ const existing = piStreamPatchStates.get(agent);
26683
+ if (existing) {
26684
+ if (agent.streamFn !== existing.wrappedStreamFn) {
26685
+ debugLogger.debug(
26686
+ "Pi Coding Agent streamFn changed while Braintrust instrumentation was active; preserving existing patch state."
26687
+ );
26688
+ }
26689
+ return existing;
26690
+ }
26691
+ const patchState = {
26692
+ activePromptStates: /* @__PURE__ */ new Set(),
26693
+ agent,
26694
+ originalStreamFn: agent.streamFn,
26695
+ queuedPromptStates: [],
26696
+ wrappedStreamFn: agent.streamFn
26697
+ };
26698
+ patchState.wrappedStreamFn = makeSharedInstrumentedStreamFn(patchState);
26699
+ agent.streamFn = patchState.wrappedStreamFn;
26700
+ piStreamPatchStates.set(agent, patchState);
26701
+ return patchState;
26702
+ }
26703
+ function resolveStreamPromptState(patchState, context) {
26704
+ let lastUserText;
26705
+ if (Array.isArray(context.messages)) {
26706
+ for (let i = context.messages.length - 1; i >= 0; i--) {
26707
+ const message = context.messages[i];
26708
+ if (isPiUserMessage(message)) {
26709
+ if (typeof message.content === "string") {
26710
+ lastUserText = message.content;
26711
+ } else {
26712
+ lastUserText = message.content.flatMap((part) => part.type === "text" ? [part.text] : []).join("");
26713
+ }
26714
+ break;
26715
+ }
26716
+ }
26717
+ }
26718
+ if (lastUserText !== void 0) {
26719
+ const queuedMatch = patchState.queuedPromptStates.find(
26720
+ (state) => state.promptText === lastUserText
26721
+ );
26722
+ if (queuedMatch) {
26723
+ return queuedMatch;
26724
+ }
26725
+ const matches = [...patchState.activePromptStates].filter(
26726
+ (state) => state.promptText === lastUserText
26727
+ );
26728
+ if (matches.length === 1) {
26729
+ return matches[0];
26730
+ }
26731
+ }
26732
+ const contextState = currentPiPromptState();
26733
+ if (contextState && patchState.activePromptStates.has(contextState) && (!contextState.queued || lastUserText !== void 0 && contextState.promptText === lastUserText)) {
26734
+ return contextState;
26735
+ }
26736
+ if (patchState.activePromptStates.size === 1) {
26737
+ return [...patchState.activePromptStates][0];
26738
+ }
26739
+ return void 0;
26740
+ }
26741
+ function makeSharedInstrumentedStreamFn(patchState) {
26742
+ return async function instrumentedPiStreamFn(model, context, options) {
26743
+ const state = resolveStreamPromptState(patchState, context);
26744
+ if (!state) {
26745
+ const invokeOriginal = () => Reflect.apply(patchState.originalStreamFn, this, [
26746
+ model,
26747
+ context,
26748
+ options
26749
+ ]);
26750
+ return patchState.activePromptStates.size > 0 ? runWithAutoInstrumentationSuppressed(invokeOriginal) : invokeOriginal();
26751
+ }
26752
+ state.sawStreamFn = true;
26753
+ removeQueuedPromptState(state);
26754
+ state.streamPatchState.eventPromptState = state;
26755
+ const llmState = await startPiLlmSpan(state, model, context, options);
26756
+ try {
26757
+ const stream = await runWithAutoInstrumentationSuppressed(
26758
+ () => Reflect.apply(patchState.originalStreamFn, this, [
26759
+ model,
26760
+ context,
26761
+ options
26762
+ ])
26763
+ );
26764
+ return patchAssistantMessageStream(stream, state, llmState);
26765
+ } catch (error) {
26766
+ finishPiLlmSpan(state, llmState, void 0, error);
26767
+ throw error;
26768
+ }
26769
+ };
26770
+ }
26771
+ async function startPiLlmSpan(state, model, context, options) {
26772
+ const metadata = {
26773
+ ...extractModelMetadata2(model),
26774
+ ...extractStreamOptionsMetadata(options),
26775
+ ...extractToolMetadata(context.tools),
26776
+ "pi_coding_agent.operation": "agent.streamFn"
26777
+ };
26778
+ const span = startSpan({
26779
+ event: {
26780
+ input: processInputAttachments(normalizePiContextInput(context)),
26781
+ metadata
26782
+ },
26783
+ name: getLlmSpanName(model),
26784
+ parent: await state.span.export(),
26785
+ spanAttributes: { type: "llm" /* LLM */ }
26786
+ });
26787
+ const llmState = {
26788
+ finalized: false,
26789
+ metadata,
26790
+ metrics: {},
26791
+ span,
26792
+ startTime: getCurrentUnixTimestamp()
26793
+ };
26794
+ state.activeLlmSpans.add(llmState);
26795
+ return llmState;
26796
+ }
26797
+ function patchAssistantMessageStream(stream, promptState, llmState) {
26798
+ if (!isObject(stream)) {
26799
+ return stream;
26800
+ }
26801
+ const streamRecord = stream;
26802
+ const originalResult = stream.result;
26803
+ if (typeof originalResult === "function") {
26804
+ streamRecord.result = function patchedPiResult() {
26805
+ return Promise.resolve(Reflect.apply(originalResult, this, [])).then(
26806
+ (message) => {
26807
+ finishPiLlmSpan(promptState, llmState, message);
26808
+ return message;
26809
+ },
26810
+ (error) => {
26811
+ finishPiLlmSpan(promptState, llmState, void 0, error);
26812
+ throw error;
26813
+ }
26814
+ );
26815
+ };
26816
+ }
26817
+ const originalIterator = stream[Symbol.asyncIterator];
26818
+ if (typeof originalIterator === "function") {
26819
+ streamRecord[Symbol.asyncIterator] = function patchedPiIterator() {
26820
+ const iterator = Reflect.apply(
26821
+ originalIterator,
26822
+ this,
26823
+ []
26824
+ );
26825
+ return {
26826
+ async next() {
26827
+ try {
26828
+ const result = await iterator.next();
26829
+ if (result.done) {
26830
+ finishPiLlmSpan(promptState, llmState);
26831
+ return result;
26832
+ }
26833
+ recordPiAssistantMessageEvent(promptState, llmState, result.value);
26834
+ return result;
26835
+ } catch (error) {
26836
+ finishPiLlmSpan(promptState, llmState, void 0, error);
26837
+ if (typeof iterator.return === "function") {
26838
+ try {
26839
+ await iterator.return();
26840
+ } catch (cleanupError) {
26841
+ logInstrumentationError4(
26842
+ "Pi Coding Agent stream cleanup",
26843
+ cleanupError
26844
+ );
26845
+ }
26846
+ }
26847
+ throw error;
26848
+ }
26849
+ },
26850
+ async return(value) {
26851
+ try {
26852
+ if (typeof iterator.return === "function") {
26853
+ return await iterator.return(value);
26854
+ }
26855
+ return {
26856
+ done: true,
26857
+ value
26858
+ };
26859
+ } catch (error) {
26860
+ finishPiLlmSpan(promptState, llmState, void 0, error);
26861
+ throw error;
26862
+ } finally {
26863
+ finishPiLlmSpan(promptState, llmState);
26864
+ }
26865
+ },
26866
+ async throw(error) {
26867
+ try {
26868
+ if (typeof iterator.throw === "function") {
26869
+ return await iterator.throw(error);
26870
+ }
26871
+ throw error;
26872
+ } catch (thrownError) {
26873
+ finishPiLlmSpan(promptState, llmState, void 0, thrownError);
26874
+ throw thrownError;
26875
+ }
26876
+ },
26877
+ [Symbol.asyncIterator]() {
26878
+ return this;
26879
+ }
26880
+ };
26881
+ };
26882
+ }
26883
+ return stream;
26884
+ }
26885
+ function recordPiAssistantMessageEvent(promptState, llmState, event) {
26886
+ recordFirstTokenMetric(llmState, event);
26887
+ const message = "message" in event ? event.message : void 0;
26888
+ const errorMessage2 = "error" in event ? event.error : void 0;
26889
+ if (event.type === "done" && isPiAssistantMessage(message)) {
26890
+ finishPiLlmSpan(promptState, llmState, message);
26891
+ } else if (event.type === "error" && isPiAssistantMessage(errorMessage2)) {
26892
+ finishPiLlmSpan(promptState, llmState, errorMessage2);
26893
+ }
26894
+ }
26895
+ function recordFirstTokenMetric(state, event) {
26896
+ if (state.metrics.time_to_first_token !== void 0 || event.type === "start") {
26897
+ return;
26898
+ }
26899
+ state.metrics.time_to_first_token = getCurrentUnixTimestamp() - state.startTime;
26900
+ }
26901
+ async function handlePiAgentEvent(state, event) {
26902
+ if (state.finalized) {
26903
+ return;
26904
+ }
26905
+ const eventPromptState = state.streamPatchState.eventPromptState;
26906
+ if (eventPromptState && eventPromptState !== state) {
26907
+ return;
26908
+ }
26909
+ if (!eventPromptState && (state.queued || state.streamPatchState.activePromptStates.size > 1 && currentPiPromptState() !== state)) {
26910
+ return;
26911
+ }
26912
+ switch (event.type) {
26913
+ case "message_end":
26914
+ if (isPiAssistantMessage(event.message)) {
26915
+ state.output = extractAssistantOutput(event.message);
26916
+ }
26917
+ return;
26918
+ case "turn_end":
26919
+ state.turnEnded = true;
26920
+ if (isPiAssistantMessage(event.message)) {
26921
+ state.output = extractAssistantOutput(event.message);
26922
+ if (!state.collectedLlmUsageMetrics) {
26923
+ addMetrics(state.metrics, extractUsageMetrics2(event.message.usage));
26924
+ }
26925
+ }
26926
+ if (state.streamPatchState.eventPromptState === state) {
26927
+ state.streamPatchState.eventPromptState = void 0;
26928
+ }
26929
+ if (state.promptCallEnded && state.deferCompletionUntilTurnEnd) {
26930
+ await finalizePiPromptRun(state);
26931
+ }
26932
+ return;
26933
+ case "tool_execution_start":
26934
+ await startPiToolSpan(state, event);
26935
+ return;
26936
+ case "tool_execution_end":
26937
+ finishPiToolSpan(state, event);
26938
+ return;
26939
+ default:
26940
+ return;
26941
+ }
26942
+ }
26943
+ async function startPiToolSpan(state, event) {
26944
+ if (!event.toolCallId || state.activeToolSpans.has(event.toolCallId)) {
26945
+ return;
26946
+ }
26947
+ const restoreAutoInstrumentation = enterAutoInstrumentationAllowed();
26948
+ const metadata = {
26949
+ "gen_ai.tool.call.id": event.toolCallId,
26950
+ "gen_ai.tool.name": event.toolName,
26951
+ "pi_coding_agent.tool.name": event.toolName
26952
+ };
26953
+ try {
26954
+ const span = startSpan({
26955
+ event: {
26956
+ input: event.args,
26957
+ metadata
26958
+ },
26959
+ name: event.toolName || "tool",
26960
+ parent: await state.span.export(),
26961
+ spanAttributes: { type: "tool" /* TOOL */ }
26962
+ });
26963
+ state.activeToolSpans.set(event.toolCallId, {
26964
+ restoreAutoInstrumentation,
26965
+ span
26966
+ });
26967
+ } catch (error) {
26968
+ restoreAutoInstrumentation();
26969
+ throw error;
26970
+ }
26971
+ }
26972
+ function finishPiToolSpan(state, event) {
26973
+ const toolState = state.activeToolSpans.get(event.toolCallId);
26974
+ if (!toolState) {
26975
+ return;
26976
+ }
26977
+ state.activeToolSpans.delete(event.toolCallId);
26978
+ const metadata = {
26979
+ "gen_ai.tool.call.id": event.toolCallId,
26980
+ "gen_ai.tool.name": event.toolName,
26981
+ "pi_coding_agent.tool.name": event.toolName,
26982
+ "pi_coding_agent.tool.is_error": event.isError
26983
+ };
26984
+ try {
26985
+ safeLog4(toolState.span, {
26986
+ ...event.isError ? { error: stringifyUnknown2(event.result) } : {},
26987
+ metadata,
26988
+ output: event.result
26989
+ });
26990
+ } finally {
26991
+ try {
26992
+ toolState.span.end();
26993
+ } finally {
26994
+ toolState.restoreAutoInstrumentation?.();
26995
+ }
26996
+ }
26997
+ }
26998
+ async function finalizePiPromptRun(state, error) {
26999
+ if (state.finalized) {
27000
+ return;
27001
+ }
27002
+ state.finalized = true;
27003
+ state.onFinalize?.(state);
27004
+ restorePiStreamFn(state);
27005
+ try {
27006
+ state.unsubscribeAgent?.();
27007
+ } catch (unsubscribeError) {
27008
+ logInstrumentationError4("Pi Coding Agent unsubscribe", unsubscribeError);
27009
+ }
27010
+ await finishOpenLlmSpans(state, error);
27011
+ finishOpenToolSpans(state, error);
27012
+ const metadata = {
27013
+ ...state.metadata,
27014
+ ...extractModelMetadata2(state.agent.state?.model)
27015
+ };
27016
+ try {
27017
+ safeLog4(state.span, {
27018
+ ...error ? { error: stringifyUnknown2(error) } : {},
27019
+ metadata,
27020
+ metrics: {
27021
+ ...cleanMetrics5(state.metrics),
27022
+ ...buildDurationMetrics3(state.startTime)
27023
+ },
27024
+ output: state.output
27025
+ });
27026
+ } finally {
27027
+ state.span.end();
27028
+ }
27029
+ }
27030
+ function restorePiStreamFn(state) {
27031
+ const patchState = state.streamPatchState;
27032
+ patchState.activePromptStates.delete(state);
27033
+ removeQueuedPromptState(state);
27034
+ if (patchState.eventPromptState === state) {
27035
+ patchState.eventPromptState = void 0;
27036
+ }
27037
+ state.restorePromptContext?.();
27038
+ if (patchState.activePromptStates.size > 0) {
27039
+ return;
27040
+ }
27041
+ if (patchState.agent.streamFn === patchState.wrappedStreamFn) {
27042
+ patchState.agent.streamFn = patchState.originalStreamFn;
27043
+ }
27044
+ piStreamPatchStates.delete(patchState.agent);
27045
+ }
27046
+ function removeQueuedPromptState(state) {
27047
+ state.queued = false;
27048
+ const queuedPromptStates = state.streamPatchState.queuedPromptStates;
27049
+ const index = queuedPromptStates.indexOf(state);
27050
+ if (index >= 0) {
27051
+ queuedPromptStates.splice(index, 1);
27052
+ }
27053
+ }
27054
+ async function finishOpenLlmSpans(state, error) {
27055
+ for (const llmState of [...state.activeLlmSpans]) {
27056
+ finishPiLlmSpan(state, llmState, void 0, error);
27057
+ }
27058
+ }
27059
+ function finishPiLlmSpan(promptState, llmState, message, error) {
27060
+ if (llmState.finalized) {
27061
+ return;
27062
+ }
27063
+ llmState.finalized = true;
27064
+ promptState.activeLlmSpans.delete(llmState);
27065
+ const messageError = message?.stopReason === "error" && message.errorMessage;
27066
+ const metrics = {
27067
+ ...extractUsageMetrics2(message?.usage),
27068
+ ...cleanMetrics5(llmState.metrics),
27069
+ ...buildDurationMetrics3(llmState.startTime)
27070
+ };
27071
+ const usageMetrics = extractUsageMetrics2(message?.usage);
27072
+ if (Object.keys(usageMetrics).length > 0) {
27073
+ promptState.collectedLlmUsageMetrics = true;
27074
+ addMetrics(promptState.metrics, usageMetrics);
27075
+ }
27076
+ try {
27077
+ safeLog4(llmState.span, {
27078
+ ...error || messageError ? { error: stringifyUnknown2(error ?? messageError) } : {},
27079
+ metadata: {
27080
+ ...llmState.metadata,
27081
+ ...message ? extractAssistantMetadata(message) : {}
27082
+ },
27083
+ metrics,
27084
+ ...message ? { output: extractAssistantOutput(message) } : {}
27085
+ });
27086
+ } finally {
27087
+ llmState.span.end();
27088
+ }
27089
+ }
27090
+ function finishOpenToolSpans(state, error) {
27091
+ for (const [, toolState] of state.activeToolSpans) {
27092
+ try {
27093
+ safeLog4(toolState.span, {
27094
+ error: error ? stringifyUnknown2(error) : "Pi tool did not complete"
27095
+ });
27096
+ toolState.span.end();
27097
+ } finally {
27098
+ toolState.restoreAutoInstrumentation?.();
27099
+ }
27100
+ }
27101
+ state.activeToolSpans.clear();
27102
+ }
27103
+ function normalizePiContextInput(context) {
27104
+ const messages = context.messages.flatMap(
27105
+ (message) => normalizePiMessage(message)
27106
+ );
27107
+ if (context.systemPrompt) {
27108
+ return [{ role: "system", content: context.systemPrompt }, ...messages];
27109
+ }
27110
+ return messages;
27111
+ }
27112
+ function normalizePiMessage(message) {
27113
+ if (isPiUserMessage(message)) {
27114
+ return [
27115
+ {
27116
+ role: "user",
27117
+ content: normalizeUserContent(message.content)
27118
+ }
27119
+ ];
27120
+ }
27121
+ if (isPiAssistantMessage(message)) {
27122
+ return [normalizeAssistantMessage(message)];
27123
+ }
27124
+ if (isPiToolResultMessage(message)) {
27125
+ return [normalizeToolResultMessage(message)];
27126
+ }
27127
+ return [];
27128
+ }
27129
+ function normalizeAssistantMessage(message) {
27130
+ const text = message.content.flatMap((part) => part.type === "text" ? [part.text] : []).join("");
27131
+ const thinking = message.content.flatMap(
27132
+ (part) => part.type === "thinking" && !part.redacted ? [part.thinking] : []
27133
+ ).join("");
27134
+ const toolCalls = message.content.flatMap(
27135
+ (part) => part.type === "toolCall" ? [normalizeToolCall(part)] : []
27136
+ );
27137
+ return {
27138
+ role: "assistant",
27139
+ content: text || (toolCalls.length > 0 ? null : ""),
27140
+ ...thinking ? { reasoning: thinking } : {},
27141
+ ...toolCalls.length > 0 ? { tool_calls: toolCalls } : {}
27142
+ };
27143
+ }
27144
+ function normalizeToolResultMessage(message) {
27145
+ return {
27146
+ role: "tool",
27147
+ tool_call_id: message.toolCallId,
27148
+ content: normalizeUserContent(message.content)
27149
+ };
27150
+ }
27151
+ function normalizeUserContent(content) {
27152
+ if (typeof content === "string") {
27153
+ return content;
27154
+ }
27155
+ return content.map((part) => {
27156
+ if (part.type === "text") {
27157
+ return { type: "text", text: part.text };
27158
+ }
27159
+ if (part.type === "image") {
27160
+ return {
27161
+ type: "image_url",
27162
+ image_url: {
27163
+ url: `data:${part.mimeType};base64,${part.data}`
27164
+ }
27165
+ };
27166
+ }
27167
+ return part;
27168
+ });
27169
+ }
27170
+ function normalizeToolCall(toolCall) {
27171
+ return {
27172
+ id: toolCall.id,
27173
+ type: "function",
27174
+ function: {
27175
+ name: toolCall.name,
27176
+ arguments: stringifyArguments(toolCall.arguments)
27177
+ }
27178
+ };
27179
+ }
27180
+ function extractAssistantOutput(message) {
27181
+ return processInputAttachments([
27182
+ {
27183
+ finish_reason: normalizeStopReason(message.stopReason),
27184
+ index: 0,
27185
+ message: normalizeAssistantMessage(message)
27186
+ }
27187
+ ]);
27188
+ }
27189
+ function isPiUserMessage(message) {
27190
+ return message.role === "user" && "content" in message;
27191
+ }
27192
+ function isPiAssistantMessage(message) {
27193
+ return isObject(message) && message.role === "assistant" && Array.isArray(message.content);
27194
+ }
27195
+ function isPiToolResultMessage(message) {
27196
+ return message.role === "toolResult" && Array.isArray(message.content);
27197
+ }
27198
+ function normalizeStopReason(reason) {
27199
+ switch (reason) {
27200
+ case "toolUse":
27201
+ return "tool_calls";
27202
+ case "length":
27203
+ case "stop":
27204
+ return reason;
27205
+ default:
27206
+ return reason ?? "stop";
27207
+ }
25202
27208
  }
25203
- function getMetricsFromResponse(response) {
25204
- for (const generation of walkGenerations(response)) {
25205
- const message = generation.message;
25206
- if (!isRecord(message)) {
25207
- continue;
25208
- }
25209
- const usageMetadata = message.usage_metadata;
25210
- if (!isRecord(usageMetadata)) {
25211
- continue;
27209
+ function extractPromptInput(text, options) {
27210
+ const images = options?.images;
27211
+ if (!images || images.length === 0) {
27212
+ return text;
27213
+ }
27214
+ return processInputAttachments([
27215
+ {
27216
+ role: "user",
27217
+ content: [
27218
+ { type: "text", text: text ?? "" },
27219
+ ...images.map((image) => ({
27220
+ type: "image_url",
27221
+ image_url: {
27222
+ url: `data:${image.mimeType};base64,${image.data}`
27223
+ }
27224
+ }))
27225
+ ]
25212
27226
  }
25213
- const inputTokenDetails = usageMetadata.input_token_details;
25214
- return cleanObject({
25215
- total_tokens: usageMetadata.total_tokens,
25216
- prompt_tokens: usageMetadata.input_tokens,
25217
- completion_tokens: usageMetadata.output_tokens,
25218
- prompt_cache_creation_tokens: isRecord(inputTokenDetails) ? inputTokenDetails.cache_creation : void 0,
25219
- prompt_cached_tokens: isRecord(inputTokenDetails) ? inputTokenDetails.cache_read : void 0
25220
- });
27227
+ ]);
27228
+ }
27229
+ function extractToolMetadata(tools) {
27230
+ if (!tools || tools.length === 0) {
27231
+ return {};
25221
27232
  }
25222
- const llmOutput = response.llmOutput || {};
25223
- const tokenUsage = isRecord(llmOutput.tokenUsage) ? llmOutput.tokenUsage : isRecord(llmOutput.estimatedTokens) ? llmOutput.estimatedTokens : {};
25224
- return cleanObject({
25225
- total_tokens: tokenUsage.totalTokens,
25226
- prompt_tokens: tokenUsage.promptTokens,
25227
- completion_tokens: tokenUsage.completionTokens
25228
- });
27233
+ return {
27234
+ tools: tools.map((tool) => ({
27235
+ type: "function",
27236
+ function: {
27237
+ name: tool.name,
27238
+ ...tool.description ? { description: tool.description } : {},
27239
+ ...tool.parameters ? { parameters: tool.parameters } : {}
27240
+ }
27241
+ }))
27242
+ };
25229
27243
  }
25230
- function safeJsonParse(input) {
25231
- try {
25232
- return JSON.parse(input);
25233
- } catch {
25234
- return input;
27244
+ function extractModelMetadata2(model) {
27245
+ if (!model) {
27246
+ return {};
25235
27247
  }
27248
+ return {
27249
+ ...model.provider ? { provider: model.provider } : {},
27250
+ ...model.id ? { model: model.id, "pi_coding_agent.model": model.id } : {},
27251
+ ...model.api ? { "pi_coding_agent.api": model.api } : {},
27252
+ ...model.name ? { "pi_coding_agent.model_name": model.name } : {}
27253
+ };
25236
27254
  }
25237
- function isRecord(value) {
25238
- return typeof value === "object" && value !== null && !Array.isArray(value);
27255
+ function extractAssistantMetadata(message) {
27256
+ return {
27257
+ ...message.provider ? { provider: message.provider } : {},
27258
+ ...message.responseModel || message.model ? { model: message.responseModel ?? message.model } : {},
27259
+ ...message.api ? { "pi_coding_agent.api": message.api } : {},
27260
+ ...message.model ? { "pi_coding_agent.model": message.model } : {},
27261
+ ...message.responseModel ? { "pi_coding_agent.response_model": message.responseModel } : {},
27262
+ ...message.responseId ? { "pi_coding_agent.response_id": message.responseId } : {},
27263
+ ...message.stopReason ? { "pi_coding_agent.stop_reason": message.stopReason } : {}
27264
+ };
25239
27265
  }
25240
-
25241
- // src/instrumentation/plugins/langchain-channels.ts
25242
- var langChainChannels = defineChannels("@langchain/core", {
25243
- configure: channel({
25244
- channelName: "CallbackManager.configure",
25245
- kind: "sync-stream"
25246
- }),
25247
- configureSync: channel({
25248
- channelName: "CallbackManager._configureSync",
25249
- kind: "sync-stream"
25250
- })
25251
- });
25252
-
25253
- // src/instrumentation/plugins/langchain-plugin.ts
25254
- var LangChainPlugin = class extends BasePlugin {
25255
- injectedManagers = /* @__PURE__ */ new WeakSet();
25256
- onEnable() {
25257
- this.subscribeToConfigure(langChainChannels.configure);
25258
- this.subscribeToConfigure(langChainChannels.configureSync);
27266
+ function extractSessionMetadata(session) {
27267
+ return {
27268
+ ...extractModelMetadata2(session.model),
27269
+ ...session.sessionId ? { "pi_coding_agent.session_id": session.sessionId } : {},
27270
+ ...session.sessionName ? { "pi_coding_agent.session_name": session.sessionName } : {},
27271
+ ...session.thinkingLevel ? { "pi_coding_agent.thinking_level": session.thinkingLevel } : {},
27272
+ ...typeof session.getActiveToolNames === "function" ? { "pi_coding_agent.active_tools": session.getActiveToolNames() } : {}
27273
+ };
27274
+ }
27275
+ function extractPromptOptionsMetadata(options) {
27276
+ if (!options) {
27277
+ return {};
25259
27278
  }
25260
- onDisable() {
25261
- for (const unsubscribe of this.unsubscribers) {
25262
- unsubscribe();
25263
- }
25264
- this.unsubscribers = [];
25265
- this.injectedManagers = /* @__PURE__ */ new WeakSet();
27279
+ return {
27280
+ ...options.source ? { "pi_coding_agent.source": options.source } : {},
27281
+ ...options.streamingBehavior ? { "pi_coding_agent.streaming_behavior": options.streamingBehavior } : {},
27282
+ ...options.expandPromptTemplates !== void 0 ? {
27283
+ "pi_coding_agent.expand_prompt_templates": options.expandPromptTemplates
27284
+ } : {}
27285
+ };
27286
+ }
27287
+ function extractStreamOptionsMetadata(options) {
27288
+ if (!options) {
27289
+ return {};
25266
27290
  }
25267
- subscribeToConfigure(channel2) {
25268
- const tracingChannel2 = channel2.tracingChannel();
25269
- const handlers = {
25270
- start: (event) => {
25271
- injectHandlerIntoArguments(event.arguments);
25272
- },
25273
- end: (event) => {
25274
- this.injectHandler(event.result);
25275
- }
25276
- };
25277
- tracingChannel2.subscribe(handlers);
25278
- this.unsubscribers.push(() => {
25279
- tracingChannel2.unsubscribe(handlers);
25280
- });
27291
+ return {
27292
+ ...options.temperature !== void 0 ? { temperature: options.temperature } : {},
27293
+ ...options.maxTokens !== void 0 ? { max_tokens: options.maxTokens } : {},
27294
+ ...options.reasoning ? { "pi_coding_agent.reasoning": options.reasoning } : {},
27295
+ ...options.transport ? { "pi_coding_agent.transport": options.transport } : {},
27296
+ ...options.cacheRetention ? { "pi_coding_agent.cache_retention": options.cacheRetention } : {},
27297
+ ...options.sessionId ? { "pi_coding_agent.session_id": options.sessionId } : {},
27298
+ ...options.timeoutMs !== void 0 ? { "pi_coding_agent.timeout_ms": options.timeoutMs } : {},
27299
+ ...options.maxRetries !== void 0 ? { "pi_coding_agent.max_retries": options.maxRetries } : {},
27300
+ ...options.maxRetryDelayMs !== void 0 ? { "pi_coding_agent.max_retry_delay_ms": options.maxRetryDelayMs } : {},
27301
+ ...options.metadata ? { "pi_coding_agent.metadata": options.metadata } : {}
27302
+ };
27303
+ }
27304
+ function getLlmSpanName(model) {
27305
+ switch (model.api) {
27306
+ case "anthropic-messages":
27307
+ return "anthropic.messages.create";
27308
+ case "openai-completions":
27309
+ return "Chat Completion";
27310
+ case "openai-responses":
27311
+ case "azure-openai-responses":
27312
+ case "openai-codex-responses":
27313
+ return "openai.responses.create";
27314
+ case "google-generative-ai":
27315
+ case "google-vertex":
27316
+ return "generate_content";
27317
+ case "mistral-conversations":
27318
+ return "mistral.chat.stream";
27319
+ case "bedrock-converse-stream":
27320
+ return "bedrock.converse_stream";
27321
+ default:
27322
+ return "pi_ai.streamSimple";
25281
27323
  }
25282
- injectHandler(result) {
25283
- if (!isCallbackManager(result)) {
25284
- return;
25285
- }
25286
- if (this.injectedManagers.has(result) || hasBraintrustHandler(result)) {
25287
- return;
25288
- }
25289
- try {
25290
- result.addHandler(new BraintrustLangChainCallbackHandler(), true);
25291
- this.injectedManagers.add(result);
25292
- } catch {
25293
- }
27324
+ }
27325
+ function extractUsageMetrics2(usage) {
27326
+ if (!usage) {
27327
+ return {};
25294
27328
  }
25295
- };
25296
- function isCallbackManager(value) {
25297
- if (typeof value !== "object" || value === null) {
25298
- return false;
27329
+ return cleanMetrics5({
27330
+ completion_tokens: usage.output,
27331
+ prompt_cache_creation_tokens: usage.cacheWrite,
27332
+ prompt_cached_tokens: usage.cacheRead,
27333
+ prompt_tokens: usage.input,
27334
+ tokens: usage.totalTokens ?? usage.tokens
27335
+ });
27336
+ }
27337
+ function addMetrics(target, source) {
27338
+ for (const [key, value] of Object.entries(source)) {
27339
+ target[key] = (target[key] ?? 0) + value;
25299
27340
  }
25300
- const maybeManager = value;
25301
- return typeof maybeManager.addHandler === "function";
25302
27341
  }
25303
- function hasBraintrustHandler(manager) {
25304
- return manager.handlers?.some((handler) => {
25305
- if (typeof handler !== "object" || handler === null) {
25306
- return false;
25307
- }
25308
- const name = Reflect.get(handler, "name");
25309
- return name === BRAINTRUST_LANGCHAIN_CALLBACK_HANDLER_NAME;
25310
- }) ?? false;
27342
+ function buildDurationMetrics3(startTime) {
27343
+ const end = getCurrentUnixTimestamp();
27344
+ return {
27345
+ duration: end - startTime,
27346
+ end,
27347
+ start: startTime
27348
+ };
25311
27349
  }
25312
- function injectHandlerIntoArguments(args) {
25313
- if (!isWritableArgumentsObject(args)) {
25314
- return;
27350
+ function cleanMetrics5(metrics) {
27351
+ const cleaned = {};
27352
+ for (const [key, value] of Object.entries(metrics)) {
27353
+ if (typeof value === "number" && Number.isFinite(value) && value >= 0) {
27354
+ cleaned[key] = value;
27355
+ }
25315
27356
  }
25316
- const inheritedHandlers = Reflect.get(args, "0");
25317
- const handler = new BraintrustLangChainCallbackHandler();
25318
- if (inheritedHandlers === void 0 || inheritedHandlers === null) {
25319
- Reflect.set(args, "0", [handler]);
25320
- return;
27357
+ return cleaned;
27358
+ }
27359
+ function stringifyArguments(value) {
27360
+ if (typeof value === "string") {
27361
+ return value;
25321
27362
  }
25322
- if (Array.isArray(inheritedHandlers)) {
25323
- if (!inheritedHandlers.some(isBraintrustHandler)) {
25324
- inheritedHandlers.push(handler);
25325
- }
27363
+ try {
27364
+ return JSON.stringify(value);
27365
+ } catch {
27366
+ return stringifyUnknown2(value);
25326
27367
  }
25327
27368
  }
25328
- function isWritableArgumentsObject(args) {
25329
- return typeof args === "object" && args !== null;
27369
+ function stringifyUnknown2(value) {
27370
+ if (value instanceof Error) {
27371
+ return value.message;
27372
+ }
27373
+ if (typeof value === "string") {
27374
+ return value;
27375
+ }
27376
+ try {
27377
+ return JSON.stringify(value);
27378
+ } catch {
27379
+ return String(value);
27380
+ }
25330
27381
  }
25331
- function isBraintrustHandler(handler) {
25332
- if (typeof handler !== "object" || handler === null) {
25333
- return false;
27382
+ function safeLog4(span, event) {
27383
+ try {
27384
+ span.log(event);
27385
+ } catch (error) {
27386
+ logInstrumentationError4("Pi Coding Agent span log", error);
25334
27387
  }
25335
- return Reflect.get(handler, "name") === BRAINTRUST_LANGCHAIN_CALLBACK_HANDLER_NAME;
27388
+ }
27389
+ function logInstrumentationError4(context, error) {
27390
+ debugLogger.debug(`${context}:`, error);
25336
27391
  }
25337
27392
 
25338
27393
  // src/instrumentation/braintrust-plugin.ts
@@ -25360,6 +27415,7 @@ var BraintrustPlugin = class extends BasePlugin {
25360
27415
  gitHubCopilotPlugin = null;
25361
27416
  fluePlugin = null;
25362
27417
  langChainPlugin = null;
27418
+ piCodingAgentPlugin = null;
25363
27419
  constructor(config = {}) {
25364
27420
  super();
25365
27421
  this.config = config;
@@ -25434,6 +27490,10 @@ var BraintrustPlugin = class extends BasePlugin {
25434
27490
  this.gitHubCopilotPlugin = new GitHubCopilotPlugin();
25435
27491
  this.gitHubCopilotPlugin.enable();
25436
27492
  }
27493
+ if (integrations.piCodingAgent !== false) {
27494
+ this.piCodingAgentPlugin = new PiCodingAgentPlugin();
27495
+ this.piCodingAgentPlugin.enable();
27496
+ }
25437
27497
  if (getIntegrationConfig(integrations, "flue") !== false) {
25438
27498
  this.fluePlugin = new FluePlugin();
25439
27499
  this.fluePlugin.enable();
@@ -25512,6 +27572,10 @@ var BraintrustPlugin = class extends BasePlugin {
25512
27572
  this.gitHubCopilotPlugin.disable();
25513
27573
  this.gitHubCopilotPlugin = null;
25514
27574
  }
27575
+ if (this.piCodingAgentPlugin) {
27576
+ this.piCodingAgentPlugin.disable();
27577
+ this.piCodingAgentPlugin = null;
27578
+ }
25515
27579
  if (this.fluePlugin) {
25516
27580
  this.fluePlugin.disable();
25517
27581
  this.fluePlugin = null;
@@ -25531,6 +27595,11 @@ var envIntegrationAliases = {
25531
27595
  openaicodexsdk: "openaiCodexSDK",
25532
27596
  codex: "openaiCodexSDK",
25533
27597
  "codex-sdk": "openaiCodexSDK",
27598
+ "pi-coding-agent": "piCodingAgent",
27599
+ "pi-coding-agent-sdk": "piCodingAgent",
27600
+ picodingagent: "piCodingAgent",
27601
+ picodingagentsdk: "piCodingAgent",
27602
+ "@earendil-works/pi-coding-agent": "piCodingAgent",
25534
27603
  anthropic: "anthropic",
25535
27604
  aisdk: "aisdk",
25536
27605
  "ai-sdk": "aisdk",
@@ -25596,7 +27665,8 @@ function getDefaultInstrumentationIntegrations() {
25596
27665
  genkit: true,
25597
27666
  gitHubCopilot: true,
25598
27667
  langchain: true,
25599
- langgraph: true
27668
+ langgraph: true,
27669
+ piCodingAgent: true
25600
27670
  };
25601
27671
  }
25602
27672
  function readDisabledInstrumentationEnvConfig(disabledList) {
@@ -25807,6 +27877,7 @@ __export(exports_exports, {
25807
27877
  _internalIso: () => isomorph_default,
25808
27878
  _internalSetInitialState: () => _internalSetInitialState,
25809
27879
  addAzureBlobHeaders: () => addAzureBlobHeaders,
27880
+ braintrustAISDKTelemetry: () => braintrustAISDKTelemetry,
25810
27881
  braintrustFlueObserver: () => braintrustFlueObserver,
25811
27882
  braintrustStreamChunkSchema: () => braintrustStreamChunkSchema,
25812
27883
  buildLocalSummary: () => buildLocalSummary,
@@ -25899,6 +27970,7 @@ __export(exports_exports, {
25899
27970
  wrapOpenAIv4: () => wrapOpenAIv4,
25900
27971
  wrapOpenRouter: () => wrapOpenRouter,
25901
27972
  wrapOpenRouterAgent: () => wrapOpenRouterAgent,
27973
+ wrapPiCodingAgentSDK: () => wrapPiCodingAgentSDK,
25902
27974
  wrapTraced: () => wrapTraced,
25903
27975
  wrapVitest: () => wrapVitest
25904
27976
  });
@@ -27959,6 +30031,54 @@ function wrapCursorAgent(agent) {
27959
30031
  return proxy;
27960
30032
  }
27961
30033
 
30034
+ // src/wrappers/pi-coding-agent.ts
30035
+ var WRAPPED_PROMPT = /* @__PURE__ */ Symbol.for("braintrust.pi-coding-agent.wrapped-prompt");
30036
+ function wrapPiCodingAgentSDK(sdk) {
30037
+ if (!sdk || typeof sdk !== "object") {
30038
+ return sdk;
30039
+ }
30040
+ const maybeSDK = sdk;
30041
+ if (!maybeSDK.AgentSession || typeof maybeSDK.AgentSession !== "function") {
30042
+ console.warn("Unsupported Pi Coding Agent SDK. Not wrapping.");
30043
+ return sdk;
30044
+ }
30045
+ patchAgentSessionClass(
30046
+ maybeSDK.AgentSession
30047
+ );
30048
+ return sdk;
30049
+ }
30050
+ function patchAgentSessionClass(AgentSession) {
30051
+ const prototype = AgentSession.prototype;
30052
+ if (!prototype || prototype[WRAPPED_PROMPT]) {
30053
+ return;
30054
+ }
30055
+ const descriptor = Object.getOwnPropertyDescriptor(prototype, "prompt");
30056
+ if (!descriptor || typeof descriptor.value !== "function") {
30057
+ console.warn("Unsupported Pi Coding Agent SDK. Not wrapping.");
30058
+ return;
30059
+ }
30060
+ const originalPrompt = descriptor.value;
30061
+ Object.defineProperty(prototype, "prompt", {
30062
+ ...descriptor,
30063
+ value: function wrappedPiCodingAgentPrompt(text, options) {
30064
+ const args = [text, options];
30065
+ return piCodingAgentChannels.prompt.tracePromise(
30066
+ () => Reflect.apply(originalPrompt, this, args),
30067
+ {
30068
+ arguments: args,
30069
+ self: this,
30070
+ session: this
30071
+ }
30072
+ );
30073
+ }
30074
+ });
30075
+ Object.defineProperty(prototype, WRAPPED_PROMPT, {
30076
+ configurable: false,
30077
+ enumerable: false,
30078
+ value: true
30079
+ });
30080
+ }
30081
+
27962
30082
  // src/wrappers/google-genai.ts
27963
30083
  function wrapGoogleGenAI(googleGenAI) {
27964
30084
  if (!googleGenAI || typeof googleGenAI !== "object") {
@@ -27995,12 +30115,25 @@ function wrapGoogleGenAIClass(OriginalGoogleGenAI) {
27995
30115
  }
27996
30116
  function wrapGoogleGenAIInstance(instance) {
27997
30117
  const wrappedModels = wrapModels(instance.models);
30118
+ let originalInteractions;
30119
+ let wrappedInteractions;
27998
30120
  patchGoogleGenAIChats(instance, wrappedModels);
27999
30121
  return new Proxy(instance, {
28000
30122
  get(target, prop, receiver) {
28001
30123
  if (prop === "models") {
28002
30124
  return wrappedModels;
28003
30125
  }
30126
+ if (prop === "interactions") {
30127
+ const interactions = Reflect.get(target, prop, receiver);
30128
+ if (!isObject(interactions) || typeof interactions.create !== "function") {
30129
+ return interactions;
30130
+ }
30131
+ if (interactions !== originalInteractions) {
30132
+ originalInteractions = interactions;
30133
+ wrappedInteractions = wrapInteractions(interactions);
30134
+ }
30135
+ return wrappedInteractions;
30136
+ }
28004
30137
  return Reflect.get(target, prop, receiver);
28005
30138
  }
28006
30139
  });
@@ -28027,6 +30160,16 @@ function wrapModels(models) {
28027
30160
  }
28028
30161
  });
28029
30162
  }
30163
+ function wrapInteractions(interactions) {
30164
+ return new Proxy(interactions, {
30165
+ get(target, prop, receiver) {
30166
+ if (prop === "create") {
30167
+ return wrapInteractionCreate(target.create.bind(target));
30168
+ }
30169
+ return Reflect.get(target, prop, receiver);
30170
+ }
30171
+ });
30172
+ }
28030
30173
  function wrapGenerateContent(original) {
28031
30174
  return function(params) {
28032
30175
  return googleGenAIChannels.generateContent.tracePromise(
@@ -28051,6 +30194,18 @@ function wrapEmbedContent(original) {
28051
30194
  );
28052
30195
  };
28053
30196
  }
30197
+ function wrapInteractionCreate(original) {
30198
+ return function(params, options) {
30199
+ if (params.background === true) {
30200
+ return options === void 0 ? original(params) : original(params, options);
30201
+ }
30202
+ const traceContext = options === void 0 ? { arguments: [params] } : { arguments: [params, options] };
30203
+ return googleGenAIChannels.interactionsCreate.tracePromise(
30204
+ () => options === void 0 ? original(params) : original(params, options),
30205
+ traceContext
30206
+ );
30207
+ };
30208
+ }
28054
30209
 
28055
30210
  // src/wrappers/google-adk.ts
28056
30211
  function wrapGoogleADK(adkModule) {
@@ -31568,6 +33723,13 @@ var EvalResultWithSummary = class {
31568
33723
  };
31569
33724
  }
31570
33725
  };
33726
+ async function getPersistedBaseExperimentId(experiment) {
33727
+ try {
33728
+ return await experiment._getBaseExperimentId();
33729
+ } catch {
33730
+ return void 0;
33731
+ }
33732
+ }
31571
33733
  function makeEvalName(projectName, experimentName) {
31572
33734
  let out = projectName;
31573
33735
  if (experimentName) {
@@ -31950,6 +34112,14 @@ async function runEvaluatorInternal(experiment, evaluator, progressReporter, fil
31950
34112
  return;
31951
34113
  }
31952
34114
  const eventDataset = experiment ? experiment.dataset : Dataset2.isDataset(evaluator.data) ? evaluator.data : void 0;
34115
+ const inlineOrigin = datum.origin === void 0 ? void 0 : ObjectReference.parse(datum.origin);
34116
+ const origin = inlineOrigin ?? (eventDataset && datum.id && datum._xact_id ? {
34117
+ object_type: "dataset",
34118
+ object_id: await eventDataset.id,
34119
+ id: datum.id,
34120
+ created: datum.created,
34121
+ _xact_id: datum._xact_id
34122
+ } : void 0);
31953
34123
  const baseEvent = {
31954
34124
  name: "eval",
31955
34125
  spanAttributes: {
@@ -31959,13 +34129,7 @@ async function runEvaluatorInternal(experiment, evaluator, progressReporter, fil
31959
34129
  input: datum.input,
31960
34130
  expected: "expected" in datum ? datum.expected : void 0,
31961
34131
  tags: datum.tags,
31962
- origin: eventDataset && datum.id && datum._xact_id ? {
31963
- object_type: "dataset",
31964
- object_id: await eventDataset.id,
31965
- id: datum.id,
31966
- created: datum.created,
31967
- _xact_id: datum._xact_id
31968
- } : void 0,
34132
+ origin,
31969
34133
  ...datum.upsert_id ? { id: datum.upsert_id } : {}
31970
34134
  }
31971
34135
  };
@@ -32322,8 +34486,10 @@ async function runEvaluatorInternal(experiment, evaluator, progressReporter, fil
32322
34486
  collectedResults.length = 0;
32323
34487
  }
32324
34488
  }
34489
+ const comparisonExperimentId = experiment ? evaluator.baseExperimentId ?? await getPersistedBaseExperimentId(experiment) : void 0;
32325
34490
  const summary = experiment ? await experiment.summarize({
32326
- summarizeScores: evaluator.summarizeScores
34491
+ summarizeScores: evaluator.summarizeScores,
34492
+ ...comparisonExperimentId !== void 0 ? { comparisonExperimentId } : {}
32327
34493
  }) : buildLocalSummary(
32328
34494
  evaluator,
32329
34495
  collectResults ? collectedResults : [],
@@ -32552,6 +34718,7 @@ var Project2 = class {
32552
34718
  prompts;
32553
34719
  parameters;
32554
34720
  scorers;
34721
+ classifiers;
32555
34722
  _publishableCodeFunctions = [];
32556
34723
  _publishablePrompts = [];
32557
34724
  _publishableParameters = [];
@@ -32563,6 +34730,7 @@ var Project2 = class {
32563
34730
  this.prompts = new PromptBuilder(this);
32564
34731
  this.parameters = new ParametersBuilder(this);
32565
34732
  this.scorers = new ScorerBuilder(this);
34733
+ this.classifiers = new ClassifierBuilder(this);
32566
34734
  }
32567
34735
  addPrompt(prompt) {
32568
34736
  this._publishablePrompts.push(prompt);
@@ -32697,6 +34865,28 @@ var ScorerBuilder = class {
32697
34865
  }
32698
34866
  }
32699
34867
  };
34868
+ var ClassifierBuilder = class {
34869
+ constructor(project) {
34870
+ this.project = project;
34871
+ }
34872
+ taskCounter = 0;
34873
+ create(opts) {
34874
+ this.taskCounter++;
34875
+ let resolvedName = opts.name ?? opts.handler.name;
34876
+ if (!resolvedName || resolvedName.trim().length === 0) {
34877
+ resolvedName = `Classifier ${isomorph_default.basename(currentFilename)} ${this.taskCounter}`;
34878
+ }
34879
+ const slug = opts.slug ?? slugify(resolvedName, { lower: true, strict: true });
34880
+ const classifier = new CodeFunction(this.project, {
34881
+ ...opts,
34882
+ name: resolvedName,
34883
+ slug,
34884
+ type: "classifier"
34885
+ });
34886
+ this.project.addCodeFunction(classifier);
34887
+ return classifier;
34888
+ }
34889
+ };
32700
34890
  var CodeFunction = class {
32701
34891
  constructor(project, opts) {
32702
34892
  this.project = project;
@@ -33046,7 +35236,7 @@ var serializedParametersContainerSchema = z13.union([
33046
35236
  staticParametersSchema
33047
35237
  ]);
33048
35238
  var evaluatorDefinitionSchema = z13.object({
33049
- parameters: serializedParametersContainerSchema.optional(),
35239
+ parameters: serializedParametersContainerSchema.nullish(),
33050
35240
  scores: z13.array(z13.object({ name: z13.string() })).optional(),
33051
35241
  classifiers: z13.array(z13.object({ name: z13.string() })).optional()
33052
35242
  });
@@ -33114,6 +35304,7 @@ export {
33114
35304
  isomorph_default as _internalIso,
33115
35305
  _internalSetInitialState,
33116
35306
  addAzureBlobHeaders,
35307
+ braintrustAISDKTelemetry,
33117
35308
  braintrustFlueObserver,
33118
35309
  braintrustStreamChunkSchema,
33119
35310
  buildLocalSummary,
@@ -33207,6 +35398,7 @@ export {
33207
35398
  wrapOpenAIv4,
33208
35399
  wrapOpenRouter,
33209
35400
  wrapOpenRouterAgent,
35401
+ wrapPiCodingAgentSDK,
33210
35402
  wrapTraced,
33211
35403
  wrapVitest
33212
35404
  };