braintrust 3.17.0 → 3.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/dev/dist/index.d.mts +13 -0
  2. package/dev/dist/index.d.ts +13 -0
  3. package/dev/dist/index.js +4300 -2199
  4. package/dev/dist/index.mjs +2211 -110
  5. package/dist/apply-auto-instrumentation.js +238 -186
  6. package/dist/apply-auto-instrumentation.mjs +68 -16
  7. package/dist/auto-instrumentations/bundler/esbuild.cjs +90 -15
  8. package/dist/auto-instrumentations/bundler/esbuild.mjs +2 -2
  9. package/dist/auto-instrumentations/bundler/next.cjs +90 -15
  10. package/dist/auto-instrumentations/bundler/next.mjs +3 -3
  11. package/dist/auto-instrumentations/bundler/rollup.cjs +90 -15
  12. package/dist/auto-instrumentations/bundler/rollup.mjs +2 -2
  13. package/dist/auto-instrumentations/bundler/vite.cjs +90 -15
  14. package/dist/auto-instrumentations/bundler/vite.mjs +2 -2
  15. package/dist/auto-instrumentations/bundler/webpack-loader.cjs +89 -14
  16. package/dist/auto-instrumentations/bundler/webpack.cjs +90 -15
  17. package/dist/auto-instrumentations/bundler/webpack.mjs +3 -3
  18. package/dist/auto-instrumentations/{chunk-VXJONZVX.mjs → chunk-GNUEZ2PE.mjs} +13 -3
  19. package/dist/auto-instrumentations/{chunk-CNQ7BUKN.mjs → chunk-MYCHHXOE.mjs} +1 -1
  20. package/dist/auto-instrumentations/{chunk-E5DUYJWK.mjs → chunk-ZYKZEMRT.mjs} +82 -15
  21. package/dist/auto-instrumentations/hook.mjs +102 -15
  22. package/dist/auto-instrumentations/index.cjs +84 -16
  23. package/dist/auto-instrumentations/index.d.mts +3 -1
  24. package/dist/auto-instrumentations/index.d.ts +3 -1
  25. package/dist/auto-instrumentations/index.mjs +5 -3
  26. package/dist/auto-instrumentations/loader/cjs-patch.cjs +1 -1
  27. package/dist/auto-instrumentations/loader/cjs-patch.mjs +1 -1
  28. package/dist/auto-instrumentations/loader/esm-hook.mjs +1 -1
  29. package/dist/browser.d.mts +177 -11
  30. package/dist/browser.d.ts +177 -11
  31. package/dist/browser.js +2296 -104
  32. package/dist/browser.mjs +2455 -263
  33. package/dist/{chunk-VMBQETG3.js → chunk-73IYIIOL.js} +28 -2
  34. package/dist/{chunk-O4ZIWXO3.mjs → chunk-BYFADLEZ.mjs} +27 -1
  35. package/dist/cli.js +2219 -118
  36. package/dist/edge-light.d.mts +1 -1
  37. package/dist/edge-light.d.ts +1 -1
  38. package/dist/edge-light.js +2296 -104
  39. package/dist/edge-light.mjs +2455 -263
  40. package/dist/index.d.mts +177 -11
  41. package/dist/index.d.ts +177 -11
  42. package/dist/index.js +3296 -1128
  43. package/dist/index.mjs +2272 -104
  44. package/dist/instrumentation/index.d.mts +3 -0
  45. package/dist/instrumentation/index.d.ts +3 -0
  46. package/dist/instrumentation/index.js +2171 -105
  47. package/dist/instrumentation/index.mjs +2171 -105
  48. package/dist/workerd.d.mts +1 -1
  49. package/dist/workerd.d.ts +1 -1
  50. package/dist/workerd.js +2296 -104
  51. package/dist/workerd.mjs +2455 -263
  52. package/package.json +10 -10
package/dist/browser.mjs CHANGED
@@ -4957,14 +4957,18 @@ function useTestBackgroundLogger() {
4957
4957
  function clearTestBackgroundLogger() {
4958
4958
  _internalGetGlobalState()?.setOverrideBgLogger(null);
4959
4959
  }
4960
- function initTestExperiment(experimentName, projectName) {
4960
+ function initTestExperiment(experimentName, projectName, experimentFullInfo = {}) {
4961
4961
  setInitialTestState();
4962
4962
  const state = _internalGetGlobalState();
4963
4963
  const project = projectName ?? experimentName;
4964
4964
  const lazyMetadata = new LazyValue(
4965
4965
  async () => ({
4966
4966
  project: { id: project, name: project, fullInfo: {} },
4967
- experiment: { id: experimentName, name: experimentName, fullInfo: {} }
4967
+ experiment: {
4968
+ id: experimentName,
4969
+ name: experimentName,
4970
+ fullInfo: experimentFullInfo
4971
+ }
4968
4972
  })
4969
4973
  );
4970
4974
  return new Experiment2(state, lazyMetadata);
@@ -8329,6 +8333,10 @@ var Experiment2 = class extends ObjectFetcher {
8329
8333
  return (await this.lazyMetadata.get()).project;
8330
8334
  })();
8331
8335
  }
8336
+ async _getBaseExperimentId() {
8337
+ const baseExperimentId = (await this.lazyMetadata.get()).experiment.fullInfo["base_exp_id"];
8338
+ return typeof baseExperimentId === "string" && baseExperimentId ? baseExperimentId : void 0;
8339
+ }
8332
8340
  parentObjectType() {
8333
8341
  return 1 /* EXPERIMENT */;
8334
8342
  }
@@ -8469,6 +8477,14 @@ var Experiment2 = class extends ObjectFetcher {
8469
8477
  comparisonExperimentId = baseExperiment.id;
8470
8478
  comparisonExperimentName = baseExperiment.name;
8471
8479
  }
8480
+ } else {
8481
+ try {
8482
+ const comparisonExperiment = await state.apiConn().get_json(`v1/experiment/${comparisonExperimentId}`);
8483
+ if (typeof comparisonExperiment["name"] === "string") {
8484
+ comparisonExperimentName = comparisonExperiment["name"];
8485
+ }
8486
+ } catch {
8487
+ }
8472
8488
  }
8473
8489
  try {
8474
8490
  const results = await state.apiConn().get_json(
@@ -10510,6 +10526,64 @@ var BasePlugin = class {
10510
10526
  }
10511
10527
  };
10512
10528
 
10529
+ // src/instrumentation/auto-instrumentation-suppression.ts
10530
+ var autoInstrumentationSuppressionStore;
10531
+ function suppressionStore() {
10532
+ autoInstrumentationSuppressionStore ??= isomorph_default.newAsyncLocalStorage();
10533
+ return autoInstrumentationSuppressionStore;
10534
+ }
10535
+ function currentFrames() {
10536
+ return suppressionStore().getStore()?.frames ?? [];
10537
+ }
10538
+ function isAutoInstrumentationSuppressed() {
10539
+ const frames = currentFrames();
10540
+ return frames[frames.length - 1]?.mode === "suppress";
10541
+ }
10542
+ function runWithAutoInstrumentationSuppressed(callback) {
10543
+ const frame = {
10544
+ id: /* @__PURE__ */ Symbol("braintrust.auto-instrumentation-suppress"),
10545
+ mode: "suppress"
10546
+ };
10547
+ return suppressionStore().run(
10548
+ { frames: [...currentFrames(), frame] },
10549
+ callback
10550
+ );
10551
+ }
10552
+ function bindAutoInstrumentationSuppressionToStart(tracingChannel2) {
10553
+ const startChannel = tracingChannel2.start;
10554
+ if (!startChannel) {
10555
+ return void 0;
10556
+ }
10557
+ const store = suppressionStore();
10558
+ startChannel.bindStore(store, () => ({
10559
+ frames: [
10560
+ ...currentFrames(),
10561
+ {
10562
+ id: /* @__PURE__ */ Symbol("braintrust.auto-instrumentation-suppress"),
10563
+ mode: "suppress"
10564
+ }
10565
+ ]
10566
+ }));
10567
+ return () => {
10568
+ startChannel.unbindStore(store);
10569
+ };
10570
+ }
10571
+ function enterAutoInstrumentationAllowed() {
10572
+ const frame = {
10573
+ id: /* @__PURE__ */ Symbol("braintrust.auto-instrumentation-allow"),
10574
+ mode: "allow"
10575
+ };
10576
+ suppressionStore().enterWith({
10577
+ frames: [...currentFrames(), frame]
10578
+ });
10579
+ return () => {
10580
+ const frames = currentFrames().filter(
10581
+ (candidate) => candidate.id !== frame.id
10582
+ );
10583
+ suppressionStore().enterWith(frames.length > 0 ? { frames } : void 0);
10584
+ };
10585
+ }
10586
+
10513
10587
  // src/instrumentation/core/channel-tracing.ts
10514
10588
  function isSyncStreamLike(value) {
10515
10589
  return !!value && typeof value === "object" && typeof value.on === "function";
@@ -10541,16 +10615,33 @@ function startSpanForEvent(config, event, channelName) {
10541
10615
  metadata: mergeInputMetadata(metadata, spanInfoMetadata)
10542
10616
  });
10543
10617
  } catch (error) {
10544
- console.error(`Error extracting input for ${channelName}:`, error);
10618
+ debugLogger.error(`Error extracting input for ${channelName}:`, error);
10545
10619
  }
10546
10620
  return { span, startTime };
10547
10621
  }
10622
+ function shouldTraceEvent(config, event, channelName) {
10623
+ if (!config.shouldTrace) {
10624
+ return true;
10625
+ }
10626
+ try {
10627
+ return config.shouldTrace(event.arguments, event);
10628
+ } catch (error) {
10629
+ debugLogger.error(
10630
+ `Error checking trace predicate for ${channelName}:`,
10631
+ error
10632
+ );
10633
+ return true;
10634
+ }
10635
+ }
10548
10636
  function ensureSpanStateForEvent(states, config, event, channelName) {
10549
10637
  const key = event;
10550
10638
  const existing = states.get(key);
10551
10639
  if (existing) {
10552
10640
  return existing;
10553
10641
  }
10642
+ if (!shouldTraceEvent(config, event, channelName)) {
10643
+ return void 0;
10644
+ }
10554
10645
  const created = startSpanForEvent(config, event, channelName);
10555
10646
  states.set(key, created);
10556
10647
  return created;
@@ -10566,13 +10657,16 @@ function bindCurrentSpanStoreToStart(tracingChannel2, states, config, channelNam
10566
10657
  startChannel.bindStore(
10567
10658
  currentSpanStore,
10568
10659
  (event) => {
10569
- const span = ensureSpanStateForEvent(
10660
+ if (isAutoInstrumentationSuppressed()) {
10661
+ return currentSpanStore.getStore();
10662
+ }
10663
+ const spanState = ensureSpanStateForEvent(
10570
10664
  states,
10571
10665
  config,
10572
10666
  event,
10573
10667
  channelName
10574
- ).span;
10575
- return contextManager.wrapSpanForStore(span);
10668
+ );
10669
+ return spanState ? contextManager.wrapSpanForStore(spanState.span) : currentSpanStore.getStore();
10576
10670
  }
10577
10671
  );
10578
10672
  return () => {
@@ -10607,7 +10701,10 @@ function runStreamingCompletionHook(args) {
10607
10701
  startTime: args.startTime
10608
10702
  });
10609
10703
  } catch (error) {
10610
- console.error(`Error in onComplete hook for ${args.channelName}:`, error);
10704
+ debugLogger.error(
10705
+ `Error in onComplete hook for ${args.channelName}:`,
10706
+ error
10707
+ );
10611
10708
  }
10612
10709
  }
10613
10710
  function traceAsyncChannel(channel2, config) {
@@ -10622,6 +10719,9 @@ function traceAsyncChannel(channel2, config) {
10622
10719
  );
10623
10720
  const handlers = {
10624
10721
  start: (event) => {
10722
+ if (isAutoInstrumentationSuppressed()) {
10723
+ return;
10724
+ }
10625
10725
  ensureSpanStateForEvent(
10626
10726
  states,
10627
10727
  config,
@@ -10656,7 +10756,7 @@ function traceAsyncChannel(channel2, config) {
10656
10756
  metrics
10657
10757
  });
10658
10758
  } catch (error) {
10659
- console.error(`Error extracting output for ${channelName}:`, error);
10759
+ debugLogger.error(`Error extracting output for ${channelName}:`, error);
10660
10760
  } finally {
10661
10761
  span.end();
10662
10762
  states.delete(event);
@@ -10684,6 +10784,9 @@ function traceStreamingChannel(channel2, config) {
10684
10784
  );
10685
10785
  const handlers = {
10686
10786
  start: (event) => {
10787
+ if (isAutoInstrumentationSuppressed()) {
10788
+ return;
10789
+ }
10687
10790
  ensureSpanStateForEvent(
10688
10791
  states,
10689
10792
  config,
@@ -10755,7 +10858,7 @@ function traceStreamingChannel(channel2, config) {
10755
10858
  metrics
10756
10859
  });
10757
10860
  } catch (error) {
10758
- console.error(
10861
+ debugLogger.error(
10759
10862
  `Error extracting output for ${channelName}:`,
10760
10863
  error
10761
10864
  );
@@ -10815,7 +10918,7 @@ function traceStreamingChannel(channel2, config) {
10815
10918
  metrics
10816
10919
  });
10817
10920
  } catch (error) {
10818
- console.error(`Error extracting output for ${channelName}:`, error);
10921
+ debugLogger.error(`Error extracting output for ${channelName}:`, error);
10819
10922
  } finally {
10820
10923
  span.end();
10821
10924
  states.delete(event);
@@ -10843,6 +10946,9 @@ function traceSyncStreamChannel(channel2, config) {
10843
10946
  );
10844
10947
  const handlers = {
10845
10948
  start: (event) => {
10949
+ if (isAutoInstrumentationSuppressed()) {
10950
+ return;
10951
+ }
10846
10952
  ensureSpanStateForEvent(
10847
10953
  states,
10848
10954
  config,
@@ -10896,7 +11002,7 @@ function traceSyncStreamChannel(channel2, config) {
10896
11002
  });
10897
11003
  }
10898
11004
  } catch (error) {
10899
- console.error(
11005
+ debugLogger.error(
10900
11006
  `Error extracting chatCompletion for ${channelName}:`,
10901
11007
  error
10902
11008
  );
@@ -10920,7 +11026,10 @@ function traceSyncStreamChannel(channel2, config) {
10920
11026
  span.log(extracted);
10921
11027
  }
10922
11028
  } catch (error) {
10923
- console.error(`Error extracting event for ${channelName}:`, error);
11029
+ debugLogger.error(
11030
+ `Error extracting event for ${channelName}:`,
11031
+ error
11032
+ );
10924
11033
  }
10925
11034
  });
10926
11035
  stream.on("end", () => {
@@ -12449,6 +12558,9 @@ var AnthropicPlugin = class extends BasePlugin {
12449
12558
  const states = /* @__PURE__ */ new WeakMap();
12450
12559
  const handlers = {
12451
12560
  start: (event) => {
12561
+ if (isAutoInstrumentationSuppressed()) {
12562
+ return;
12563
+ }
12452
12564
  const params = event.arguments[0] ?? {};
12453
12565
  const span = startSpan({
12454
12566
  name: "anthropic.beta.messages.toolRunner",
@@ -13178,6 +13290,520 @@ function serializeAISDKToolsForLogging(tools) {
13178
13290
  return serialized;
13179
13291
  }
13180
13292
 
13293
+ // src/wrappers/ai-sdk/telemetry.ts
13294
+ function braintrustAISDKTelemetry() {
13295
+ const operations = /* @__PURE__ */ new Map();
13296
+ const modelSpans = /* @__PURE__ */ new Map();
13297
+ const objectSpans = /* @__PURE__ */ new Map();
13298
+ const embedSpans = /* @__PURE__ */ new Map();
13299
+ const rerankSpans = /* @__PURE__ */ new Map();
13300
+ const toolSpans = /* @__PURE__ */ new Map();
13301
+ const runSafely = (name, callback) => {
13302
+ try {
13303
+ callback();
13304
+ } catch (error) {
13305
+ console.error(`Error in Braintrust AI SDK telemetry ${name}:`, error);
13306
+ }
13307
+ };
13308
+ const startChildSpan = (callId, name, type, event) => {
13309
+ const parent = operations.get(callId)?.span;
13310
+ const spanArgs = {
13311
+ name,
13312
+ spanAttributes: { type },
13313
+ ...event ? { event } : {}
13314
+ };
13315
+ const span = parent ? parent.startSpan(spanArgs) : startSpan(spanArgs);
13316
+ const state = operations.get(callId);
13317
+ if (state && type === "llm" /* LLM */) {
13318
+ state.hadModelChild = true;
13319
+ }
13320
+ return span;
13321
+ };
13322
+ return {
13323
+ onStart(event) {
13324
+ runSafely("onStart", () => {
13325
+ const operationName = operationNameFromId(event.operationId);
13326
+ const span = startSpan({
13327
+ name: operationName,
13328
+ spanAttributes: { type: "function" /* FUNCTION */ }
13329
+ });
13330
+ operations.set(event.callId, {
13331
+ hadModelChild: false,
13332
+ operationName,
13333
+ span,
13334
+ startTime: getCurrentUnixTimestamp()
13335
+ });
13336
+ const metadata = metadataFromEvent(event);
13337
+ const logPayload = { metadata };
13338
+ if (shouldRecordInputs(event)) {
13339
+ const { input, outputPromise } = processAISDKCallInput(
13340
+ operationInput(event, operationName)
13341
+ );
13342
+ logPayload.input = input;
13343
+ if (outputPromise && input && typeof input === "object") {
13344
+ outputPromise.then((resolvedData) => {
13345
+ span.log({
13346
+ input: {
13347
+ ...input,
13348
+ ...resolvedData
13349
+ }
13350
+ });
13351
+ }).catch(() => {
13352
+ });
13353
+ }
13354
+ }
13355
+ span.log(logPayload);
13356
+ });
13357
+ },
13358
+ onLanguageModelCallStart(event) {
13359
+ runSafely("onLanguageModelCallStart", () => {
13360
+ const state = operations.get(event.callId);
13361
+ const openSpans = modelSpans.get(event.callId);
13362
+ if (openSpans) {
13363
+ for (const span2 of openSpans) {
13364
+ span2.end();
13365
+ }
13366
+ modelSpans.delete(event.callId);
13367
+ }
13368
+ const span = startChildSpan(
13369
+ event.callId,
13370
+ state?.operationName === "streamText" ? "doStream" : "doGenerate",
13371
+ "llm" /* LLM */,
13372
+ {
13373
+ ...shouldRecordInputs(event) ? {
13374
+ input: processAISDKCallInput(
13375
+ operationInput(
13376
+ event,
13377
+ state?.operationName ?? "generateText"
13378
+ )
13379
+ ).input
13380
+ } : {},
13381
+ metadata: metadataFromEvent(event)
13382
+ }
13383
+ );
13384
+ const spans = modelSpans.get(event.callId) ?? [];
13385
+ spans.push(span);
13386
+ modelSpans.set(event.callId, spans);
13387
+ });
13388
+ },
13389
+ onLanguageModelCallEnd(event) {
13390
+ runSafely("onLanguageModelCallEnd", () => {
13391
+ const span = shiftModelSpan(modelSpans, event.callId);
13392
+ if (!span) {
13393
+ return;
13394
+ }
13395
+ const result = {
13396
+ ...event,
13397
+ response: event.responseId ? { id: event.responseId } : void 0
13398
+ };
13399
+ span.log({
13400
+ ...shouldRecordOutputs(event) ? {
13401
+ output: processAISDKOutput(result, DEFAULT_DENY_OUTPUT_PATHS)
13402
+ } : {},
13403
+ metrics: extractTokenMetrics(result)
13404
+ });
13405
+ span.end();
13406
+ });
13407
+ },
13408
+ onObjectStepStart(event) {
13409
+ runSafely("onObjectStepStart", () => {
13410
+ const state = operations.get(event.callId);
13411
+ const openSpan = objectSpans.get(event.callId);
13412
+ if (openSpan) {
13413
+ openSpan.end();
13414
+ objectSpans.delete(event.callId);
13415
+ }
13416
+ const span = startChildSpan(
13417
+ event.callId,
13418
+ state?.operationName === "streamObject" ? "doStream" : "doGenerate",
13419
+ "llm" /* LLM */,
13420
+ {
13421
+ ...shouldRecordInputs(event) ? {
13422
+ input: {
13423
+ prompt: event.promptMessages
13424
+ }
13425
+ } : {},
13426
+ metadata: metadataFromEvent(event)
13427
+ }
13428
+ );
13429
+ objectSpans.set(event.callId, span);
13430
+ });
13431
+ },
13432
+ onObjectStepFinish(event) {
13433
+ runSafely("onObjectStepFinish", () => {
13434
+ const span = objectSpans.get(event.callId);
13435
+ if (!span) {
13436
+ return;
13437
+ }
13438
+ const result = {
13439
+ ...event,
13440
+ text: event.objectText
13441
+ };
13442
+ span.log({
13443
+ ...shouldRecordOutputs(event) ? {
13444
+ output: processAISDKOutput(result, DEFAULT_DENY_OUTPUT_PATHS)
13445
+ } : {},
13446
+ metrics: extractTokenMetrics(result)
13447
+ });
13448
+ span.end();
13449
+ objectSpans.delete(event.callId);
13450
+ });
13451
+ },
13452
+ onEmbedStart(event) {
13453
+ runSafely("onEmbedStart", () => {
13454
+ const state = operations.get(event.callId);
13455
+ for (const [embedCallId, embedState] of embedSpans) {
13456
+ if (embedState.callId === event.callId && (state?.operationName === "embed" || embedState.values === event.values)) {
13457
+ embedState.span.end();
13458
+ embedSpans.delete(embedCallId);
13459
+ }
13460
+ }
13461
+ const span = startChildSpan(
13462
+ event.callId,
13463
+ "doEmbed",
13464
+ "llm" /* LLM */,
13465
+ {
13466
+ ...shouldRecordInputs(event) ? {
13467
+ input: {
13468
+ values: event.values
13469
+ }
13470
+ } : {},
13471
+ metadata: metadataFromEvent(event)
13472
+ }
13473
+ );
13474
+ embedSpans.set(event.embedCallId, {
13475
+ callId: event.callId,
13476
+ span,
13477
+ values: event.values
13478
+ });
13479
+ });
13480
+ },
13481
+ onEmbedFinish(event) {
13482
+ runSafely("onEmbedFinish", () => {
13483
+ const state = embedSpans.get(event.embedCallId);
13484
+ if (!state) {
13485
+ return;
13486
+ }
13487
+ const result = {
13488
+ ...event,
13489
+ embeddings: event.embeddings
13490
+ };
13491
+ state.span.log({
13492
+ ...shouldRecordOutputs(event) ? {
13493
+ output: processAISDKEmbeddingOutput(
13494
+ result,
13495
+ DEFAULT_DENY_OUTPUT_PATHS
13496
+ )
13497
+ } : {},
13498
+ metrics: extractTokenMetrics(result)
13499
+ });
13500
+ state.span.end();
13501
+ embedSpans.delete(event.embedCallId);
13502
+ });
13503
+ },
13504
+ onRerankStart(event) {
13505
+ runSafely("onRerankStart", () => {
13506
+ const openSpan = rerankSpans.get(event.callId);
13507
+ if (openSpan) {
13508
+ openSpan.end();
13509
+ rerankSpans.delete(event.callId);
13510
+ }
13511
+ const span = startChildSpan(
13512
+ event.callId,
13513
+ "doRerank",
13514
+ "llm" /* LLM */,
13515
+ {
13516
+ ...shouldRecordInputs(event) ? {
13517
+ input: {
13518
+ documents: event.documents,
13519
+ query: event.query,
13520
+ topN: event.topN
13521
+ }
13522
+ } : {},
13523
+ metadata: metadataFromEvent(event)
13524
+ }
13525
+ );
13526
+ rerankSpans.set(event.callId, span);
13527
+ });
13528
+ },
13529
+ onRerankFinish(event) {
13530
+ runSafely("onRerankFinish", () => {
13531
+ const span = rerankSpans.get(event.callId);
13532
+ if (!span) {
13533
+ return;
13534
+ }
13535
+ const result = {
13536
+ ranking: event.ranking?.map((entry) => ({
13537
+ originalIndex: entry.index,
13538
+ score: entry.relevanceScore
13539
+ }))
13540
+ };
13541
+ span.log({
13542
+ ...shouldRecordOutputs(event) ? {
13543
+ output: processAISDKRerankOutput(
13544
+ result,
13545
+ DEFAULT_DENY_OUTPUT_PATHS
13546
+ )
13547
+ } : {}
13548
+ });
13549
+ span.end();
13550
+ rerankSpans.delete(event.callId);
13551
+ });
13552
+ },
13553
+ onToolExecutionStart(event) {
13554
+ runSafely("onToolExecutionStart", () => {
13555
+ const toolCallId = event.toolCall.toolCallId;
13556
+ if (!toolCallId) {
13557
+ return;
13558
+ }
13559
+ const span = startChildSpan(
13560
+ event.callId,
13561
+ event.toolCall.toolName || "tool",
13562
+ "tool" /* TOOL */,
13563
+ {
13564
+ ...shouldRecordInputs(event) ? {
13565
+ input: event.toolCall.input
13566
+ } : {},
13567
+ metadata: {
13568
+ ...createAISDKIntegrationMetadata(),
13569
+ toolCallId,
13570
+ ...typeof event.toolCall.toolName === "string" ? { toolName: event.toolCall.toolName } : {}
13571
+ }
13572
+ }
13573
+ );
13574
+ toolSpans.set(toolCallId, { callId: event.callId, span });
13575
+ });
13576
+ },
13577
+ onToolExecutionEnd(event) {
13578
+ runSafely("onToolExecutionEnd", () => {
13579
+ const toolCallId = event.toolCall.toolCallId;
13580
+ const state = toolCallId ? toolSpans.get(toolCallId) : void 0;
13581
+ if (!toolCallId || !state) {
13582
+ return;
13583
+ }
13584
+ const toolOutput = event.toolOutput;
13585
+ if (toolOutput?.type === "tool-error") {
13586
+ state.span.log({
13587
+ error: toolOutput.error instanceof Error ? toolOutput.error.message : String(toolOutput?.error),
13588
+ metrics: typeof event.durationMs === "number" ? { duration_ms: event.durationMs } : {}
13589
+ });
13590
+ } else {
13591
+ state.span.log({
13592
+ ...shouldRecordOutputs(event) ? { output: toolOutput?.output } : {},
13593
+ metrics: typeof event.durationMs === "number" ? { duration_ms: event.durationMs } : {}
13594
+ });
13595
+ }
13596
+ state.span.end();
13597
+ toolSpans.delete(toolCallId);
13598
+ });
13599
+ },
13600
+ onChunk(event) {
13601
+ runSafely("onChunk", () => {
13602
+ const callId = event.chunk?.callId;
13603
+ if (!callId) {
13604
+ return;
13605
+ }
13606
+ const state = operations.get(callId);
13607
+ if (!state || state.firstChunkTime !== void 0) {
13608
+ return;
13609
+ }
13610
+ state.firstChunkTime = getCurrentUnixTimestamp();
13611
+ });
13612
+ },
13613
+ onFinish(event) {
13614
+ runSafely("onFinish", () => {
13615
+ const state = operations.get(event.callId);
13616
+ if (!state) {
13617
+ return;
13618
+ }
13619
+ const result = finishResult(event, state.operationName);
13620
+ const metrics = state.hadModelChild ? {} : extractTokenMetrics(result);
13621
+ if (state.firstChunkTime !== void 0) {
13622
+ metrics.time_to_first_token = state.firstChunkTime - state.startTime;
13623
+ }
13624
+ state.span.log({
13625
+ ...shouldRecordOutputs(event) ? {
13626
+ output: finishOutput(result, state.operationName)
13627
+ } : {},
13628
+ metrics
13629
+ });
13630
+ state.span.end();
13631
+ operations.delete(event.callId);
13632
+ });
13633
+ },
13634
+ onError(event) {
13635
+ runSafely("onError", () => {
13636
+ const errorEvent = isObject(event) ? event : {};
13637
+ const callId = typeof errorEvent.callId === "string" ? errorEvent.callId : void 0;
13638
+ if (!callId) {
13639
+ return;
13640
+ }
13641
+ const state = operations.get(callId);
13642
+ if (!state) {
13643
+ return;
13644
+ }
13645
+ const error = errorEvent.error ?? event;
13646
+ const openModelSpans = modelSpans.get(callId);
13647
+ if (openModelSpans) {
13648
+ for (const span of openModelSpans) {
13649
+ logError(span, error);
13650
+ span.end();
13651
+ }
13652
+ modelSpans.delete(callId);
13653
+ }
13654
+ const openObjectSpan = objectSpans.get(callId);
13655
+ if (openObjectSpan) {
13656
+ logError(openObjectSpan, error);
13657
+ openObjectSpan.end();
13658
+ objectSpans.delete(callId);
13659
+ }
13660
+ for (const [embedCallId, embedState] of embedSpans) {
13661
+ if (embedState.callId === callId) {
13662
+ logError(embedState.span, error);
13663
+ embedState.span.end();
13664
+ embedSpans.delete(embedCallId);
13665
+ }
13666
+ }
13667
+ const openRerankSpan = rerankSpans.get(callId);
13668
+ if (openRerankSpan) {
13669
+ logError(openRerankSpan, error);
13670
+ openRerankSpan.end();
13671
+ rerankSpans.delete(callId);
13672
+ }
13673
+ for (const [toolCallId, toolState] of toolSpans) {
13674
+ if (toolState.callId === callId) {
13675
+ logError(toolState.span, error);
13676
+ toolState.span.end();
13677
+ toolSpans.delete(toolCallId);
13678
+ }
13679
+ }
13680
+ logError(state.span, error);
13681
+ state.span.end();
13682
+ operations.delete(callId);
13683
+ });
13684
+ },
13685
+ executeTool({ toolCallId, execute }) {
13686
+ const state = toolSpans.get(toolCallId);
13687
+ return state ? withCurrent(state.span, () => execute()) : execute();
13688
+ }
13689
+ };
13690
+ }
13691
+ function shouldRecordInputs(event) {
13692
+ return event.recordInputs !== false;
13693
+ }
13694
+ function shouldRecordOutputs(event) {
13695
+ return event.recordOutputs !== false;
13696
+ }
13697
+ function operationNameFromId(operationId) {
13698
+ return operationId?.startsWith("ai.") ? operationId.slice("ai.".length) : operationId || "ai-sdk";
13699
+ }
13700
+ function modelFromEvent(event) {
13701
+ return event.modelId ? {
13702
+ modelId: event.modelId,
13703
+ ...event.provider ? { provider: event.provider } : {}
13704
+ } : void 0;
13705
+ }
13706
+ function metadataFromEvent(event) {
13707
+ const metadata = createAISDKIntegrationMetadata();
13708
+ const { model, provider } = serializeModelWithProvider(modelFromEvent(event));
13709
+ if (model) {
13710
+ metadata.model = model;
13711
+ }
13712
+ if (provider) {
13713
+ metadata.provider = provider;
13714
+ }
13715
+ if (typeof event.functionId === "string") {
13716
+ metadata.functionId = event.functionId;
13717
+ }
13718
+ return metadata;
13719
+ }
13720
+ function operationInput(event, operationName) {
13721
+ if (operationName === "embed") {
13722
+ return {
13723
+ model: modelFromEvent(event),
13724
+ value: event.value
13725
+ };
13726
+ }
13727
+ if (operationName === "embedMany") {
13728
+ return {
13729
+ model: modelFromEvent(event),
13730
+ values: Array.isArray(event.value) ? event.value ?? [] : void 0
13731
+ };
13732
+ }
13733
+ if (operationName === "rerank") {
13734
+ return {
13735
+ model: modelFromEvent(event),
13736
+ documents: event.documents,
13737
+ query: event.query,
13738
+ topN: event.topN
13739
+ };
13740
+ }
13741
+ return {
13742
+ model: modelFromEvent(event),
13743
+ system: event.system,
13744
+ prompt: event.prompt,
13745
+ messages: event.messages,
13746
+ tools: event.tools,
13747
+ toolChoice: event.toolChoice,
13748
+ activeTools: event.activeTools,
13749
+ output: event.output,
13750
+ schema: event.schema,
13751
+ schemaName: event.schemaName,
13752
+ schemaDescription: event.schemaDescription,
13753
+ maxOutputTokens: event.maxOutputTokens,
13754
+ temperature: event.temperature,
13755
+ topP: event.topP,
13756
+ topK: event.topK,
13757
+ presencePenalty: event.presencePenalty,
13758
+ frequencyPenalty: event.frequencyPenalty,
13759
+ seed: event.seed,
13760
+ maxRetries: event.maxRetries,
13761
+ headers: event.headers,
13762
+ providerOptions: event.providerOptions
13763
+ };
13764
+ }
13765
+ function shiftModelSpan(modelSpans, callId) {
13766
+ const spans = modelSpans.get(callId);
13767
+ const span = spans?.shift();
13768
+ if (spans && spans.length === 0) {
13769
+ modelSpans.delete(callId);
13770
+ }
13771
+ return span;
13772
+ }
13773
+ function finishResult(event, operationName) {
13774
+ if (operationName === "embed") {
13775
+ return {
13776
+ ...event,
13777
+ embedding: event.embedding
13778
+ };
13779
+ }
13780
+ if (operationName === "embedMany") {
13781
+ return {
13782
+ ...event,
13783
+ embeddings: event.embedding
13784
+ };
13785
+ }
13786
+ if (operationName === "rerank") {
13787
+ return event;
13788
+ }
13789
+ return event;
13790
+ }
13791
+ function finishOutput(result, operationName) {
13792
+ if (operationName === "embed" || operationName === "embedMany") {
13793
+ return processAISDKEmbeddingOutput(
13794
+ result,
13795
+ DEFAULT_DENY_OUTPUT_PATHS
13796
+ );
13797
+ }
13798
+ if (operationName === "rerank") {
13799
+ return processAISDKRerankOutput(
13800
+ result,
13801
+ DEFAULT_DENY_OUTPUT_PATHS
13802
+ );
13803
+ }
13804
+ return processAISDKOutput(result, DEFAULT_DENY_OUTPUT_PATHS);
13805
+ }
13806
+
13181
13807
  // src/instrumentation/plugins/ai-sdk-channels.ts
13182
13808
  var aiSDKChannels = defineChannels("ai", {
13183
13809
  generateText: channel({
@@ -13237,6 +13863,10 @@ var aiSDKChannels = defineChannels("ai", {
13237
13863
  toolLoopAgentStream: channel({
13238
13864
  channelName: "ToolLoopAgent.stream",
13239
13865
  kind: "async"
13866
+ }),
13867
+ v7CreateTelemetryDispatcher: channel({
13868
+ channelName: "createTelemetryDispatcher",
13869
+ kind: "sync-stream"
13240
13870
  })
13241
13871
  });
13242
13872
 
@@ -13257,9 +13887,30 @@ var DEFAULT_DENY_OUTPUT_PATHS = [
13257
13887
  ];
13258
13888
  var AUTO_PATCHED_MODEL = /* @__PURE__ */ Symbol.for("braintrust.ai-sdk.auto-patched-model");
13259
13889
  var AUTO_PATCHED_TOOL = /* @__PURE__ */ Symbol.for("braintrust.ai-sdk.auto-patched-tool");
13890
+ var AUTO_PATCHED_V7_TELEMETRY_DISPATCHER = /* @__PURE__ */ Symbol.for(
13891
+ "braintrust.ai-sdk.v7.auto-patched-telemetry-dispatcher"
13892
+ );
13260
13893
  var RUNTIME_DENY_OUTPUT_PATHS = /* @__PURE__ */ Symbol.for(
13261
13894
  "braintrust.ai-sdk.deny-output-paths"
13262
13895
  );
13896
+ var AI_SDK_V7_TELEMETRY_CALLBACKS = [
13897
+ "onStart",
13898
+ "onStepStart",
13899
+ "onLanguageModelCallStart",
13900
+ "onLanguageModelCallEnd",
13901
+ "onToolExecutionStart",
13902
+ "onToolExecutionEnd",
13903
+ "onChunk",
13904
+ "onStepFinish",
13905
+ "onObjectStepStart",
13906
+ "onObjectStepFinish",
13907
+ "onEmbedStart",
13908
+ "onEmbedFinish",
13909
+ "onRerankStart",
13910
+ "onRerankFinish",
13911
+ "onFinish",
13912
+ "onError"
13913
+ ];
13263
13914
  var AISDKPlugin = class extends BasePlugin {
13264
13915
  config;
13265
13916
  constructor(config = {}) {
@@ -13274,6 +13925,7 @@ var AISDKPlugin = class extends BasePlugin {
13274
13925
  }
13275
13926
  subscribeToAISDK() {
13276
13927
  const denyOutputPaths = this.config.denyOutputPaths || DEFAULT_DENY_OUTPUT_PATHS;
13928
+ this.unsubscribers.push(subscribeToAISDKV7TelemetryDispatcher());
13277
13929
  this.unsubscribers.push(
13278
13930
  traceStreamingChannel(aiSDKChannels.generateText, {
13279
13931
  name: "generateText",
@@ -13498,18 +14150,69 @@ var AISDKPlugin = class extends BasePlugin {
13498
14150
  );
13499
14151
  }
13500
14152
  };
13501
- function resolveDenyOutputPaths(event, defaultDenyOutputPaths) {
13502
- if (Array.isArray(event?.denyOutputPaths)) {
13503
- return event.denyOutputPaths;
13504
- }
13505
- const firstArgument2 = event?.arguments && event.arguments.length > 0 ? event.arguments[0] : void 0;
13506
- if (!firstArgument2 || typeof firstArgument2 !== "object") {
13507
- return defaultDenyOutputPaths;
13508
- }
13509
- const runtimeDenyOutputPaths = firstArgument2[RUNTIME_DENY_OUTPUT_PATHS];
13510
- if (Array.isArray(runtimeDenyOutputPaths) && runtimeDenyOutputPaths.every((path) => typeof path === "string")) {
13511
- return runtimeDenyOutputPaths;
13512
- }
14153
+ function subscribeToAISDKV7TelemetryDispatcher() {
14154
+ const channel2 = aiSDKChannels.v7CreateTelemetryDispatcher.tracingChannel();
14155
+ const telemetry = braintrustAISDKTelemetry();
14156
+ const handlers = {
14157
+ end: (event) => {
14158
+ const telemetryOptions = event.arguments?.[0]?.telemetry;
14159
+ if (telemetryOptions?.isEnabled === false) {
14160
+ return;
14161
+ }
14162
+ patchAISDKV7TelemetryDispatcher(event.result, telemetry);
14163
+ }
14164
+ };
14165
+ channel2.subscribe(handlers);
14166
+ return () => {
14167
+ channel2.unsubscribe(handlers);
14168
+ };
14169
+ }
14170
+ function patchAISDKV7TelemetryDispatcher(dispatcher, telemetry) {
14171
+ if (!isObject(dispatcher)) {
14172
+ return;
14173
+ }
14174
+ const dispatcherRecord = dispatcher;
14175
+ if (dispatcherRecord[AUTO_PATCHED_V7_TELEMETRY_DISPATCHER]) {
14176
+ return;
14177
+ }
14178
+ dispatcherRecord[AUTO_PATCHED_V7_TELEMETRY_DISPATCHER] = true;
14179
+ for (const key of AI_SDK_V7_TELEMETRY_CALLBACKS) {
14180
+ const braintrustCallback = telemetry[key];
14181
+ if (typeof braintrustCallback !== "function") {
14182
+ continue;
14183
+ }
14184
+ const existingCallback = dispatcherRecord[key];
14185
+ dispatcherRecord[key] = (event) => {
14186
+ const existingResult = typeof existingCallback === "function" ? existingCallback.call(dispatcher, event) : void 0;
14187
+ const braintrustResult = braintrustCallback.call(telemetry, event);
14188
+ const pending = [existingResult, braintrustResult].filter(isPromiseLike);
14189
+ if (pending.length > 0) {
14190
+ return Promise.allSettled(pending).then(() => void 0);
14191
+ }
14192
+ };
14193
+ }
14194
+ const braintrustExecuteTool = telemetry.executeTool;
14195
+ if (typeof braintrustExecuteTool !== "function") {
14196
+ return;
14197
+ }
14198
+ const existingExecuteTool = dispatcherRecord.executeTool;
14199
+ dispatcherRecord.executeTool = (args) => braintrustExecuteTool.call(telemetry, {
14200
+ ...args,
14201
+ execute: () => typeof existingExecuteTool === "function" ? existingExecuteTool.call(dispatcher, args) : args.execute()
14202
+ });
14203
+ }
14204
+ function resolveDenyOutputPaths(event, defaultDenyOutputPaths) {
14205
+ if (Array.isArray(event?.denyOutputPaths)) {
14206
+ return event.denyOutputPaths;
14207
+ }
14208
+ const firstArgument2 = event?.arguments && event.arguments.length > 0 ? event.arguments[0] : void 0;
14209
+ if (!firstArgument2 || typeof firstArgument2 !== "object") {
14210
+ return defaultDenyOutputPaths;
14211
+ }
14212
+ const runtimeDenyOutputPaths = firstArgument2[RUNTIME_DENY_OUTPUT_PATHS];
14213
+ if (Array.isArray(runtimeDenyOutputPaths) && runtimeDenyOutputPaths.every((path) => typeof path === "string")) {
14214
+ return runtimeDenyOutputPaths;
14215
+ }
13513
14216
  return defaultDenyOutputPaths;
13514
14217
  }
13515
14218
  var isZodSchema2 = (value) => {
@@ -13949,11 +14652,11 @@ function prepareAISDKChildTracing(params, self, parentSpan, denyOutputPaths, aiS
13949
14652
  metadata: baseMetadata
13950
14653
  }
13951
14654
  });
14655
+ const streamStartTime = getCurrentUnixTimestamp();
13952
14656
  const result = await withCurrent(
13953
14657
  span,
13954
14658
  () => Reflect.apply(originalDoStream, resolvedModel, [options])
13955
14659
  );
13956
- const streamStartTime = getCurrentUnixTimestamp();
13957
14660
  let firstChunkTime;
13958
14661
  const output = {};
13959
14662
  let text = "";
@@ -13962,7 +14665,7 @@ function prepareAISDKChildTracing(params, self, parentSpan, denyOutputPaths, aiS
13962
14665
  let object = void 0;
13963
14666
  const transformStream = new TransformStream({
13964
14667
  transform(chunk, controller) {
13965
- if (firstChunkTime === void 0) {
14668
+ if (firstChunkTime === void 0 && isAISDKContentStreamChunk(chunk)) {
13966
14669
  firstChunkTime = getCurrentUnixTimestamp();
13967
14670
  }
13968
14671
  switch (chunk.type) {
@@ -14154,6 +14857,78 @@ function finalizeAISDKChildTracing(event) {
14154
14857
  delete event.__braintrust_ai_sdk_cleanup;
14155
14858
  }
14156
14859
  }
14860
+ function extractAISDKStreamPart(chunk) {
14861
+ if (!isObject(chunk) || !isObject(chunk.part)) {
14862
+ return chunk;
14863
+ }
14864
+ return chunk.part;
14865
+ }
14866
+ function stringContent(value) {
14867
+ return typeof value === "string" && value.length > 0 ? value : void 0;
14868
+ }
14869
+ function rawValueHasAISDKContent(value) {
14870
+ if (value === void 0 || value === null) {
14871
+ return false;
14872
+ }
14873
+ if (typeof value === "string") {
14874
+ return value.length > 0;
14875
+ }
14876
+ if (!isObject(value)) {
14877
+ return true;
14878
+ }
14879
+ const delta = value.delta;
14880
+ 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) => {
14881
+ if (!isObject(choice) || !isObject(choice.delta)) {
14882
+ return false;
14883
+ }
14884
+ const choiceDelta = choice.delta;
14885
+ if (stringContent(choiceDelta.content) || stringContent(choiceDelta.text)) {
14886
+ return true;
14887
+ }
14888
+ if (isObject(choiceDelta.function_call) && stringContent(choiceDelta.function_call.arguments)) {
14889
+ return true;
14890
+ }
14891
+ return Array.isArray(choiceDelta.tool_calls) && choiceDelta.tool_calls.some(
14892
+ (toolCall) => isObject(toolCall) && isObject(toolCall.function) && stringContent(toolCall.function.arguments)
14893
+ );
14894
+ })) {
14895
+ return true;
14896
+ }
14897
+ return false;
14898
+ }
14899
+ function isAISDKContentStreamChunk(chunk) {
14900
+ const part = extractAISDKStreamPart(chunk);
14901
+ if (typeof part === "string") {
14902
+ return part.length > 0;
14903
+ }
14904
+ if (!isObject(part) || typeof part.type !== "string") {
14905
+ return false;
14906
+ }
14907
+ switch (part.type) {
14908
+ case "text-delta":
14909
+ return stringContent(part.textDelta) !== void 0 || stringContent(part.delta) !== void 0 || stringContent(part.text) !== void 0 || stringContent(part.content) !== void 0;
14910
+ case "reasoning-delta":
14911
+ return stringContent(part.delta) !== void 0 || stringContent(part.text) !== void 0 || stringContent(part.content) !== void 0;
14912
+ case "tool-call":
14913
+ case "object":
14914
+ case "file":
14915
+ return true;
14916
+ case "tool-input-delta":
14917
+ case "tool-call-delta":
14918
+ 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;
14919
+ case "raw":
14920
+ return rawValueHasAISDKContent(part.rawValue);
14921
+ default:
14922
+ return false;
14923
+ }
14924
+ }
14925
+ function isAISDKContentAsyncIterableChunk(chunk) {
14926
+ if (isAISDKContentStreamChunk(chunk)) {
14927
+ return true;
14928
+ }
14929
+ const part = extractAISDKStreamPart(chunk);
14930
+ return isObject(part) && typeof part.type !== "string";
14931
+ }
14157
14932
  function patchAISDKStreamingResult(args) {
14158
14933
  const { defaultDenyOutputPaths, endEvent, result, span, startTime } = args;
14159
14934
  if (!result || typeof result !== "object") {
@@ -14166,7 +14941,7 @@ function patchAISDKStreamingResult(args) {
14166
14941
  const wrappedBaseStream = resultRecord.baseStream.pipeThrough(
14167
14942
  new TransformStream({
14168
14943
  transform(chunk, controller) {
14169
- if (firstChunkTime2 === void 0) {
14944
+ if (firstChunkTime2 === void 0 && isAISDKContentStreamChunk(chunk)) {
14170
14945
  firstChunkTime2 = getCurrentUnixTimestamp();
14171
14946
  }
14172
14947
  controller.enqueue(chunk);
@@ -14210,8 +14985,8 @@ function patchAISDKStreamingResult(args) {
14210
14985
  }
14211
14986
  let firstChunkTime;
14212
14987
  const wrappedStream = createPatchedAsyncIterable(streamField.stream, {
14213
- onChunk: () => {
14214
- if (firstChunkTime === void 0) {
14988
+ onChunk: (chunk) => {
14989
+ if (firstChunkTime === void 0 && isAISDKContentAsyncIterableChunk(chunk)) {
14215
14990
  firstChunkTime = getCurrentUnixTimestamp();
14216
14991
  }
14217
14992
  },
@@ -15183,15 +15958,17 @@ function collectLocalMcpServerToolHookNames(serverName, serverConfig) {
15183
15958
 
15184
15959
  // src/instrumentation/plugins/claude-agent-sdk-plugin.ts
15185
15960
  var ROOT_LLM_PARENT_KEY = "__root__";
15961
+ var SUB_AGENT_PROMPT_SOURCE_PRIORITY = {
15962
+ delegation: 0,
15963
+ lifecycle: 1,
15964
+ sidechain: 2
15965
+ };
15186
15966
  function llmParentKey(parentToolUseId) {
15187
15967
  return parentToolUseId ?? ROOT_LLM_PARENT_KEY;
15188
15968
  }
15189
15969
  function isSubAgentDelegationToolName(toolName) {
15190
15970
  return toolName === "Agent" || toolName === "Task";
15191
15971
  }
15192
- function shouldParentToolAsTaskSibling(toolName) {
15193
- return toolName === "Agent" || toolName === "Task" || toolName === "Bash";
15194
- }
15195
15972
  function filterSerializableOptions(options) {
15196
15973
  const allowedKeys = [
15197
15974
  "model",
@@ -15328,26 +16105,39 @@ function extractUsageFromMessage(message) {
15328
16105
  }
15329
16106
  return metrics;
15330
16107
  }
15331
- function buildLLMInput(prompt, conversationHistory, capturedPromptMessages) {
15332
- const promptMessages = [];
15333
- if (typeof prompt === "string") {
15334
- promptMessages.push({ content: prompt, role: "user" });
15335
- } else if (capturedPromptMessages && capturedPromptMessages.length > 0) {
15336
- for (const msg of capturedPromptMessages) {
15337
- const role = msg.message?.role;
15338
- const content = msg.message?.content;
15339
- if (role && content !== void 0) {
15340
- promptMessages.push({ content, role });
15341
- }
15342
- }
15343
- }
16108
+ function buildLLMInput(promptMessages, conversationHistory) {
15344
16109
  const inputParts = [...promptMessages, ...conversationHistory];
15345
16110
  return inputParts.length > 0 ? inputParts : void 0;
15346
16111
  }
16112
+ function conversationMessageFromSDKMessage(message) {
16113
+ const role = message.message?.role;
16114
+ const content = message.message?.content;
16115
+ if (role && content !== void 0) {
16116
+ return { content, role };
16117
+ }
16118
+ return void 0;
16119
+ }
16120
+ function messageContentHasBlockType(message, blockType) {
16121
+ const content = message.message?.content;
16122
+ return Array.isArray(content) && content.some(
16123
+ (block) => typeof block === "object" && block !== null && "type" in block && block.type === blockType
16124
+ );
16125
+ }
16126
+ function buildRootPromptMessages(prompt, capturedPromptMessages) {
16127
+ if (typeof prompt === "string") {
16128
+ return [{ content: prompt, role: "user" }];
16129
+ }
16130
+ if (!capturedPromptMessages || capturedPromptMessages.length === 0) {
16131
+ return [];
16132
+ }
16133
+ return capturedPromptMessages.map(conversationMessageFromSDKMessage).filter(
16134
+ (message) => message !== void 0
16135
+ );
16136
+ }
15347
16137
  function formatCapturedMessages(messages) {
15348
16138
  return messages.length > 0 ? messages : [];
15349
16139
  }
15350
- async function createLLMSpanForMessages(messages, prompt, conversationHistory, options, startTime, capturedPromptMessages, parentSpan, existingSpan) {
16140
+ async function createLLMSpanForMessages(messages, promptMessages, conversationHistory, options, startTime, parentSpan, existingSpan) {
15351
16141
  if (messages.length === 0) {
15352
16142
  return void 0;
15353
16143
  }
@@ -15357,11 +16147,7 @@ async function createLLMSpanForMessages(messages, prompt, conversationHistory, o
15357
16147
  }
15358
16148
  const model = lastMessage.message.model || options.model;
15359
16149
  const usage = extractUsageFromMessage(lastMessage);
15360
- const input = buildLLMInput(
15361
- prompt,
15362
- conversationHistory,
15363
- capturedPromptMessages
15364
- );
16150
+ const input = buildLLMInput(promptMessages, conversationHistory);
15365
16151
  const outputs = messages.map(
15366
16152
  (m) => m.message?.content && m.message?.role ? { content: m.message.content, role: m.message.role } : void 0
15367
16153
  ).filter(
@@ -15492,8 +16278,7 @@ function createToolTracingHooks(resolveParentSpan, activeToolSpans, mcpServers,
15492
16278
  },
15493
16279
  name: parsed.displayName,
15494
16280
  parent: await resolveParentSpan(toolUseID, {
15495
- agentId: input.agent_id,
15496
- preferTaskSiblingParent: shouldParentToolAsTaskSibling(parsed.toolName)
16281
+ agentId: input.agent_id
15497
16282
  }),
15498
16283
  spanAttributes: { type: "tool" /* TOOL */ }
15499
16284
  });
@@ -15739,12 +16524,37 @@ function injectTracingHooks(options, resolveParentSpan, activeToolSpans, localTo
15739
16524
  }
15740
16525
  };
15741
16526
  }
16527
+ function setSubAgentPromptMessages(state, parentToolUseId, promptMessages, source) {
16528
+ if (promptMessages.length === 0) {
16529
+ return;
16530
+ }
16531
+ const parentKey = llmParentKey(parentToolUseId);
16532
+ const sourcePriority = SUB_AGENT_PROMPT_SOURCE_PRIORITY[source];
16533
+ const currentPriority = state.promptSourcePriorityByParentKey.get(parentKey) ?? -1;
16534
+ if (sourcePriority > currentPriority) {
16535
+ state.promptMessagesByParentKey.set(parentKey, promptMessages);
16536
+ state.promptSourcePriorityByParentKey.set(parentKey, sourcePriority);
16537
+ }
16538
+ }
16539
+ function getConversationHistory(state, parentKey) {
16540
+ let conversationHistory = state.conversationHistoryByParentKey.get(parentKey);
16541
+ if (!conversationHistory) {
16542
+ conversationHistory = [];
16543
+ state.conversationHistoryByParentKey.set(parentKey, conversationHistory);
16544
+ }
16545
+ return conversationHistory;
16546
+ }
15742
16547
  async function finalizeCurrentMessageGroup(state) {
15743
16548
  if (state.currentMessages.length === 0) {
15744
16549
  return;
15745
16550
  }
15746
16551
  const parentToolUseId = state.currentMessages[0]?.parent_tool_use_id ?? null;
15747
16552
  const parentKey = llmParentKey(parentToolUseId);
16553
+ const conversationHistory = getConversationHistory(state, parentKey);
16554
+ const promptMessages = parentToolUseId ? state.promptMessagesByParentKey.get(parentKey) ?? [] : buildRootPromptMessages(
16555
+ state.originalPrompt,
16556
+ state.capturedPromptMessages
16557
+ );
15748
16558
  let parentSpan = await state.span.export();
15749
16559
  if (parentToolUseId) {
15750
16560
  const subAgentSpan = state.subAgentSpans.get(parentToolUseId);
@@ -15755,11 +16565,10 @@ async function finalizeCurrentMessageGroup(state) {
15755
16565
  const existingLlmSpan = state.activeLlmSpansByParentToolUse.get(parentKey);
15756
16566
  const llmSpanResult = await createLLMSpanForMessages(
15757
16567
  state.currentMessages,
15758
- state.originalPrompt,
15759
- state.finalResults,
16568
+ promptMessages,
16569
+ conversationHistory,
15760
16570
  state.options,
15761
16571
  state.currentMessageStartTime,
15762
- state.capturedPromptMessages,
15763
16572
  parentSpan,
15764
16573
  existingLlmSpan
15765
16574
  );
@@ -15773,6 +16582,7 @@ async function finalizeCurrentMessageGroup(state) {
15773
16582
  state.latestRootLlmParentRef.value = llmSpanResult.spanExport;
15774
16583
  }
15775
16584
  if (llmSpanResult.finalMessage) {
16585
+ conversationHistory.push(llmSpanResult.finalMessage);
15776
16586
  state.finalResults.push(llmSpanResult.finalMessage);
15777
16587
  }
15778
16588
  }
@@ -15800,6 +16610,15 @@ function maybeTrackToolUseContext(state, message) {
15800
16610
  description: getStringProperty(block.input, "description"),
15801
16611
  toolUseId: block.id
15802
16612
  });
16613
+ const prompt = getStringProperty(block.input, "prompt");
16614
+ if (prompt) {
16615
+ setSubAgentPromptMessages(
16616
+ state,
16617
+ block.id,
16618
+ [{ content: prompt, role: "user" }],
16619
+ "delegation"
16620
+ );
16621
+ }
15803
16622
  }
15804
16623
  }
15805
16624
  }
@@ -15918,6 +16737,14 @@ async function maybeHandleTaskLifecycleMessage(state, message) {
15918
16737
  };
15919
16738
  if (message.subtype === "task_started") {
15920
16739
  const prompt = getStringProperty(message, "prompt");
16740
+ if (prompt) {
16741
+ setSubAgentPromptMessages(
16742
+ state,
16743
+ toolUseId,
16744
+ [{ content: prompt, role: "user" }],
16745
+ "lifecycle"
16746
+ );
16747
+ }
15921
16748
  subAgentSpan.log({
15922
16749
  input: prompt,
15923
16750
  metadata
@@ -15968,6 +16795,28 @@ async function handleStreamMessage(state, message) {
15968
16795
  return;
15969
16796
  }
15970
16797
  await maybeStartSubAgentSpan(state, message);
16798
+ const messageParentToolUseId = message.parent_tool_use_id;
16799
+ if (messageParentToolUseId && message.type === "user") {
16800
+ const conversationMessage = conversationMessageFromSDKMessage(message);
16801
+ if (conversationMessage?.role === "user") {
16802
+ await finalizeCurrentMessageGroup(state);
16803
+ const parentKey = llmParentKey(messageParentToolUseId);
16804
+ const conversationHistory = getConversationHistory(state, parentKey);
16805
+ const currentPromptSourcePriority = state.promptSourcePriorityByParentKey.get(parentKey) ?? -1;
16806
+ const canUseAsInitialSidechainPrompt = conversationHistory.length === 0 && currentPromptSourcePriority < SUB_AGENT_PROMPT_SOURCE_PRIORITY.sidechain && !messageContentHasBlockType(message, "tool_result");
16807
+ if (!canUseAsInitialSidechainPrompt) {
16808
+ conversationHistory.push(conversationMessage);
16809
+ return;
16810
+ }
16811
+ setSubAgentPromptMessages(
16812
+ state,
16813
+ messageParentToolUseId,
16814
+ [conversationMessage],
16815
+ "sidechain"
16816
+ );
16817
+ return;
16818
+ }
16819
+ }
15971
16820
  const messageId = message.message?.id;
15972
16821
  if (messageId && messageId !== state.currentMessageId) {
15973
16822
  await finalizeCurrentMessageGroup(state);
@@ -16119,6 +16968,7 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
16119
16968
  }
16120
16969
  const activeToolSpans = /* @__PURE__ */ new Map();
16121
16970
  const activeLlmSpansByParentToolUse = /* @__PURE__ */ new Map();
16971
+ const conversationHistoryByParentKey = /* @__PURE__ */ new Map();
16122
16972
  const subAgentSpans = /* @__PURE__ */ new Map();
16123
16973
  const endedSubAgentSpans = /* @__PURE__ */ new Set();
16124
16974
  const toolUseToParent = /* @__PURE__ */ new Map();
@@ -16128,6 +16978,8 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
16128
16978
  };
16129
16979
  const subAgentDetailsByToolUseId = /* @__PURE__ */ new Map();
16130
16980
  const taskIdToToolUseId = /* @__PURE__ */ new Map();
16981
+ const promptMessagesByParentKey = /* @__PURE__ */ new Map();
16982
+ const promptSourcePriorityByParentKey = /* @__PURE__ */ new Map();
16131
16983
  const localToolContext = createClaudeLocalToolContext();
16132
16984
  const { hasLocalToolHandlers, localToolHookNames } = prepareLocalToolHandlersInMcpServers(options.mcpServers);
16133
16985
  const skipLocalToolHooks = options[CLAUDE_AGENT_SDK_SKIP_LOCAL_TOOL_HOOKS_OPTION] === true || hasLocalToolHandlers;
@@ -16136,38 +16988,19 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
16136
16988
  const parentToolUseId = trackedParentToolUseId ?? (context?.agentId ? taskIdToToolUseId.get(context.agentId) ?? null : null);
16137
16989
  const parentKey = llmParentKey(parentToolUseId);
16138
16990
  const activeLlmSpan = activeLlmSpansByParentToolUse.get(parentKey);
16139
- if (context?.preferTaskSiblingParent) {
16140
- if (!activeLlmSpan) {
16141
- await ensureActiveLlmSpanForParentToolUse(
16142
- span,
16143
- activeLlmSpansByParentToolUse,
16144
- subAgentDetailsByToolUseId,
16145
- activeToolSpans,
16146
- subAgentSpans,
16147
- parentToolUseId,
16148
- getCurrentUnixTimestamp()
16149
- );
16150
- }
16151
- if (parentToolUseId) {
16152
- const subAgentSpan = await ensureSubAgentSpan(
16153
- subAgentDetailsByToolUseId,
16154
- span,
16155
- activeToolSpans,
16156
- subAgentSpans,
16157
- parentToolUseId
16158
- );
16159
- return subAgentSpan.export();
16160
- }
16161
- return span.export();
16162
- }
16163
- if (activeLlmSpan) {
16164
- return activeLlmSpan.export();
16991
+ const latestLlmParent = parentToolUseId ? latestLlmParentBySubAgentToolUse.get(parentToolUseId) : latestRootLlmParentRef.value;
16992
+ if (!activeLlmSpan && !latestLlmParent) {
16993
+ await ensureActiveLlmSpanForParentToolUse(
16994
+ span,
16995
+ activeLlmSpansByParentToolUse,
16996
+ subAgentDetailsByToolUseId,
16997
+ activeToolSpans,
16998
+ subAgentSpans,
16999
+ parentToolUseId,
17000
+ getCurrentUnixTimestamp()
17001
+ );
16165
17002
  }
16166
17003
  if (parentToolUseId) {
16167
- const parentLlm = latestLlmParentBySubAgentToolUse.get(parentToolUseId);
16168
- if (parentLlm) {
16169
- return parentLlm;
16170
- }
16171
17004
  const subAgentSpan = await ensureSubAgentSpan(
16172
17005
  subAgentDetailsByToolUseId,
16173
17006
  span,
@@ -16177,9 +17010,6 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
16177
17010
  );
16178
17011
  return subAgentSpan.export();
16179
17012
  }
16180
- if (latestRootLlmParentRef.value) {
16181
- return latestRootLlmParentRef.value;
16182
- }
16183
17013
  return span.export();
16184
17014
  };
16185
17015
  localToolContext.resolveLocalToolParent = resolveToolUseParentSpan;
@@ -16200,6 +17030,7 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
16200
17030
  accumulatedOutputTokens: 0,
16201
17031
  activeLlmSpansByParentToolUse,
16202
17032
  activeToolSpans,
17033
+ conversationHistoryByParentKey,
16203
17034
  capturedPromptMessages,
16204
17035
  currentMessageId: void 0,
16205
17036
  currentMessageStartTime: startTime,
@@ -16210,7 +17041,9 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
16210
17041
  originalPrompt,
16211
17042
  processing: Promise.resolve(),
16212
17043
  promptDone,
17044
+ promptMessagesByParentKey,
16213
17045
  promptStarted: () => promptStarted,
17046
+ promptSourcePriorityByParentKey,
16214
17047
  span,
16215
17048
  subAgentDetailsByToolUseId,
16216
17049
  subAgentSpans,
@@ -17639,6 +18472,10 @@ var googleGenAIChannels = defineChannels("@google/genai", {
17639
18472
  embedContent: channel({
17640
18473
  channelName: "models.embedContent",
17641
18474
  kind: "async"
18475
+ }),
18476
+ interactionsCreate: channel({
18477
+ channelName: "interactions.create",
18478
+ kind: "async"
17642
18479
  })
17643
18480
  });
17644
18481
 
@@ -17666,6 +18503,7 @@ var GoogleGenAIPlugin = class extends BasePlugin {
17666
18503
  this.subscribeToGenerateContentChannel();
17667
18504
  this.subscribeToGenerateContentStreamChannel();
17668
18505
  this.subscribeToEmbedContentChannel();
18506
+ this.subscribeToInteractionsCreateChannel();
17669
18507
  }
17670
18508
  subscribeToGenerateContentChannel() {
17671
18509
  const tracingChannel2 = googleGenAIChannels.generateContent.tracingChannel();
@@ -17838,7 +18676,30 @@ var GoogleGenAIPlugin = class extends BasePlugin {
17838
18676
  tracingChannel2.unsubscribe(handlers);
17839
18677
  });
17840
18678
  }
18679
+ subscribeToInteractionsCreateChannel() {
18680
+ this.unsubscribers.push(
18681
+ traceStreamingChannel(
18682
+ googleGenAIChannels.interactionsCreate,
18683
+ {
18684
+ name: "create_interaction",
18685
+ shouldTrace: ([params]) => !isBackgroundInteractionCreate(params),
18686
+ type: "llm" /* LLM */,
18687
+ extractInput: ([params]) => ({
18688
+ input: serializeInteractionInput(params),
18689
+ metadata: extractInteractionMetadata(params)
18690
+ }),
18691
+ extractOutput: (result) => serializeInteractionValue(result),
18692
+ extractMetadata: (result) => extractInteractionResponseMetadata(result),
18693
+ extractMetrics: (result, startTime) => cleanMetrics3(extractInteractionMetrics(result, startTime)),
18694
+ aggregateChunks: (chunks, _result, _event, startTime) => aggregateInteractionEvents(chunks, startTime)
18695
+ }
18696
+ )
18697
+ );
18698
+ }
17841
18699
  };
18700
+ function isBackgroundInteractionCreate(params) {
18701
+ return tryToDict(params)?.background === true;
18702
+ }
17842
18703
  function ensureSpanState(states, event, create) {
17843
18704
  const existing = states.get(event);
17844
18705
  if (existing) {
@@ -18046,6 +18907,60 @@ function serializeEmbedContentInput(params) {
18046
18907
  }
18047
18908
  return input;
18048
18909
  }
18910
+ function serializeInteractionInput(params) {
18911
+ const input = {
18912
+ input: serializeInteractionValue(params.input)
18913
+ };
18914
+ for (const key of [
18915
+ "model",
18916
+ "agent",
18917
+ "agent_config",
18918
+ "api_version",
18919
+ "background",
18920
+ "environment",
18921
+ "generation_config",
18922
+ "previous_interaction_id",
18923
+ "response_format",
18924
+ "response_mime_type",
18925
+ "response_modalities",
18926
+ "service_tier",
18927
+ "store",
18928
+ "stream",
18929
+ "system_instruction",
18930
+ "webhook_config"
18931
+ ]) {
18932
+ const value = params[key];
18933
+ if (value !== void 0) {
18934
+ input[key] = serializeInteractionValue(value);
18935
+ }
18936
+ }
18937
+ return input;
18938
+ }
18939
+ function extractInteractionMetadata(params) {
18940
+ const metadata = {};
18941
+ for (const key of [
18942
+ "model",
18943
+ "agent",
18944
+ "agent_config",
18945
+ "generation_config",
18946
+ "system_instruction",
18947
+ "response_format",
18948
+ "response_mime_type",
18949
+ "response_modalities",
18950
+ "service_tier"
18951
+ ]) {
18952
+ const value = params[key];
18953
+ if (value !== void 0) {
18954
+ metadata[key] = serializeInteractionValue(value);
18955
+ }
18956
+ }
18957
+ if (Array.isArray(params.tools)) {
18958
+ metadata.tools = params.tools.map(
18959
+ (tool) => serializeInteractionValue(tool)
18960
+ );
18961
+ }
18962
+ return metadata;
18963
+ }
18049
18964
  function serializeContentCollection(contents) {
18050
18965
  if (contents === null || contents === void 0) {
18051
18966
  return null;
@@ -18076,21 +18991,8 @@ function serializePart(part) {
18076
18991
  }
18077
18992
  if (part.inlineData && part.inlineData.data) {
18078
18993
  const { data, mimeType } = part.inlineData;
18079
- if (data instanceof Uint8Array || typeof Buffer !== "undefined" && Buffer.isBuffer(data) || typeof data === "string") {
18080
- const extension = mimeType ? mimeType.split("/")[1] : "bin";
18081
- const filename = `file.${extension}`;
18082
- const buffer = typeof data === "string" ? typeof Buffer !== "undefined" ? Buffer.from(data, "base64") : new Uint8Array(
18083
- atob(data).split("").map((c) => c.charCodeAt(0))
18084
- ) : typeof Buffer !== "undefined" ? Buffer.from(data) : new Uint8Array(data);
18085
- const arrayBuffer = buffer instanceof Uint8Array ? buffer.buffer.slice(
18086
- buffer.byteOffset,
18087
- buffer.byteOffset + buffer.byteLength
18088
- ) : buffer;
18089
- const attachment = new Attachment({
18090
- data: arrayBuffer,
18091
- filename,
18092
- contentType: mimeType || "application/octet-stream"
18093
- });
18994
+ const attachment = createAttachmentFromInlineData(data, mimeType);
18995
+ if (attachment) {
18094
18996
  return {
18095
18997
  image_url: { url: attachment }
18096
18998
  };
@@ -18098,6 +19000,59 @@ function serializePart(part) {
18098
19000
  }
18099
19001
  return part;
18100
19002
  }
19003
+ function serializeInteractionValue(value, seen = /* @__PURE__ */ new WeakSet()) {
19004
+ if (value === null || value === void 0 || typeof value !== "object") {
19005
+ return value;
19006
+ }
19007
+ if (Array.isArray(value)) {
19008
+ return value.map((item) => serializeInteractionValue(item, seen));
19009
+ }
19010
+ const dict = tryToDict(value);
19011
+ if (dict === null || dict === void 0 || typeof dict !== "object") {
19012
+ return dict;
19013
+ }
19014
+ if (Array.isArray(dict)) {
19015
+ return dict.map((item) => serializeInteractionValue(item, seen));
19016
+ }
19017
+ if (seen.has(dict)) {
19018
+ return "[Circular]";
19019
+ }
19020
+ seen.add(dict);
19021
+ try {
19022
+ const serialized = {};
19023
+ 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;
19024
+ const attachment = mimeType && "data" in dict && dict.data !== void 0 ? createAttachmentFromInlineData(dict.data, mimeType) : null;
19025
+ for (const [key, entry] of Object.entries(dict)) {
19026
+ if (key === "data" && attachment) {
19027
+ serialized[key] = attachment;
19028
+ } else {
19029
+ serialized[key] = serializeInteractionValue(entry, seen);
19030
+ }
19031
+ }
19032
+ return serialized;
19033
+ } finally {
19034
+ seen.delete(dict);
19035
+ }
19036
+ }
19037
+ function createAttachmentFromInlineData(data, mimeType) {
19038
+ if (!(data instanceof Uint8Array || typeof Buffer !== "undefined" && Buffer.isBuffer(data) || typeof data === "string")) {
19039
+ return null;
19040
+ }
19041
+ const extension = mimeType ? mimeType.split("/")[1] : "bin";
19042
+ const filename = `file.${extension}`;
19043
+ const buffer = typeof data === "string" ? typeof Buffer !== "undefined" ? Buffer.from(data, "base64") : new Uint8Array(
19044
+ atob(data).split("").map((c) => c.charCodeAt(0))
19045
+ ) : typeof Buffer !== "undefined" ? Buffer.from(data) : new Uint8Array(data);
19046
+ const arrayBuffer = buffer instanceof Uint8Array ? buffer.buffer.slice(
19047
+ buffer.byteOffset,
19048
+ buffer.byteOffset + buffer.byteLength
19049
+ ) : buffer;
19050
+ return new Attachment({
19051
+ data: arrayBuffer,
19052
+ filename,
19053
+ contentType: mimeType || "application/octet-stream"
19054
+ });
19055
+ }
18101
19056
  function serializeGenerateContentTools(params) {
18102
19057
  const config = params.config ? tryToDict(params.config) : null;
18103
19058
  const tools = config?.tools;
@@ -18182,6 +19137,33 @@ function extractEmbedContentMetrics(response, startTime) {
18182
19137
  }
18183
19138
  return metrics;
18184
19139
  }
19140
+ function extractInteractionMetrics(response, startTime) {
19141
+ const metrics = {};
19142
+ if (startTime !== void 0) {
19143
+ const end = getCurrentUnixTimestamp();
19144
+ metrics.start = startTime;
19145
+ metrics.end = end;
19146
+ metrics.duration = end - startTime;
19147
+ }
19148
+ if (response?.usage) {
19149
+ populateInteractionUsageMetrics(metrics, response.usage);
19150
+ }
19151
+ return metrics;
19152
+ }
19153
+ function extractInteractionResponseMetadata(response) {
19154
+ const responseDict = tryToDict(response);
19155
+ if (!responseDict) {
19156
+ return void 0;
19157
+ }
19158
+ const metadata = {};
19159
+ if (typeof responseDict.id === "string") {
19160
+ metadata.interaction_id = responseDict.id;
19161
+ }
19162
+ if (typeof responseDict.status === "string") {
19163
+ metadata.status = responseDict.status;
19164
+ }
19165
+ return Object.keys(metadata).length > 0 ? metadata : void 0;
19166
+ }
18185
19167
  function extractEmbedPromptTokenCount(response) {
18186
19168
  if (!response) {
18187
19169
  return void 0;
@@ -18244,6 +19226,23 @@ function populateUsageMetrics(metrics, usage) {
18244
19226
  metrics.completion_reasoning_tokens = usage.thoughtsTokenCount;
18245
19227
  }
18246
19228
  }
19229
+ function populateInteractionUsageMetrics(metrics, usage) {
19230
+ if (typeof usage.total_input_tokens === "number") {
19231
+ metrics.prompt_tokens = usage.total_input_tokens;
19232
+ }
19233
+ if (typeof usage.total_output_tokens === "number") {
19234
+ metrics.completion_tokens = usage.total_output_tokens;
19235
+ }
19236
+ if (typeof usage.total_tokens === "number") {
19237
+ metrics.tokens = usage.total_tokens;
19238
+ }
19239
+ if (typeof usage.total_cached_tokens === "number") {
19240
+ metrics.prompt_cached_tokens = usage.total_cached_tokens;
19241
+ }
19242
+ if (typeof usage.total_thought_tokens === "number") {
19243
+ metrics.completion_reasoning_tokens = usage.total_thought_tokens;
19244
+ }
19245
+ }
18247
19246
  function aggregateGenerateContentChunks(chunks, startTime, firstTokenTime) {
18248
19247
  const end = getCurrentUnixTimestamp();
18249
19248
  const metrics = {
@@ -18341,41 +19340,181 @@ function aggregateGenerateContentChunks(chunks, startTime, firstTokenTime) {
18341
19340
  }
18342
19341
  return { aggregated, metrics };
18343
19342
  }
18344
- function cleanMetrics3(metrics) {
18345
- const cleaned = {};
18346
- for (const [key, value] of Object.entries(metrics)) {
18347
- if (value !== null && value !== void 0) {
18348
- cleaned[key] = value;
18349
- }
18350
- }
18351
- return cleaned;
18352
- }
18353
- function extractResponseMetadata(response) {
18354
- const responseDict = tryToDict(response);
18355
- if (!responseDict) {
18356
- return void 0;
19343
+ function aggregateInteractionEvents(chunks, startTime) {
19344
+ const end = getCurrentUnixTimestamp();
19345
+ const metrics = {};
19346
+ if (startTime !== void 0) {
19347
+ metrics.start = startTime;
19348
+ metrics.end = end;
19349
+ metrics.duration = end - startTime;
18357
19350
  }
18358
- const metadata = {};
18359
- const responseGroundingMetadata = responseDict.groundingMetadata;
18360
- const candidateGroundingMetadata = [];
18361
- if (Array.isArray(responseDict.candidates)) {
18362
- for (const candidate of responseDict.candidates) {
18363
- const candidateDict = tryToDict(candidate);
18364
- if (candidateDict?.groundingMetadata !== void 0) {
18365
- candidateGroundingMetadata.push(candidateDict.groundingMetadata);
19351
+ let latestInteraction;
19352
+ let latestUsage;
19353
+ let status;
19354
+ let outputText = "";
19355
+ const steps = /* @__PURE__ */ new Map();
19356
+ for (const chunk of chunks) {
19357
+ const event = tryToDict(chunk);
19358
+ if (!event) {
19359
+ continue;
19360
+ }
19361
+ const usage = extractInteractionUsageFromEvent(event);
19362
+ if (usage) {
19363
+ latestUsage = usage;
19364
+ }
19365
+ const interaction = tryToDict(event.interaction);
19366
+ if (interaction) {
19367
+ latestInteraction = serializeInteractionValue(interaction);
19368
+ if (typeof interaction.status === "string") {
19369
+ status = interaction.status;
18366
19370
  }
18367
19371
  }
19372
+ if (typeof event.status === "string") {
19373
+ status = event.status;
19374
+ }
19375
+ const index = typeof event.index === "number" ? event.index : void 0;
19376
+ if (index === void 0) {
19377
+ continue;
19378
+ }
19379
+ if (event.event_type === "step.start") {
19380
+ const compact = compactInteractionStep(event.step);
19381
+ compact.index = index;
19382
+ steps.set(index, compact);
19383
+ continue;
19384
+ }
19385
+ if (event.event_type === "step.delta") {
19386
+ const step = steps.get(index) ?? { index };
19387
+ const textDelta = applyInteractionDelta(step, event.delta);
19388
+ if (textDelta) {
19389
+ outputText += textDelta;
19390
+ }
19391
+ steps.set(index, step);
19392
+ }
18368
19393
  }
18369
- if (responseGroundingMetadata !== void 0) {
18370
- metadata.groundingMetadata = responseGroundingMetadata;
18371
- } else if (candidateGroundingMetadata.length === 1) {
18372
- [metadata.groundingMetadata] = candidateGroundingMetadata;
18373
- } else if (candidateGroundingMetadata.length > 1) {
18374
- metadata.groundingMetadata = candidateGroundingMetadata;
19394
+ if (latestUsage) {
19395
+ populateInteractionUsageMetrics(metrics, latestUsage);
18375
19396
  }
18376
- return Object.keys(metadata).length > 0 ? metadata : void 0;
18377
- }
18378
- function tryToDict(obj) {
19397
+ const output = latestInteraction ? { ...latestInteraction } : {};
19398
+ if (status) {
19399
+ output.status = status;
19400
+ }
19401
+ if (outputText) {
19402
+ output.output_text = outputText;
19403
+ }
19404
+ if (latestUsage) {
19405
+ output.usage = serializeInteractionValue(latestUsage);
19406
+ }
19407
+ const compactSteps = Array.from(steps.values()).sort(
19408
+ (left, right) => Number(left.index ?? 0) - Number(right.index ?? 0)
19409
+ );
19410
+ if (compactSteps.length > 0) {
19411
+ output.steps = compactSteps;
19412
+ }
19413
+ const metadata = {};
19414
+ if (typeof output.id === "string") {
19415
+ metadata.interaction_id = output.id;
19416
+ }
19417
+ if (typeof output.status === "string") {
19418
+ metadata.status = output.status;
19419
+ }
19420
+ return {
19421
+ output,
19422
+ metrics: cleanMetrics3(metrics),
19423
+ ...Object.keys(metadata).length > 0 ? { metadata } : {}
19424
+ };
19425
+ }
19426
+ function extractInteractionUsageFromEvent(event) {
19427
+ const metadata = tryToDict(event.metadata);
19428
+ const metadataUsage = tryToDict(metadata?.usage);
19429
+ if (metadataUsage) {
19430
+ return metadataUsage;
19431
+ }
19432
+ const metadataTotalUsage = tryToDict(metadata?.total_usage);
19433
+ if (metadataTotalUsage) {
19434
+ return metadataTotalUsage;
19435
+ }
19436
+ const interaction = tryToDict(event.interaction);
19437
+ const interactionUsage = tryToDict(interaction?.usage);
19438
+ return interactionUsage ? interactionUsage : void 0;
19439
+ }
19440
+ function compactInteractionStep(step) {
19441
+ const stepDict = tryToDict(step);
19442
+ if (!stepDict) {
19443
+ return {};
19444
+ }
19445
+ const compact = {};
19446
+ for (const key of [
19447
+ "type",
19448
+ "content",
19449
+ "name",
19450
+ "server_name",
19451
+ "arguments",
19452
+ "result",
19453
+ "is_error"
19454
+ ]) {
19455
+ if (stepDict[key] !== void 0) {
19456
+ compact[key] = serializeInteractionValue(stepDict[key]);
19457
+ }
19458
+ }
19459
+ return Object.keys(compact).length > 0 ? compact : serializeInteractionValue(stepDict);
19460
+ }
19461
+ function applyInteractionDelta(step, delta) {
19462
+ const deltaDict = tryToDict(delta);
19463
+ if (!deltaDict) {
19464
+ return void 0;
19465
+ }
19466
+ const deltaType = deltaDict.type;
19467
+ if (typeof deltaType === "string" && typeof step.type !== "string") {
19468
+ step.type = deltaType === "text" ? "model_output" : deltaType;
19469
+ }
19470
+ if (deltaType === "text" && typeof deltaDict.text === "string") {
19471
+ step.text = `${typeof step.text === "string" ? step.text : ""}${deltaDict.text}`;
19472
+ return deltaDict.text;
19473
+ }
19474
+ if (deltaType === "arguments_delta" && typeof deltaDict.arguments === "string") {
19475
+ step.arguments = `${typeof step.arguments === "string" ? step.arguments : ""}${deltaDict.arguments}`;
19476
+ return void 0;
19477
+ }
19478
+ const deltas = Array.isArray(step.deltas) ? step.deltas : [];
19479
+ deltas.push(serializeInteractionValue(deltaDict));
19480
+ step.deltas = deltas;
19481
+ return void 0;
19482
+ }
19483
+ function cleanMetrics3(metrics) {
19484
+ const cleaned = {};
19485
+ for (const [key, value] of Object.entries(metrics)) {
19486
+ if (value !== null && value !== void 0) {
19487
+ cleaned[key] = value;
19488
+ }
19489
+ }
19490
+ return cleaned;
19491
+ }
19492
+ function extractResponseMetadata(response) {
19493
+ const responseDict = tryToDict(response);
19494
+ if (!responseDict) {
19495
+ return void 0;
19496
+ }
19497
+ const metadata = {};
19498
+ const responseGroundingMetadata = responseDict.groundingMetadata;
19499
+ const candidateGroundingMetadata = [];
19500
+ if (Array.isArray(responseDict.candidates)) {
19501
+ for (const candidate of responseDict.candidates) {
19502
+ const candidateDict = tryToDict(candidate);
19503
+ if (candidateDict?.groundingMetadata !== void 0) {
19504
+ candidateGroundingMetadata.push(candidateDict.groundingMetadata);
19505
+ }
19506
+ }
19507
+ }
19508
+ if (responseGroundingMetadata !== void 0) {
19509
+ metadata.groundingMetadata = responseGroundingMetadata;
19510
+ } else if (candidateGroundingMetadata.length === 1) {
19511
+ [metadata.groundingMetadata] = candidateGroundingMetadata;
19512
+ } else if (candidateGroundingMetadata.length > 1) {
19513
+ metadata.groundingMetadata = candidateGroundingMetadata;
19514
+ }
19515
+ return Object.keys(metadata).length > 0 ? metadata : void 0;
19516
+ }
19517
+ function tryToDict(obj) {
18379
19518
  if (obj === null || obj === void 0) {
18380
19519
  return null;
18381
19520
  }
@@ -24167,7 +25306,8 @@ var FlueObserveBridge = class {
24167
25306
  metadata
24168
25307
  }
24169
25308
  });
24170
- this.runsById.set(event.runId, { metadata, span });
25309
+ const activeContext = enterCurrentFlueSpan(span);
25310
+ this.runsById.set(event.runId, { activeContext, metadata, span });
24171
25311
  }
24172
25312
  handleRunEnd(event) {
24173
25313
  const state = this.runsById.get(event.runId);
@@ -24185,6 +25325,7 @@ var FlueObserveBridge = class {
24185
25325
  });
24186
25326
  safeEnd(state.span, eventTime(event.timestamp));
24187
25327
  this.runsById.delete(event.runId);
25328
+ restoreCurrentFlueSpan(state.activeContext);
24188
25329
  }
24189
25330
  void flush().catch((error) => {
24190
25331
  logInstrumentationError3("Flue flush", error);
@@ -24311,7 +25452,8 @@ var FlueObserveBridge = class {
24311
25452
  metadata
24312
25453
  }
24313
25454
  });
24314
- this.toolsByKey.set(toolKey(event), { metadata, span });
25455
+ const activeContext = enterCurrentFlueSpan(span);
25456
+ this.toolsByKey.set(toolKey(event), { activeContext, metadata, span });
24315
25457
  }
24316
25458
  handleToolCall(event) {
24317
25459
  if (!event.toolCallId) {
@@ -24334,6 +25476,7 @@ var FlueObserveBridge = class {
24334
25476
  });
24335
25477
  safeEnd(state.span, eventTime(event.timestamp));
24336
25478
  this.toolsByKey.delete(key);
25479
+ restoreCurrentFlueSpan(state.activeContext);
24337
25480
  }
24338
25481
  handleTaskStart(event) {
24339
25482
  if (!event.taskId) {
@@ -24738,6 +25881,34 @@ function stateMatchesRun(state, runId) {
24738
25881
  function startFlueSpan(parent, args) {
24739
25882
  return parent ? withCurrent(parent, () => startSpan(args)) : startSpan(args);
24740
25883
  }
25884
+ function enterCurrentFlueSpan(span) {
25885
+ const contextManager = _internalGetGlobalState()?.contextManager;
25886
+ const store = contextManager ? Reflect.get(contextManager, BRAINTRUST_CURRENT_SPAN_STORE) : void 0;
25887
+ if (!contextManager || !isCurrentSpanStore(store)) {
25888
+ return void 0;
25889
+ }
25890
+ const previous = store.getStore();
25891
+ try {
25892
+ store.enterWith(contextManager.wrapSpanForStore(span));
25893
+ return { previous, store };
25894
+ } catch (error) {
25895
+ logInstrumentationError3("Flue context propagation", error);
25896
+ return void 0;
25897
+ }
25898
+ }
25899
+ function isCurrentSpanStore(value) {
25900
+ return isObjectLike(value) && typeof Reflect.get(value, "enterWith") === "function" && typeof Reflect.get(value, "getStore") === "function";
25901
+ }
25902
+ function restoreCurrentFlueSpan(activeContext) {
25903
+ if (!activeContext) {
25904
+ return;
25905
+ }
25906
+ try {
25907
+ activeContext.store.enterWith(activeContext.previous);
25908
+ } catch (error) {
25909
+ logInstrumentationError3("Flue context restoration", error);
25910
+ }
25911
+ }
24741
25912
  function safeLog3(span, event) {
24742
25913
  try {
24743
25914
  span.log(event);
@@ -25076,143 +26247,1027 @@ function getModelNameFromResponse(response) {
25076
26247
  return modelName3;
25077
26248
  }
25078
26249
  }
25079
- const llmOutput = response.llmOutput || {};
25080
- const modelName2 = llmOutput.model_name ?? llmOutput.model;
25081
- return typeof modelName2 === "string" ? modelName2 : void 0;
26250
+ const llmOutput = response.llmOutput || {};
26251
+ const modelName2 = llmOutput.model_name ?? llmOutput.model;
26252
+ return typeof modelName2 === "string" ? modelName2 : void 0;
26253
+ }
26254
+ function getMetricsFromResponse(response) {
26255
+ for (const generation of walkGenerations(response)) {
26256
+ const message = generation.message;
26257
+ if (!isRecord(message)) {
26258
+ continue;
26259
+ }
26260
+ const usageMetadata = message.usage_metadata;
26261
+ if (!isRecord(usageMetadata)) {
26262
+ continue;
26263
+ }
26264
+ const inputTokenDetails = usageMetadata.input_token_details;
26265
+ return cleanObject({
26266
+ total_tokens: usageMetadata.total_tokens,
26267
+ prompt_tokens: usageMetadata.input_tokens,
26268
+ completion_tokens: usageMetadata.output_tokens,
26269
+ prompt_cache_creation_tokens: isRecord(inputTokenDetails) ? inputTokenDetails.cache_creation : void 0,
26270
+ prompt_cached_tokens: isRecord(inputTokenDetails) ? inputTokenDetails.cache_read : void 0
26271
+ });
26272
+ }
26273
+ const llmOutput = response.llmOutput || {};
26274
+ const tokenUsage = isRecord(llmOutput.tokenUsage) ? llmOutput.tokenUsage : isRecord(llmOutput.estimatedTokens) ? llmOutput.estimatedTokens : {};
26275
+ return cleanObject({
26276
+ total_tokens: tokenUsage.totalTokens,
26277
+ prompt_tokens: tokenUsage.promptTokens,
26278
+ completion_tokens: tokenUsage.completionTokens
26279
+ });
26280
+ }
26281
+ function safeJsonParse(input) {
26282
+ try {
26283
+ return JSON.parse(input);
26284
+ } catch {
26285
+ return input;
26286
+ }
26287
+ }
26288
+ function isRecord(value) {
26289
+ return typeof value === "object" && value !== null && !Array.isArray(value);
26290
+ }
26291
+
26292
+ // src/instrumentation/plugins/langchain-channels.ts
26293
+ var langChainChannels = defineChannels("@langchain/core", {
26294
+ configure: channel({
26295
+ channelName: "CallbackManager.configure",
26296
+ kind: "sync-stream"
26297
+ }),
26298
+ configureSync: channel({
26299
+ channelName: "CallbackManager._configureSync",
26300
+ kind: "sync-stream"
26301
+ })
26302
+ });
26303
+
26304
+ // src/instrumentation/plugins/langchain-plugin.ts
26305
+ var LangChainPlugin = class extends BasePlugin {
26306
+ injectedManagers = /* @__PURE__ */ new WeakSet();
26307
+ onEnable() {
26308
+ this.subscribeToConfigure(langChainChannels.configure);
26309
+ this.subscribeToConfigure(langChainChannels.configureSync);
26310
+ }
26311
+ onDisable() {
26312
+ for (const unsubscribe of this.unsubscribers) {
26313
+ unsubscribe();
26314
+ }
26315
+ this.unsubscribers = [];
26316
+ this.injectedManagers = /* @__PURE__ */ new WeakSet();
26317
+ }
26318
+ subscribeToConfigure(channel2) {
26319
+ const tracingChannel2 = channel2.tracingChannel();
26320
+ const handlers = {
26321
+ start: (event) => {
26322
+ injectHandlerIntoArguments(event.arguments);
26323
+ },
26324
+ end: (event) => {
26325
+ this.injectHandler(event.result);
26326
+ }
26327
+ };
26328
+ tracingChannel2.subscribe(handlers);
26329
+ this.unsubscribers.push(() => {
26330
+ tracingChannel2.unsubscribe(handlers);
26331
+ });
26332
+ }
26333
+ injectHandler(result) {
26334
+ if (!isCallbackManager(result)) {
26335
+ return;
26336
+ }
26337
+ if (this.injectedManagers.has(result) || hasBraintrustHandler(result)) {
26338
+ return;
26339
+ }
26340
+ try {
26341
+ result.addHandler(new BraintrustLangChainCallbackHandler(), true);
26342
+ this.injectedManagers.add(result);
26343
+ } catch {
26344
+ }
26345
+ }
26346
+ };
26347
+ function isCallbackManager(value) {
26348
+ if (typeof value !== "object" || value === null) {
26349
+ return false;
26350
+ }
26351
+ const maybeManager = value;
26352
+ return typeof maybeManager.addHandler === "function";
26353
+ }
26354
+ function hasBraintrustHandler(manager) {
26355
+ return manager.handlers?.some((handler) => {
26356
+ if (typeof handler !== "object" || handler === null) {
26357
+ return false;
26358
+ }
26359
+ const name = Reflect.get(handler, "name");
26360
+ return name === BRAINTRUST_LANGCHAIN_CALLBACK_HANDLER_NAME;
26361
+ }) ?? false;
26362
+ }
26363
+ function injectHandlerIntoArguments(args) {
26364
+ if (!isWritableArgumentsObject(args)) {
26365
+ return;
26366
+ }
26367
+ const inheritedHandlers = Reflect.get(args, "0");
26368
+ const handler = new BraintrustLangChainCallbackHandler();
26369
+ if (inheritedHandlers === void 0 || inheritedHandlers === null) {
26370
+ Reflect.set(args, "0", [handler]);
26371
+ return;
26372
+ }
26373
+ if (Array.isArray(inheritedHandlers)) {
26374
+ if (!inheritedHandlers.some(isBraintrustHandler)) {
26375
+ inheritedHandlers.push(handler);
26376
+ }
26377
+ }
26378
+ }
26379
+ function isWritableArgumentsObject(args) {
26380
+ return typeof args === "object" && args !== null;
26381
+ }
26382
+ function isBraintrustHandler(handler) {
26383
+ if (typeof handler !== "object" || handler === null) {
26384
+ return false;
26385
+ }
26386
+ return Reflect.get(handler, "name") === BRAINTRUST_LANGCHAIN_CALLBACK_HANDLER_NAME;
26387
+ }
26388
+
26389
+ // src/instrumentation/plugins/pi-coding-agent-channels.ts
26390
+ var piCodingAgentChannels = defineChannels(
26391
+ "@earendil-works/pi-coding-agent",
26392
+ {
26393
+ prompt: channel({
26394
+ channelName: "AgentSession.prompt",
26395
+ kind: "async"
26396
+ })
26397
+ }
26398
+ );
26399
+
26400
+ // src/instrumentation/plugins/pi-coding-agent-plugin.ts
26401
+ var piStreamPatchStates = /* @__PURE__ */ new WeakMap();
26402
+ var piPromptContextStore;
26403
+ var PiCodingAgentPlugin = class extends BasePlugin {
26404
+ activePromptStates = /* @__PURE__ */ new Set();
26405
+ onEnable() {
26406
+ this.subscribeToPrompt();
26407
+ }
26408
+ onDisable() {
26409
+ for (const unsubscribe of this.unsubscribers) {
26410
+ unsubscribe();
26411
+ }
26412
+ this.unsubscribers = [];
26413
+ for (const state of [...this.activePromptStates]) {
26414
+ void finalizePiPromptRun(state).catch((error) => {
26415
+ logInstrumentationError4("Pi Coding Agent disable cleanup", error);
26416
+ });
26417
+ }
26418
+ }
26419
+ subscribeToPrompt() {
26420
+ const channel2 = piCodingAgentChannels.prompt.tracingChannel();
26421
+ const states = /* @__PURE__ */ new WeakMap();
26422
+ const unbindAutoInstrumentationSuppression = bindAutoInstrumentationSuppressionToStart(channel2);
26423
+ const handlers = {
26424
+ start: (event) => {
26425
+ const state = startPiPromptRun(event, (state2) => {
26426
+ this.activePromptStates.delete(state2);
26427
+ });
26428
+ if (state) {
26429
+ this.activePromptStates.add(state);
26430
+ states.set(event, state);
26431
+ }
26432
+ },
26433
+ asyncEnd: async (event) => {
26434
+ const state = states.get(event);
26435
+ if (!state) {
26436
+ return;
26437
+ }
26438
+ states.delete(event);
26439
+ state.promptCallEnded = true;
26440
+ if (!state.finalized && state.deferCompletionUntilTurnEnd && !state.turnEnded) {
26441
+ if (!state.sawStreamFn) {
26442
+ state.queued = true;
26443
+ if (!state.streamPatchState.queuedPromptStates.includes(state)) {
26444
+ state.streamPatchState.queuedPromptStates.push(state);
26445
+ }
26446
+ }
26447
+ return;
26448
+ }
26449
+ await finalizePiPromptRun(state);
26450
+ },
26451
+ error: async (event) => {
26452
+ const state = states.get(event);
26453
+ if (!state) {
26454
+ return;
26455
+ }
26456
+ states.delete(event);
26457
+ await finalizePiPromptRun(state, event.error);
26458
+ }
26459
+ };
26460
+ channel2.subscribe(handlers);
26461
+ this.unsubscribers.push(() => {
26462
+ unbindAutoInstrumentationSuppression?.();
26463
+ channel2.unsubscribe(handlers);
26464
+ });
26465
+ }
26466
+ };
26467
+ function startPiPromptRun(event, onFinalize) {
26468
+ const session = extractSession(event);
26469
+ const agent = session?.agent;
26470
+ if (!session || !isPiAgent(agent)) {
26471
+ return void 0;
26472
+ }
26473
+ const metadata = {
26474
+ ...extractSessionMetadata(session),
26475
+ ...extractPromptOptionsMetadata(event.arguments[1]),
26476
+ "pi_coding_agent.operation": "AgentSession.prompt",
26477
+ provider: session.model?.provider ?? agent.state?.model?.provider ?? "pi",
26478
+ ...session.model?.id || agent.state?.model?.id ? { model: session.model?.id ?? agent.state?.model?.id } : {},
26479
+ ...event.moduleVersion ? { "pi_coding_agent.version": event.moduleVersion } : {}
26480
+ };
26481
+ const span = startSpan({
26482
+ event: {
26483
+ input: extractPromptInput(event.arguments[0], event.arguments[1]),
26484
+ metadata
26485
+ },
26486
+ name: "AgentSession.prompt",
26487
+ spanAttributes: { type: "task" /* TASK */ }
26488
+ });
26489
+ const streamPatchState = installPiStreamPatch(agent);
26490
+ const options = event.arguments[1];
26491
+ const promptText = event.arguments[0];
26492
+ const state = {
26493
+ activeLlmSpans: /* @__PURE__ */ new Set(),
26494
+ activeToolSpans: /* @__PURE__ */ new Map(),
26495
+ agent,
26496
+ collectedLlmUsageMetrics: false,
26497
+ deferCompletionUntilTurnEnd: options?.streamingBehavior === "followUp" || options?.streamingBehavior === "steer",
26498
+ finalized: false,
26499
+ metadata,
26500
+ metrics: {},
26501
+ onFinalize,
26502
+ promptCallEnded: false,
26503
+ ...typeof promptText === "string" ? { promptText } : {},
26504
+ queued: false,
26505
+ span,
26506
+ sawStreamFn: false,
26507
+ startTime: getCurrentUnixTimestamp(),
26508
+ streamPatchState,
26509
+ turnEnded: false
26510
+ };
26511
+ state.restorePromptContext = enterPiPromptContext(state);
26512
+ streamPatchState.activePromptStates.add(state);
26513
+ try {
26514
+ state.unsubscribeAgent = agent.subscribe(async (agentEvent) => {
26515
+ try {
26516
+ await runWithAutoInstrumentationSuppressed(
26517
+ () => handlePiAgentEvent(state, agentEvent)
26518
+ );
26519
+ } catch (error) {
26520
+ logInstrumentationError4("Pi Coding Agent event", error);
26521
+ }
26522
+ });
26523
+ } catch (error) {
26524
+ logInstrumentationError4("Pi Coding Agent event subscription", error);
26525
+ }
26526
+ return state;
26527
+ }
26528
+ function extractSession(event) {
26529
+ const candidate = event.session ?? event.self;
26530
+ return isObject(candidate) && typeof candidate.prompt === "function" ? candidate : void 0;
26531
+ }
26532
+ function isPiAgent(value) {
26533
+ return isObject(value) && typeof value.streamFn === "function" && typeof value.subscribe === "function";
26534
+ }
26535
+ function promptContextStore() {
26536
+ piPromptContextStore ??= isomorph_default.newAsyncLocalStorage();
26537
+ return piPromptContextStore;
26538
+ }
26539
+ function currentPromptContextFrames() {
26540
+ return promptContextStore().getStore()?.frames ?? [];
26541
+ }
26542
+ function currentPiPromptState() {
26543
+ const frames = currentPromptContextFrames();
26544
+ return frames[frames.length - 1]?.state;
26545
+ }
26546
+ function enterPiPromptContext(state) {
26547
+ const frame = {
26548
+ id: /* @__PURE__ */ Symbol("braintrust.pi-coding-agent.prompt"),
26549
+ state
26550
+ };
26551
+ promptContextStore().enterWith({
26552
+ frames: [...currentPromptContextFrames(), frame]
26553
+ });
26554
+ return () => {
26555
+ const frames = currentPromptContextFrames().filter(
26556
+ (candidate) => candidate.id !== frame.id
26557
+ );
26558
+ promptContextStore().enterWith(frames.length > 0 ? { frames } : void 0);
26559
+ };
26560
+ }
26561
+ function installPiStreamPatch(agent) {
26562
+ const existing = piStreamPatchStates.get(agent);
26563
+ if (existing) {
26564
+ if (agent.streamFn !== existing.wrappedStreamFn) {
26565
+ debugLogger.debug(
26566
+ "Pi Coding Agent streamFn changed while Braintrust instrumentation was active; preserving existing patch state."
26567
+ );
26568
+ }
26569
+ return existing;
26570
+ }
26571
+ const patchState = {
26572
+ activePromptStates: /* @__PURE__ */ new Set(),
26573
+ agent,
26574
+ originalStreamFn: agent.streamFn,
26575
+ queuedPromptStates: [],
26576
+ wrappedStreamFn: agent.streamFn
26577
+ };
26578
+ patchState.wrappedStreamFn = makeSharedInstrumentedStreamFn(patchState);
26579
+ agent.streamFn = patchState.wrappedStreamFn;
26580
+ piStreamPatchStates.set(agent, patchState);
26581
+ return patchState;
26582
+ }
26583
+ function resolveStreamPromptState(patchState, context) {
26584
+ let lastUserText;
26585
+ if (Array.isArray(context.messages)) {
26586
+ for (let i = context.messages.length - 1; i >= 0; i--) {
26587
+ const message = context.messages[i];
26588
+ if (isPiUserMessage(message)) {
26589
+ if (typeof message.content === "string") {
26590
+ lastUserText = message.content;
26591
+ } else {
26592
+ lastUserText = message.content.flatMap((part) => part.type === "text" ? [part.text] : []).join("");
26593
+ }
26594
+ break;
26595
+ }
26596
+ }
26597
+ }
26598
+ if (lastUserText !== void 0) {
26599
+ const queuedMatch = patchState.queuedPromptStates.find(
26600
+ (state) => state.promptText === lastUserText
26601
+ );
26602
+ if (queuedMatch) {
26603
+ return queuedMatch;
26604
+ }
26605
+ const matches = [...patchState.activePromptStates].filter(
26606
+ (state) => state.promptText === lastUserText
26607
+ );
26608
+ if (matches.length === 1) {
26609
+ return matches[0];
26610
+ }
26611
+ }
26612
+ const contextState = currentPiPromptState();
26613
+ if (contextState && patchState.activePromptStates.has(contextState) && (!contextState.queued || lastUserText !== void 0 && contextState.promptText === lastUserText)) {
26614
+ return contextState;
26615
+ }
26616
+ if (patchState.activePromptStates.size === 1) {
26617
+ return [...patchState.activePromptStates][0];
26618
+ }
26619
+ return void 0;
26620
+ }
26621
+ function makeSharedInstrumentedStreamFn(patchState) {
26622
+ return async function instrumentedPiStreamFn(model, context, options) {
26623
+ const state = resolveStreamPromptState(patchState, context);
26624
+ if (!state) {
26625
+ const invokeOriginal = () => Reflect.apply(patchState.originalStreamFn, this, [
26626
+ model,
26627
+ context,
26628
+ options
26629
+ ]);
26630
+ return patchState.activePromptStates.size > 0 ? runWithAutoInstrumentationSuppressed(invokeOriginal) : invokeOriginal();
26631
+ }
26632
+ state.sawStreamFn = true;
26633
+ removeQueuedPromptState(state);
26634
+ state.streamPatchState.eventPromptState = state;
26635
+ const llmState = await startPiLlmSpan(state, model, context, options);
26636
+ try {
26637
+ const stream = await runWithAutoInstrumentationSuppressed(
26638
+ () => Reflect.apply(patchState.originalStreamFn, this, [
26639
+ model,
26640
+ context,
26641
+ options
26642
+ ])
26643
+ );
26644
+ return patchAssistantMessageStream(stream, state, llmState);
26645
+ } catch (error) {
26646
+ finishPiLlmSpan(state, llmState, void 0, error);
26647
+ throw error;
26648
+ }
26649
+ };
26650
+ }
26651
+ async function startPiLlmSpan(state, model, context, options) {
26652
+ const metadata = {
26653
+ ...extractModelMetadata2(model),
26654
+ ...extractStreamOptionsMetadata(options),
26655
+ ...extractToolMetadata(context.tools),
26656
+ "pi_coding_agent.operation": "agent.streamFn"
26657
+ };
26658
+ const span = startSpan({
26659
+ event: {
26660
+ input: processInputAttachments(normalizePiContextInput(context)),
26661
+ metadata
26662
+ },
26663
+ name: getLlmSpanName(model),
26664
+ parent: await state.span.export(),
26665
+ spanAttributes: { type: "llm" /* LLM */ }
26666
+ });
26667
+ const llmState = {
26668
+ finalized: false,
26669
+ metadata,
26670
+ metrics: {},
26671
+ span,
26672
+ startTime: getCurrentUnixTimestamp()
26673
+ };
26674
+ state.activeLlmSpans.add(llmState);
26675
+ return llmState;
26676
+ }
26677
+ function patchAssistantMessageStream(stream, promptState, llmState) {
26678
+ if (!isObject(stream)) {
26679
+ return stream;
26680
+ }
26681
+ const streamRecord = stream;
26682
+ const originalResult = stream.result;
26683
+ if (typeof originalResult === "function") {
26684
+ streamRecord.result = function patchedPiResult() {
26685
+ return Promise.resolve(Reflect.apply(originalResult, this, [])).then(
26686
+ (message) => {
26687
+ finishPiLlmSpan(promptState, llmState, message);
26688
+ return message;
26689
+ },
26690
+ (error) => {
26691
+ finishPiLlmSpan(promptState, llmState, void 0, error);
26692
+ throw error;
26693
+ }
26694
+ );
26695
+ };
26696
+ }
26697
+ const originalIterator = stream[Symbol.asyncIterator];
26698
+ if (typeof originalIterator === "function") {
26699
+ streamRecord[Symbol.asyncIterator] = function patchedPiIterator() {
26700
+ const iterator = Reflect.apply(
26701
+ originalIterator,
26702
+ this,
26703
+ []
26704
+ );
26705
+ return {
26706
+ async next() {
26707
+ try {
26708
+ const result = await iterator.next();
26709
+ if (result.done) {
26710
+ finishPiLlmSpan(promptState, llmState);
26711
+ return result;
26712
+ }
26713
+ recordPiAssistantMessageEvent(promptState, llmState, result.value);
26714
+ return result;
26715
+ } catch (error) {
26716
+ finishPiLlmSpan(promptState, llmState, void 0, error);
26717
+ if (typeof iterator.return === "function") {
26718
+ try {
26719
+ await iterator.return();
26720
+ } catch (cleanupError) {
26721
+ logInstrumentationError4(
26722
+ "Pi Coding Agent stream cleanup",
26723
+ cleanupError
26724
+ );
26725
+ }
26726
+ }
26727
+ throw error;
26728
+ }
26729
+ },
26730
+ async return(value) {
26731
+ try {
26732
+ if (typeof iterator.return === "function") {
26733
+ return await iterator.return(value);
26734
+ }
26735
+ return {
26736
+ done: true,
26737
+ value
26738
+ };
26739
+ } catch (error) {
26740
+ finishPiLlmSpan(promptState, llmState, void 0, error);
26741
+ throw error;
26742
+ } finally {
26743
+ finishPiLlmSpan(promptState, llmState);
26744
+ }
26745
+ },
26746
+ async throw(error) {
26747
+ try {
26748
+ if (typeof iterator.throw === "function") {
26749
+ return await iterator.throw(error);
26750
+ }
26751
+ throw error;
26752
+ } catch (thrownError) {
26753
+ finishPiLlmSpan(promptState, llmState, void 0, thrownError);
26754
+ throw thrownError;
26755
+ }
26756
+ },
26757
+ [Symbol.asyncIterator]() {
26758
+ return this;
26759
+ }
26760
+ };
26761
+ };
26762
+ }
26763
+ return stream;
26764
+ }
26765
+ function recordPiAssistantMessageEvent(promptState, llmState, event) {
26766
+ recordFirstTokenMetric(llmState, event);
26767
+ const message = "message" in event ? event.message : void 0;
26768
+ const errorMessage2 = "error" in event ? event.error : void 0;
26769
+ if (event.type === "done" && isPiAssistantMessage(message)) {
26770
+ finishPiLlmSpan(promptState, llmState, message);
26771
+ } else if (event.type === "error" && isPiAssistantMessage(errorMessage2)) {
26772
+ finishPiLlmSpan(promptState, llmState, errorMessage2);
26773
+ }
26774
+ }
26775
+ function recordFirstTokenMetric(state, event) {
26776
+ if (state.metrics.time_to_first_token !== void 0 || event.type === "start") {
26777
+ return;
26778
+ }
26779
+ state.metrics.time_to_first_token = getCurrentUnixTimestamp() - state.startTime;
26780
+ }
26781
+ async function handlePiAgentEvent(state, event) {
26782
+ if (state.finalized) {
26783
+ return;
26784
+ }
26785
+ const eventPromptState = state.streamPatchState.eventPromptState;
26786
+ if (eventPromptState && eventPromptState !== state) {
26787
+ return;
26788
+ }
26789
+ if (!eventPromptState && (state.queued || state.streamPatchState.activePromptStates.size > 1 && currentPiPromptState() !== state)) {
26790
+ return;
26791
+ }
26792
+ switch (event.type) {
26793
+ case "message_end":
26794
+ if (isPiAssistantMessage(event.message)) {
26795
+ state.output = extractAssistantOutput(event.message);
26796
+ }
26797
+ return;
26798
+ case "turn_end":
26799
+ state.turnEnded = true;
26800
+ if (isPiAssistantMessage(event.message)) {
26801
+ state.output = extractAssistantOutput(event.message);
26802
+ if (!state.collectedLlmUsageMetrics) {
26803
+ addMetrics(state.metrics, extractUsageMetrics2(event.message.usage));
26804
+ }
26805
+ }
26806
+ if (state.streamPatchState.eventPromptState === state) {
26807
+ state.streamPatchState.eventPromptState = void 0;
26808
+ }
26809
+ if (state.promptCallEnded && state.deferCompletionUntilTurnEnd) {
26810
+ await finalizePiPromptRun(state);
26811
+ }
26812
+ return;
26813
+ case "tool_execution_start":
26814
+ await startPiToolSpan(state, event);
26815
+ return;
26816
+ case "tool_execution_end":
26817
+ finishPiToolSpan(state, event);
26818
+ return;
26819
+ default:
26820
+ return;
26821
+ }
26822
+ }
26823
+ async function startPiToolSpan(state, event) {
26824
+ if (!event.toolCallId || state.activeToolSpans.has(event.toolCallId)) {
26825
+ return;
26826
+ }
26827
+ const restoreAutoInstrumentation = enterAutoInstrumentationAllowed();
26828
+ const metadata = {
26829
+ "gen_ai.tool.call.id": event.toolCallId,
26830
+ "gen_ai.tool.name": event.toolName,
26831
+ "pi_coding_agent.tool.name": event.toolName
26832
+ };
26833
+ try {
26834
+ const span = startSpan({
26835
+ event: {
26836
+ input: event.args,
26837
+ metadata
26838
+ },
26839
+ name: event.toolName || "tool",
26840
+ parent: await state.span.export(),
26841
+ spanAttributes: { type: "tool" /* TOOL */ }
26842
+ });
26843
+ state.activeToolSpans.set(event.toolCallId, {
26844
+ restoreAutoInstrumentation,
26845
+ span
26846
+ });
26847
+ } catch (error) {
26848
+ restoreAutoInstrumentation();
26849
+ throw error;
26850
+ }
26851
+ }
26852
+ function finishPiToolSpan(state, event) {
26853
+ const toolState = state.activeToolSpans.get(event.toolCallId);
26854
+ if (!toolState) {
26855
+ return;
26856
+ }
26857
+ state.activeToolSpans.delete(event.toolCallId);
26858
+ const metadata = {
26859
+ "gen_ai.tool.call.id": event.toolCallId,
26860
+ "gen_ai.tool.name": event.toolName,
26861
+ "pi_coding_agent.tool.name": event.toolName,
26862
+ "pi_coding_agent.tool.is_error": event.isError
26863
+ };
26864
+ try {
26865
+ safeLog4(toolState.span, {
26866
+ ...event.isError ? { error: stringifyUnknown2(event.result) } : {},
26867
+ metadata,
26868
+ output: event.result
26869
+ });
26870
+ } finally {
26871
+ try {
26872
+ toolState.span.end();
26873
+ } finally {
26874
+ toolState.restoreAutoInstrumentation?.();
26875
+ }
26876
+ }
26877
+ }
26878
+ async function finalizePiPromptRun(state, error) {
26879
+ if (state.finalized) {
26880
+ return;
26881
+ }
26882
+ state.finalized = true;
26883
+ state.onFinalize?.(state);
26884
+ restorePiStreamFn(state);
26885
+ try {
26886
+ state.unsubscribeAgent?.();
26887
+ } catch (unsubscribeError) {
26888
+ logInstrumentationError4("Pi Coding Agent unsubscribe", unsubscribeError);
26889
+ }
26890
+ await finishOpenLlmSpans(state, error);
26891
+ finishOpenToolSpans(state, error);
26892
+ const metadata = {
26893
+ ...state.metadata,
26894
+ ...extractModelMetadata2(state.agent.state?.model)
26895
+ };
26896
+ try {
26897
+ safeLog4(state.span, {
26898
+ ...error ? { error: stringifyUnknown2(error) } : {},
26899
+ metadata,
26900
+ metrics: {
26901
+ ...cleanMetrics5(state.metrics),
26902
+ ...buildDurationMetrics3(state.startTime)
26903
+ },
26904
+ output: state.output
26905
+ });
26906
+ } finally {
26907
+ state.span.end();
26908
+ }
26909
+ }
26910
+ function restorePiStreamFn(state) {
26911
+ const patchState = state.streamPatchState;
26912
+ patchState.activePromptStates.delete(state);
26913
+ removeQueuedPromptState(state);
26914
+ if (patchState.eventPromptState === state) {
26915
+ patchState.eventPromptState = void 0;
26916
+ }
26917
+ state.restorePromptContext?.();
26918
+ if (patchState.activePromptStates.size > 0) {
26919
+ return;
26920
+ }
26921
+ if (patchState.agent.streamFn === patchState.wrappedStreamFn) {
26922
+ patchState.agent.streamFn = patchState.originalStreamFn;
26923
+ }
26924
+ piStreamPatchStates.delete(patchState.agent);
26925
+ }
26926
+ function removeQueuedPromptState(state) {
26927
+ state.queued = false;
26928
+ const queuedPromptStates = state.streamPatchState.queuedPromptStates;
26929
+ const index = queuedPromptStates.indexOf(state);
26930
+ if (index >= 0) {
26931
+ queuedPromptStates.splice(index, 1);
26932
+ }
26933
+ }
26934
+ async function finishOpenLlmSpans(state, error) {
26935
+ for (const llmState of [...state.activeLlmSpans]) {
26936
+ finishPiLlmSpan(state, llmState, void 0, error);
26937
+ }
26938
+ }
26939
+ function finishPiLlmSpan(promptState, llmState, message, error) {
26940
+ if (llmState.finalized) {
26941
+ return;
26942
+ }
26943
+ llmState.finalized = true;
26944
+ promptState.activeLlmSpans.delete(llmState);
26945
+ const messageError = message?.stopReason === "error" && message.errorMessage;
26946
+ const metrics = {
26947
+ ...extractUsageMetrics2(message?.usage),
26948
+ ...cleanMetrics5(llmState.metrics),
26949
+ ...buildDurationMetrics3(llmState.startTime)
26950
+ };
26951
+ const usageMetrics = extractUsageMetrics2(message?.usage);
26952
+ if (Object.keys(usageMetrics).length > 0) {
26953
+ promptState.collectedLlmUsageMetrics = true;
26954
+ addMetrics(promptState.metrics, usageMetrics);
26955
+ }
26956
+ try {
26957
+ safeLog4(llmState.span, {
26958
+ ...error || messageError ? { error: stringifyUnknown2(error ?? messageError) } : {},
26959
+ metadata: {
26960
+ ...llmState.metadata,
26961
+ ...message ? extractAssistantMetadata(message) : {}
26962
+ },
26963
+ metrics,
26964
+ ...message ? { output: extractAssistantOutput(message) } : {}
26965
+ });
26966
+ } finally {
26967
+ llmState.span.end();
26968
+ }
26969
+ }
26970
+ function finishOpenToolSpans(state, error) {
26971
+ for (const [, toolState] of state.activeToolSpans) {
26972
+ try {
26973
+ safeLog4(toolState.span, {
26974
+ error: error ? stringifyUnknown2(error) : "Pi tool did not complete"
26975
+ });
26976
+ toolState.span.end();
26977
+ } finally {
26978
+ toolState.restoreAutoInstrumentation?.();
26979
+ }
26980
+ }
26981
+ state.activeToolSpans.clear();
26982
+ }
26983
+ function normalizePiContextInput(context) {
26984
+ const messages = context.messages.flatMap(
26985
+ (message) => normalizePiMessage(message)
26986
+ );
26987
+ if (context.systemPrompt) {
26988
+ return [{ role: "system", content: context.systemPrompt }, ...messages];
26989
+ }
26990
+ return messages;
26991
+ }
26992
+ function normalizePiMessage(message) {
26993
+ if (isPiUserMessage(message)) {
26994
+ return [
26995
+ {
26996
+ role: "user",
26997
+ content: normalizeUserContent(message.content)
26998
+ }
26999
+ ];
27000
+ }
27001
+ if (isPiAssistantMessage(message)) {
27002
+ return [normalizeAssistantMessage(message)];
27003
+ }
27004
+ if (isPiToolResultMessage(message)) {
27005
+ return [normalizeToolResultMessage(message)];
27006
+ }
27007
+ return [];
27008
+ }
27009
+ function normalizeAssistantMessage(message) {
27010
+ const text = message.content.flatMap((part) => part.type === "text" ? [part.text] : []).join("");
27011
+ const thinking = message.content.flatMap(
27012
+ (part) => part.type === "thinking" && !part.redacted ? [part.thinking] : []
27013
+ ).join("");
27014
+ const toolCalls = message.content.flatMap(
27015
+ (part) => part.type === "toolCall" ? [normalizeToolCall(part)] : []
27016
+ );
27017
+ return {
27018
+ role: "assistant",
27019
+ content: text || (toolCalls.length > 0 ? null : ""),
27020
+ ...thinking ? { reasoning: thinking } : {},
27021
+ ...toolCalls.length > 0 ? { tool_calls: toolCalls } : {}
27022
+ };
27023
+ }
27024
+ function normalizeToolResultMessage(message) {
27025
+ return {
27026
+ role: "tool",
27027
+ tool_call_id: message.toolCallId,
27028
+ content: normalizeUserContent(message.content)
27029
+ };
27030
+ }
27031
+ function normalizeUserContent(content) {
27032
+ if (typeof content === "string") {
27033
+ return content;
27034
+ }
27035
+ return content.map((part) => {
27036
+ if (part.type === "text") {
27037
+ return { type: "text", text: part.text };
27038
+ }
27039
+ if (part.type === "image") {
27040
+ return {
27041
+ type: "image_url",
27042
+ image_url: {
27043
+ url: `data:${part.mimeType};base64,${part.data}`
27044
+ }
27045
+ };
27046
+ }
27047
+ return part;
27048
+ });
27049
+ }
27050
+ function normalizeToolCall(toolCall) {
27051
+ return {
27052
+ id: toolCall.id,
27053
+ type: "function",
27054
+ function: {
27055
+ name: toolCall.name,
27056
+ arguments: stringifyArguments(toolCall.arguments)
27057
+ }
27058
+ };
27059
+ }
27060
+ function extractAssistantOutput(message) {
27061
+ return processInputAttachments([
27062
+ {
27063
+ finish_reason: normalizeStopReason(message.stopReason),
27064
+ index: 0,
27065
+ message: normalizeAssistantMessage(message)
27066
+ }
27067
+ ]);
27068
+ }
27069
+ function isPiUserMessage(message) {
27070
+ return message.role === "user" && "content" in message;
27071
+ }
27072
+ function isPiAssistantMessage(message) {
27073
+ return isObject(message) && message.role === "assistant" && Array.isArray(message.content);
27074
+ }
27075
+ function isPiToolResultMessage(message) {
27076
+ return message.role === "toolResult" && Array.isArray(message.content);
27077
+ }
27078
+ function normalizeStopReason(reason) {
27079
+ switch (reason) {
27080
+ case "toolUse":
27081
+ return "tool_calls";
27082
+ case "length":
27083
+ case "stop":
27084
+ return reason;
27085
+ default:
27086
+ return reason ?? "stop";
27087
+ }
25082
27088
  }
25083
- function getMetricsFromResponse(response) {
25084
- for (const generation of walkGenerations(response)) {
25085
- const message = generation.message;
25086
- if (!isRecord(message)) {
25087
- continue;
25088
- }
25089
- const usageMetadata = message.usage_metadata;
25090
- if (!isRecord(usageMetadata)) {
25091
- continue;
27089
+ function extractPromptInput(text, options) {
27090
+ const images = options?.images;
27091
+ if (!images || images.length === 0) {
27092
+ return text;
27093
+ }
27094
+ return processInputAttachments([
27095
+ {
27096
+ role: "user",
27097
+ content: [
27098
+ { type: "text", text: text ?? "" },
27099
+ ...images.map((image) => ({
27100
+ type: "image_url",
27101
+ image_url: {
27102
+ url: `data:${image.mimeType};base64,${image.data}`
27103
+ }
27104
+ }))
27105
+ ]
25092
27106
  }
25093
- const inputTokenDetails = usageMetadata.input_token_details;
25094
- return cleanObject({
25095
- total_tokens: usageMetadata.total_tokens,
25096
- prompt_tokens: usageMetadata.input_tokens,
25097
- completion_tokens: usageMetadata.output_tokens,
25098
- prompt_cache_creation_tokens: isRecord(inputTokenDetails) ? inputTokenDetails.cache_creation : void 0,
25099
- prompt_cached_tokens: isRecord(inputTokenDetails) ? inputTokenDetails.cache_read : void 0
25100
- });
27107
+ ]);
27108
+ }
27109
+ function extractToolMetadata(tools) {
27110
+ if (!tools || tools.length === 0) {
27111
+ return {};
25101
27112
  }
25102
- const llmOutput = response.llmOutput || {};
25103
- const tokenUsage = isRecord(llmOutput.tokenUsage) ? llmOutput.tokenUsage : isRecord(llmOutput.estimatedTokens) ? llmOutput.estimatedTokens : {};
25104
- return cleanObject({
25105
- total_tokens: tokenUsage.totalTokens,
25106
- prompt_tokens: tokenUsage.promptTokens,
25107
- completion_tokens: tokenUsage.completionTokens
25108
- });
27113
+ return {
27114
+ tools: tools.map((tool) => ({
27115
+ type: "function",
27116
+ function: {
27117
+ name: tool.name,
27118
+ ...tool.description ? { description: tool.description } : {},
27119
+ ...tool.parameters ? { parameters: tool.parameters } : {}
27120
+ }
27121
+ }))
27122
+ };
25109
27123
  }
25110
- function safeJsonParse(input) {
25111
- try {
25112
- return JSON.parse(input);
25113
- } catch {
25114
- return input;
27124
+ function extractModelMetadata2(model) {
27125
+ if (!model) {
27126
+ return {};
25115
27127
  }
27128
+ return {
27129
+ ...model.provider ? { provider: model.provider } : {},
27130
+ ...model.id ? { model: model.id, "pi_coding_agent.model": model.id } : {},
27131
+ ...model.api ? { "pi_coding_agent.api": model.api } : {},
27132
+ ...model.name ? { "pi_coding_agent.model_name": model.name } : {}
27133
+ };
25116
27134
  }
25117
- function isRecord(value) {
25118
- return typeof value === "object" && value !== null && !Array.isArray(value);
27135
+ function extractAssistantMetadata(message) {
27136
+ return {
27137
+ ...message.provider ? { provider: message.provider } : {},
27138
+ ...message.responseModel || message.model ? { model: message.responseModel ?? message.model } : {},
27139
+ ...message.api ? { "pi_coding_agent.api": message.api } : {},
27140
+ ...message.model ? { "pi_coding_agent.model": message.model } : {},
27141
+ ...message.responseModel ? { "pi_coding_agent.response_model": message.responseModel } : {},
27142
+ ...message.responseId ? { "pi_coding_agent.response_id": message.responseId } : {},
27143
+ ...message.stopReason ? { "pi_coding_agent.stop_reason": message.stopReason } : {}
27144
+ };
25119
27145
  }
25120
-
25121
- // src/instrumentation/plugins/langchain-channels.ts
25122
- var langChainChannels = defineChannels("@langchain/core", {
25123
- configure: channel({
25124
- channelName: "CallbackManager.configure",
25125
- kind: "sync-stream"
25126
- }),
25127
- configureSync: channel({
25128
- channelName: "CallbackManager._configureSync",
25129
- kind: "sync-stream"
25130
- })
25131
- });
25132
-
25133
- // src/instrumentation/plugins/langchain-plugin.ts
25134
- var LangChainPlugin = class extends BasePlugin {
25135
- injectedManagers = /* @__PURE__ */ new WeakSet();
25136
- onEnable() {
25137
- this.subscribeToConfigure(langChainChannels.configure);
25138
- this.subscribeToConfigure(langChainChannels.configureSync);
27146
+ function extractSessionMetadata(session) {
27147
+ return {
27148
+ ...extractModelMetadata2(session.model),
27149
+ ...session.sessionId ? { "pi_coding_agent.session_id": session.sessionId } : {},
27150
+ ...session.sessionName ? { "pi_coding_agent.session_name": session.sessionName } : {},
27151
+ ...session.thinkingLevel ? { "pi_coding_agent.thinking_level": session.thinkingLevel } : {},
27152
+ ...typeof session.getActiveToolNames === "function" ? { "pi_coding_agent.active_tools": session.getActiveToolNames() } : {}
27153
+ };
27154
+ }
27155
+ function extractPromptOptionsMetadata(options) {
27156
+ if (!options) {
27157
+ return {};
25139
27158
  }
25140
- onDisable() {
25141
- for (const unsubscribe of this.unsubscribers) {
25142
- unsubscribe();
25143
- }
25144
- this.unsubscribers = [];
25145
- this.injectedManagers = /* @__PURE__ */ new WeakSet();
27159
+ return {
27160
+ ...options.source ? { "pi_coding_agent.source": options.source } : {},
27161
+ ...options.streamingBehavior ? { "pi_coding_agent.streaming_behavior": options.streamingBehavior } : {},
27162
+ ...options.expandPromptTemplates !== void 0 ? {
27163
+ "pi_coding_agent.expand_prompt_templates": options.expandPromptTemplates
27164
+ } : {}
27165
+ };
27166
+ }
27167
+ function extractStreamOptionsMetadata(options) {
27168
+ if (!options) {
27169
+ return {};
25146
27170
  }
25147
- subscribeToConfigure(channel2) {
25148
- const tracingChannel2 = channel2.tracingChannel();
25149
- const handlers = {
25150
- start: (event) => {
25151
- injectHandlerIntoArguments(event.arguments);
25152
- },
25153
- end: (event) => {
25154
- this.injectHandler(event.result);
25155
- }
25156
- };
25157
- tracingChannel2.subscribe(handlers);
25158
- this.unsubscribers.push(() => {
25159
- tracingChannel2.unsubscribe(handlers);
25160
- });
27171
+ return {
27172
+ ...options.temperature !== void 0 ? { temperature: options.temperature } : {},
27173
+ ...options.maxTokens !== void 0 ? { max_tokens: options.maxTokens } : {},
27174
+ ...options.reasoning ? { "pi_coding_agent.reasoning": options.reasoning } : {},
27175
+ ...options.transport ? { "pi_coding_agent.transport": options.transport } : {},
27176
+ ...options.cacheRetention ? { "pi_coding_agent.cache_retention": options.cacheRetention } : {},
27177
+ ...options.sessionId ? { "pi_coding_agent.session_id": options.sessionId } : {},
27178
+ ...options.timeoutMs !== void 0 ? { "pi_coding_agent.timeout_ms": options.timeoutMs } : {},
27179
+ ...options.maxRetries !== void 0 ? { "pi_coding_agent.max_retries": options.maxRetries } : {},
27180
+ ...options.maxRetryDelayMs !== void 0 ? { "pi_coding_agent.max_retry_delay_ms": options.maxRetryDelayMs } : {},
27181
+ ...options.metadata ? { "pi_coding_agent.metadata": options.metadata } : {}
27182
+ };
27183
+ }
27184
+ function getLlmSpanName(model) {
27185
+ switch (model.api) {
27186
+ case "anthropic-messages":
27187
+ return "anthropic.messages.create";
27188
+ case "openai-completions":
27189
+ return "Chat Completion";
27190
+ case "openai-responses":
27191
+ case "azure-openai-responses":
27192
+ case "openai-codex-responses":
27193
+ return "openai.responses.create";
27194
+ case "google-generative-ai":
27195
+ case "google-vertex":
27196
+ return "generate_content";
27197
+ case "mistral-conversations":
27198
+ return "mistral.chat.stream";
27199
+ case "bedrock-converse-stream":
27200
+ return "bedrock.converse_stream";
27201
+ default:
27202
+ return "pi_ai.streamSimple";
25161
27203
  }
25162
- injectHandler(result) {
25163
- if (!isCallbackManager(result)) {
25164
- return;
25165
- }
25166
- if (this.injectedManagers.has(result) || hasBraintrustHandler(result)) {
25167
- return;
25168
- }
25169
- try {
25170
- result.addHandler(new BraintrustLangChainCallbackHandler(), true);
25171
- this.injectedManagers.add(result);
25172
- } catch {
25173
- }
27204
+ }
27205
+ function extractUsageMetrics2(usage) {
27206
+ if (!usage) {
27207
+ return {};
25174
27208
  }
25175
- };
25176
- function isCallbackManager(value) {
25177
- if (typeof value !== "object" || value === null) {
25178
- return false;
27209
+ return cleanMetrics5({
27210
+ completion_tokens: usage.output,
27211
+ prompt_cache_creation_tokens: usage.cacheWrite,
27212
+ prompt_cached_tokens: usage.cacheRead,
27213
+ prompt_tokens: usage.input,
27214
+ tokens: usage.totalTokens ?? usage.tokens
27215
+ });
27216
+ }
27217
+ function addMetrics(target, source) {
27218
+ for (const [key, value] of Object.entries(source)) {
27219
+ target[key] = (target[key] ?? 0) + value;
25179
27220
  }
25180
- const maybeManager = value;
25181
- return typeof maybeManager.addHandler === "function";
25182
27221
  }
25183
- function hasBraintrustHandler(manager) {
25184
- return manager.handlers?.some((handler) => {
25185
- if (typeof handler !== "object" || handler === null) {
25186
- return false;
25187
- }
25188
- const name = Reflect.get(handler, "name");
25189
- return name === BRAINTRUST_LANGCHAIN_CALLBACK_HANDLER_NAME;
25190
- }) ?? false;
27222
+ function buildDurationMetrics3(startTime) {
27223
+ const end = getCurrentUnixTimestamp();
27224
+ return {
27225
+ duration: end - startTime,
27226
+ end,
27227
+ start: startTime
27228
+ };
25191
27229
  }
25192
- function injectHandlerIntoArguments(args) {
25193
- if (!isWritableArgumentsObject(args)) {
25194
- return;
27230
+ function cleanMetrics5(metrics) {
27231
+ const cleaned = {};
27232
+ for (const [key, value] of Object.entries(metrics)) {
27233
+ if (typeof value === "number" && Number.isFinite(value) && value >= 0) {
27234
+ cleaned[key] = value;
27235
+ }
25195
27236
  }
25196
- const inheritedHandlers = Reflect.get(args, "0");
25197
- const handler = new BraintrustLangChainCallbackHandler();
25198
- if (inheritedHandlers === void 0 || inheritedHandlers === null) {
25199
- Reflect.set(args, "0", [handler]);
25200
- return;
27237
+ return cleaned;
27238
+ }
27239
+ function stringifyArguments(value) {
27240
+ if (typeof value === "string") {
27241
+ return value;
25201
27242
  }
25202
- if (Array.isArray(inheritedHandlers)) {
25203
- if (!inheritedHandlers.some(isBraintrustHandler)) {
25204
- inheritedHandlers.push(handler);
25205
- }
27243
+ try {
27244
+ return JSON.stringify(value);
27245
+ } catch {
27246
+ return stringifyUnknown2(value);
25206
27247
  }
25207
27248
  }
25208
- function isWritableArgumentsObject(args) {
25209
- return typeof args === "object" && args !== null;
27249
+ function stringifyUnknown2(value) {
27250
+ if (value instanceof Error) {
27251
+ return value.message;
27252
+ }
27253
+ if (typeof value === "string") {
27254
+ return value;
27255
+ }
27256
+ try {
27257
+ return JSON.stringify(value);
27258
+ } catch {
27259
+ return String(value);
27260
+ }
25210
27261
  }
25211
- function isBraintrustHandler(handler) {
25212
- if (typeof handler !== "object" || handler === null) {
25213
- return false;
27262
+ function safeLog4(span, event) {
27263
+ try {
27264
+ span.log(event);
27265
+ } catch (error) {
27266
+ logInstrumentationError4("Pi Coding Agent span log", error);
25214
27267
  }
25215
- return Reflect.get(handler, "name") === BRAINTRUST_LANGCHAIN_CALLBACK_HANDLER_NAME;
27268
+ }
27269
+ function logInstrumentationError4(context, error) {
27270
+ debugLogger.debug(`${context}:`, error);
25216
27271
  }
25217
27272
 
25218
27273
  // src/instrumentation/braintrust-plugin.ts
@@ -25240,6 +27295,7 @@ var BraintrustPlugin = class extends BasePlugin {
25240
27295
  gitHubCopilotPlugin = null;
25241
27296
  fluePlugin = null;
25242
27297
  langChainPlugin = null;
27298
+ piCodingAgentPlugin = null;
25243
27299
  constructor(config = {}) {
25244
27300
  super();
25245
27301
  this.config = config;
@@ -25314,6 +27370,10 @@ var BraintrustPlugin = class extends BasePlugin {
25314
27370
  this.gitHubCopilotPlugin = new GitHubCopilotPlugin();
25315
27371
  this.gitHubCopilotPlugin.enable();
25316
27372
  }
27373
+ if (integrations.piCodingAgent !== false) {
27374
+ this.piCodingAgentPlugin = new PiCodingAgentPlugin();
27375
+ this.piCodingAgentPlugin.enable();
27376
+ }
25317
27377
  if (getIntegrationConfig(integrations, "flue") !== false) {
25318
27378
  this.fluePlugin = new FluePlugin();
25319
27379
  this.fluePlugin.enable();
@@ -25392,6 +27452,10 @@ var BraintrustPlugin = class extends BasePlugin {
25392
27452
  this.gitHubCopilotPlugin.disable();
25393
27453
  this.gitHubCopilotPlugin = null;
25394
27454
  }
27455
+ if (this.piCodingAgentPlugin) {
27456
+ this.piCodingAgentPlugin.disable();
27457
+ this.piCodingAgentPlugin = null;
27458
+ }
25395
27459
  if (this.fluePlugin) {
25396
27460
  this.fluePlugin.disable();
25397
27461
  this.fluePlugin = null;
@@ -25411,6 +27475,11 @@ var envIntegrationAliases = {
25411
27475
  openaicodexsdk: "openaiCodexSDK",
25412
27476
  codex: "openaiCodexSDK",
25413
27477
  "codex-sdk": "openaiCodexSDK",
27478
+ "pi-coding-agent": "piCodingAgent",
27479
+ "pi-coding-agent-sdk": "piCodingAgent",
27480
+ picodingagent: "piCodingAgent",
27481
+ picodingagentsdk: "piCodingAgent",
27482
+ "@earendil-works/pi-coding-agent": "piCodingAgent",
25414
27483
  anthropic: "anthropic",
25415
27484
  aisdk: "aisdk",
25416
27485
  "ai-sdk": "aisdk",
@@ -25476,7 +27545,8 @@ function getDefaultInstrumentationIntegrations() {
25476
27545
  genkit: true,
25477
27546
  gitHubCopilot: true,
25478
27547
  langchain: true,
25479
- langgraph: true
27548
+ langgraph: true,
27549
+ piCodingAgent: true
25480
27550
  };
25481
27551
  }
25482
27552
  function readDisabledInstrumentationEnvConfig(disabledList) {
@@ -25772,6 +27842,7 @@ __export(exports_exports, {
25772
27842
  _internalIso: () => isomorph_default,
25773
27843
  _internalSetInitialState: () => _internalSetInitialState,
25774
27844
  addAzureBlobHeaders: () => addAzureBlobHeaders,
27845
+ braintrustAISDKTelemetry: () => braintrustAISDKTelemetry,
25775
27846
  braintrustFlueObserver: () => braintrustFlueObserver,
25776
27847
  braintrustStreamChunkSchema: () => braintrustStreamChunkSchema,
25777
27848
  buildLocalSummary: () => buildLocalSummary,
@@ -25864,6 +27935,7 @@ __export(exports_exports, {
25864
27935
  wrapOpenAIv4: () => wrapOpenAIv4,
25865
27936
  wrapOpenRouter: () => wrapOpenRouter,
25866
27937
  wrapOpenRouterAgent: () => wrapOpenRouterAgent,
27938
+ wrapPiCodingAgentSDK: () => wrapPiCodingAgentSDK,
25867
27939
  wrapTraced: () => wrapTraced,
25868
27940
  wrapVitest: () => wrapVitest
25869
27941
  });
@@ -27924,6 +29996,54 @@ function wrapCursorAgent(agent) {
27924
29996
  return proxy;
27925
29997
  }
27926
29998
 
29999
+ // src/wrappers/pi-coding-agent.ts
30000
+ var WRAPPED_PROMPT = /* @__PURE__ */ Symbol.for("braintrust.pi-coding-agent.wrapped-prompt");
30001
+ function wrapPiCodingAgentSDK(sdk) {
30002
+ if (!sdk || typeof sdk !== "object") {
30003
+ return sdk;
30004
+ }
30005
+ const maybeSDK = sdk;
30006
+ if (!maybeSDK.AgentSession || typeof maybeSDK.AgentSession !== "function") {
30007
+ console.warn("Unsupported Pi Coding Agent SDK. Not wrapping.");
30008
+ return sdk;
30009
+ }
30010
+ patchAgentSessionClass(
30011
+ maybeSDK.AgentSession
30012
+ );
30013
+ return sdk;
30014
+ }
30015
+ function patchAgentSessionClass(AgentSession) {
30016
+ const prototype = AgentSession.prototype;
30017
+ if (!prototype || prototype[WRAPPED_PROMPT]) {
30018
+ return;
30019
+ }
30020
+ const descriptor = Object.getOwnPropertyDescriptor(prototype, "prompt");
30021
+ if (!descriptor || typeof descriptor.value !== "function") {
30022
+ console.warn("Unsupported Pi Coding Agent SDK. Not wrapping.");
30023
+ return;
30024
+ }
30025
+ const originalPrompt = descriptor.value;
30026
+ Object.defineProperty(prototype, "prompt", {
30027
+ ...descriptor,
30028
+ value: function wrappedPiCodingAgentPrompt(text, options) {
30029
+ const args = [text, options];
30030
+ return piCodingAgentChannels.prompt.tracePromise(
30031
+ () => Reflect.apply(originalPrompt, this, args),
30032
+ {
30033
+ arguments: args,
30034
+ self: this,
30035
+ session: this
30036
+ }
30037
+ );
30038
+ }
30039
+ });
30040
+ Object.defineProperty(prototype, WRAPPED_PROMPT, {
30041
+ configurable: false,
30042
+ enumerable: false,
30043
+ value: true
30044
+ });
30045
+ }
30046
+
27927
30047
  // src/wrappers/google-genai.ts
27928
30048
  function wrapGoogleGenAI(googleGenAI) {
27929
30049
  if (!googleGenAI || typeof googleGenAI !== "object") {
@@ -27960,12 +30080,25 @@ function wrapGoogleGenAIClass(OriginalGoogleGenAI) {
27960
30080
  }
27961
30081
  function wrapGoogleGenAIInstance(instance) {
27962
30082
  const wrappedModels = wrapModels(instance.models);
30083
+ let originalInteractions;
30084
+ let wrappedInteractions;
27963
30085
  patchGoogleGenAIChats(instance, wrappedModels);
27964
30086
  return new Proxy(instance, {
27965
30087
  get(target, prop, receiver) {
27966
30088
  if (prop === "models") {
27967
30089
  return wrappedModels;
27968
30090
  }
30091
+ if (prop === "interactions") {
30092
+ const interactions = Reflect.get(target, prop, receiver);
30093
+ if (!isObject(interactions) || typeof interactions.create !== "function") {
30094
+ return interactions;
30095
+ }
30096
+ if (interactions !== originalInteractions) {
30097
+ originalInteractions = interactions;
30098
+ wrappedInteractions = wrapInteractions(interactions);
30099
+ }
30100
+ return wrappedInteractions;
30101
+ }
27969
30102
  return Reflect.get(target, prop, receiver);
27970
30103
  }
27971
30104
  });
@@ -27992,6 +30125,16 @@ function wrapModels(models) {
27992
30125
  }
27993
30126
  });
27994
30127
  }
30128
+ function wrapInteractions(interactions) {
30129
+ return new Proxy(interactions, {
30130
+ get(target, prop, receiver) {
30131
+ if (prop === "create") {
30132
+ return wrapInteractionCreate(target.create.bind(target));
30133
+ }
30134
+ return Reflect.get(target, prop, receiver);
30135
+ }
30136
+ });
30137
+ }
27995
30138
  function wrapGenerateContent(original) {
27996
30139
  return function(params) {
27997
30140
  return googleGenAIChannels.generateContent.tracePromise(
@@ -28016,6 +30159,18 @@ function wrapEmbedContent(original) {
28016
30159
  );
28017
30160
  };
28018
30161
  }
30162
+ function wrapInteractionCreate(original) {
30163
+ return function(params, options) {
30164
+ if (params.background === true) {
30165
+ return options === void 0 ? original(params) : original(params, options);
30166
+ }
30167
+ const traceContext = options === void 0 ? { arguments: [params] } : { arguments: [params, options] };
30168
+ return googleGenAIChannels.interactionsCreate.tracePromise(
30169
+ () => options === void 0 ? original(params) : original(params, options),
30170
+ traceContext
30171
+ );
30172
+ };
30173
+ }
28019
30174
 
28020
30175
  // src/wrappers/google-adk.ts
28021
30176
  function wrapGoogleADK(adkModule) {
@@ -31533,6 +33688,13 @@ var EvalResultWithSummary = class {
31533
33688
  };
31534
33689
  }
31535
33690
  };
33691
+ async function getPersistedBaseExperimentId(experiment) {
33692
+ try {
33693
+ return await experiment._getBaseExperimentId();
33694
+ } catch {
33695
+ return void 0;
33696
+ }
33697
+ }
31536
33698
  function makeEvalName(projectName, experimentName) {
31537
33699
  let out = projectName;
31538
33700
  if (experimentName) {
@@ -31915,6 +34077,14 @@ async function runEvaluatorInternal(experiment, evaluator, progressReporter, fil
31915
34077
  return;
31916
34078
  }
31917
34079
  const eventDataset = experiment ? experiment.dataset : Dataset2.isDataset(evaluator.data) ? evaluator.data : void 0;
34080
+ const inlineOrigin = datum.origin === void 0 ? void 0 : ObjectReference.parse(datum.origin);
34081
+ const origin = inlineOrigin ?? (eventDataset && datum.id && datum._xact_id ? {
34082
+ object_type: "dataset",
34083
+ object_id: await eventDataset.id,
34084
+ id: datum.id,
34085
+ created: datum.created,
34086
+ _xact_id: datum._xact_id
34087
+ } : void 0);
31918
34088
  const baseEvent = {
31919
34089
  name: "eval",
31920
34090
  spanAttributes: {
@@ -31924,13 +34094,7 @@ async function runEvaluatorInternal(experiment, evaluator, progressReporter, fil
31924
34094
  input: datum.input,
31925
34095
  expected: "expected" in datum ? datum.expected : void 0,
31926
34096
  tags: datum.tags,
31927
- origin: eventDataset && datum.id && datum._xact_id ? {
31928
- object_type: "dataset",
31929
- object_id: await eventDataset.id,
31930
- id: datum.id,
31931
- created: datum.created,
31932
- _xact_id: datum._xact_id
31933
- } : void 0,
34097
+ origin,
31934
34098
  ...datum.upsert_id ? { id: datum.upsert_id } : {}
31935
34099
  }
31936
34100
  };
@@ -32287,8 +34451,10 @@ async function runEvaluatorInternal(experiment, evaluator, progressReporter, fil
32287
34451
  collectedResults.length = 0;
32288
34452
  }
32289
34453
  }
34454
+ const comparisonExperimentId = experiment ? evaluator.baseExperimentId ?? await getPersistedBaseExperimentId(experiment) : void 0;
32290
34455
  const summary = experiment ? await experiment.summarize({
32291
- summarizeScores: evaluator.summarizeScores
34456
+ summarizeScores: evaluator.summarizeScores,
34457
+ ...comparisonExperimentId !== void 0 ? { comparisonExperimentId } : {}
32292
34458
  }) : buildLocalSummary(
32293
34459
  evaluator,
32294
34460
  collectResults ? collectedResults : [],
@@ -32517,6 +34683,7 @@ var Project2 = class {
32517
34683
  prompts;
32518
34684
  parameters;
32519
34685
  scorers;
34686
+ classifiers;
32520
34687
  _publishableCodeFunctions = [];
32521
34688
  _publishablePrompts = [];
32522
34689
  _publishableParameters = [];
@@ -32528,6 +34695,7 @@ var Project2 = class {
32528
34695
  this.prompts = new PromptBuilder(this);
32529
34696
  this.parameters = new ParametersBuilder(this);
32530
34697
  this.scorers = new ScorerBuilder(this);
34698
+ this.classifiers = new ClassifierBuilder(this);
32531
34699
  }
32532
34700
  addPrompt(prompt) {
32533
34701
  this._publishablePrompts.push(prompt);
@@ -32662,6 +34830,28 @@ var ScorerBuilder = class {
32662
34830
  }
32663
34831
  }
32664
34832
  };
34833
+ var ClassifierBuilder = class {
34834
+ constructor(project) {
34835
+ this.project = project;
34836
+ }
34837
+ taskCounter = 0;
34838
+ create(opts) {
34839
+ this.taskCounter++;
34840
+ let resolvedName = opts.name ?? opts.handler.name;
34841
+ if (!resolvedName || resolvedName.trim().length === 0) {
34842
+ resolvedName = `Classifier ${isomorph_default.basename(currentFilename)} ${this.taskCounter}`;
34843
+ }
34844
+ const slug = opts.slug ?? slugify(resolvedName, { lower: true, strict: true });
34845
+ const classifier = new CodeFunction(this.project, {
34846
+ ...opts,
34847
+ name: resolvedName,
34848
+ slug,
34849
+ type: "classifier"
34850
+ });
34851
+ this.project.addCodeFunction(classifier);
34852
+ return classifier;
34853
+ }
34854
+ };
32665
34855
  var CodeFunction = class {
32666
34856
  constructor(project, opts) {
32667
34857
  this.project = project;
@@ -33011,7 +35201,7 @@ var serializedParametersContainerSchema = z13.union([
33011
35201
  staticParametersSchema
33012
35202
  ]);
33013
35203
  var evaluatorDefinitionSchema = z13.object({
33014
- parameters: serializedParametersContainerSchema.optional(),
35204
+ parameters: serializedParametersContainerSchema.nullish(),
33015
35205
  scores: z13.array(z13.object({ name: z13.string() })).optional(),
33016
35206
  classifiers: z13.array(z13.object({ name: z13.string() })).optional()
33017
35207
  });
@@ -33079,6 +35269,7 @@ export {
33079
35269
  isomorph_default as _internalIso,
33080
35270
  _internalSetInitialState,
33081
35271
  addAzureBlobHeaders,
35272
+ braintrustAISDKTelemetry,
33082
35273
  braintrustFlueObserver,
33083
35274
  braintrustStreamChunkSchema,
33084
35275
  buildLocalSummary,
@@ -33172,6 +35363,7 @@ export {
33172
35363
  wrapOpenAIv4,
33173
35364
  wrapOpenRouter,
33174
35365
  wrapOpenRouterAgent,
35366
+ wrapPiCodingAgentSDK,
33175
35367
  wrapTraced,
33176
35368
  wrapVitest
33177
35369
  };