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/cli.js CHANGED
@@ -1232,7 +1232,7 @@ var require_package = __commonJS({
1232
1232
  "package.json"(exports2, module2) {
1233
1233
  module2.exports = {
1234
1234
  name: "braintrust",
1235
- version: "3.17.0",
1235
+ version: "3.18.0",
1236
1236
  description: "SDK for integrating Braintrust",
1237
1237
  repository: {
1238
1238
  type: "git",
@@ -1419,14 +1419,14 @@ var require_package = __commonJS({
1419
1419
  "eslint-plugin-node-import": "^1.0.5",
1420
1420
  openai: "6.25.0",
1421
1421
  rollup: "^4.60.3",
1422
- tar: "^7.5.2",
1422
+ tar: "^7.5.16",
1423
1423
  tinybench: "^4.0.1",
1424
1424
  tsup: "^8.5.1",
1425
1425
  tsx: "^4.21.0",
1426
1426
  typedoc: "^0.25.13",
1427
1427
  "typedoc-plugin-markdown": "^3.17.1",
1428
1428
  typescript: "5.4.4",
1429
- vite: "^6.4.2",
1429
+ vite: "^6.4.3",
1430
1430
  "vite-tsconfig-paths": "^4.3.2",
1431
1431
  vitest: "4.1.5",
1432
1432
  webpack: "^5.106.2",
@@ -1462,13 +1462,13 @@ var require_package = __commonJS({
1462
1462
  zod: "^3.25.34 || ^4.0"
1463
1463
  },
1464
1464
  optionalDependencies: {
1465
- "@braintrust/bt-darwin-arm64": "0.11.1",
1466
- "@braintrust/bt-darwin-x64": "0.11.1",
1467
- "@braintrust/bt-linux-arm64": "0.11.1",
1468
- "@braintrust/bt-linux-x64": "0.11.1",
1469
- "@braintrust/bt-linux-x64-musl": "0.11.1",
1470
- "@braintrust/bt-win32-arm64": "0.11.1",
1471
- "@braintrust/bt-win32-x64": "0.11.1"
1465
+ "@braintrust/bt-darwin-arm64": "0.12.0",
1466
+ "@braintrust/bt-darwin-x64": "0.12.0",
1467
+ "@braintrust/bt-linux-arm64": "0.12.0",
1468
+ "@braintrust/bt-linux-x64": "0.12.0",
1469
+ "@braintrust/bt-linux-x64-musl": "0.12.0",
1470
+ "@braintrust/bt-win32-arm64": "0.12.0",
1471
+ "@braintrust/bt-win32-x64": "0.12.0"
1472
1472
  },
1473
1473
  publishConfig: {
1474
1474
  access: "public",
@@ -9133,6 +9133,10 @@ var Experiment2 = class extends ObjectFetcher {
9133
9133
  return (await this.lazyMetadata.get()).project;
9134
9134
  })();
9135
9135
  }
9136
+ async _getBaseExperimentId() {
9137
+ const baseExperimentId = (await this.lazyMetadata.get()).experiment.fullInfo["base_exp_id"];
9138
+ return typeof baseExperimentId === "string" && baseExperimentId ? baseExperimentId : void 0;
9139
+ }
9136
9140
  parentObjectType() {
9137
9141
  return 1 /* EXPERIMENT */;
9138
9142
  }
@@ -9273,6 +9277,14 @@ var Experiment2 = class extends ObjectFetcher {
9273
9277
  comparisonExperimentId = baseExperiment.id;
9274
9278
  comparisonExperimentName = baseExperiment.name;
9275
9279
  }
9280
+ } else {
9281
+ try {
9282
+ const comparisonExperiment = await state.apiConn().get_json(`v1/experiment/${comparisonExperimentId}`);
9283
+ if (typeof comparisonExperiment["name"] === "string") {
9284
+ comparisonExperimentName = comparisonExperiment["name"];
9285
+ }
9286
+ } catch {
9287
+ }
9276
9288
  }
9277
9289
  try {
9278
9290
  const results = await state.apiConn().get_json(
@@ -12257,6 +12269,13 @@ var EvalResultWithSummary = class {
12257
12269
  };
12258
12270
  }
12259
12271
  };
12272
+ async function getPersistedBaseExperimentId(experiment) {
12273
+ try {
12274
+ return await experiment._getBaseExperimentId();
12275
+ } catch {
12276
+ return void 0;
12277
+ }
12278
+ }
12260
12279
  function makeEvalName(projectName, experimentName) {
12261
12280
  let out = projectName;
12262
12281
  if (experimentName) {
@@ -12646,6 +12665,14 @@ async function runEvaluatorInternal(experiment, evaluator, progressReporter, fil
12646
12665
  return;
12647
12666
  }
12648
12667
  const eventDataset = experiment ? experiment.dataset : Dataset2.isDataset(evaluator.data) ? evaluator.data : void 0;
12668
+ const inlineOrigin = datum.origin === void 0 ? void 0 : ObjectReference.parse(datum.origin);
12669
+ const origin = inlineOrigin ?? (eventDataset && datum.id && datum._xact_id ? {
12670
+ object_type: "dataset",
12671
+ object_id: await eventDataset.id,
12672
+ id: datum.id,
12673
+ created: datum.created,
12674
+ _xact_id: datum._xact_id
12675
+ } : void 0);
12649
12676
  const baseEvent = {
12650
12677
  name: "eval",
12651
12678
  spanAttributes: {
@@ -12655,13 +12682,7 @@ async function runEvaluatorInternal(experiment, evaluator, progressReporter, fil
12655
12682
  input: datum.input,
12656
12683
  expected: "expected" in datum ? datum.expected : void 0,
12657
12684
  tags: datum.tags,
12658
- origin: eventDataset && datum.id && datum._xact_id ? {
12659
- object_type: "dataset",
12660
- object_id: await eventDataset.id,
12661
- id: datum.id,
12662
- created: datum.created,
12663
- _xact_id: datum._xact_id
12664
- } : void 0,
12685
+ origin,
12665
12686
  ...datum.upsert_id ? { id: datum.upsert_id } : {}
12666
12687
  }
12667
12688
  };
@@ -13018,8 +13039,10 @@ async function runEvaluatorInternal(experiment, evaluator, progressReporter, fil
13018
13039
  collectedResults.length = 0;
13019
13040
  }
13020
13041
  }
13042
+ const comparisonExperimentId = experiment ? evaluator.baseExperimentId ?? await getPersistedBaseExperimentId(experiment) : void 0;
13021
13043
  const summary = experiment ? await experiment.summarize({
13022
- summarizeScores: evaluator.summarizeScores
13044
+ summarizeScores: evaluator.summarizeScores,
13045
+ ...comparisonExperimentId !== void 0 ? { comparisonExperimentId } : {}
13023
13046
  }) : buildLocalSummary(
13024
13047
  evaluator,
13025
13048
  collectResults ? collectedResults : [],
@@ -14287,6 +14310,64 @@ var BasePlugin = class {
14287
14310
  }
14288
14311
  };
14289
14312
 
14313
+ // src/instrumentation/auto-instrumentation-suppression.ts
14314
+ var autoInstrumentationSuppressionStore;
14315
+ function suppressionStore() {
14316
+ autoInstrumentationSuppressionStore ??= isomorph_default.newAsyncLocalStorage();
14317
+ return autoInstrumentationSuppressionStore;
14318
+ }
14319
+ function currentFrames() {
14320
+ return suppressionStore().getStore()?.frames ?? [];
14321
+ }
14322
+ function isAutoInstrumentationSuppressed() {
14323
+ const frames = currentFrames();
14324
+ return frames[frames.length - 1]?.mode === "suppress";
14325
+ }
14326
+ function runWithAutoInstrumentationSuppressed(callback) {
14327
+ const frame = {
14328
+ id: /* @__PURE__ */ Symbol("braintrust.auto-instrumentation-suppress"),
14329
+ mode: "suppress"
14330
+ };
14331
+ return suppressionStore().run(
14332
+ { frames: [...currentFrames(), frame] },
14333
+ callback
14334
+ );
14335
+ }
14336
+ function bindAutoInstrumentationSuppressionToStart(tracingChannel2) {
14337
+ const startChannel = tracingChannel2.start;
14338
+ if (!startChannel) {
14339
+ return void 0;
14340
+ }
14341
+ const store = suppressionStore();
14342
+ startChannel.bindStore(store, () => ({
14343
+ frames: [
14344
+ ...currentFrames(),
14345
+ {
14346
+ id: /* @__PURE__ */ Symbol("braintrust.auto-instrumentation-suppress"),
14347
+ mode: "suppress"
14348
+ }
14349
+ ]
14350
+ }));
14351
+ return () => {
14352
+ startChannel.unbindStore(store);
14353
+ };
14354
+ }
14355
+ function enterAutoInstrumentationAllowed() {
14356
+ const frame = {
14357
+ id: /* @__PURE__ */ Symbol("braintrust.auto-instrumentation-allow"),
14358
+ mode: "allow"
14359
+ };
14360
+ suppressionStore().enterWith({
14361
+ frames: [...currentFrames(), frame]
14362
+ });
14363
+ return () => {
14364
+ const frames = currentFrames().filter(
14365
+ (candidate) => candidate.id !== frame.id
14366
+ );
14367
+ suppressionStore().enterWith(frames.length > 0 ? { frames } : void 0);
14368
+ };
14369
+ }
14370
+
14290
14371
  // src/instrumentation/core/channel-tracing.ts
14291
14372
  function isSyncStreamLike(value) {
14292
14373
  return !!value && typeof value === "object" && typeof value.on === "function";
@@ -14318,16 +14399,33 @@ function startSpanForEvent(config3, event, channelName) {
14318
14399
  metadata: mergeInputMetadata(metadata, spanInfoMetadata)
14319
14400
  });
14320
14401
  } catch (error2) {
14321
- console.error(`Error extracting input for ${channelName}:`, error2);
14402
+ debugLogger.error(`Error extracting input for ${channelName}:`, error2);
14322
14403
  }
14323
14404
  return { span, startTime };
14324
14405
  }
14406
+ function shouldTraceEvent(config3, event, channelName) {
14407
+ if (!config3.shouldTrace) {
14408
+ return true;
14409
+ }
14410
+ try {
14411
+ return config3.shouldTrace(event.arguments, event);
14412
+ } catch (error2) {
14413
+ debugLogger.error(
14414
+ `Error checking trace predicate for ${channelName}:`,
14415
+ error2
14416
+ );
14417
+ return true;
14418
+ }
14419
+ }
14325
14420
  function ensureSpanStateForEvent(states, config3, event, channelName) {
14326
14421
  const key = event;
14327
14422
  const existing = states.get(key);
14328
14423
  if (existing) {
14329
14424
  return existing;
14330
14425
  }
14426
+ if (!shouldTraceEvent(config3, event, channelName)) {
14427
+ return void 0;
14428
+ }
14331
14429
  const created = startSpanForEvent(config3, event, channelName);
14332
14430
  states.set(key, created);
14333
14431
  return created;
@@ -14343,13 +14441,16 @@ function bindCurrentSpanStoreToStart(tracingChannel2, states, config3, channelNa
14343
14441
  startChannel.bindStore(
14344
14442
  currentSpanStore,
14345
14443
  (event) => {
14346
- const span = ensureSpanStateForEvent(
14444
+ if (isAutoInstrumentationSuppressed()) {
14445
+ return currentSpanStore.getStore();
14446
+ }
14447
+ const spanState = ensureSpanStateForEvent(
14347
14448
  states,
14348
14449
  config3,
14349
14450
  event,
14350
14451
  channelName
14351
- ).span;
14352
- return contextManager.wrapSpanForStore(span);
14452
+ );
14453
+ return spanState ? contextManager.wrapSpanForStore(spanState.span) : currentSpanStore.getStore();
14353
14454
  }
14354
14455
  );
14355
14456
  return () => {
@@ -14384,7 +14485,10 @@ function runStreamingCompletionHook(args) {
14384
14485
  startTime: args.startTime
14385
14486
  });
14386
14487
  } catch (error2) {
14387
- console.error(`Error in onComplete hook for ${args.channelName}:`, error2);
14488
+ debugLogger.error(
14489
+ `Error in onComplete hook for ${args.channelName}:`,
14490
+ error2
14491
+ );
14388
14492
  }
14389
14493
  }
14390
14494
  function traceAsyncChannel(channel2, config3) {
@@ -14399,6 +14503,9 @@ function traceAsyncChannel(channel2, config3) {
14399
14503
  );
14400
14504
  const handlers = {
14401
14505
  start: (event) => {
14506
+ if (isAutoInstrumentationSuppressed()) {
14507
+ return;
14508
+ }
14402
14509
  ensureSpanStateForEvent(
14403
14510
  states,
14404
14511
  config3,
@@ -14433,7 +14540,7 @@ function traceAsyncChannel(channel2, config3) {
14433
14540
  metrics
14434
14541
  });
14435
14542
  } catch (error2) {
14436
- console.error(`Error extracting output for ${channelName}:`, error2);
14543
+ debugLogger.error(`Error extracting output for ${channelName}:`, error2);
14437
14544
  } finally {
14438
14545
  span.end();
14439
14546
  states.delete(event);
@@ -14461,6 +14568,9 @@ function traceStreamingChannel(channel2, config3) {
14461
14568
  );
14462
14569
  const handlers = {
14463
14570
  start: (event) => {
14571
+ if (isAutoInstrumentationSuppressed()) {
14572
+ return;
14573
+ }
14464
14574
  ensureSpanStateForEvent(
14465
14575
  states,
14466
14576
  config3,
@@ -14532,7 +14642,7 @@ function traceStreamingChannel(channel2, config3) {
14532
14642
  metrics
14533
14643
  });
14534
14644
  } catch (error2) {
14535
- console.error(
14645
+ debugLogger.error(
14536
14646
  `Error extracting output for ${channelName}:`,
14537
14647
  error2
14538
14648
  );
@@ -14592,7 +14702,7 @@ function traceStreamingChannel(channel2, config3) {
14592
14702
  metrics
14593
14703
  });
14594
14704
  } catch (error2) {
14595
- console.error(`Error extracting output for ${channelName}:`, error2);
14705
+ debugLogger.error(`Error extracting output for ${channelName}:`, error2);
14596
14706
  } finally {
14597
14707
  span.end();
14598
14708
  states.delete(event);
@@ -14620,6 +14730,9 @@ function traceSyncStreamChannel(channel2, config3) {
14620
14730
  );
14621
14731
  const handlers = {
14622
14732
  start: (event) => {
14733
+ if (isAutoInstrumentationSuppressed()) {
14734
+ return;
14735
+ }
14623
14736
  ensureSpanStateForEvent(
14624
14737
  states,
14625
14738
  config3,
@@ -14673,7 +14786,7 @@ function traceSyncStreamChannel(channel2, config3) {
14673
14786
  });
14674
14787
  }
14675
14788
  } catch (error2) {
14676
- console.error(
14789
+ debugLogger.error(
14677
14790
  `Error extracting chatCompletion for ${channelName}:`,
14678
14791
  error2
14679
14792
  );
@@ -14697,7 +14810,10 @@ function traceSyncStreamChannel(channel2, config3) {
14697
14810
  span.log(extracted);
14698
14811
  }
14699
14812
  } catch (error2) {
14700
- console.error(`Error extracting event for ${channelName}:`, error2);
14813
+ debugLogger.error(
14814
+ `Error extracting event for ${channelName}:`,
14815
+ error2
14816
+ );
14701
14817
  }
14702
14818
  });
14703
14819
  stream.on("end", () => {
@@ -16226,6 +16342,9 @@ var AnthropicPlugin = class extends BasePlugin {
16226
16342
  const states = /* @__PURE__ */ new WeakMap();
16227
16343
  const handlers = {
16228
16344
  start: (event) => {
16345
+ if (isAutoInstrumentationSuppressed()) {
16346
+ return;
16347
+ }
16229
16348
  const params = event.arguments[0] ?? {};
16230
16349
  const span = startSpan({
16231
16350
  name: "anthropic.beta.messages.toolRunner",
@@ -16955,6 +17074,520 @@ function serializeAISDKToolsForLogging(tools) {
16955
17074
  return serialized;
16956
17075
  }
16957
17076
 
17077
+ // src/wrappers/ai-sdk/telemetry.ts
17078
+ function braintrustAISDKTelemetry() {
17079
+ const operations = /* @__PURE__ */ new Map();
17080
+ const modelSpans = /* @__PURE__ */ new Map();
17081
+ const objectSpans = /* @__PURE__ */ new Map();
17082
+ const embedSpans = /* @__PURE__ */ new Map();
17083
+ const rerankSpans = /* @__PURE__ */ new Map();
17084
+ const toolSpans = /* @__PURE__ */ new Map();
17085
+ const runSafely = (name, callback) => {
17086
+ try {
17087
+ callback();
17088
+ } catch (error2) {
17089
+ console.error(`Error in Braintrust AI SDK telemetry ${name}:`, error2);
17090
+ }
17091
+ };
17092
+ const startChildSpan = (callId, name, type, event) => {
17093
+ const parent = operations.get(callId)?.span;
17094
+ const spanArgs = {
17095
+ name,
17096
+ spanAttributes: { type },
17097
+ ...event ? { event } : {}
17098
+ };
17099
+ const span = parent ? parent.startSpan(spanArgs) : startSpan(spanArgs);
17100
+ const state = operations.get(callId);
17101
+ if (state && type === "llm" /* LLM */) {
17102
+ state.hadModelChild = true;
17103
+ }
17104
+ return span;
17105
+ };
17106
+ return {
17107
+ onStart(event) {
17108
+ runSafely("onStart", () => {
17109
+ const operationName = operationNameFromId(event.operationId);
17110
+ const span = startSpan({
17111
+ name: operationName,
17112
+ spanAttributes: { type: "function" /* FUNCTION */ }
17113
+ });
17114
+ operations.set(event.callId, {
17115
+ hadModelChild: false,
17116
+ operationName,
17117
+ span,
17118
+ startTime: getCurrentUnixTimestamp()
17119
+ });
17120
+ const metadata = metadataFromEvent(event);
17121
+ const logPayload = { metadata };
17122
+ if (shouldRecordInputs(event)) {
17123
+ const { input, outputPromise } = processAISDKCallInput(
17124
+ operationInput(event, operationName)
17125
+ );
17126
+ logPayload.input = input;
17127
+ if (outputPromise && input && typeof input === "object") {
17128
+ outputPromise.then((resolvedData) => {
17129
+ span.log({
17130
+ input: {
17131
+ ...input,
17132
+ ...resolvedData
17133
+ }
17134
+ });
17135
+ }).catch(() => {
17136
+ });
17137
+ }
17138
+ }
17139
+ span.log(logPayload);
17140
+ });
17141
+ },
17142
+ onLanguageModelCallStart(event) {
17143
+ runSafely("onLanguageModelCallStart", () => {
17144
+ const state = operations.get(event.callId);
17145
+ const openSpans = modelSpans.get(event.callId);
17146
+ if (openSpans) {
17147
+ for (const span2 of openSpans) {
17148
+ span2.end();
17149
+ }
17150
+ modelSpans.delete(event.callId);
17151
+ }
17152
+ const span = startChildSpan(
17153
+ event.callId,
17154
+ state?.operationName === "streamText" ? "doStream" : "doGenerate",
17155
+ "llm" /* LLM */,
17156
+ {
17157
+ ...shouldRecordInputs(event) ? {
17158
+ input: processAISDKCallInput(
17159
+ operationInput(
17160
+ event,
17161
+ state?.operationName ?? "generateText"
17162
+ )
17163
+ ).input
17164
+ } : {},
17165
+ metadata: metadataFromEvent(event)
17166
+ }
17167
+ );
17168
+ const spans = modelSpans.get(event.callId) ?? [];
17169
+ spans.push(span);
17170
+ modelSpans.set(event.callId, spans);
17171
+ });
17172
+ },
17173
+ onLanguageModelCallEnd(event) {
17174
+ runSafely("onLanguageModelCallEnd", () => {
17175
+ const span = shiftModelSpan(modelSpans, event.callId);
17176
+ if (!span) {
17177
+ return;
17178
+ }
17179
+ const result = {
17180
+ ...event,
17181
+ response: event.responseId ? { id: event.responseId } : void 0
17182
+ };
17183
+ span.log({
17184
+ ...shouldRecordOutputs(event) ? {
17185
+ output: processAISDKOutput(result, DEFAULT_DENY_OUTPUT_PATHS)
17186
+ } : {},
17187
+ metrics: extractTokenMetrics(result)
17188
+ });
17189
+ span.end();
17190
+ });
17191
+ },
17192
+ onObjectStepStart(event) {
17193
+ runSafely("onObjectStepStart", () => {
17194
+ const state = operations.get(event.callId);
17195
+ const openSpan = objectSpans.get(event.callId);
17196
+ if (openSpan) {
17197
+ openSpan.end();
17198
+ objectSpans.delete(event.callId);
17199
+ }
17200
+ const span = startChildSpan(
17201
+ event.callId,
17202
+ state?.operationName === "streamObject" ? "doStream" : "doGenerate",
17203
+ "llm" /* LLM */,
17204
+ {
17205
+ ...shouldRecordInputs(event) ? {
17206
+ input: {
17207
+ prompt: event.promptMessages
17208
+ }
17209
+ } : {},
17210
+ metadata: metadataFromEvent(event)
17211
+ }
17212
+ );
17213
+ objectSpans.set(event.callId, span);
17214
+ });
17215
+ },
17216
+ onObjectStepFinish(event) {
17217
+ runSafely("onObjectStepFinish", () => {
17218
+ const span = objectSpans.get(event.callId);
17219
+ if (!span) {
17220
+ return;
17221
+ }
17222
+ const result = {
17223
+ ...event,
17224
+ text: event.objectText
17225
+ };
17226
+ span.log({
17227
+ ...shouldRecordOutputs(event) ? {
17228
+ output: processAISDKOutput(result, DEFAULT_DENY_OUTPUT_PATHS)
17229
+ } : {},
17230
+ metrics: extractTokenMetrics(result)
17231
+ });
17232
+ span.end();
17233
+ objectSpans.delete(event.callId);
17234
+ });
17235
+ },
17236
+ onEmbedStart(event) {
17237
+ runSafely("onEmbedStart", () => {
17238
+ const state = operations.get(event.callId);
17239
+ for (const [embedCallId, embedState] of embedSpans) {
17240
+ if (embedState.callId === event.callId && (state?.operationName === "embed" || embedState.values === event.values)) {
17241
+ embedState.span.end();
17242
+ embedSpans.delete(embedCallId);
17243
+ }
17244
+ }
17245
+ const span = startChildSpan(
17246
+ event.callId,
17247
+ "doEmbed",
17248
+ "llm" /* LLM */,
17249
+ {
17250
+ ...shouldRecordInputs(event) ? {
17251
+ input: {
17252
+ values: event.values
17253
+ }
17254
+ } : {},
17255
+ metadata: metadataFromEvent(event)
17256
+ }
17257
+ );
17258
+ embedSpans.set(event.embedCallId, {
17259
+ callId: event.callId,
17260
+ span,
17261
+ values: event.values
17262
+ });
17263
+ });
17264
+ },
17265
+ onEmbedFinish(event) {
17266
+ runSafely("onEmbedFinish", () => {
17267
+ const state = embedSpans.get(event.embedCallId);
17268
+ if (!state) {
17269
+ return;
17270
+ }
17271
+ const result = {
17272
+ ...event,
17273
+ embeddings: event.embeddings
17274
+ };
17275
+ state.span.log({
17276
+ ...shouldRecordOutputs(event) ? {
17277
+ output: processAISDKEmbeddingOutput(
17278
+ result,
17279
+ DEFAULT_DENY_OUTPUT_PATHS
17280
+ )
17281
+ } : {},
17282
+ metrics: extractTokenMetrics(result)
17283
+ });
17284
+ state.span.end();
17285
+ embedSpans.delete(event.embedCallId);
17286
+ });
17287
+ },
17288
+ onRerankStart(event) {
17289
+ runSafely("onRerankStart", () => {
17290
+ const openSpan = rerankSpans.get(event.callId);
17291
+ if (openSpan) {
17292
+ openSpan.end();
17293
+ rerankSpans.delete(event.callId);
17294
+ }
17295
+ const span = startChildSpan(
17296
+ event.callId,
17297
+ "doRerank",
17298
+ "llm" /* LLM */,
17299
+ {
17300
+ ...shouldRecordInputs(event) ? {
17301
+ input: {
17302
+ documents: event.documents,
17303
+ query: event.query,
17304
+ topN: event.topN
17305
+ }
17306
+ } : {},
17307
+ metadata: metadataFromEvent(event)
17308
+ }
17309
+ );
17310
+ rerankSpans.set(event.callId, span);
17311
+ });
17312
+ },
17313
+ onRerankFinish(event) {
17314
+ runSafely("onRerankFinish", () => {
17315
+ const span = rerankSpans.get(event.callId);
17316
+ if (!span) {
17317
+ return;
17318
+ }
17319
+ const result = {
17320
+ ranking: event.ranking?.map((entry) => ({
17321
+ originalIndex: entry.index,
17322
+ score: entry.relevanceScore
17323
+ }))
17324
+ };
17325
+ span.log({
17326
+ ...shouldRecordOutputs(event) ? {
17327
+ output: processAISDKRerankOutput(
17328
+ result,
17329
+ DEFAULT_DENY_OUTPUT_PATHS
17330
+ )
17331
+ } : {}
17332
+ });
17333
+ span.end();
17334
+ rerankSpans.delete(event.callId);
17335
+ });
17336
+ },
17337
+ onToolExecutionStart(event) {
17338
+ runSafely("onToolExecutionStart", () => {
17339
+ const toolCallId = event.toolCall.toolCallId;
17340
+ if (!toolCallId) {
17341
+ return;
17342
+ }
17343
+ const span = startChildSpan(
17344
+ event.callId,
17345
+ event.toolCall.toolName || "tool",
17346
+ "tool" /* TOOL */,
17347
+ {
17348
+ ...shouldRecordInputs(event) ? {
17349
+ input: event.toolCall.input
17350
+ } : {},
17351
+ metadata: {
17352
+ ...createAISDKIntegrationMetadata(),
17353
+ toolCallId,
17354
+ ...typeof event.toolCall.toolName === "string" ? { toolName: event.toolCall.toolName } : {}
17355
+ }
17356
+ }
17357
+ );
17358
+ toolSpans.set(toolCallId, { callId: event.callId, span });
17359
+ });
17360
+ },
17361
+ onToolExecutionEnd(event) {
17362
+ runSafely("onToolExecutionEnd", () => {
17363
+ const toolCallId = event.toolCall.toolCallId;
17364
+ const state = toolCallId ? toolSpans.get(toolCallId) : void 0;
17365
+ if (!toolCallId || !state) {
17366
+ return;
17367
+ }
17368
+ const toolOutput = event.toolOutput;
17369
+ if (toolOutput?.type === "tool-error") {
17370
+ state.span.log({
17371
+ error: toolOutput.error instanceof Error ? toolOutput.error.message : String(toolOutput?.error),
17372
+ metrics: typeof event.durationMs === "number" ? { duration_ms: event.durationMs } : {}
17373
+ });
17374
+ } else {
17375
+ state.span.log({
17376
+ ...shouldRecordOutputs(event) ? { output: toolOutput?.output } : {},
17377
+ metrics: typeof event.durationMs === "number" ? { duration_ms: event.durationMs } : {}
17378
+ });
17379
+ }
17380
+ state.span.end();
17381
+ toolSpans.delete(toolCallId);
17382
+ });
17383
+ },
17384
+ onChunk(event) {
17385
+ runSafely("onChunk", () => {
17386
+ const callId = event.chunk?.callId;
17387
+ if (!callId) {
17388
+ return;
17389
+ }
17390
+ const state = operations.get(callId);
17391
+ if (!state || state.firstChunkTime !== void 0) {
17392
+ return;
17393
+ }
17394
+ state.firstChunkTime = getCurrentUnixTimestamp();
17395
+ });
17396
+ },
17397
+ onFinish(event) {
17398
+ runSafely("onFinish", () => {
17399
+ const state = operations.get(event.callId);
17400
+ if (!state) {
17401
+ return;
17402
+ }
17403
+ const result = finishResult(event, state.operationName);
17404
+ const metrics = state.hadModelChild ? {} : extractTokenMetrics(result);
17405
+ if (state.firstChunkTime !== void 0) {
17406
+ metrics.time_to_first_token = state.firstChunkTime - state.startTime;
17407
+ }
17408
+ state.span.log({
17409
+ ...shouldRecordOutputs(event) ? {
17410
+ output: finishOutput(result, state.operationName)
17411
+ } : {},
17412
+ metrics
17413
+ });
17414
+ state.span.end();
17415
+ operations.delete(event.callId);
17416
+ });
17417
+ },
17418
+ onError(event) {
17419
+ runSafely("onError", () => {
17420
+ const errorEvent = isObject(event) ? event : {};
17421
+ const callId = typeof errorEvent.callId === "string" ? errorEvent.callId : void 0;
17422
+ if (!callId) {
17423
+ return;
17424
+ }
17425
+ const state = operations.get(callId);
17426
+ if (!state) {
17427
+ return;
17428
+ }
17429
+ const error2 = errorEvent.error ?? event;
17430
+ const openModelSpans = modelSpans.get(callId);
17431
+ if (openModelSpans) {
17432
+ for (const span of openModelSpans) {
17433
+ logError(span, error2);
17434
+ span.end();
17435
+ }
17436
+ modelSpans.delete(callId);
17437
+ }
17438
+ const openObjectSpan = objectSpans.get(callId);
17439
+ if (openObjectSpan) {
17440
+ logError(openObjectSpan, error2);
17441
+ openObjectSpan.end();
17442
+ objectSpans.delete(callId);
17443
+ }
17444
+ for (const [embedCallId, embedState] of embedSpans) {
17445
+ if (embedState.callId === callId) {
17446
+ logError(embedState.span, error2);
17447
+ embedState.span.end();
17448
+ embedSpans.delete(embedCallId);
17449
+ }
17450
+ }
17451
+ const openRerankSpan = rerankSpans.get(callId);
17452
+ if (openRerankSpan) {
17453
+ logError(openRerankSpan, error2);
17454
+ openRerankSpan.end();
17455
+ rerankSpans.delete(callId);
17456
+ }
17457
+ for (const [toolCallId, toolState] of toolSpans) {
17458
+ if (toolState.callId === callId) {
17459
+ logError(toolState.span, error2);
17460
+ toolState.span.end();
17461
+ toolSpans.delete(toolCallId);
17462
+ }
17463
+ }
17464
+ logError(state.span, error2);
17465
+ state.span.end();
17466
+ operations.delete(callId);
17467
+ });
17468
+ },
17469
+ executeTool({ toolCallId, execute }) {
17470
+ const state = toolSpans.get(toolCallId);
17471
+ return state ? withCurrent(state.span, () => execute()) : execute();
17472
+ }
17473
+ };
17474
+ }
17475
+ function shouldRecordInputs(event) {
17476
+ return event.recordInputs !== false;
17477
+ }
17478
+ function shouldRecordOutputs(event) {
17479
+ return event.recordOutputs !== false;
17480
+ }
17481
+ function operationNameFromId(operationId) {
17482
+ return operationId?.startsWith("ai.") ? operationId.slice("ai.".length) : operationId || "ai-sdk";
17483
+ }
17484
+ function modelFromEvent(event) {
17485
+ return event.modelId ? {
17486
+ modelId: event.modelId,
17487
+ ...event.provider ? { provider: event.provider } : {}
17488
+ } : void 0;
17489
+ }
17490
+ function metadataFromEvent(event) {
17491
+ const metadata = createAISDKIntegrationMetadata();
17492
+ const { model, provider } = serializeModelWithProvider(modelFromEvent(event));
17493
+ if (model) {
17494
+ metadata.model = model;
17495
+ }
17496
+ if (provider) {
17497
+ metadata.provider = provider;
17498
+ }
17499
+ if (typeof event.functionId === "string") {
17500
+ metadata.functionId = event.functionId;
17501
+ }
17502
+ return metadata;
17503
+ }
17504
+ function operationInput(event, operationName) {
17505
+ if (operationName === "embed") {
17506
+ return {
17507
+ model: modelFromEvent(event),
17508
+ value: event.value
17509
+ };
17510
+ }
17511
+ if (operationName === "embedMany") {
17512
+ return {
17513
+ model: modelFromEvent(event),
17514
+ values: Array.isArray(event.value) ? event.value ?? [] : void 0
17515
+ };
17516
+ }
17517
+ if (operationName === "rerank") {
17518
+ return {
17519
+ model: modelFromEvent(event),
17520
+ documents: event.documents,
17521
+ query: event.query,
17522
+ topN: event.topN
17523
+ };
17524
+ }
17525
+ return {
17526
+ model: modelFromEvent(event),
17527
+ system: event.system,
17528
+ prompt: event.prompt,
17529
+ messages: event.messages,
17530
+ tools: event.tools,
17531
+ toolChoice: event.toolChoice,
17532
+ activeTools: event.activeTools,
17533
+ output: event.output,
17534
+ schema: event.schema,
17535
+ schemaName: event.schemaName,
17536
+ schemaDescription: event.schemaDescription,
17537
+ maxOutputTokens: event.maxOutputTokens,
17538
+ temperature: event.temperature,
17539
+ topP: event.topP,
17540
+ topK: event.topK,
17541
+ presencePenalty: event.presencePenalty,
17542
+ frequencyPenalty: event.frequencyPenalty,
17543
+ seed: event.seed,
17544
+ maxRetries: event.maxRetries,
17545
+ headers: event.headers,
17546
+ providerOptions: event.providerOptions
17547
+ };
17548
+ }
17549
+ function shiftModelSpan(modelSpans, callId) {
17550
+ const spans = modelSpans.get(callId);
17551
+ const span = spans?.shift();
17552
+ if (spans && spans.length === 0) {
17553
+ modelSpans.delete(callId);
17554
+ }
17555
+ return span;
17556
+ }
17557
+ function finishResult(event, operationName) {
17558
+ if (operationName === "embed") {
17559
+ return {
17560
+ ...event,
17561
+ embedding: event.embedding
17562
+ };
17563
+ }
17564
+ if (operationName === "embedMany") {
17565
+ return {
17566
+ ...event,
17567
+ embeddings: event.embedding
17568
+ };
17569
+ }
17570
+ if (operationName === "rerank") {
17571
+ return event;
17572
+ }
17573
+ return event;
17574
+ }
17575
+ function finishOutput(result, operationName) {
17576
+ if (operationName === "embed" || operationName === "embedMany") {
17577
+ return processAISDKEmbeddingOutput(
17578
+ result,
17579
+ DEFAULT_DENY_OUTPUT_PATHS
17580
+ );
17581
+ }
17582
+ if (operationName === "rerank") {
17583
+ return processAISDKRerankOutput(
17584
+ result,
17585
+ DEFAULT_DENY_OUTPUT_PATHS
17586
+ );
17587
+ }
17588
+ return processAISDKOutput(result, DEFAULT_DENY_OUTPUT_PATHS);
17589
+ }
17590
+
16958
17591
  // src/instrumentation/plugins/ai-sdk-channels.ts
16959
17592
  var aiSDKChannels = defineChannels("ai", {
16960
17593
  generateText: channel({
@@ -17014,6 +17647,10 @@ var aiSDKChannels = defineChannels("ai", {
17014
17647
  toolLoopAgentStream: channel({
17015
17648
  channelName: "ToolLoopAgent.stream",
17016
17649
  kind: "async"
17650
+ }),
17651
+ v7CreateTelemetryDispatcher: channel({
17652
+ channelName: "createTelemetryDispatcher",
17653
+ kind: "sync-stream"
17017
17654
  })
17018
17655
  });
17019
17656
 
@@ -17034,9 +17671,30 @@ var DEFAULT_DENY_OUTPUT_PATHS = [
17034
17671
  ];
17035
17672
  var AUTO_PATCHED_MODEL = /* @__PURE__ */ Symbol.for("braintrust.ai-sdk.auto-patched-model");
17036
17673
  var AUTO_PATCHED_TOOL = /* @__PURE__ */ Symbol.for("braintrust.ai-sdk.auto-patched-tool");
17674
+ var AUTO_PATCHED_V7_TELEMETRY_DISPATCHER = /* @__PURE__ */ Symbol.for(
17675
+ "braintrust.ai-sdk.v7.auto-patched-telemetry-dispatcher"
17676
+ );
17037
17677
  var RUNTIME_DENY_OUTPUT_PATHS = /* @__PURE__ */ Symbol.for(
17038
17678
  "braintrust.ai-sdk.deny-output-paths"
17039
17679
  );
17680
+ var AI_SDK_V7_TELEMETRY_CALLBACKS = [
17681
+ "onStart",
17682
+ "onStepStart",
17683
+ "onLanguageModelCallStart",
17684
+ "onLanguageModelCallEnd",
17685
+ "onToolExecutionStart",
17686
+ "onToolExecutionEnd",
17687
+ "onChunk",
17688
+ "onStepFinish",
17689
+ "onObjectStepStart",
17690
+ "onObjectStepFinish",
17691
+ "onEmbedStart",
17692
+ "onEmbedFinish",
17693
+ "onRerankStart",
17694
+ "onRerankFinish",
17695
+ "onFinish",
17696
+ "onError"
17697
+ ];
17040
17698
  var AISDKPlugin = class extends BasePlugin {
17041
17699
  config;
17042
17700
  constructor(config3 = {}) {
@@ -17051,6 +17709,7 @@ var AISDKPlugin = class extends BasePlugin {
17051
17709
  }
17052
17710
  subscribeToAISDK() {
17053
17711
  const denyOutputPaths = this.config.denyOutputPaths || DEFAULT_DENY_OUTPUT_PATHS;
17712
+ this.unsubscribers.push(subscribeToAISDKV7TelemetryDispatcher());
17054
17713
  this.unsubscribers.push(
17055
17714
  traceStreamingChannel(aiSDKChannels.generateText, {
17056
17715
  name: "generateText",
@@ -17275,10 +17934,61 @@ var AISDKPlugin = class extends BasePlugin {
17275
17934
  );
17276
17935
  }
17277
17936
  };
17278
- function resolveDenyOutputPaths(event, defaultDenyOutputPaths) {
17279
- if (Array.isArray(event?.denyOutputPaths)) {
17280
- return event.denyOutputPaths;
17281
- }
17937
+ function subscribeToAISDKV7TelemetryDispatcher() {
17938
+ const channel2 = aiSDKChannels.v7CreateTelemetryDispatcher.tracingChannel();
17939
+ const telemetry = braintrustAISDKTelemetry();
17940
+ const handlers = {
17941
+ end: (event) => {
17942
+ const telemetryOptions = event.arguments?.[0]?.telemetry;
17943
+ if (telemetryOptions?.isEnabled === false) {
17944
+ return;
17945
+ }
17946
+ patchAISDKV7TelemetryDispatcher(event.result, telemetry);
17947
+ }
17948
+ };
17949
+ channel2.subscribe(handlers);
17950
+ return () => {
17951
+ channel2.unsubscribe(handlers);
17952
+ };
17953
+ }
17954
+ function patchAISDKV7TelemetryDispatcher(dispatcher, telemetry) {
17955
+ if (!isObject(dispatcher)) {
17956
+ return;
17957
+ }
17958
+ const dispatcherRecord = dispatcher;
17959
+ if (dispatcherRecord[AUTO_PATCHED_V7_TELEMETRY_DISPATCHER]) {
17960
+ return;
17961
+ }
17962
+ dispatcherRecord[AUTO_PATCHED_V7_TELEMETRY_DISPATCHER] = true;
17963
+ for (const key of AI_SDK_V7_TELEMETRY_CALLBACKS) {
17964
+ const braintrustCallback = telemetry[key];
17965
+ if (typeof braintrustCallback !== "function") {
17966
+ continue;
17967
+ }
17968
+ const existingCallback = dispatcherRecord[key];
17969
+ dispatcherRecord[key] = (event) => {
17970
+ const existingResult = typeof existingCallback === "function" ? existingCallback.call(dispatcher, event) : void 0;
17971
+ const braintrustResult = braintrustCallback.call(telemetry, event);
17972
+ const pending = [existingResult, braintrustResult].filter(isPromiseLike);
17973
+ if (pending.length > 0) {
17974
+ return Promise.allSettled(pending).then(() => void 0);
17975
+ }
17976
+ };
17977
+ }
17978
+ const braintrustExecuteTool = telemetry.executeTool;
17979
+ if (typeof braintrustExecuteTool !== "function") {
17980
+ return;
17981
+ }
17982
+ const existingExecuteTool = dispatcherRecord.executeTool;
17983
+ dispatcherRecord.executeTool = (args) => braintrustExecuteTool.call(telemetry, {
17984
+ ...args,
17985
+ execute: () => typeof existingExecuteTool === "function" ? existingExecuteTool.call(dispatcher, args) : args.execute()
17986
+ });
17987
+ }
17988
+ function resolveDenyOutputPaths(event, defaultDenyOutputPaths) {
17989
+ if (Array.isArray(event?.denyOutputPaths)) {
17990
+ return event.denyOutputPaths;
17991
+ }
17282
17992
  const firstArgument2 = event?.arguments && event.arguments.length > 0 ? event.arguments[0] : void 0;
17283
17993
  if (!firstArgument2 || typeof firstArgument2 !== "object") {
17284
17994
  return defaultDenyOutputPaths;
@@ -17726,11 +18436,11 @@ function prepareAISDKChildTracing(params, self, parentSpan, denyOutputPaths, aiS
17726
18436
  metadata: baseMetadata
17727
18437
  }
17728
18438
  });
18439
+ const streamStartTime = getCurrentUnixTimestamp();
17729
18440
  const result = await withCurrent(
17730
18441
  span,
17731
18442
  () => Reflect.apply(originalDoStream, resolvedModel, [options])
17732
18443
  );
17733
- const streamStartTime = getCurrentUnixTimestamp();
17734
18444
  let firstChunkTime;
17735
18445
  const output = {};
17736
18446
  let text = "";
@@ -17739,7 +18449,7 @@ function prepareAISDKChildTracing(params, self, parentSpan, denyOutputPaths, aiS
17739
18449
  let object = void 0;
17740
18450
  const transformStream = new TransformStream({
17741
18451
  transform(chunk, controller) {
17742
- if (firstChunkTime === void 0) {
18452
+ if (firstChunkTime === void 0 && isAISDKContentStreamChunk(chunk)) {
17743
18453
  firstChunkTime = getCurrentUnixTimestamp();
17744
18454
  }
17745
18455
  switch (chunk.type) {
@@ -17931,6 +18641,78 @@ function finalizeAISDKChildTracing(event) {
17931
18641
  delete event.__braintrust_ai_sdk_cleanup;
17932
18642
  }
17933
18643
  }
18644
+ function extractAISDKStreamPart(chunk) {
18645
+ if (!isObject(chunk) || !isObject(chunk.part)) {
18646
+ return chunk;
18647
+ }
18648
+ return chunk.part;
18649
+ }
18650
+ function stringContent(value) {
18651
+ return typeof value === "string" && value.length > 0 ? value : void 0;
18652
+ }
18653
+ function rawValueHasAISDKContent(value) {
18654
+ if (value === void 0 || value === null) {
18655
+ return false;
18656
+ }
18657
+ if (typeof value === "string") {
18658
+ return value.length > 0;
18659
+ }
18660
+ if (!isObject(value)) {
18661
+ return true;
18662
+ }
18663
+ const delta = value.delta;
18664
+ 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) => {
18665
+ if (!isObject(choice) || !isObject(choice.delta)) {
18666
+ return false;
18667
+ }
18668
+ const choiceDelta = choice.delta;
18669
+ if (stringContent(choiceDelta.content) || stringContent(choiceDelta.text)) {
18670
+ return true;
18671
+ }
18672
+ if (isObject(choiceDelta.function_call) && stringContent(choiceDelta.function_call.arguments)) {
18673
+ return true;
18674
+ }
18675
+ return Array.isArray(choiceDelta.tool_calls) && choiceDelta.tool_calls.some(
18676
+ (toolCall) => isObject(toolCall) && isObject(toolCall.function) && stringContent(toolCall.function.arguments)
18677
+ );
18678
+ })) {
18679
+ return true;
18680
+ }
18681
+ return false;
18682
+ }
18683
+ function isAISDKContentStreamChunk(chunk) {
18684
+ const part = extractAISDKStreamPart(chunk);
18685
+ if (typeof part === "string") {
18686
+ return part.length > 0;
18687
+ }
18688
+ if (!isObject(part) || typeof part.type !== "string") {
18689
+ return false;
18690
+ }
18691
+ switch (part.type) {
18692
+ case "text-delta":
18693
+ return stringContent(part.textDelta) !== void 0 || stringContent(part.delta) !== void 0 || stringContent(part.text) !== void 0 || stringContent(part.content) !== void 0;
18694
+ case "reasoning-delta":
18695
+ return stringContent(part.delta) !== void 0 || stringContent(part.text) !== void 0 || stringContent(part.content) !== void 0;
18696
+ case "tool-call":
18697
+ case "object":
18698
+ case "file":
18699
+ return true;
18700
+ case "tool-input-delta":
18701
+ case "tool-call-delta":
18702
+ 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;
18703
+ case "raw":
18704
+ return rawValueHasAISDKContent(part.rawValue);
18705
+ default:
18706
+ return false;
18707
+ }
18708
+ }
18709
+ function isAISDKContentAsyncIterableChunk(chunk) {
18710
+ if (isAISDKContentStreamChunk(chunk)) {
18711
+ return true;
18712
+ }
18713
+ const part = extractAISDKStreamPart(chunk);
18714
+ return isObject(part) && typeof part.type !== "string";
18715
+ }
17934
18716
  function patchAISDKStreamingResult(args) {
17935
18717
  const { defaultDenyOutputPaths, endEvent, result, span, startTime } = args;
17936
18718
  if (!result || typeof result !== "object") {
@@ -17943,7 +18725,7 @@ function patchAISDKStreamingResult(args) {
17943
18725
  const wrappedBaseStream = resultRecord.baseStream.pipeThrough(
17944
18726
  new TransformStream({
17945
18727
  transform(chunk, controller) {
17946
- if (firstChunkTime2 === void 0) {
18728
+ if (firstChunkTime2 === void 0 && isAISDKContentStreamChunk(chunk)) {
17947
18729
  firstChunkTime2 = getCurrentUnixTimestamp();
17948
18730
  }
17949
18731
  controller.enqueue(chunk);
@@ -17987,8 +18769,8 @@ function patchAISDKStreamingResult(args) {
17987
18769
  }
17988
18770
  let firstChunkTime;
17989
18771
  const wrappedStream = createPatchedAsyncIterable(streamField.stream, {
17990
- onChunk: () => {
17991
- if (firstChunkTime === void 0) {
18772
+ onChunk: (chunk) => {
18773
+ if (firstChunkTime === void 0 && isAISDKContentAsyncIterableChunk(chunk)) {
17992
18774
  firstChunkTime = getCurrentUnixTimestamp();
17993
18775
  }
17994
18776
  },
@@ -18960,15 +19742,17 @@ function collectLocalMcpServerToolHookNames(serverName, serverConfig) {
18960
19742
 
18961
19743
  // src/instrumentation/plugins/claude-agent-sdk-plugin.ts
18962
19744
  var ROOT_LLM_PARENT_KEY = "__root__";
19745
+ var SUB_AGENT_PROMPT_SOURCE_PRIORITY = {
19746
+ delegation: 0,
19747
+ lifecycle: 1,
19748
+ sidechain: 2
19749
+ };
18963
19750
  function llmParentKey(parentToolUseId) {
18964
19751
  return parentToolUseId ?? ROOT_LLM_PARENT_KEY;
18965
19752
  }
18966
19753
  function isSubAgentDelegationToolName(toolName) {
18967
19754
  return toolName === "Agent" || toolName === "Task";
18968
19755
  }
18969
- function shouldParentToolAsTaskSibling(toolName) {
18970
- return toolName === "Agent" || toolName === "Task" || toolName === "Bash";
18971
- }
18972
19756
  function filterSerializableOptions(options) {
18973
19757
  const allowedKeys = [
18974
19758
  "model",
@@ -19105,26 +19889,39 @@ function extractUsageFromMessage(message) {
19105
19889
  }
19106
19890
  return metrics;
19107
19891
  }
19108
- function buildLLMInput(prompt, conversationHistory, capturedPromptMessages) {
19109
- const promptMessages = [];
19110
- if (typeof prompt === "string") {
19111
- promptMessages.push({ content: prompt, role: "user" });
19112
- } else if (capturedPromptMessages && capturedPromptMessages.length > 0) {
19113
- for (const msg of capturedPromptMessages) {
19114
- const role = msg.message?.role;
19115
- const content = msg.message?.content;
19116
- if (role && content !== void 0) {
19117
- promptMessages.push({ content, role });
19118
- }
19119
- }
19120
- }
19892
+ function buildLLMInput(promptMessages, conversationHistory) {
19121
19893
  const inputParts = [...promptMessages, ...conversationHistory];
19122
19894
  return inputParts.length > 0 ? inputParts : void 0;
19123
19895
  }
19896
+ function conversationMessageFromSDKMessage(message) {
19897
+ const role = message.message?.role;
19898
+ const content = message.message?.content;
19899
+ if (role && content !== void 0) {
19900
+ return { content, role };
19901
+ }
19902
+ return void 0;
19903
+ }
19904
+ function messageContentHasBlockType(message, blockType) {
19905
+ const content = message.message?.content;
19906
+ return Array.isArray(content) && content.some(
19907
+ (block) => typeof block === "object" && block !== null && "type" in block && block.type === blockType
19908
+ );
19909
+ }
19910
+ function buildRootPromptMessages(prompt, capturedPromptMessages) {
19911
+ if (typeof prompt === "string") {
19912
+ return [{ content: prompt, role: "user" }];
19913
+ }
19914
+ if (!capturedPromptMessages || capturedPromptMessages.length === 0) {
19915
+ return [];
19916
+ }
19917
+ return capturedPromptMessages.map(conversationMessageFromSDKMessage).filter(
19918
+ (message) => message !== void 0
19919
+ );
19920
+ }
19124
19921
  function formatCapturedMessages(messages) {
19125
19922
  return messages.length > 0 ? messages : [];
19126
19923
  }
19127
- async function createLLMSpanForMessages(messages, prompt, conversationHistory, options, startTime, capturedPromptMessages, parentSpan, existingSpan) {
19924
+ async function createLLMSpanForMessages(messages, promptMessages, conversationHistory, options, startTime, parentSpan, existingSpan) {
19128
19925
  if (messages.length === 0) {
19129
19926
  return void 0;
19130
19927
  }
@@ -19134,11 +19931,7 @@ async function createLLMSpanForMessages(messages, prompt, conversationHistory, o
19134
19931
  }
19135
19932
  const model = lastMessage.message.model || options.model;
19136
19933
  const usage = extractUsageFromMessage(lastMessage);
19137
- const input = buildLLMInput(
19138
- prompt,
19139
- conversationHistory,
19140
- capturedPromptMessages
19141
- );
19934
+ const input = buildLLMInput(promptMessages, conversationHistory);
19142
19935
  const outputs = messages.map(
19143
19936
  (m) => m.message?.content && m.message?.role ? { content: m.message.content, role: m.message.role } : void 0
19144
19937
  ).filter(
@@ -19269,8 +20062,7 @@ function createToolTracingHooks(resolveParentSpan, activeToolSpans, mcpServers,
19269
20062
  },
19270
20063
  name: parsed.displayName,
19271
20064
  parent: await resolveParentSpan(toolUseID, {
19272
- agentId: input.agent_id,
19273
- preferTaskSiblingParent: shouldParentToolAsTaskSibling(parsed.toolName)
20065
+ agentId: input.agent_id
19274
20066
  }),
19275
20067
  spanAttributes: { type: "tool" /* TOOL */ }
19276
20068
  });
@@ -19516,12 +20308,37 @@ function injectTracingHooks(options, resolveParentSpan, activeToolSpans, localTo
19516
20308
  }
19517
20309
  };
19518
20310
  }
20311
+ function setSubAgentPromptMessages(state, parentToolUseId, promptMessages, source) {
20312
+ if (promptMessages.length === 0) {
20313
+ return;
20314
+ }
20315
+ const parentKey = llmParentKey(parentToolUseId);
20316
+ const sourcePriority = SUB_AGENT_PROMPT_SOURCE_PRIORITY[source];
20317
+ const currentPriority = state.promptSourcePriorityByParentKey.get(parentKey) ?? -1;
20318
+ if (sourcePriority > currentPriority) {
20319
+ state.promptMessagesByParentKey.set(parentKey, promptMessages);
20320
+ state.promptSourcePriorityByParentKey.set(parentKey, sourcePriority);
20321
+ }
20322
+ }
20323
+ function getConversationHistory(state, parentKey) {
20324
+ let conversationHistory = state.conversationHistoryByParentKey.get(parentKey);
20325
+ if (!conversationHistory) {
20326
+ conversationHistory = [];
20327
+ state.conversationHistoryByParentKey.set(parentKey, conversationHistory);
20328
+ }
20329
+ return conversationHistory;
20330
+ }
19519
20331
  async function finalizeCurrentMessageGroup(state) {
19520
20332
  if (state.currentMessages.length === 0) {
19521
20333
  return;
19522
20334
  }
19523
20335
  const parentToolUseId = state.currentMessages[0]?.parent_tool_use_id ?? null;
19524
20336
  const parentKey = llmParentKey(parentToolUseId);
20337
+ const conversationHistory = getConversationHistory(state, parentKey);
20338
+ const promptMessages = parentToolUseId ? state.promptMessagesByParentKey.get(parentKey) ?? [] : buildRootPromptMessages(
20339
+ state.originalPrompt,
20340
+ state.capturedPromptMessages
20341
+ );
19525
20342
  let parentSpan = await state.span.export();
19526
20343
  if (parentToolUseId) {
19527
20344
  const subAgentSpan = state.subAgentSpans.get(parentToolUseId);
@@ -19532,11 +20349,10 @@ async function finalizeCurrentMessageGroup(state) {
19532
20349
  const existingLlmSpan = state.activeLlmSpansByParentToolUse.get(parentKey);
19533
20350
  const llmSpanResult = await createLLMSpanForMessages(
19534
20351
  state.currentMessages,
19535
- state.originalPrompt,
19536
- state.finalResults,
20352
+ promptMessages,
20353
+ conversationHistory,
19537
20354
  state.options,
19538
20355
  state.currentMessageStartTime,
19539
- state.capturedPromptMessages,
19540
20356
  parentSpan,
19541
20357
  existingLlmSpan
19542
20358
  );
@@ -19550,6 +20366,7 @@ async function finalizeCurrentMessageGroup(state) {
19550
20366
  state.latestRootLlmParentRef.value = llmSpanResult.spanExport;
19551
20367
  }
19552
20368
  if (llmSpanResult.finalMessage) {
20369
+ conversationHistory.push(llmSpanResult.finalMessage);
19553
20370
  state.finalResults.push(llmSpanResult.finalMessage);
19554
20371
  }
19555
20372
  }
@@ -19577,6 +20394,15 @@ function maybeTrackToolUseContext(state, message) {
19577
20394
  description: getStringProperty(block.input, "description"),
19578
20395
  toolUseId: block.id
19579
20396
  });
20397
+ const prompt = getStringProperty(block.input, "prompt");
20398
+ if (prompt) {
20399
+ setSubAgentPromptMessages(
20400
+ state,
20401
+ block.id,
20402
+ [{ content: prompt, role: "user" }],
20403
+ "delegation"
20404
+ );
20405
+ }
19580
20406
  }
19581
20407
  }
19582
20408
  }
@@ -19695,6 +20521,14 @@ async function maybeHandleTaskLifecycleMessage(state, message) {
19695
20521
  };
19696
20522
  if (message.subtype === "task_started") {
19697
20523
  const prompt = getStringProperty(message, "prompt");
20524
+ if (prompt) {
20525
+ setSubAgentPromptMessages(
20526
+ state,
20527
+ toolUseId,
20528
+ [{ content: prompt, role: "user" }],
20529
+ "lifecycle"
20530
+ );
20531
+ }
19698
20532
  subAgentSpan.log({
19699
20533
  input: prompt,
19700
20534
  metadata
@@ -19745,6 +20579,28 @@ async function handleStreamMessage(state, message) {
19745
20579
  return;
19746
20580
  }
19747
20581
  await maybeStartSubAgentSpan(state, message);
20582
+ const messageParentToolUseId = message.parent_tool_use_id;
20583
+ if (messageParentToolUseId && message.type === "user") {
20584
+ const conversationMessage = conversationMessageFromSDKMessage(message);
20585
+ if (conversationMessage?.role === "user") {
20586
+ await finalizeCurrentMessageGroup(state);
20587
+ const parentKey = llmParentKey(messageParentToolUseId);
20588
+ const conversationHistory = getConversationHistory(state, parentKey);
20589
+ const currentPromptSourcePriority = state.promptSourcePriorityByParentKey.get(parentKey) ?? -1;
20590
+ const canUseAsInitialSidechainPrompt = conversationHistory.length === 0 && currentPromptSourcePriority < SUB_AGENT_PROMPT_SOURCE_PRIORITY.sidechain && !messageContentHasBlockType(message, "tool_result");
20591
+ if (!canUseAsInitialSidechainPrompt) {
20592
+ conversationHistory.push(conversationMessage);
20593
+ return;
20594
+ }
20595
+ setSubAgentPromptMessages(
20596
+ state,
20597
+ messageParentToolUseId,
20598
+ [conversationMessage],
20599
+ "sidechain"
20600
+ );
20601
+ return;
20602
+ }
20603
+ }
19748
20604
  const messageId = message.message?.id;
19749
20605
  if (messageId && messageId !== state.currentMessageId) {
19750
20606
  await finalizeCurrentMessageGroup(state);
@@ -19896,6 +20752,7 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
19896
20752
  }
19897
20753
  const activeToolSpans = /* @__PURE__ */ new Map();
19898
20754
  const activeLlmSpansByParentToolUse = /* @__PURE__ */ new Map();
20755
+ const conversationHistoryByParentKey = /* @__PURE__ */ new Map();
19899
20756
  const subAgentSpans = /* @__PURE__ */ new Map();
19900
20757
  const endedSubAgentSpans = /* @__PURE__ */ new Set();
19901
20758
  const toolUseToParent = /* @__PURE__ */ new Map();
@@ -19905,6 +20762,8 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
19905
20762
  };
19906
20763
  const subAgentDetailsByToolUseId = /* @__PURE__ */ new Map();
19907
20764
  const taskIdToToolUseId = /* @__PURE__ */ new Map();
20765
+ const promptMessagesByParentKey = /* @__PURE__ */ new Map();
20766
+ const promptSourcePriorityByParentKey = /* @__PURE__ */ new Map();
19908
20767
  const localToolContext = createClaudeLocalToolContext();
19909
20768
  const { hasLocalToolHandlers, localToolHookNames } = prepareLocalToolHandlersInMcpServers(options.mcpServers);
19910
20769
  const skipLocalToolHooks = options[CLAUDE_AGENT_SDK_SKIP_LOCAL_TOOL_HOOKS_OPTION] === true || hasLocalToolHandlers;
@@ -19913,38 +20772,19 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
19913
20772
  const parentToolUseId = trackedParentToolUseId ?? (context2?.agentId ? taskIdToToolUseId.get(context2.agentId) ?? null : null);
19914
20773
  const parentKey = llmParentKey(parentToolUseId);
19915
20774
  const activeLlmSpan = activeLlmSpansByParentToolUse.get(parentKey);
19916
- if (context2?.preferTaskSiblingParent) {
19917
- if (!activeLlmSpan) {
19918
- await ensureActiveLlmSpanForParentToolUse(
19919
- span,
19920
- activeLlmSpansByParentToolUse,
19921
- subAgentDetailsByToolUseId,
19922
- activeToolSpans,
19923
- subAgentSpans,
19924
- parentToolUseId,
19925
- getCurrentUnixTimestamp()
19926
- );
19927
- }
19928
- if (parentToolUseId) {
19929
- const subAgentSpan = await ensureSubAgentSpan(
19930
- subAgentDetailsByToolUseId,
19931
- span,
19932
- activeToolSpans,
19933
- subAgentSpans,
19934
- parentToolUseId
19935
- );
19936
- return subAgentSpan.export();
19937
- }
19938
- return span.export();
19939
- }
19940
- if (activeLlmSpan) {
19941
- return activeLlmSpan.export();
20775
+ const latestLlmParent = parentToolUseId ? latestLlmParentBySubAgentToolUse.get(parentToolUseId) : latestRootLlmParentRef.value;
20776
+ if (!activeLlmSpan && !latestLlmParent) {
20777
+ await ensureActiveLlmSpanForParentToolUse(
20778
+ span,
20779
+ activeLlmSpansByParentToolUse,
20780
+ subAgentDetailsByToolUseId,
20781
+ activeToolSpans,
20782
+ subAgentSpans,
20783
+ parentToolUseId,
20784
+ getCurrentUnixTimestamp()
20785
+ );
19942
20786
  }
19943
20787
  if (parentToolUseId) {
19944
- const parentLlm = latestLlmParentBySubAgentToolUse.get(parentToolUseId);
19945
- if (parentLlm) {
19946
- return parentLlm;
19947
- }
19948
20788
  const subAgentSpan = await ensureSubAgentSpan(
19949
20789
  subAgentDetailsByToolUseId,
19950
20790
  span,
@@ -19954,9 +20794,6 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
19954
20794
  );
19955
20795
  return subAgentSpan.export();
19956
20796
  }
19957
- if (latestRootLlmParentRef.value) {
19958
- return latestRootLlmParentRef.value;
19959
- }
19960
20797
  return span.export();
19961
20798
  };
19962
20799
  localToolContext.resolveLocalToolParent = resolveToolUseParentSpan;
@@ -19977,6 +20814,7 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
19977
20814
  accumulatedOutputTokens: 0,
19978
20815
  activeLlmSpansByParentToolUse,
19979
20816
  activeToolSpans,
20817
+ conversationHistoryByParentKey,
19980
20818
  capturedPromptMessages,
19981
20819
  currentMessageId: void 0,
19982
20820
  currentMessageStartTime: startTime,
@@ -19987,7 +20825,9 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
19987
20825
  originalPrompt,
19988
20826
  processing: Promise.resolve(),
19989
20827
  promptDone,
20828
+ promptMessagesByParentKey,
19990
20829
  promptStarted: () => promptStarted,
20830
+ promptSourcePriorityByParentKey,
19991
20831
  span,
19992
20832
  subAgentDetailsByToolUseId,
19993
20833
  subAgentSpans,
@@ -21416,6 +22256,10 @@ var googleGenAIChannels = defineChannels("@google/genai", {
21416
22256
  embedContent: channel({
21417
22257
  channelName: "models.embedContent",
21418
22258
  kind: "async"
22259
+ }),
22260
+ interactionsCreate: channel({
22261
+ channelName: "interactions.create",
22262
+ kind: "async"
21419
22263
  })
21420
22264
  });
21421
22265
 
@@ -21443,6 +22287,7 @@ var GoogleGenAIPlugin = class extends BasePlugin {
21443
22287
  this.subscribeToGenerateContentChannel();
21444
22288
  this.subscribeToGenerateContentStreamChannel();
21445
22289
  this.subscribeToEmbedContentChannel();
22290
+ this.subscribeToInteractionsCreateChannel();
21446
22291
  }
21447
22292
  subscribeToGenerateContentChannel() {
21448
22293
  const tracingChannel2 = googleGenAIChannels.generateContent.tracingChannel();
@@ -21615,7 +22460,30 @@ var GoogleGenAIPlugin = class extends BasePlugin {
21615
22460
  tracingChannel2.unsubscribe(handlers);
21616
22461
  });
21617
22462
  }
22463
+ subscribeToInteractionsCreateChannel() {
22464
+ this.unsubscribers.push(
22465
+ traceStreamingChannel(
22466
+ googleGenAIChannels.interactionsCreate,
22467
+ {
22468
+ name: "create_interaction",
22469
+ shouldTrace: ([params]) => !isBackgroundInteractionCreate(params),
22470
+ type: "llm" /* LLM */,
22471
+ extractInput: ([params]) => ({
22472
+ input: serializeInteractionInput(params),
22473
+ metadata: extractInteractionMetadata(params)
22474
+ }),
22475
+ extractOutput: (result) => serializeInteractionValue(result),
22476
+ extractMetadata: (result) => extractInteractionResponseMetadata(result),
22477
+ extractMetrics: (result, startTime) => cleanMetrics3(extractInteractionMetrics(result, startTime)),
22478
+ aggregateChunks: (chunks, _result, _event, startTime) => aggregateInteractionEvents(chunks, startTime)
22479
+ }
22480
+ )
22481
+ );
22482
+ }
21618
22483
  };
22484
+ function isBackgroundInteractionCreate(params) {
22485
+ return tryToDict(params)?.background === true;
22486
+ }
21619
22487
  function ensureSpanState(states, event, create) {
21620
22488
  const existing = states.get(event);
21621
22489
  if (existing) {
@@ -21823,6 +22691,60 @@ function serializeEmbedContentInput(params) {
21823
22691
  }
21824
22692
  return input;
21825
22693
  }
22694
+ function serializeInteractionInput(params) {
22695
+ const input = {
22696
+ input: serializeInteractionValue(params.input)
22697
+ };
22698
+ for (const key of [
22699
+ "model",
22700
+ "agent",
22701
+ "agent_config",
22702
+ "api_version",
22703
+ "background",
22704
+ "environment",
22705
+ "generation_config",
22706
+ "previous_interaction_id",
22707
+ "response_format",
22708
+ "response_mime_type",
22709
+ "response_modalities",
22710
+ "service_tier",
22711
+ "store",
22712
+ "stream",
22713
+ "system_instruction",
22714
+ "webhook_config"
22715
+ ]) {
22716
+ const value = params[key];
22717
+ if (value !== void 0) {
22718
+ input[key] = serializeInteractionValue(value);
22719
+ }
22720
+ }
22721
+ return input;
22722
+ }
22723
+ function extractInteractionMetadata(params) {
22724
+ const metadata = {};
22725
+ for (const key of [
22726
+ "model",
22727
+ "agent",
22728
+ "agent_config",
22729
+ "generation_config",
22730
+ "system_instruction",
22731
+ "response_format",
22732
+ "response_mime_type",
22733
+ "response_modalities",
22734
+ "service_tier"
22735
+ ]) {
22736
+ const value = params[key];
22737
+ if (value !== void 0) {
22738
+ metadata[key] = serializeInteractionValue(value);
22739
+ }
22740
+ }
22741
+ if (Array.isArray(params.tools)) {
22742
+ metadata.tools = params.tools.map(
22743
+ (tool) => serializeInteractionValue(tool)
22744
+ );
22745
+ }
22746
+ return metadata;
22747
+ }
21826
22748
  function serializeContentCollection(contents) {
21827
22749
  if (contents === null || contents === void 0) {
21828
22750
  return null;
@@ -21853,21 +22775,8 @@ function serializePart(part) {
21853
22775
  }
21854
22776
  if (part.inlineData && part.inlineData.data) {
21855
22777
  const { data, mimeType } = part.inlineData;
21856
- if (data instanceof Uint8Array || typeof Buffer !== "undefined" && Buffer.isBuffer(data) || typeof data === "string") {
21857
- const extension = mimeType ? mimeType.split("/")[1] : "bin";
21858
- const filename = `file.${extension}`;
21859
- const buffer = typeof data === "string" ? typeof Buffer !== "undefined" ? Buffer.from(data, "base64") : new Uint8Array(
21860
- atob(data).split("").map((c) => c.charCodeAt(0))
21861
- ) : typeof Buffer !== "undefined" ? Buffer.from(data) : new Uint8Array(data);
21862
- const arrayBuffer = buffer instanceof Uint8Array ? buffer.buffer.slice(
21863
- buffer.byteOffset,
21864
- buffer.byteOffset + buffer.byteLength
21865
- ) : buffer;
21866
- const attachment = new Attachment({
21867
- data: arrayBuffer,
21868
- filename,
21869
- contentType: mimeType || "application/octet-stream"
21870
- });
22778
+ const attachment = createAttachmentFromInlineData(data, mimeType);
22779
+ if (attachment) {
21871
22780
  return {
21872
22781
  image_url: { url: attachment }
21873
22782
  };
@@ -21875,6 +22784,59 @@ function serializePart(part) {
21875
22784
  }
21876
22785
  return part;
21877
22786
  }
22787
+ function serializeInteractionValue(value, seen = /* @__PURE__ */ new WeakSet()) {
22788
+ if (value === null || value === void 0 || typeof value !== "object") {
22789
+ return value;
22790
+ }
22791
+ if (Array.isArray(value)) {
22792
+ return value.map((item) => serializeInteractionValue(item, seen));
22793
+ }
22794
+ const dict = tryToDict(value);
22795
+ if (dict === null || dict === void 0 || typeof dict !== "object") {
22796
+ return dict;
22797
+ }
22798
+ if (Array.isArray(dict)) {
22799
+ return dict.map((item) => serializeInteractionValue(item, seen));
22800
+ }
22801
+ if (seen.has(dict)) {
22802
+ return "[Circular]";
22803
+ }
22804
+ seen.add(dict);
22805
+ try {
22806
+ const serialized = {};
22807
+ 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;
22808
+ const attachment = mimeType && "data" in dict && dict.data !== void 0 ? createAttachmentFromInlineData(dict.data, mimeType) : null;
22809
+ for (const [key, entry] of Object.entries(dict)) {
22810
+ if (key === "data" && attachment) {
22811
+ serialized[key] = attachment;
22812
+ } else {
22813
+ serialized[key] = serializeInteractionValue(entry, seen);
22814
+ }
22815
+ }
22816
+ return serialized;
22817
+ } finally {
22818
+ seen.delete(dict);
22819
+ }
22820
+ }
22821
+ function createAttachmentFromInlineData(data, mimeType) {
22822
+ if (!(data instanceof Uint8Array || typeof Buffer !== "undefined" && Buffer.isBuffer(data) || typeof data === "string")) {
22823
+ return null;
22824
+ }
22825
+ const extension = mimeType ? mimeType.split("/")[1] : "bin";
22826
+ const filename = `file.${extension}`;
22827
+ const buffer = typeof data === "string" ? typeof Buffer !== "undefined" ? Buffer.from(data, "base64") : new Uint8Array(
22828
+ atob(data).split("").map((c) => c.charCodeAt(0))
22829
+ ) : typeof Buffer !== "undefined" ? Buffer.from(data) : new Uint8Array(data);
22830
+ const arrayBuffer = buffer instanceof Uint8Array ? buffer.buffer.slice(
22831
+ buffer.byteOffset,
22832
+ buffer.byteOffset + buffer.byteLength
22833
+ ) : buffer;
22834
+ return new Attachment({
22835
+ data: arrayBuffer,
22836
+ filename,
22837
+ contentType: mimeType || "application/octet-stream"
22838
+ });
22839
+ }
21878
22840
  function serializeGenerateContentTools(params) {
21879
22841
  const config3 = params.config ? tryToDict(params.config) : null;
21880
22842
  const tools = config3?.tools;
@@ -21959,6 +22921,33 @@ function extractEmbedContentMetrics(response, startTime) {
21959
22921
  }
21960
22922
  return metrics;
21961
22923
  }
22924
+ function extractInteractionMetrics(response, startTime) {
22925
+ const metrics = {};
22926
+ if (startTime !== void 0) {
22927
+ const end = getCurrentUnixTimestamp();
22928
+ metrics.start = startTime;
22929
+ metrics.end = end;
22930
+ metrics.duration = end - startTime;
22931
+ }
22932
+ if (response?.usage) {
22933
+ populateInteractionUsageMetrics(metrics, response.usage);
22934
+ }
22935
+ return metrics;
22936
+ }
22937
+ function extractInteractionResponseMetadata(response) {
22938
+ const responseDict = tryToDict(response);
22939
+ if (!responseDict) {
22940
+ return void 0;
22941
+ }
22942
+ const metadata = {};
22943
+ if (typeof responseDict.id === "string") {
22944
+ metadata.interaction_id = responseDict.id;
22945
+ }
22946
+ if (typeof responseDict.status === "string") {
22947
+ metadata.status = responseDict.status;
22948
+ }
22949
+ return Object.keys(metadata).length > 0 ? metadata : void 0;
22950
+ }
21962
22951
  function extractEmbedPromptTokenCount(response) {
21963
22952
  if (!response) {
21964
22953
  return void 0;
@@ -22021,6 +23010,23 @@ function populateUsageMetrics(metrics, usage) {
22021
23010
  metrics.completion_reasoning_tokens = usage.thoughtsTokenCount;
22022
23011
  }
22023
23012
  }
23013
+ function populateInteractionUsageMetrics(metrics, usage) {
23014
+ if (typeof usage.total_input_tokens === "number") {
23015
+ metrics.prompt_tokens = usage.total_input_tokens;
23016
+ }
23017
+ if (typeof usage.total_output_tokens === "number") {
23018
+ metrics.completion_tokens = usage.total_output_tokens;
23019
+ }
23020
+ if (typeof usage.total_tokens === "number") {
23021
+ metrics.tokens = usage.total_tokens;
23022
+ }
23023
+ if (typeof usage.total_cached_tokens === "number") {
23024
+ metrics.prompt_cached_tokens = usage.total_cached_tokens;
23025
+ }
23026
+ if (typeof usage.total_thought_tokens === "number") {
23027
+ metrics.completion_reasoning_tokens = usage.total_thought_tokens;
23028
+ }
23029
+ }
22024
23030
  function aggregateGenerateContentChunks(chunks, startTime, firstTokenTime) {
22025
23031
  const end = getCurrentUnixTimestamp();
22026
23032
  const metrics = {
@@ -22118,6 +23124,146 @@ function aggregateGenerateContentChunks(chunks, startTime, firstTokenTime) {
22118
23124
  }
22119
23125
  return { aggregated, metrics };
22120
23126
  }
23127
+ function aggregateInteractionEvents(chunks, startTime) {
23128
+ const end = getCurrentUnixTimestamp();
23129
+ const metrics = {};
23130
+ if (startTime !== void 0) {
23131
+ metrics.start = startTime;
23132
+ metrics.end = end;
23133
+ metrics.duration = end - startTime;
23134
+ }
23135
+ let latestInteraction;
23136
+ let latestUsage;
23137
+ let status;
23138
+ let outputText = "";
23139
+ const steps = /* @__PURE__ */ new Map();
23140
+ for (const chunk of chunks) {
23141
+ const event = tryToDict(chunk);
23142
+ if (!event) {
23143
+ continue;
23144
+ }
23145
+ const usage = extractInteractionUsageFromEvent(event);
23146
+ if (usage) {
23147
+ latestUsage = usage;
23148
+ }
23149
+ const interaction = tryToDict(event.interaction);
23150
+ if (interaction) {
23151
+ latestInteraction = serializeInteractionValue(interaction);
23152
+ if (typeof interaction.status === "string") {
23153
+ status = interaction.status;
23154
+ }
23155
+ }
23156
+ if (typeof event.status === "string") {
23157
+ status = event.status;
23158
+ }
23159
+ const index = typeof event.index === "number" ? event.index : void 0;
23160
+ if (index === void 0) {
23161
+ continue;
23162
+ }
23163
+ if (event.event_type === "step.start") {
23164
+ const compact = compactInteractionStep(event.step);
23165
+ compact.index = index;
23166
+ steps.set(index, compact);
23167
+ continue;
23168
+ }
23169
+ if (event.event_type === "step.delta") {
23170
+ const step = steps.get(index) ?? { index };
23171
+ const textDelta = applyInteractionDelta(step, event.delta);
23172
+ if (textDelta) {
23173
+ outputText += textDelta;
23174
+ }
23175
+ steps.set(index, step);
23176
+ }
23177
+ }
23178
+ if (latestUsage) {
23179
+ populateInteractionUsageMetrics(metrics, latestUsage);
23180
+ }
23181
+ const output = latestInteraction ? { ...latestInteraction } : {};
23182
+ if (status) {
23183
+ output.status = status;
23184
+ }
23185
+ if (outputText) {
23186
+ output.output_text = outputText;
23187
+ }
23188
+ if (latestUsage) {
23189
+ output.usage = serializeInteractionValue(latestUsage);
23190
+ }
23191
+ const compactSteps = Array.from(steps.values()).sort(
23192
+ (left, right) => Number(left.index ?? 0) - Number(right.index ?? 0)
23193
+ );
23194
+ if (compactSteps.length > 0) {
23195
+ output.steps = compactSteps;
23196
+ }
23197
+ const metadata = {};
23198
+ if (typeof output.id === "string") {
23199
+ metadata.interaction_id = output.id;
23200
+ }
23201
+ if (typeof output.status === "string") {
23202
+ metadata.status = output.status;
23203
+ }
23204
+ return {
23205
+ output,
23206
+ metrics: cleanMetrics3(metrics),
23207
+ ...Object.keys(metadata).length > 0 ? { metadata } : {}
23208
+ };
23209
+ }
23210
+ function extractInteractionUsageFromEvent(event) {
23211
+ const metadata = tryToDict(event.metadata);
23212
+ const metadataUsage = tryToDict(metadata?.usage);
23213
+ if (metadataUsage) {
23214
+ return metadataUsage;
23215
+ }
23216
+ const metadataTotalUsage = tryToDict(metadata?.total_usage);
23217
+ if (metadataTotalUsage) {
23218
+ return metadataTotalUsage;
23219
+ }
23220
+ const interaction = tryToDict(event.interaction);
23221
+ const interactionUsage = tryToDict(interaction?.usage);
23222
+ return interactionUsage ? interactionUsage : void 0;
23223
+ }
23224
+ function compactInteractionStep(step) {
23225
+ const stepDict = tryToDict(step);
23226
+ if (!stepDict) {
23227
+ return {};
23228
+ }
23229
+ const compact = {};
23230
+ for (const key of [
23231
+ "type",
23232
+ "content",
23233
+ "name",
23234
+ "server_name",
23235
+ "arguments",
23236
+ "result",
23237
+ "is_error"
23238
+ ]) {
23239
+ if (stepDict[key] !== void 0) {
23240
+ compact[key] = serializeInteractionValue(stepDict[key]);
23241
+ }
23242
+ }
23243
+ return Object.keys(compact).length > 0 ? compact : serializeInteractionValue(stepDict);
23244
+ }
23245
+ function applyInteractionDelta(step, delta) {
23246
+ const deltaDict = tryToDict(delta);
23247
+ if (!deltaDict) {
23248
+ return void 0;
23249
+ }
23250
+ const deltaType = deltaDict.type;
23251
+ if (typeof deltaType === "string" && typeof step.type !== "string") {
23252
+ step.type = deltaType === "text" ? "model_output" : deltaType;
23253
+ }
23254
+ if (deltaType === "text" && typeof deltaDict.text === "string") {
23255
+ step.text = `${typeof step.text === "string" ? step.text : ""}${deltaDict.text}`;
23256
+ return deltaDict.text;
23257
+ }
23258
+ if (deltaType === "arguments_delta" && typeof deltaDict.arguments === "string") {
23259
+ step.arguments = `${typeof step.arguments === "string" ? step.arguments : ""}${deltaDict.arguments}`;
23260
+ return void 0;
23261
+ }
23262
+ const deltas = Array.isArray(step.deltas) ? step.deltas : [];
23263
+ deltas.push(serializeInteractionValue(deltaDict));
23264
+ step.deltas = deltas;
23265
+ return void 0;
23266
+ }
22121
23267
  function cleanMetrics3(metrics) {
22122
23268
  const cleaned = {};
22123
23269
  for (const [key, value] of Object.entries(metrics)) {
@@ -27944,7 +29090,8 @@ var FlueObserveBridge = class {
27944
29090
  metadata
27945
29091
  }
27946
29092
  });
27947
- this.runsById.set(event.runId, { metadata, span });
29093
+ const activeContext = enterCurrentFlueSpan(span);
29094
+ this.runsById.set(event.runId, { activeContext, metadata, span });
27948
29095
  }
27949
29096
  handleRunEnd(event) {
27950
29097
  const state = this.runsById.get(event.runId);
@@ -27962,6 +29109,7 @@ var FlueObserveBridge = class {
27962
29109
  });
27963
29110
  safeEnd(state.span, eventTime(event.timestamp));
27964
29111
  this.runsById.delete(event.runId);
29112
+ restoreCurrentFlueSpan(state.activeContext);
27965
29113
  }
27966
29114
  void flush().catch((error2) => {
27967
29115
  logInstrumentationError3("Flue flush", error2);
@@ -28088,7 +29236,8 @@ var FlueObserveBridge = class {
28088
29236
  metadata
28089
29237
  }
28090
29238
  });
28091
- this.toolsByKey.set(toolKey(event), { metadata, span });
29239
+ const activeContext = enterCurrentFlueSpan(span);
29240
+ this.toolsByKey.set(toolKey(event), { activeContext, metadata, span });
28092
29241
  }
28093
29242
  handleToolCall(event) {
28094
29243
  if (!event.toolCallId) {
@@ -28111,6 +29260,7 @@ var FlueObserveBridge = class {
28111
29260
  });
28112
29261
  safeEnd(state.span, eventTime(event.timestamp));
28113
29262
  this.toolsByKey.delete(key);
29263
+ restoreCurrentFlueSpan(state.activeContext);
28114
29264
  }
28115
29265
  handleTaskStart(event) {
28116
29266
  if (!event.taskId) {
@@ -28515,9 +29665,37 @@ function stateMatchesRun(state, runId) {
28515
29665
  function startFlueSpan(parent, args) {
28516
29666
  return parent ? withCurrent(parent, () => startSpan(args)) : startSpan(args);
28517
29667
  }
28518
- function safeLog3(span, event) {
29668
+ function enterCurrentFlueSpan(span) {
29669
+ const contextManager = _internalGetGlobalState()?.contextManager;
29670
+ const store = contextManager ? Reflect.get(contextManager, BRAINTRUST_CURRENT_SPAN_STORE) : void 0;
29671
+ if (!contextManager || !isCurrentSpanStore(store)) {
29672
+ return void 0;
29673
+ }
29674
+ const previous = store.getStore();
28519
29675
  try {
28520
- span.log(event);
29676
+ store.enterWith(contextManager.wrapSpanForStore(span));
29677
+ return { previous, store };
29678
+ } catch (error2) {
29679
+ logInstrumentationError3("Flue context propagation", error2);
29680
+ return void 0;
29681
+ }
29682
+ }
29683
+ function isCurrentSpanStore(value) {
29684
+ return isObjectLike(value) && typeof Reflect.get(value, "enterWith") === "function" && typeof Reflect.get(value, "getStore") === "function";
29685
+ }
29686
+ function restoreCurrentFlueSpan(activeContext) {
29687
+ if (!activeContext) {
29688
+ return;
29689
+ }
29690
+ try {
29691
+ activeContext.store.enterWith(activeContext.previous);
29692
+ } catch (error2) {
29693
+ logInstrumentationError3("Flue context restoration", error2);
29694
+ }
29695
+ }
29696
+ function safeLog3(span, event) {
29697
+ try {
29698
+ span.log(event);
28521
29699
  } catch (error2) {
28522
29700
  logInstrumentationError3("Flue span log", error2);
28523
29701
  }
@@ -28992,6 +30170,890 @@ function isBraintrustHandler(handler) {
28992
30170
  return Reflect.get(handler, "name") === BRAINTRUST_LANGCHAIN_CALLBACK_HANDLER_NAME;
28993
30171
  }
28994
30172
 
30173
+ // src/instrumentation/plugins/pi-coding-agent-channels.ts
30174
+ var piCodingAgentChannels = defineChannels(
30175
+ "@earendil-works/pi-coding-agent",
30176
+ {
30177
+ prompt: channel({
30178
+ channelName: "AgentSession.prompt",
30179
+ kind: "async"
30180
+ })
30181
+ }
30182
+ );
30183
+
30184
+ // src/instrumentation/plugins/pi-coding-agent-plugin.ts
30185
+ var piStreamPatchStates = /* @__PURE__ */ new WeakMap();
30186
+ var piPromptContextStore;
30187
+ var PiCodingAgentPlugin = class extends BasePlugin {
30188
+ activePromptStates = /* @__PURE__ */ new Set();
30189
+ onEnable() {
30190
+ this.subscribeToPrompt();
30191
+ }
30192
+ onDisable() {
30193
+ for (const unsubscribe of this.unsubscribers) {
30194
+ unsubscribe();
30195
+ }
30196
+ this.unsubscribers = [];
30197
+ for (const state of [...this.activePromptStates]) {
30198
+ void finalizePiPromptRun(state).catch((error2) => {
30199
+ logInstrumentationError4("Pi Coding Agent disable cleanup", error2);
30200
+ });
30201
+ }
30202
+ }
30203
+ subscribeToPrompt() {
30204
+ const channel2 = piCodingAgentChannels.prompt.tracingChannel();
30205
+ const states = /* @__PURE__ */ new WeakMap();
30206
+ const unbindAutoInstrumentationSuppression = bindAutoInstrumentationSuppressionToStart(channel2);
30207
+ const handlers = {
30208
+ start: (event) => {
30209
+ const state = startPiPromptRun(event, (state2) => {
30210
+ this.activePromptStates.delete(state2);
30211
+ });
30212
+ if (state) {
30213
+ this.activePromptStates.add(state);
30214
+ states.set(event, state);
30215
+ }
30216
+ },
30217
+ asyncEnd: async (event) => {
30218
+ const state = states.get(event);
30219
+ if (!state) {
30220
+ return;
30221
+ }
30222
+ states.delete(event);
30223
+ state.promptCallEnded = true;
30224
+ if (!state.finalized && state.deferCompletionUntilTurnEnd && !state.turnEnded) {
30225
+ if (!state.sawStreamFn) {
30226
+ state.queued = true;
30227
+ if (!state.streamPatchState.queuedPromptStates.includes(state)) {
30228
+ state.streamPatchState.queuedPromptStates.push(state);
30229
+ }
30230
+ }
30231
+ return;
30232
+ }
30233
+ await finalizePiPromptRun(state);
30234
+ },
30235
+ error: async (event) => {
30236
+ const state = states.get(event);
30237
+ if (!state) {
30238
+ return;
30239
+ }
30240
+ states.delete(event);
30241
+ await finalizePiPromptRun(state, event.error);
30242
+ }
30243
+ };
30244
+ channel2.subscribe(handlers);
30245
+ this.unsubscribers.push(() => {
30246
+ unbindAutoInstrumentationSuppression?.();
30247
+ channel2.unsubscribe(handlers);
30248
+ });
30249
+ }
30250
+ };
30251
+ function startPiPromptRun(event, onFinalize) {
30252
+ const session = extractSession(event);
30253
+ const agent = session?.agent;
30254
+ if (!session || !isPiAgent(agent)) {
30255
+ return void 0;
30256
+ }
30257
+ const metadata = {
30258
+ ...extractSessionMetadata(session),
30259
+ ...extractPromptOptionsMetadata(event.arguments[1]),
30260
+ "pi_coding_agent.operation": "AgentSession.prompt",
30261
+ provider: session.model?.provider ?? agent.state?.model?.provider ?? "pi",
30262
+ ...session.model?.id || agent.state?.model?.id ? { model: session.model?.id ?? agent.state?.model?.id } : {},
30263
+ ...event.moduleVersion ? { "pi_coding_agent.version": event.moduleVersion } : {}
30264
+ };
30265
+ const span = startSpan({
30266
+ event: {
30267
+ input: extractPromptInput(event.arguments[0], event.arguments[1]),
30268
+ metadata
30269
+ },
30270
+ name: "AgentSession.prompt",
30271
+ spanAttributes: { type: "task" /* TASK */ }
30272
+ });
30273
+ const streamPatchState = installPiStreamPatch(agent);
30274
+ const options = event.arguments[1];
30275
+ const promptText = event.arguments[0];
30276
+ const state = {
30277
+ activeLlmSpans: /* @__PURE__ */ new Set(),
30278
+ activeToolSpans: /* @__PURE__ */ new Map(),
30279
+ agent,
30280
+ collectedLlmUsageMetrics: false,
30281
+ deferCompletionUntilTurnEnd: options?.streamingBehavior === "followUp" || options?.streamingBehavior === "steer",
30282
+ finalized: false,
30283
+ metadata,
30284
+ metrics: {},
30285
+ onFinalize,
30286
+ promptCallEnded: false,
30287
+ ...typeof promptText === "string" ? { promptText } : {},
30288
+ queued: false,
30289
+ span,
30290
+ sawStreamFn: false,
30291
+ startTime: getCurrentUnixTimestamp(),
30292
+ streamPatchState,
30293
+ turnEnded: false
30294
+ };
30295
+ state.restorePromptContext = enterPiPromptContext(state);
30296
+ streamPatchState.activePromptStates.add(state);
30297
+ try {
30298
+ state.unsubscribeAgent = agent.subscribe(async (agentEvent) => {
30299
+ try {
30300
+ await runWithAutoInstrumentationSuppressed(
30301
+ () => handlePiAgentEvent(state, agentEvent)
30302
+ );
30303
+ } catch (error2) {
30304
+ logInstrumentationError4("Pi Coding Agent event", error2);
30305
+ }
30306
+ });
30307
+ } catch (error2) {
30308
+ logInstrumentationError4("Pi Coding Agent event subscription", error2);
30309
+ }
30310
+ return state;
30311
+ }
30312
+ function extractSession(event) {
30313
+ const candidate = event.session ?? event.self;
30314
+ return isObject(candidate) && typeof candidate.prompt === "function" ? candidate : void 0;
30315
+ }
30316
+ function isPiAgent(value) {
30317
+ return isObject(value) && typeof value.streamFn === "function" && typeof value.subscribe === "function";
30318
+ }
30319
+ function promptContextStore() {
30320
+ piPromptContextStore ??= isomorph_default.newAsyncLocalStorage();
30321
+ return piPromptContextStore;
30322
+ }
30323
+ function currentPromptContextFrames() {
30324
+ return promptContextStore().getStore()?.frames ?? [];
30325
+ }
30326
+ function currentPiPromptState() {
30327
+ const frames = currentPromptContextFrames();
30328
+ return frames[frames.length - 1]?.state;
30329
+ }
30330
+ function enterPiPromptContext(state) {
30331
+ const frame = {
30332
+ id: /* @__PURE__ */ Symbol("braintrust.pi-coding-agent.prompt"),
30333
+ state
30334
+ };
30335
+ promptContextStore().enterWith({
30336
+ frames: [...currentPromptContextFrames(), frame]
30337
+ });
30338
+ return () => {
30339
+ const frames = currentPromptContextFrames().filter(
30340
+ (candidate) => candidate.id !== frame.id
30341
+ );
30342
+ promptContextStore().enterWith(frames.length > 0 ? { frames } : void 0);
30343
+ };
30344
+ }
30345
+ function installPiStreamPatch(agent) {
30346
+ const existing = piStreamPatchStates.get(agent);
30347
+ if (existing) {
30348
+ if (agent.streamFn !== existing.wrappedStreamFn) {
30349
+ debugLogger.debug(
30350
+ "Pi Coding Agent streamFn changed while Braintrust instrumentation was active; preserving existing patch state."
30351
+ );
30352
+ }
30353
+ return existing;
30354
+ }
30355
+ const patchState = {
30356
+ activePromptStates: /* @__PURE__ */ new Set(),
30357
+ agent,
30358
+ originalStreamFn: agent.streamFn,
30359
+ queuedPromptStates: [],
30360
+ wrappedStreamFn: agent.streamFn
30361
+ };
30362
+ patchState.wrappedStreamFn = makeSharedInstrumentedStreamFn(patchState);
30363
+ agent.streamFn = patchState.wrappedStreamFn;
30364
+ piStreamPatchStates.set(agent, patchState);
30365
+ return patchState;
30366
+ }
30367
+ function resolveStreamPromptState(patchState, context2) {
30368
+ let lastUserText;
30369
+ if (Array.isArray(context2.messages)) {
30370
+ for (let i = context2.messages.length - 1; i >= 0; i--) {
30371
+ const message = context2.messages[i];
30372
+ if (isPiUserMessage(message)) {
30373
+ if (typeof message.content === "string") {
30374
+ lastUserText = message.content;
30375
+ } else {
30376
+ lastUserText = message.content.flatMap((part) => part.type === "text" ? [part.text] : []).join("");
30377
+ }
30378
+ break;
30379
+ }
30380
+ }
30381
+ }
30382
+ if (lastUserText !== void 0) {
30383
+ const queuedMatch = patchState.queuedPromptStates.find(
30384
+ (state) => state.promptText === lastUserText
30385
+ );
30386
+ if (queuedMatch) {
30387
+ return queuedMatch;
30388
+ }
30389
+ const matches = [...patchState.activePromptStates].filter(
30390
+ (state) => state.promptText === lastUserText
30391
+ );
30392
+ if (matches.length === 1) {
30393
+ return matches[0];
30394
+ }
30395
+ }
30396
+ const contextState = currentPiPromptState();
30397
+ if (contextState && patchState.activePromptStates.has(contextState) && (!contextState.queued || lastUserText !== void 0 && contextState.promptText === lastUserText)) {
30398
+ return contextState;
30399
+ }
30400
+ if (patchState.activePromptStates.size === 1) {
30401
+ return [...patchState.activePromptStates][0];
30402
+ }
30403
+ return void 0;
30404
+ }
30405
+ function makeSharedInstrumentedStreamFn(patchState) {
30406
+ return async function instrumentedPiStreamFn(model, context2, options) {
30407
+ const state = resolveStreamPromptState(patchState, context2);
30408
+ if (!state) {
30409
+ const invokeOriginal = () => Reflect.apply(patchState.originalStreamFn, this, [
30410
+ model,
30411
+ context2,
30412
+ options
30413
+ ]);
30414
+ return patchState.activePromptStates.size > 0 ? runWithAutoInstrumentationSuppressed(invokeOriginal) : invokeOriginal();
30415
+ }
30416
+ state.sawStreamFn = true;
30417
+ removeQueuedPromptState(state);
30418
+ state.streamPatchState.eventPromptState = state;
30419
+ const llmState = await startPiLlmSpan(state, model, context2, options);
30420
+ try {
30421
+ const stream = await runWithAutoInstrumentationSuppressed(
30422
+ () => Reflect.apply(patchState.originalStreamFn, this, [
30423
+ model,
30424
+ context2,
30425
+ options
30426
+ ])
30427
+ );
30428
+ return patchAssistantMessageStream(stream, state, llmState);
30429
+ } catch (error2) {
30430
+ finishPiLlmSpan(state, llmState, void 0, error2);
30431
+ throw error2;
30432
+ }
30433
+ };
30434
+ }
30435
+ async function startPiLlmSpan(state, model, context2, options) {
30436
+ const metadata = {
30437
+ ...extractModelMetadata2(model),
30438
+ ...extractStreamOptionsMetadata(options),
30439
+ ...extractToolMetadata(context2.tools),
30440
+ "pi_coding_agent.operation": "agent.streamFn"
30441
+ };
30442
+ const span = startSpan({
30443
+ event: {
30444
+ input: processInputAttachments(normalizePiContextInput(context2)),
30445
+ metadata
30446
+ },
30447
+ name: getLlmSpanName(model),
30448
+ parent: await state.span.export(),
30449
+ spanAttributes: { type: "llm" /* LLM */ }
30450
+ });
30451
+ const llmState = {
30452
+ finalized: false,
30453
+ metadata,
30454
+ metrics: {},
30455
+ span,
30456
+ startTime: getCurrentUnixTimestamp()
30457
+ };
30458
+ state.activeLlmSpans.add(llmState);
30459
+ return llmState;
30460
+ }
30461
+ function patchAssistantMessageStream(stream, promptState, llmState) {
30462
+ if (!isObject(stream)) {
30463
+ return stream;
30464
+ }
30465
+ const streamRecord = stream;
30466
+ const originalResult = stream.result;
30467
+ if (typeof originalResult === "function") {
30468
+ streamRecord.result = function patchedPiResult() {
30469
+ return Promise.resolve(Reflect.apply(originalResult, this, [])).then(
30470
+ (message) => {
30471
+ finishPiLlmSpan(promptState, llmState, message);
30472
+ return message;
30473
+ },
30474
+ (error2) => {
30475
+ finishPiLlmSpan(promptState, llmState, void 0, error2);
30476
+ throw error2;
30477
+ }
30478
+ );
30479
+ };
30480
+ }
30481
+ const originalIterator = stream[Symbol.asyncIterator];
30482
+ if (typeof originalIterator === "function") {
30483
+ streamRecord[Symbol.asyncIterator] = function patchedPiIterator() {
30484
+ const iterator = Reflect.apply(
30485
+ originalIterator,
30486
+ this,
30487
+ []
30488
+ );
30489
+ return {
30490
+ async next() {
30491
+ try {
30492
+ const result = await iterator.next();
30493
+ if (result.done) {
30494
+ finishPiLlmSpan(promptState, llmState);
30495
+ return result;
30496
+ }
30497
+ recordPiAssistantMessageEvent(promptState, llmState, result.value);
30498
+ return result;
30499
+ } catch (error2) {
30500
+ finishPiLlmSpan(promptState, llmState, void 0, error2);
30501
+ if (typeof iterator.return === "function") {
30502
+ try {
30503
+ await iterator.return();
30504
+ } catch (cleanupError) {
30505
+ logInstrumentationError4(
30506
+ "Pi Coding Agent stream cleanup",
30507
+ cleanupError
30508
+ );
30509
+ }
30510
+ }
30511
+ throw error2;
30512
+ }
30513
+ },
30514
+ async return(value) {
30515
+ try {
30516
+ if (typeof iterator.return === "function") {
30517
+ return await iterator.return(value);
30518
+ }
30519
+ return {
30520
+ done: true,
30521
+ value
30522
+ };
30523
+ } catch (error2) {
30524
+ finishPiLlmSpan(promptState, llmState, void 0, error2);
30525
+ throw error2;
30526
+ } finally {
30527
+ finishPiLlmSpan(promptState, llmState);
30528
+ }
30529
+ },
30530
+ async throw(error2) {
30531
+ try {
30532
+ if (typeof iterator.throw === "function") {
30533
+ return await iterator.throw(error2);
30534
+ }
30535
+ throw error2;
30536
+ } catch (thrownError) {
30537
+ finishPiLlmSpan(promptState, llmState, void 0, thrownError);
30538
+ throw thrownError;
30539
+ }
30540
+ },
30541
+ [Symbol.asyncIterator]() {
30542
+ return this;
30543
+ }
30544
+ };
30545
+ };
30546
+ }
30547
+ return stream;
30548
+ }
30549
+ function recordPiAssistantMessageEvent(promptState, llmState, event) {
30550
+ recordFirstTokenMetric(llmState, event);
30551
+ const message = "message" in event ? event.message : void 0;
30552
+ const errorMessage2 = "error" in event ? event.error : void 0;
30553
+ if (event.type === "done" && isPiAssistantMessage(message)) {
30554
+ finishPiLlmSpan(promptState, llmState, message);
30555
+ } else if (event.type === "error" && isPiAssistantMessage(errorMessage2)) {
30556
+ finishPiLlmSpan(promptState, llmState, errorMessage2);
30557
+ }
30558
+ }
30559
+ function recordFirstTokenMetric(state, event) {
30560
+ if (state.metrics.time_to_first_token !== void 0 || event.type === "start") {
30561
+ return;
30562
+ }
30563
+ state.metrics.time_to_first_token = getCurrentUnixTimestamp() - state.startTime;
30564
+ }
30565
+ async function handlePiAgentEvent(state, event) {
30566
+ if (state.finalized) {
30567
+ return;
30568
+ }
30569
+ const eventPromptState = state.streamPatchState.eventPromptState;
30570
+ if (eventPromptState && eventPromptState !== state) {
30571
+ return;
30572
+ }
30573
+ if (!eventPromptState && (state.queued || state.streamPatchState.activePromptStates.size > 1 && currentPiPromptState() !== state)) {
30574
+ return;
30575
+ }
30576
+ switch (event.type) {
30577
+ case "message_end":
30578
+ if (isPiAssistantMessage(event.message)) {
30579
+ state.output = extractAssistantOutput(event.message);
30580
+ }
30581
+ return;
30582
+ case "turn_end":
30583
+ state.turnEnded = true;
30584
+ if (isPiAssistantMessage(event.message)) {
30585
+ state.output = extractAssistantOutput(event.message);
30586
+ if (!state.collectedLlmUsageMetrics) {
30587
+ addMetrics(state.metrics, extractUsageMetrics2(event.message.usage));
30588
+ }
30589
+ }
30590
+ if (state.streamPatchState.eventPromptState === state) {
30591
+ state.streamPatchState.eventPromptState = void 0;
30592
+ }
30593
+ if (state.promptCallEnded && state.deferCompletionUntilTurnEnd) {
30594
+ await finalizePiPromptRun(state);
30595
+ }
30596
+ return;
30597
+ case "tool_execution_start":
30598
+ await startPiToolSpan(state, event);
30599
+ return;
30600
+ case "tool_execution_end":
30601
+ finishPiToolSpan(state, event);
30602
+ return;
30603
+ default:
30604
+ return;
30605
+ }
30606
+ }
30607
+ async function startPiToolSpan(state, event) {
30608
+ if (!event.toolCallId || state.activeToolSpans.has(event.toolCallId)) {
30609
+ return;
30610
+ }
30611
+ const restoreAutoInstrumentation = enterAutoInstrumentationAllowed();
30612
+ const metadata = {
30613
+ "gen_ai.tool.call.id": event.toolCallId,
30614
+ "gen_ai.tool.name": event.toolName,
30615
+ "pi_coding_agent.tool.name": event.toolName
30616
+ };
30617
+ try {
30618
+ const span = startSpan({
30619
+ event: {
30620
+ input: event.args,
30621
+ metadata
30622
+ },
30623
+ name: event.toolName || "tool",
30624
+ parent: await state.span.export(),
30625
+ spanAttributes: { type: "tool" /* TOOL */ }
30626
+ });
30627
+ state.activeToolSpans.set(event.toolCallId, {
30628
+ restoreAutoInstrumentation,
30629
+ span
30630
+ });
30631
+ } catch (error2) {
30632
+ restoreAutoInstrumentation();
30633
+ throw error2;
30634
+ }
30635
+ }
30636
+ function finishPiToolSpan(state, event) {
30637
+ const toolState = state.activeToolSpans.get(event.toolCallId);
30638
+ if (!toolState) {
30639
+ return;
30640
+ }
30641
+ state.activeToolSpans.delete(event.toolCallId);
30642
+ const metadata = {
30643
+ "gen_ai.tool.call.id": event.toolCallId,
30644
+ "gen_ai.tool.name": event.toolName,
30645
+ "pi_coding_agent.tool.name": event.toolName,
30646
+ "pi_coding_agent.tool.is_error": event.isError
30647
+ };
30648
+ try {
30649
+ safeLog4(toolState.span, {
30650
+ ...event.isError ? { error: stringifyUnknown2(event.result) } : {},
30651
+ metadata,
30652
+ output: event.result
30653
+ });
30654
+ } finally {
30655
+ try {
30656
+ toolState.span.end();
30657
+ } finally {
30658
+ toolState.restoreAutoInstrumentation?.();
30659
+ }
30660
+ }
30661
+ }
30662
+ async function finalizePiPromptRun(state, error2) {
30663
+ if (state.finalized) {
30664
+ return;
30665
+ }
30666
+ state.finalized = true;
30667
+ state.onFinalize?.(state);
30668
+ restorePiStreamFn(state);
30669
+ try {
30670
+ state.unsubscribeAgent?.();
30671
+ } catch (unsubscribeError) {
30672
+ logInstrumentationError4("Pi Coding Agent unsubscribe", unsubscribeError);
30673
+ }
30674
+ await finishOpenLlmSpans(state, error2);
30675
+ finishOpenToolSpans(state, error2);
30676
+ const metadata = {
30677
+ ...state.metadata,
30678
+ ...extractModelMetadata2(state.agent.state?.model)
30679
+ };
30680
+ try {
30681
+ safeLog4(state.span, {
30682
+ ...error2 ? { error: stringifyUnknown2(error2) } : {},
30683
+ metadata,
30684
+ metrics: {
30685
+ ...cleanMetrics5(state.metrics),
30686
+ ...buildDurationMetrics3(state.startTime)
30687
+ },
30688
+ output: state.output
30689
+ });
30690
+ } finally {
30691
+ state.span.end();
30692
+ }
30693
+ }
30694
+ function restorePiStreamFn(state) {
30695
+ const patchState = state.streamPatchState;
30696
+ patchState.activePromptStates.delete(state);
30697
+ removeQueuedPromptState(state);
30698
+ if (patchState.eventPromptState === state) {
30699
+ patchState.eventPromptState = void 0;
30700
+ }
30701
+ state.restorePromptContext?.();
30702
+ if (patchState.activePromptStates.size > 0) {
30703
+ return;
30704
+ }
30705
+ if (patchState.agent.streamFn === patchState.wrappedStreamFn) {
30706
+ patchState.agent.streamFn = patchState.originalStreamFn;
30707
+ }
30708
+ piStreamPatchStates.delete(patchState.agent);
30709
+ }
30710
+ function removeQueuedPromptState(state) {
30711
+ state.queued = false;
30712
+ const queuedPromptStates = state.streamPatchState.queuedPromptStates;
30713
+ const index = queuedPromptStates.indexOf(state);
30714
+ if (index >= 0) {
30715
+ queuedPromptStates.splice(index, 1);
30716
+ }
30717
+ }
30718
+ async function finishOpenLlmSpans(state, error2) {
30719
+ for (const llmState of [...state.activeLlmSpans]) {
30720
+ finishPiLlmSpan(state, llmState, void 0, error2);
30721
+ }
30722
+ }
30723
+ function finishPiLlmSpan(promptState, llmState, message, error2) {
30724
+ if (llmState.finalized) {
30725
+ return;
30726
+ }
30727
+ llmState.finalized = true;
30728
+ promptState.activeLlmSpans.delete(llmState);
30729
+ const messageError = message?.stopReason === "error" && message.errorMessage;
30730
+ const metrics = {
30731
+ ...extractUsageMetrics2(message?.usage),
30732
+ ...cleanMetrics5(llmState.metrics),
30733
+ ...buildDurationMetrics3(llmState.startTime)
30734
+ };
30735
+ const usageMetrics = extractUsageMetrics2(message?.usage);
30736
+ if (Object.keys(usageMetrics).length > 0) {
30737
+ promptState.collectedLlmUsageMetrics = true;
30738
+ addMetrics(promptState.metrics, usageMetrics);
30739
+ }
30740
+ try {
30741
+ safeLog4(llmState.span, {
30742
+ ...error2 || messageError ? { error: stringifyUnknown2(error2 ?? messageError) } : {},
30743
+ metadata: {
30744
+ ...llmState.metadata,
30745
+ ...message ? extractAssistantMetadata(message) : {}
30746
+ },
30747
+ metrics,
30748
+ ...message ? { output: extractAssistantOutput(message) } : {}
30749
+ });
30750
+ } finally {
30751
+ llmState.span.end();
30752
+ }
30753
+ }
30754
+ function finishOpenToolSpans(state, error2) {
30755
+ for (const [, toolState] of state.activeToolSpans) {
30756
+ try {
30757
+ safeLog4(toolState.span, {
30758
+ error: error2 ? stringifyUnknown2(error2) : "Pi tool did not complete"
30759
+ });
30760
+ toolState.span.end();
30761
+ } finally {
30762
+ toolState.restoreAutoInstrumentation?.();
30763
+ }
30764
+ }
30765
+ state.activeToolSpans.clear();
30766
+ }
30767
+ function normalizePiContextInput(context2) {
30768
+ const messages = context2.messages.flatMap(
30769
+ (message) => normalizePiMessage(message)
30770
+ );
30771
+ if (context2.systemPrompt) {
30772
+ return [{ role: "system", content: context2.systemPrompt }, ...messages];
30773
+ }
30774
+ return messages;
30775
+ }
30776
+ function normalizePiMessage(message) {
30777
+ if (isPiUserMessage(message)) {
30778
+ return [
30779
+ {
30780
+ role: "user",
30781
+ content: normalizeUserContent(message.content)
30782
+ }
30783
+ ];
30784
+ }
30785
+ if (isPiAssistantMessage(message)) {
30786
+ return [normalizeAssistantMessage(message)];
30787
+ }
30788
+ if (isPiToolResultMessage(message)) {
30789
+ return [normalizeToolResultMessage(message)];
30790
+ }
30791
+ return [];
30792
+ }
30793
+ function normalizeAssistantMessage(message) {
30794
+ const text = message.content.flatMap((part) => part.type === "text" ? [part.text] : []).join("");
30795
+ const thinking = message.content.flatMap(
30796
+ (part) => part.type === "thinking" && !part.redacted ? [part.thinking] : []
30797
+ ).join("");
30798
+ const toolCalls = message.content.flatMap(
30799
+ (part) => part.type === "toolCall" ? [normalizeToolCall(part)] : []
30800
+ );
30801
+ return {
30802
+ role: "assistant",
30803
+ content: text || (toolCalls.length > 0 ? null : ""),
30804
+ ...thinking ? { reasoning: thinking } : {},
30805
+ ...toolCalls.length > 0 ? { tool_calls: toolCalls } : {}
30806
+ };
30807
+ }
30808
+ function normalizeToolResultMessage(message) {
30809
+ return {
30810
+ role: "tool",
30811
+ tool_call_id: message.toolCallId,
30812
+ content: normalizeUserContent(message.content)
30813
+ };
30814
+ }
30815
+ function normalizeUserContent(content) {
30816
+ if (typeof content === "string") {
30817
+ return content;
30818
+ }
30819
+ return content.map((part) => {
30820
+ if (part.type === "text") {
30821
+ return { type: "text", text: part.text };
30822
+ }
30823
+ if (part.type === "image") {
30824
+ return {
30825
+ type: "image_url",
30826
+ image_url: {
30827
+ url: `data:${part.mimeType};base64,${part.data}`
30828
+ }
30829
+ };
30830
+ }
30831
+ return part;
30832
+ });
30833
+ }
30834
+ function normalizeToolCall(toolCall) {
30835
+ return {
30836
+ id: toolCall.id,
30837
+ type: "function",
30838
+ function: {
30839
+ name: toolCall.name,
30840
+ arguments: stringifyArguments(toolCall.arguments)
30841
+ }
30842
+ };
30843
+ }
30844
+ function extractAssistantOutput(message) {
30845
+ return processInputAttachments([
30846
+ {
30847
+ finish_reason: normalizeStopReason(message.stopReason),
30848
+ index: 0,
30849
+ message: normalizeAssistantMessage(message)
30850
+ }
30851
+ ]);
30852
+ }
30853
+ function isPiUserMessage(message) {
30854
+ return message.role === "user" && "content" in message;
30855
+ }
30856
+ function isPiAssistantMessage(message) {
30857
+ return isObject(message) && message.role === "assistant" && Array.isArray(message.content);
30858
+ }
30859
+ function isPiToolResultMessage(message) {
30860
+ return message.role === "toolResult" && Array.isArray(message.content);
30861
+ }
30862
+ function normalizeStopReason(reason) {
30863
+ switch (reason) {
30864
+ case "toolUse":
30865
+ return "tool_calls";
30866
+ case "length":
30867
+ case "stop":
30868
+ return reason;
30869
+ default:
30870
+ return reason ?? "stop";
30871
+ }
30872
+ }
30873
+ function extractPromptInput(text, options) {
30874
+ const images = options?.images;
30875
+ if (!images || images.length === 0) {
30876
+ return text;
30877
+ }
30878
+ return processInputAttachments([
30879
+ {
30880
+ role: "user",
30881
+ content: [
30882
+ { type: "text", text: text ?? "" },
30883
+ ...images.map((image) => ({
30884
+ type: "image_url",
30885
+ image_url: {
30886
+ url: `data:${image.mimeType};base64,${image.data}`
30887
+ }
30888
+ }))
30889
+ ]
30890
+ }
30891
+ ]);
30892
+ }
30893
+ function extractToolMetadata(tools) {
30894
+ if (!tools || tools.length === 0) {
30895
+ return {};
30896
+ }
30897
+ return {
30898
+ tools: tools.map((tool) => ({
30899
+ type: "function",
30900
+ function: {
30901
+ name: tool.name,
30902
+ ...tool.description ? { description: tool.description } : {},
30903
+ ...tool.parameters ? { parameters: tool.parameters } : {}
30904
+ }
30905
+ }))
30906
+ };
30907
+ }
30908
+ function extractModelMetadata2(model) {
30909
+ if (!model) {
30910
+ return {};
30911
+ }
30912
+ return {
30913
+ ...model.provider ? { provider: model.provider } : {},
30914
+ ...model.id ? { model: model.id, "pi_coding_agent.model": model.id } : {},
30915
+ ...model.api ? { "pi_coding_agent.api": model.api } : {},
30916
+ ...model.name ? { "pi_coding_agent.model_name": model.name } : {}
30917
+ };
30918
+ }
30919
+ function extractAssistantMetadata(message) {
30920
+ return {
30921
+ ...message.provider ? { provider: message.provider } : {},
30922
+ ...message.responseModel || message.model ? { model: message.responseModel ?? message.model } : {},
30923
+ ...message.api ? { "pi_coding_agent.api": message.api } : {},
30924
+ ...message.model ? { "pi_coding_agent.model": message.model } : {},
30925
+ ...message.responseModel ? { "pi_coding_agent.response_model": message.responseModel } : {},
30926
+ ...message.responseId ? { "pi_coding_agent.response_id": message.responseId } : {},
30927
+ ...message.stopReason ? { "pi_coding_agent.stop_reason": message.stopReason } : {}
30928
+ };
30929
+ }
30930
+ function extractSessionMetadata(session) {
30931
+ return {
30932
+ ...extractModelMetadata2(session.model),
30933
+ ...session.sessionId ? { "pi_coding_agent.session_id": session.sessionId } : {},
30934
+ ...session.sessionName ? { "pi_coding_agent.session_name": session.sessionName } : {},
30935
+ ...session.thinkingLevel ? { "pi_coding_agent.thinking_level": session.thinkingLevel } : {},
30936
+ ...typeof session.getActiveToolNames === "function" ? { "pi_coding_agent.active_tools": session.getActiveToolNames() } : {}
30937
+ };
30938
+ }
30939
+ function extractPromptOptionsMetadata(options) {
30940
+ if (!options) {
30941
+ return {};
30942
+ }
30943
+ return {
30944
+ ...options.source ? { "pi_coding_agent.source": options.source } : {},
30945
+ ...options.streamingBehavior ? { "pi_coding_agent.streaming_behavior": options.streamingBehavior } : {},
30946
+ ...options.expandPromptTemplates !== void 0 ? {
30947
+ "pi_coding_agent.expand_prompt_templates": options.expandPromptTemplates
30948
+ } : {}
30949
+ };
30950
+ }
30951
+ function extractStreamOptionsMetadata(options) {
30952
+ if (!options) {
30953
+ return {};
30954
+ }
30955
+ return {
30956
+ ...options.temperature !== void 0 ? { temperature: options.temperature } : {},
30957
+ ...options.maxTokens !== void 0 ? { max_tokens: options.maxTokens } : {},
30958
+ ...options.reasoning ? { "pi_coding_agent.reasoning": options.reasoning } : {},
30959
+ ...options.transport ? { "pi_coding_agent.transport": options.transport } : {},
30960
+ ...options.cacheRetention ? { "pi_coding_agent.cache_retention": options.cacheRetention } : {},
30961
+ ...options.sessionId ? { "pi_coding_agent.session_id": options.sessionId } : {},
30962
+ ...options.timeoutMs !== void 0 ? { "pi_coding_agent.timeout_ms": options.timeoutMs } : {},
30963
+ ...options.maxRetries !== void 0 ? { "pi_coding_agent.max_retries": options.maxRetries } : {},
30964
+ ...options.maxRetryDelayMs !== void 0 ? { "pi_coding_agent.max_retry_delay_ms": options.maxRetryDelayMs } : {},
30965
+ ...options.metadata ? { "pi_coding_agent.metadata": options.metadata } : {}
30966
+ };
30967
+ }
30968
+ function getLlmSpanName(model) {
30969
+ switch (model.api) {
30970
+ case "anthropic-messages":
30971
+ return "anthropic.messages.create";
30972
+ case "openai-completions":
30973
+ return "Chat Completion";
30974
+ case "openai-responses":
30975
+ case "azure-openai-responses":
30976
+ case "openai-codex-responses":
30977
+ return "openai.responses.create";
30978
+ case "google-generative-ai":
30979
+ case "google-vertex":
30980
+ return "generate_content";
30981
+ case "mistral-conversations":
30982
+ return "mistral.chat.stream";
30983
+ case "bedrock-converse-stream":
30984
+ return "bedrock.converse_stream";
30985
+ default:
30986
+ return "pi_ai.streamSimple";
30987
+ }
30988
+ }
30989
+ function extractUsageMetrics2(usage) {
30990
+ if (!usage) {
30991
+ return {};
30992
+ }
30993
+ return cleanMetrics5({
30994
+ completion_tokens: usage.output,
30995
+ prompt_cache_creation_tokens: usage.cacheWrite,
30996
+ prompt_cached_tokens: usage.cacheRead,
30997
+ prompt_tokens: usage.input,
30998
+ tokens: usage.totalTokens ?? usage.tokens
30999
+ });
31000
+ }
31001
+ function addMetrics(target, source) {
31002
+ for (const [key, value] of Object.entries(source)) {
31003
+ target[key] = (target[key] ?? 0) + value;
31004
+ }
31005
+ }
31006
+ function buildDurationMetrics3(startTime) {
31007
+ const end = getCurrentUnixTimestamp();
31008
+ return {
31009
+ duration: end - startTime,
31010
+ end,
31011
+ start: startTime
31012
+ };
31013
+ }
31014
+ function cleanMetrics5(metrics) {
31015
+ const cleaned = {};
31016
+ for (const [key, value] of Object.entries(metrics)) {
31017
+ if (typeof value === "number" && Number.isFinite(value) && value >= 0) {
31018
+ cleaned[key] = value;
31019
+ }
31020
+ }
31021
+ return cleaned;
31022
+ }
31023
+ function stringifyArguments(value) {
31024
+ if (typeof value === "string") {
31025
+ return value;
31026
+ }
31027
+ try {
31028
+ return JSON.stringify(value);
31029
+ } catch {
31030
+ return stringifyUnknown2(value);
31031
+ }
31032
+ }
31033
+ function stringifyUnknown2(value) {
31034
+ if (value instanceof Error) {
31035
+ return value.message;
31036
+ }
31037
+ if (typeof value === "string") {
31038
+ return value;
31039
+ }
31040
+ try {
31041
+ return JSON.stringify(value);
31042
+ } catch {
31043
+ return String(value);
31044
+ }
31045
+ }
31046
+ function safeLog4(span, event) {
31047
+ try {
31048
+ span.log(event);
31049
+ } catch (error2) {
31050
+ logInstrumentationError4("Pi Coding Agent span log", error2);
31051
+ }
31052
+ }
31053
+ function logInstrumentationError4(context2, error2) {
31054
+ debugLogger.debug(`${context2}:`, error2);
31055
+ }
31056
+
28995
31057
  // src/instrumentation/braintrust-plugin.ts
28996
31058
  function getIntegrationConfig(integrations, key) {
28997
31059
  return integrations[key];
@@ -29017,6 +31079,7 @@ var BraintrustPlugin = class extends BasePlugin {
29017
31079
  gitHubCopilotPlugin = null;
29018
31080
  fluePlugin = null;
29019
31081
  langChainPlugin = null;
31082
+ piCodingAgentPlugin = null;
29020
31083
  constructor(config3 = {}) {
29021
31084
  super();
29022
31085
  this.config = config3;
@@ -29091,6 +31154,10 @@ var BraintrustPlugin = class extends BasePlugin {
29091
31154
  this.gitHubCopilotPlugin = new GitHubCopilotPlugin();
29092
31155
  this.gitHubCopilotPlugin.enable();
29093
31156
  }
31157
+ if (integrations.piCodingAgent !== false) {
31158
+ this.piCodingAgentPlugin = new PiCodingAgentPlugin();
31159
+ this.piCodingAgentPlugin.enable();
31160
+ }
29094
31161
  if (getIntegrationConfig(integrations, "flue") !== false) {
29095
31162
  this.fluePlugin = new FluePlugin();
29096
31163
  this.fluePlugin.enable();
@@ -29169,6 +31236,10 @@ var BraintrustPlugin = class extends BasePlugin {
29169
31236
  this.gitHubCopilotPlugin.disable();
29170
31237
  this.gitHubCopilotPlugin = null;
29171
31238
  }
31239
+ if (this.piCodingAgentPlugin) {
31240
+ this.piCodingAgentPlugin.disable();
31241
+ this.piCodingAgentPlugin = null;
31242
+ }
29172
31243
  if (this.fluePlugin) {
29173
31244
  this.fluePlugin.disable();
29174
31245
  this.fluePlugin = null;
@@ -29188,6 +31259,11 @@ var envIntegrationAliases = {
29188
31259
  openaicodexsdk: "openaiCodexSDK",
29189
31260
  codex: "openaiCodexSDK",
29190
31261
  "codex-sdk": "openaiCodexSDK",
31262
+ "pi-coding-agent": "piCodingAgent",
31263
+ "pi-coding-agent-sdk": "piCodingAgent",
31264
+ picodingagent: "piCodingAgent",
31265
+ picodingagentsdk: "piCodingAgent",
31266
+ "@earendil-works/pi-coding-agent": "piCodingAgent",
29191
31267
  anthropic: "anthropic",
29192
31268
  aisdk: "aisdk",
29193
31269
  "ai-sdk": "aisdk",
@@ -29253,7 +31329,8 @@ function getDefaultInstrumentationIntegrations() {
29253
31329
  genkit: true,
29254
31330
  gitHubCopilot: true,
29255
31331
  langchain: true,
29256
- langgraph: true
31332
+ langgraph: true,
31333
+ piCodingAgent: true
29257
31334
  };
29258
31335
  }
29259
31336
  function readDisabledInstrumentationEnvConfig(disabledList) {
@@ -29984,6 +32061,7 @@ var Project2 = class {
29984
32061
  prompts;
29985
32062
  parameters;
29986
32063
  scorers;
32064
+ classifiers;
29987
32065
  _publishableCodeFunctions = [];
29988
32066
  _publishablePrompts = [];
29989
32067
  _publishableParameters = [];
@@ -29995,6 +32073,7 @@ var Project2 = class {
29995
32073
  this.prompts = new PromptBuilder(this);
29996
32074
  this.parameters = new ParametersBuilder(this);
29997
32075
  this.scorers = new ScorerBuilder(this);
32076
+ this.classifiers = new ClassifierBuilder(this);
29998
32077
  }
29999
32078
  addPrompt(prompt) {
30000
32079
  this._publishablePrompts.push(prompt);
@@ -30129,6 +32208,28 @@ var ScorerBuilder = class {
30129
32208
  }
30130
32209
  }
30131
32210
  };
32211
+ var ClassifierBuilder = class {
32212
+ constructor(project) {
32213
+ this.project = project;
32214
+ }
32215
+ taskCounter = 0;
32216
+ create(opts) {
32217
+ this.taskCounter++;
32218
+ let resolvedName = opts.name ?? opts.handler.name;
32219
+ if (!resolvedName || resolvedName.trim().length === 0) {
32220
+ resolvedName = `Classifier ${isomorph_default.basename(currentFilename)} ${this.taskCounter}`;
32221
+ }
32222
+ const slug = opts.slug ?? slugify(resolvedName, { lower: true, strict: true });
32223
+ const classifier = new CodeFunction(this.project, {
32224
+ ...opts,
32225
+ name: resolvedName,
32226
+ slug,
32227
+ type: "classifier"
32228
+ });
32229
+ this.project.addCodeFunction(classifier);
32230
+ return classifier;
32231
+ }
32232
+ };
30132
32233
  var CodeFunction = class {
30133
32234
  constructor(project, opts) {
30134
32235
  this.project = project;
@@ -31459,7 +33560,7 @@ var serializedParametersContainerSchema = import_v315.z.union([
31459
33560
  staticParametersSchema
31460
33561
  ]);
31461
33562
  var evaluatorDefinitionSchema = import_v315.z.object({
31462
- parameters: serializedParametersContainerSchema.optional(),
33563
+ parameters: serializedParametersContainerSchema.nullish(),
31463
33564
  scores: import_v315.z.array(import_v315.z.object({ name: import_v315.z.string() })).optional(),
31464
33565
  classifiers: import_v315.z.array(import_v315.z.object({ name: import_v315.z.string() })).optional()
31465
33566
  });