braintrust 3.11.0 → 3.12.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 (75) hide show
  1. package/README.md +8 -8
  2. package/dev/dist/index.d.mts +1 -1
  3. package/dev/dist/index.d.ts +1 -1
  4. package/dev/dist/index.js +2607 -316
  5. package/dev/dist/index.mjs +2388 -97
  6. package/dist/apply-auto-instrumentation.browser.d.mts +2 -0
  7. package/dist/apply-auto-instrumentation.browser.d.ts +2 -0
  8. package/dist/apply-auto-instrumentation.browser.js +18 -0
  9. package/dist/apply-auto-instrumentation.browser.mjs +0 -0
  10. package/dist/apply-auto-instrumentation.d.mts +2 -0
  11. package/dist/apply-auto-instrumentation.d.ts +2 -0
  12. package/dist/apply-auto-instrumentation.js +2534 -0
  13. package/dist/apply-auto-instrumentation.mjs +2534 -0
  14. package/dist/auto-instrumentations/bundler/esbuild.cjs +1802 -1283
  15. package/dist/auto-instrumentations/bundler/esbuild.d.mts +9 -5
  16. package/dist/auto-instrumentations/bundler/esbuild.d.ts +9 -5
  17. package/dist/auto-instrumentations/bundler/esbuild.mjs +10 -2
  18. package/dist/auto-instrumentations/bundler/next.cjs +3268 -0
  19. package/dist/auto-instrumentations/bundler/next.d.mts +3 -0
  20. package/dist/auto-instrumentations/bundler/next.d.ts +3 -0
  21. package/dist/auto-instrumentations/bundler/next.mjs +189 -0
  22. package/dist/auto-instrumentations/bundler/rollup.cjs +1802 -1283
  23. package/dist/auto-instrumentations/bundler/rollup.d.mts +9 -5
  24. package/dist/auto-instrumentations/bundler/rollup.d.ts +9 -5
  25. package/dist/auto-instrumentations/bundler/rollup.mjs +10 -2
  26. package/dist/auto-instrumentations/bundler/vite.cjs +1802 -1283
  27. package/dist/auto-instrumentations/bundler/vite.d.mts +9 -5
  28. package/dist/auto-instrumentations/bundler/vite.d.ts +9 -5
  29. package/dist/auto-instrumentations/bundler/vite.mjs +10 -2
  30. package/dist/auto-instrumentations/bundler/webpack-loader.cjs +1860 -1308
  31. package/dist/auto-instrumentations/bundler/webpack-loader.d.ts +3 -3
  32. package/dist/auto-instrumentations/bundler/webpack.cjs +1802 -1283
  33. package/dist/auto-instrumentations/bundler/webpack.d.mts +9 -5
  34. package/dist/auto-instrumentations/bundler/webpack.d.ts +9 -5
  35. package/dist/auto-instrumentations/bundler/webpack.mjs +6 -6
  36. package/dist/auto-instrumentations/{chunk-DIV5TO4S.mjs → chunk-2DPA74KK.mjs} +337 -1
  37. package/dist/auto-instrumentations/chunk-73BZUKVI.mjs +300 -0
  38. package/dist/auto-instrumentations/chunk-AFXRW7I7.mjs +18 -0
  39. package/dist/auto-instrumentations/hook.mjs +1712 -1460
  40. package/dist/auto-instrumentations/index.cjs +93 -0
  41. package/dist/auto-instrumentations/index.d.mts +5 -1
  42. package/dist/auto-instrumentations/index.d.ts +5 -1
  43. package/dist/auto-instrumentations/index.mjs +6 -247
  44. package/dist/auto-instrumentations/loader/esm-hook.mjs +19 -2
  45. package/dist/auto-instrumentations/plugin-D7nDswtC.d.mts +44 -0
  46. package/dist/auto-instrumentations/plugin-D7nDswtC.d.ts +44 -0
  47. package/dist/browser.d.mts +120 -31
  48. package/dist/browser.d.ts +120 -31
  49. package/dist/browser.js +2395 -123
  50. package/dist/browser.mjs +2395 -123
  51. package/dist/chunk-BW4DF4CY.js +816 -0
  52. package/dist/chunk-MSLBGITU.mjs +816 -0
  53. package/dist/cli.js +2407 -96
  54. package/dist/edge-light.d.mts +1 -1
  55. package/dist/edge-light.d.ts +1 -1
  56. package/dist/edge-light.js +2395 -123
  57. package/dist/edge-light.mjs +2395 -123
  58. package/dist/index.d.mts +120 -31
  59. package/dist/index.d.ts +120 -31
  60. package/dist/index.js +3362 -1849
  61. package/dist/index.mjs +2505 -992
  62. package/dist/instrumentation/index.d.mts +7860 -48
  63. package/dist/instrumentation/index.d.ts +7860 -48
  64. package/dist/instrumentation/index.js +2395 -95
  65. package/dist/instrumentation/index.mjs +2394 -95
  66. package/dist/workerd.d.mts +1 -1
  67. package/dist/workerd.d.ts +1 -1
  68. package/dist/workerd.js +2395 -123
  69. package/dist/workerd.mjs +2395 -123
  70. package/package.json +23 -3
  71. package/util/dist/index.js +6 -0
  72. package/util/dist/index.mjs +6 -0
  73. package/dist/auto-instrumentations/chunk-G6ZWXGZB.mjs +0 -116
  74. package/dist/auto-instrumentations/plugin-Df3qKIl2.d.mts +0 -22
  75. package/dist/auto-instrumentations/plugin-Df3qKIl2.d.ts +0 -22
@@ -406,11 +406,11 @@ function truncateToByteLimit(s, byteLimit = 65536) {
406
406
  return new TextDecoder().decode(truncated);
407
407
  }
408
408
  async function getRepoInfo(settings) {
409
- if (settings && settings.collect === "none") {
409
+ if (!settings || settings.collect === "none") {
410
410
  return void 0;
411
411
  }
412
412
  const repo = await repoInfo();
413
- if (!repo || !settings || settings.collect === "all") {
413
+ if (!repo || settings.collect === "all") {
414
414
  return repo;
415
415
  }
416
416
  let sanitized = {};
@@ -1228,6 +1228,11 @@ function isPromiseLike(value) {
1228
1228
 
1229
1229
  // util/object_util.ts
1230
1230
  var SET_UNION_FIELDS = /* @__PURE__ */ new Set(["tags"]);
1231
+ var FORBIDDEN_MERGE_KEYS = /* @__PURE__ */ new Set([
1232
+ "__proto__",
1233
+ "constructor",
1234
+ "prototype"
1235
+ ]);
1231
1236
  function mergeDictsWithPaths({
1232
1237
  mergeInto,
1233
1238
  mergeFrom,
@@ -1250,6 +1255,7 @@ function mergeDictsWithPathsHelper({
1250
1255
  mergePaths
1251
1256
  }) {
1252
1257
  Object.entries(mergeFrom).forEach(([k, mergeFromV]) => {
1258
+ if (FORBIDDEN_MERGE_KEYS.has(k)) return;
1253
1259
  const fullPath = path2.concat([k]);
1254
1260
  const fullPathSerialized = JSON.stringify(fullPath);
1255
1261
  const mergeIntoV = recordFind(mergeInto, k);
@@ -5306,6 +5312,13 @@ var HTTPConnection = class _HTTPConnection {
5306
5312
  debugLogger.debug(
5307
5313
  `Retrying API request ${object_type} ${JSON.stringify(args)} ${e.status} ${e.text}`
5308
5314
  );
5315
+ const sleepTimeS = HTTP_RETRY_BASE_SLEEP_TIME_S * 2 ** i;
5316
+ debugLogger.info(
5317
+ `Sleeping for ${sleepTimeS}s before retrying API request`
5318
+ );
5319
+ await new Promise(
5320
+ (resolve) => setTimeout(resolve, sleepTimeS * 1e3)
5321
+ );
5309
5322
  continue;
5310
5323
  }
5311
5324
  throw e;
@@ -5828,20 +5841,7 @@ function startSpanParentArgs(args) {
5828
5841
  `Mismatch between expected span parent object type ${args.parentObjectType} and provided type ${parentComponents.data.object_type}`
5829
5842
  );
5830
5843
  }
5831
- const parentComponentsObjectIdLambda = spanComponentsToObjectIdLambda(
5832
- args.state,
5833
- parentComponents
5834
- );
5835
- const computeParentObjectId = async () => {
5836
- const parentComponentsObjectId = await parentComponentsObjectIdLambda();
5837
- if (await args.parentObjectId.get() !== parentComponentsObjectId) {
5838
- throw new Error(
5839
- `Mismatch between expected span parent object id ${await args.parentObjectId.get()} and provided id ${parentComponentsObjectId}`
5840
- );
5841
- }
5842
- return await args.parentObjectId.get();
5843
- };
5844
- argParentObjectId = new LazyValue(computeParentObjectId);
5844
+ argParentObjectId = args.parentObjectId;
5845
5845
  if (parentComponents.data.row_id) {
5846
5846
  argParentSpanIds = {
5847
5847
  spanId: parentComponents.data.span_id,
@@ -6170,6 +6170,7 @@ function now() {
6170
6170
  }
6171
6171
  var DEFAULT_FLUSH_BACKPRESSURE_BYTES = 10 * 1024 * 1024;
6172
6172
  var BACKGROUND_LOGGER_BASE_SLEEP_TIME_S = 1;
6173
+ var HTTP_RETRY_BASE_SLEEP_TIME_S = 1;
6173
6174
  var HTTPBackgroundLogger = class _HTTPBackgroundLogger {
6174
6175
  apiConn;
6175
6176
  queue;
@@ -6800,17 +6801,10 @@ function init(projectOrOptions, optionalOptions) {
6800
6801
  if (repoInfo2) {
6801
6802
  return repoInfo2;
6802
6803
  }
6803
- let mergedGitMetadataSettings = {
6804
- ...state.gitMetadataSettings || {
6805
- collect: "all"
6806
- }
6807
- };
6808
- if (gitMetadataSettings) {
6809
- mergedGitMetadataSettings = mergeGitMetadataSettings(
6810
- mergedGitMetadataSettings,
6811
- gitMetadataSettings
6812
- );
6813
- }
6804
+ const mergedGitMetadataSettings = state.gitMetadataSettings == null ? gitMetadataSettings ?? { collect: "none" } : mergeGitMetadataSettings(
6805
+ state.gitMetadataSettings,
6806
+ gitMetadataSettings ?? { collect: "all" }
6807
+ );
6814
6808
  return await isomorph_default.getRepoInfo(mergedGitMetadataSettings);
6815
6809
  })();
6816
6810
  if (repoInfoArg) {
@@ -7192,6 +7186,55 @@ async function computeLoggerMetadata(state, {
7192
7186
  };
7193
7187
  }
7194
7188
  }
7189
+ function initLogger(options = {}) {
7190
+ const {
7191
+ projectName,
7192
+ projectId,
7193
+ asyncFlush: asyncFlushArg,
7194
+ appUrl,
7195
+ apiKey,
7196
+ orgName,
7197
+ forceLogin,
7198
+ debugLogLevel,
7199
+ fetch: fetch2,
7200
+ state: stateArg
7201
+ } = options || {};
7202
+ const asyncFlush = asyncFlushArg === void 0 ? true : asyncFlushArg;
7203
+ const computeMetadataArgs = {
7204
+ project_name: projectName,
7205
+ project_id: projectId
7206
+ };
7207
+ const linkArgs = {
7208
+ org_name: orgName,
7209
+ app_url: appUrl,
7210
+ project_name: projectName,
7211
+ project_id: projectId
7212
+ };
7213
+ const state = stateArg ?? _globalState;
7214
+ state.setDebugLogLevel(debugLogLevel);
7215
+ state.enforceQueueSizeLimit(true);
7216
+ const lazyMetadata = new LazyValue(
7217
+ async () => {
7218
+ await state.login({
7219
+ orgName,
7220
+ apiKey,
7221
+ appUrl,
7222
+ forceLogin,
7223
+ fetch: fetch2
7224
+ });
7225
+ return computeLoggerMetadata(state, computeMetadataArgs);
7226
+ }
7227
+ );
7228
+ const ret = new Logger(state, lazyMetadata, {
7229
+ asyncFlush,
7230
+ computeMetadataArgs,
7231
+ linkArgs
7232
+ });
7233
+ if (options.setCurrent ?? true) {
7234
+ state.currentLogger = ret;
7235
+ }
7236
+ return ret;
7237
+ }
7195
7238
  async function login(options = {}) {
7196
7239
  const { forceLogin = false } = options || {};
7197
7240
  if (!_internalGetGlobalState()) {
@@ -12877,11 +12920,11 @@ function resolveDenyOutputPaths(event, defaultDenyOutputPaths) {
12877
12920
  if (Array.isArray(event?.denyOutputPaths)) {
12878
12921
  return event.denyOutputPaths;
12879
12922
  }
12880
- const firstArgument = event?.arguments && event.arguments.length > 0 ? event.arguments[0] : void 0;
12881
- if (!firstArgument || typeof firstArgument !== "object") {
12923
+ const firstArgument2 = event?.arguments && event.arguments.length > 0 ? event.arguments[0] : void 0;
12924
+ if (!firstArgument2 || typeof firstArgument2 !== "object") {
12882
12925
  return defaultDenyOutputPaths;
12883
12926
  }
12884
- const runtimeDenyOutputPaths = firstArgument[RUNTIME_DENY_OUTPUT_PATHS];
12927
+ const runtimeDenyOutputPaths = firstArgument2[RUNTIME_DENY_OUTPUT_PATHS];
12885
12928
  if (Array.isArray(runtimeDenyOutputPaths) && runtimeDenyOutputPaths.every((path2) => typeof path2 === "string")) {
12886
12929
  return runtimeDenyOutputPaths;
12887
12930
  }
@@ -16540,6 +16583,467 @@ function cleanMetrics2(metrics) {
16540
16583
  return cleaned;
16541
16584
  }
16542
16585
 
16586
+ // src/instrumentation/plugins/openai-agents-channels.ts
16587
+ var openAIAgentsCoreChannels = defineChannels("@openai/agents-core", {
16588
+ onTraceStart: channel({
16589
+ channelName: "tracing.processor.onTraceStart",
16590
+ kind: "async"
16591
+ }),
16592
+ onTraceEnd: channel({
16593
+ channelName: "tracing.processor.onTraceEnd",
16594
+ kind: "async"
16595
+ }),
16596
+ onSpanStart: channel({
16597
+ channelName: "tracing.processor.onSpanStart",
16598
+ kind: "async"
16599
+ }),
16600
+ onSpanEnd: channel({
16601
+ channelName: "tracing.processor.onSpanEnd",
16602
+ kind: "async"
16603
+ })
16604
+ });
16605
+
16606
+ // src/instrumentation/plugins/openai-agents-trace-processor.ts
16607
+ function isSpanData(spanData, type) {
16608
+ return spanData.type === type;
16609
+ }
16610
+ function spanTypeFromAgents(span) {
16611
+ const spanType = span.spanData.type;
16612
+ if (spanType === "function" || spanType === "guardrail" || spanType === "mcp_tools") {
16613
+ return "tool" /* TOOL */;
16614
+ }
16615
+ if (spanType === "generation" || spanType === "response" || spanType === "transcription" || spanType === "speech") {
16616
+ return "llm" /* LLM */;
16617
+ }
16618
+ return "task" /* TASK */;
16619
+ }
16620
+ function spanNameFromAgents(span) {
16621
+ const spanData = span.spanData;
16622
+ if ("name" in spanData && spanData.name) {
16623
+ return spanData.name;
16624
+ }
16625
+ switch (spanData.type) {
16626
+ case "generation":
16627
+ return "Generation";
16628
+ case "response":
16629
+ return "Response";
16630
+ case "handoff":
16631
+ return "Handoff";
16632
+ case "mcp_tools":
16633
+ return isSpanData(spanData, "mcp_tools") && spanData.server ? `List Tools (${spanData.server})` : "MCP List Tools";
16634
+ case "transcription":
16635
+ return "Transcription";
16636
+ case "speech":
16637
+ return "Speech";
16638
+ case "speech_group":
16639
+ return "Speech Group";
16640
+ default:
16641
+ return "Unknown";
16642
+ }
16643
+ }
16644
+ function getTimeElapsed(end, start) {
16645
+ if (!start || !end) {
16646
+ return void 0;
16647
+ }
16648
+ const startTime = new Date(start).getTime();
16649
+ const endTime = new Date(end).getTime();
16650
+ if (Number.isNaN(startTime) || Number.isNaN(endTime)) {
16651
+ return void 0;
16652
+ }
16653
+ return (endTime - startTime) / 1e3;
16654
+ }
16655
+ function getNumberProperty2(obj, key) {
16656
+ if (!isObject(obj) || !(key in obj)) {
16657
+ return void 0;
16658
+ }
16659
+ const value = obj[key];
16660
+ return typeof value === "number" ? value : void 0;
16661
+ }
16662
+ function parseUsageMetrics(usage) {
16663
+ const metrics = {};
16664
+ if (!isObject(usage)) {
16665
+ return metrics;
16666
+ }
16667
+ const promptTokens = getNumberProperty2(usage, "prompt_tokens") ?? getNumberProperty2(usage, "input_tokens") ?? getNumberProperty2(usage, "promptTokens") ?? getNumberProperty2(usage, "inputTokens");
16668
+ const completionTokens = getNumberProperty2(usage, "completion_tokens") ?? getNumberProperty2(usage, "output_tokens") ?? getNumberProperty2(usage, "completionTokens") ?? getNumberProperty2(usage, "outputTokens");
16669
+ const totalTokens = getNumberProperty2(usage, "total_tokens") ?? getNumberProperty2(usage, "totalTokens");
16670
+ if (promptTokens !== void 0) {
16671
+ metrics.prompt_tokens = promptTokens;
16672
+ }
16673
+ if (completionTokens !== void 0) {
16674
+ metrics.completion_tokens = completionTokens;
16675
+ }
16676
+ if (totalTokens !== void 0) {
16677
+ metrics.tokens = totalTokens;
16678
+ } else if (promptTokens !== void 0 && completionTokens !== void 0) {
16679
+ metrics.tokens = promptTokens + completionTokens;
16680
+ }
16681
+ const inputDetails = usage.input_tokens_details;
16682
+ const cachedTokens = getNumberProperty2(inputDetails, "cached_tokens");
16683
+ const cacheWriteTokens = getNumberProperty2(
16684
+ inputDetails,
16685
+ "cache_write_tokens"
16686
+ );
16687
+ if (cachedTokens !== void 0) {
16688
+ metrics.prompt_cached_tokens = cachedTokens;
16689
+ }
16690
+ if (cacheWriteTokens !== void 0) {
16691
+ metrics.prompt_cache_creation_tokens = cacheWriteTokens;
16692
+ }
16693
+ return metrics;
16694
+ }
16695
+ var OpenAIAgentsTraceProcessor = class _OpenAIAgentsTraceProcessor {
16696
+ static DEFAULT_MAX_TRACES = 1e4;
16697
+ logger;
16698
+ maxTraces;
16699
+ traceSpans = /* @__PURE__ */ new Map();
16700
+ traceOrder = [];
16701
+ _traceSpans = this.traceSpans;
16702
+ constructor(options = {}) {
16703
+ this.logger = options.logger;
16704
+ this.maxTraces = options.maxTraces ?? _OpenAIAgentsTraceProcessor.DEFAULT_MAX_TRACES;
16705
+ }
16706
+ evictOldestTrace() {
16707
+ const oldestTraceId = this.traceOrder.shift();
16708
+ if (oldestTraceId) {
16709
+ this.traceSpans.delete(oldestTraceId);
16710
+ }
16711
+ }
16712
+ onTraceStart(trace) {
16713
+ if (!trace?.traceId) {
16714
+ return Promise.resolve();
16715
+ }
16716
+ if (this.traceOrder.length >= this.maxTraces) {
16717
+ this.evictOldestTrace();
16718
+ }
16719
+ const current = currentSpan();
16720
+ const span = current && current !== NOOP_SPAN ? current.startSpan({
16721
+ name: trace.name,
16722
+ type: "task" /* TASK */
16723
+ }) : this.logger ? this.logger.startSpan({
16724
+ name: trace.name,
16725
+ type: "task" /* TASK */
16726
+ }) : startSpan({
16727
+ name: trace.name,
16728
+ type: "task" /* TASK */
16729
+ });
16730
+ span.log({
16731
+ input: "Agent workflow started",
16732
+ metadata: {
16733
+ group_id: trace.groupId,
16734
+ ...trace.metadata || {}
16735
+ }
16736
+ });
16737
+ this.traceSpans.set(trace.traceId, {
16738
+ rootSpan: span,
16739
+ childSpans: /* @__PURE__ */ new Map(),
16740
+ metadata: {
16741
+ firstInput: null,
16742
+ lastOutput: null
16743
+ }
16744
+ });
16745
+ this.traceOrder.push(trace.traceId);
16746
+ return Promise.resolve();
16747
+ }
16748
+ async onTraceEnd(trace) {
16749
+ const traceData = this.traceSpans.get(trace?.traceId);
16750
+ if (!traceData) {
16751
+ return;
16752
+ }
16753
+ try {
16754
+ traceData.rootSpan.log({
16755
+ input: traceData.metadata.firstInput,
16756
+ output: traceData.metadata.lastOutput
16757
+ });
16758
+ traceData.rootSpan.end();
16759
+ await traceData.rootSpan.flush();
16760
+ } finally {
16761
+ this.traceSpans.delete(trace.traceId);
16762
+ const orderIndex = this.traceOrder.indexOf(trace.traceId);
16763
+ if (orderIndex > -1) {
16764
+ this.traceOrder.splice(orderIndex, 1);
16765
+ }
16766
+ }
16767
+ }
16768
+ onSpanStart(span) {
16769
+ if (!span?.spanId || !span.traceId) {
16770
+ return Promise.resolve();
16771
+ }
16772
+ const traceData = this.traceSpans.get(span.traceId);
16773
+ if (!traceData) {
16774
+ return Promise.resolve();
16775
+ }
16776
+ const parentSpan = span.parentId ? traceData.childSpans.get(span.parentId) : traceData.rootSpan;
16777
+ if (!parentSpan) {
16778
+ return Promise.resolve();
16779
+ }
16780
+ const childSpan = parentSpan.startSpan({
16781
+ name: spanNameFromAgents(span),
16782
+ type: spanTypeFromAgents(span)
16783
+ });
16784
+ traceData.childSpans.set(span.spanId, childSpan);
16785
+ return Promise.resolve();
16786
+ }
16787
+ onSpanEnd(span) {
16788
+ if (!span?.spanId || !span.traceId) {
16789
+ return Promise.resolve();
16790
+ }
16791
+ const traceData = this.traceSpans.get(span.traceId);
16792
+ if (!traceData) {
16793
+ return Promise.resolve();
16794
+ }
16795
+ const braintrustSpan = traceData.childSpans.get(span.spanId);
16796
+ if (!braintrustSpan) {
16797
+ return Promise.resolve();
16798
+ }
16799
+ const logData = this.extractLogData(span);
16800
+ braintrustSpan.log({
16801
+ error: span.error,
16802
+ ...logData
16803
+ });
16804
+ braintrustSpan.end();
16805
+ traceData.childSpans.delete(span.spanId);
16806
+ const input = logData.input;
16807
+ const output = logData.output;
16808
+ if (traceData.metadata.firstInput === null && input != null) {
16809
+ traceData.metadata.firstInput = input;
16810
+ }
16811
+ if (output != null) {
16812
+ traceData.metadata.lastOutput = output;
16813
+ }
16814
+ return Promise.resolve();
16815
+ }
16816
+ async shutdown() {
16817
+ if (this.logger && typeof this.logger.flush === "function") {
16818
+ await this.logger.flush();
16819
+ }
16820
+ }
16821
+ async forceFlush() {
16822
+ if (this.logger && typeof this.logger.flush === "function") {
16823
+ await this.logger.flush();
16824
+ }
16825
+ }
16826
+ extractLogData(span) {
16827
+ const spanData = span.spanData;
16828
+ switch (spanData.type) {
16829
+ case "agent":
16830
+ return this.extractAgentLogData(spanData);
16831
+ case "response":
16832
+ return this.extractResponseLogData(spanData, span);
16833
+ case "function":
16834
+ return this.extractFunctionLogData(spanData);
16835
+ case "handoff":
16836
+ return this.extractHandoffLogData(spanData);
16837
+ case "guardrail":
16838
+ return this.extractGuardrailLogData(spanData);
16839
+ case "generation":
16840
+ return this.extractGenerationLogData(spanData, span);
16841
+ case "custom":
16842
+ return this.extractCustomLogData(spanData);
16843
+ case "mcp_tools":
16844
+ return this.extractMCPListToolsLogData(spanData);
16845
+ case "transcription":
16846
+ return this.extractTranscriptionLogData(spanData);
16847
+ case "speech":
16848
+ return this.extractSpeechLogData(spanData);
16849
+ case "speech_group":
16850
+ return this.extractSpeechGroupLogData(spanData);
16851
+ default:
16852
+ return {};
16853
+ }
16854
+ }
16855
+ extractAgentLogData(spanData) {
16856
+ return {
16857
+ metadata: {
16858
+ tools: spanData.tools,
16859
+ handoffs: spanData.handoffs,
16860
+ output_type: spanData.output_type
16861
+ }
16862
+ };
16863
+ }
16864
+ extractResponseLogData(spanData, span) {
16865
+ const response = spanData._response;
16866
+ const output = isObject(response) ? response.output : void 0;
16867
+ const usage = isObject(response) ? response.usage : void 0;
16868
+ const metrics = {
16869
+ ...this.extractTimingMetrics(span),
16870
+ ...parseUsageMetrics(usage)
16871
+ };
16872
+ return {
16873
+ input: spanData._input,
16874
+ output,
16875
+ metadata: isObject(response) ? this.omitKeys(response, ["output", "usage"]) : {},
16876
+ metrics
16877
+ };
16878
+ }
16879
+ extractFunctionLogData(spanData) {
16880
+ return {
16881
+ input: spanData.input,
16882
+ output: spanData.output
16883
+ };
16884
+ }
16885
+ extractHandoffLogData(spanData) {
16886
+ return {
16887
+ metadata: {
16888
+ from_agent: spanData.from_agent,
16889
+ to_agent: spanData.to_agent
16890
+ }
16891
+ };
16892
+ }
16893
+ extractGuardrailLogData(spanData) {
16894
+ return {
16895
+ metadata: {
16896
+ triggered: spanData.triggered
16897
+ }
16898
+ };
16899
+ }
16900
+ extractGenerationLogData(spanData, span) {
16901
+ return {
16902
+ input: spanData.input,
16903
+ output: spanData.output,
16904
+ metadata: {
16905
+ model: spanData.model,
16906
+ model_config: spanData.model_config
16907
+ },
16908
+ metrics: {
16909
+ ...this.extractTimingMetrics(span),
16910
+ ...parseUsageMetrics(spanData.usage)
16911
+ }
16912
+ };
16913
+ }
16914
+ extractCustomLogData(spanData) {
16915
+ return spanData.data || {};
16916
+ }
16917
+ extractMCPListToolsLogData(spanData) {
16918
+ return {
16919
+ output: spanData.result,
16920
+ metadata: {
16921
+ server: spanData.server
16922
+ }
16923
+ };
16924
+ }
16925
+ extractTranscriptionLogData(spanData) {
16926
+ return {
16927
+ input: spanData.input,
16928
+ output: spanData.output,
16929
+ metadata: {
16930
+ model: spanData.model,
16931
+ model_config: spanData.model_config
16932
+ }
16933
+ };
16934
+ }
16935
+ extractSpeechLogData(spanData) {
16936
+ return {
16937
+ input: spanData.input,
16938
+ output: spanData.output,
16939
+ metadata: {
16940
+ model: spanData.model,
16941
+ model_config: spanData.model_config
16942
+ }
16943
+ };
16944
+ }
16945
+ extractSpeechGroupLogData(spanData) {
16946
+ return {
16947
+ input: spanData.input
16948
+ };
16949
+ }
16950
+ extractTimingMetrics(span) {
16951
+ const timeToFirstToken = getTimeElapsed(
16952
+ span.endedAt ?? void 0,
16953
+ span.startedAt ?? void 0
16954
+ );
16955
+ return timeToFirstToken === void 0 ? {} : { time_to_first_token: timeToFirstToken };
16956
+ }
16957
+ omitKeys(value, keys) {
16958
+ const result = {};
16959
+ for (const [key, fieldValue] of Object.entries(value)) {
16960
+ if (!keys.includes(key)) {
16961
+ result[key] = fieldValue;
16962
+ }
16963
+ }
16964
+ return result;
16965
+ }
16966
+ };
16967
+
16968
+ // src/instrumentation/plugins/openai-agents-plugin.ts
16969
+ function firstArgument(args) {
16970
+ if (Array.isArray(args)) {
16971
+ return args[0];
16972
+ }
16973
+ if (isObject(args) && "length" in args && typeof args.length === "number" && Number.isInteger(args.length) && args.length >= 0) {
16974
+ return Array.from(args)[0];
16975
+ }
16976
+ return void 0;
16977
+ }
16978
+ function isOpenAIAgentsTrace(value) {
16979
+ return isObject(value) && value.type === "trace" && typeof value.traceId === "string";
16980
+ }
16981
+ function isOpenAIAgentsSpan(value) {
16982
+ return isObject(value) && value.type === "trace.span" && typeof value.traceId === "string" && typeof value.spanId === "string";
16983
+ }
16984
+ var OpenAIAgentsPlugin = class extends BasePlugin {
16985
+ processor = new OpenAIAgentsTraceProcessor();
16986
+ onEnable() {
16987
+ this.subscribeToTraceLifecycle();
16988
+ }
16989
+ onDisable() {
16990
+ this.unsubscribers = unsubscribeAll(this.unsubscribers);
16991
+ void this.processor.shutdown();
16992
+ }
16993
+ subscribeToTraceLifecycle() {
16994
+ const traceStartChannel = openAIAgentsCoreChannels.onTraceStart.tracingChannel();
16995
+ const traceStartHandlers = {
16996
+ start: (event) => {
16997
+ const trace = firstArgument(event.arguments);
16998
+ if (isOpenAIAgentsTrace(trace)) {
16999
+ void this.processor.onTraceStart(trace);
17000
+ }
17001
+ }
17002
+ };
17003
+ traceStartChannel.subscribe(traceStartHandlers);
17004
+ this.unsubscribers.push(
17005
+ () => traceStartChannel.unsubscribe(traceStartHandlers)
17006
+ );
17007
+ const traceEndChannel = openAIAgentsCoreChannels.onTraceEnd.tracingChannel();
17008
+ const traceEndHandlers = {
17009
+ start: (event) => {
17010
+ const trace = firstArgument(event.arguments);
17011
+ if (isOpenAIAgentsTrace(trace)) {
17012
+ void this.processor.onTraceEnd(trace);
17013
+ }
17014
+ }
17015
+ };
17016
+ traceEndChannel.subscribe(traceEndHandlers);
17017
+ this.unsubscribers.push(
17018
+ () => traceEndChannel.unsubscribe(traceEndHandlers)
17019
+ );
17020
+ const spanStartChannel = openAIAgentsCoreChannels.onSpanStart.tracingChannel();
17021
+ const spanStartHandlers = {
17022
+ start: (event) => {
17023
+ const span = firstArgument(event.arguments);
17024
+ if (isOpenAIAgentsSpan(span)) {
17025
+ void this.processor.onSpanStart(span);
17026
+ }
17027
+ }
17028
+ };
17029
+ spanStartChannel.subscribe(spanStartHandlers);
17030
+ this.unsubscribers.push(
17031
+ () => spanStartChannel.unsubscribe(spanStartHandlers)
17032
+ );
17033
+ const spanEndChannel = openAIAgentsCoreChannels.onSpanEnd.tracingChannel();
17034
+ const spanEndHandlers = {
17035
+ start: (event) => {
17036
+ const span = firstArgument(event.arguments);
17037
+ if (isOpenAIAgentsSpan(span)) {
17038
+ void this.processor.onSpanEnd(span);
17039
+ }
17040
+ }
17041
+ };
17042
+ spanEndChannel.subscribe(spanEndHandlers);
17043
+ this.unsubscribers.push(() => spanEndChannel.unsubscribe(spanEndHandlers));
17044
+ }
17045
+ };
17046
+
16543
17047
  // src/instrumentation/plugins/google-genai-channels.ts
16544
17048
  var googleGenAIChannels = defineChannels("@google/genai", {
16545
17049
  generateContent: channel({
@@ -22832,37 +23336,1747 @@ var GitHubCopilotPlugin = class extends BasePlugin {
22832
23336
  }
22833
23337
  };
22834
23338
 
22835
- // src/instrumentation/braintrust-plugin.ts
22836
- function getIntegrationConfig(integrations, key) {
22837
- return integrations[key];
23339
+ // src/instrumentation/plugins/flue-channels.ts
23340
+ var flueChannels = defineChannels("@flue/runtime", {
23341
+ createContext: channel({
23342
+ channelName: "createFlueContext",
23343
+ kind: "sync-stream"
23344
+ }),
23345
+ openSession: channel({
23346
+ channelName: "Harness.openSession",
23347
+ kind: "async"
23348
+ }),
23349
+ contextEvent: channel({
23350
+ channelName: "context.event",
23351
+ kind: "sync-stream"
23352
+ }),
23353
+ prompt: channel({
23354
+ channelName: "session.prompt",
23355
+ kind: "async"
23356
+ }),
23357
+ skill: channel({
23358
+ channelName: "session.skill",
23359
+ kind: "async"
23360
+ }),
23361
+ task: channel({
23362
+ channelName: "session.task",
23363
+ kind: "async"
23364
+ }),
23365
+ compact: channel({
23366
+ channelName: "session.compact",
23367
+ kind: "async"
23368
+ })
23369
+ });
23370
+
23371
+ // src/wrappers/flue.ts
23372
+ var WRAPPED_FLUE_CONTEXT = /* @__PURE__ */ Symbol.for("braintrust.flue.wrapped-context");
23373
+ var WRAPPED_FLUE_HARNESS = /* @__PURE__ */ Symbol.for("braintrust.flue.wrapped-harness");
23374
+ var WRAPPED_FLUE_SESSION = /* @__PURE__ */ Symbol.for("braintrust.flue.wrapped-session");
23375
+ var SUBSCRIBED_FLUE_CONTEXT_EVENTS = /* @__PURE__ */ Symbol.for(
23376
+ "braintrust.flue.subscribed-context-events"
23377
+ );
23378
+ function patchFlueContextInPlace(ctx) {
23379
+ const context = ctx;
23380
+ if (context[WRAPPED_FLUE_CONTEXT]) {
23381
+ return ctx;
23382
+ }
23383
+ const originalInit = context.init.bind(context);
23384
+ try {
23385
+ Object.defineProperty(context, WRAPPED_FLUE_CONTEXT, {
23386
+ configurable: false,
23387
+ enumerable: false,
23388
+ value: true
23389
+ });
23390
+ Object.defineProperty(context, "init", {
23391
+ configurable: true,
23392
+ value: async function wrappedFlueInit(options) {
23393
+ const harness = await originalInit(options);
23394
+ return wrapFlueHarness(harness);
23395
+ },
23396
+ writable: true
23397
+ });
23398
+ } catch {
23399
+ }
23400
+ return ctx;
22838
23401
  }
22839
- var BraintrustPlugin = class extends BasePlugin {
22840
- config;
22841
- openaiPlugin = null;
22842
- openAICodexPlugin = null;
22843
- anthropicPlugin = null;
22844
- aiSDKPlugin = null;
22845
- claudeAgentSDKPlugin = null;
22846
- cursorSDKPlugin = null;
22847
- googleGenAIPlugin = null;
22848
- huggingFacePlugin = null;
22849
- openRouterPlugin = null;
22850
- openRouterAgentPlugin = null;
22851
- mistralPlugin = null;
22852
- googleADKPlugin = null;
22853
- coherePlugin = null;
22854
- groqPlugin = null;
22855
- genkitPlugin = null;
22856
- gitHubCopilotPlugin = null;
22857
- constructor(config = {}) {
22858
- super();
22859
- this.config = config;
23402
+ function subscribeFlueContextEvents(ctx, options = {}) {
23403
+ if (!ctx || typeof ctx !== "object" || typeof ctx.subscribeEvent !== "function") {
23404
+ return void 0;
22860
23405
  }
22861
- onEnable() {
22862
- const integrations = this.config.integrations || {};
22863
- if (integrations.openai !== false) {
22864
- this.openaiPlugin = new OpenAIPlugin();
22865
- this.openaiPlugin.enable();
23406
+ const context = ctx;
23407
+ const captureTurnSpans = options.captureTurnSpans ?? true;
23408
+ const existingSubscription = context[SUBSCRIBED_FLUE_CONTEXT_EVENTS];
23409
+ if (existingSubscription) {
23410
+ if (existingSubscription.captureTurnSpans || !captureTurnSpans) {
23411
+ return void 0;
23412
+ }
23413
+ try {
23414
+ existingSubscription.unsubscribe();
23415
+ } catch {
23416
+ }
23417
+ }
23418
+ try {
23419
+ const unsubscribe = ctx.subscribeEvent((event) => {
23420
+ flueChannels.contextEvent.traceSync(() => void 0, {
23421
+ arguments: [event],
23422
+ captureTurnSpans,
23423
+ context: ctx
23424
+ });
23425
+ });
23426
+ if (existingSubscription) {
23427
+ existingSubscription.captureTurnSpans = captureTurnSpans;
23428
+ existingSubscription.unsubscribe = unsubscribe;
23429
+ } else {
23430
+ Object.defineProperty(context, SUBSCRIBED_FLUE_CONTEXT_EVENTS, {
23431
+ configurable: false,
23432
+ enumerable: false,
23433
+ value: {
23434
+ captureTurnSpans,
23435
+ unsubscribe
23436
+ }
23437
+ });
23438
+ }
23439
+ return unsubscribe;
23440
+ } catch {
23441
+ return void 0;
23442
+ }
23443
+ }
23444
+ function wrapFlueHarness(harness) {
23445
+ if (!isPlausibleFlueHarness(harness)) {
23446
+ return harness;
23447
+ }
23448
+ const target = harness;
23449
+ if (target[WRAPPED_FLUE_HARNESS]) {
23450
+ return harness;
23451
+ }
23452
+ const originalSession = target.session.bind(target);
23453
+ try {
23454
+ Object.defineProperty(target, WRAPPED_FLUE_HARNESS, {
23455
+ configurable: false,
23456
+ enumerable: false,
23457
+ value: true
23458
+ });
23459
+ Object.defineProperty(target, "session", {
23460
+ configurable: true,
23461
+ value: async function wrappedFlueHarnessSession(name, options) {
23462
+ const session = await originalSession(name, options);
23463
+ return patchFlueSessionInPlace(session);
23464
+ },
23465
+ writable: true
23466
+ });
23467
+ const sessions = target.sessions;
23468
+ if (sessions && typeof sessions === "object") {
23469
+ patchFlueSessionFactory(sessions, "get");
23470
+ patchFlueSessionFactory(sessions, "create");
23471
+ }
23472
+ } catch {
23473
+ }
23474
+ return harness;
23475
+ }
23476
+ function patchFlueSessionInPlace(session) {
23477
+ if (session[WRAPPED_FLUE_SESSION]) {
23478
+ return session;
23479
+ }
23480
+ try {
23481
+ Object.defineProperty(session, WRAPPED_FLUE_SESSION, {
23482
+ configurable: false,
23483
+ enumerable: false,
23484
+ value: true
23485
+ });
23486
+ patchCallHandleMethod(session, "prompt", flueChannels.prompt);
23487
+ patchCallHandleMethod(session, "skill", flueChannels.skill);
23488
+ patchCallHandleMethod(session, "task", flueChannels.task);
23489
+ patchCompact(session);
23490
+ } catch {
23491
+ }
23492
+ return session;
23493
+ }
23494
+ function patchFlueSessionFactory(sessions, method) {
23495
+ const original = sessions[method];
23496
+ if (typeof original !== "function") {
23497
+ return;
23498
+ }
23499
+ const bound = original.bind(sessions);
23500
+ Object.defineProperty(sessions, method, {
23501
+ configurable: true,
23502
+ value: async function wrappedFlueSessionFactory(name, options) {
23503
+ const session = await bound(name, options);
23504
+ return patchFlueSessionInPlace(session);
23505
+ },
23506
+ writable: true
23507
+ });
23508
+ }
23509
+ function patchCallHandleMethod(session, method, channel2) {
23510
+ const original = session[method];
23511
+ if (typeof original !== "function") {
23512
+ return;
23513
+ }
23514
+ const bound = original.bind(session);
23515
+ Object.defineProperty(session, method, {
23516
+ configurable: true,
23517
+ value(input, options) {
23518
+ const args = [input, options];
23519
+ const { originalResult, traced: traced2 } = traceFlueOperation(channel2, {
23520
+ context: {
23521
+ arguments: args,
23522
+ operation: method,
23523
+ session
23524
+ },
23525
+ run: () => bound(input, options)
23526
+ });
23527
+ return preserveCallHandle(originalResult, traced2);
23528
+ },
23529
+ writable: true
23530
+ });
23531
+ }
23532
+ function patchCompact(session) {
23533
+ const original = session.compact;
23534
+ if (typeof original !== "function") {
23535
+ return;
23536
+ }
23537
+ const bound = original.bind(session);
23538
+ Object.defineProperty(session, "compact", {
23539
+ configurable: true,
23540
+ value() {
23541
+ const context = {
23542
+ arguments: [],
23543
+ operation: "compact",
23544
+ session
23545
+ };
23546
+ return flueChannels.compact.tracePromise(() => bound(), context);
23547
+ },
23548
+ writable: true
23549
+ });
23550
+ }
23551
+ function traceFlueOperation(channel2, args) {
23552
+ const tracingChannel2 = channel2.tracingChannel();
23553
+ const context = args.context;
23554
+ let originalResult;
23555
+ let traced2;
23556
+ const run = () => {
23557
+ try {
23558
+ originalResult = args.run();
23559
+ tracingChannel2.end?.publish(context);
23560
+ } catch (error) {
23561
+ context.error = normalizeError3(error);
23562
+ tracingChannel2.error?.publish(context);
23563
+ tracingChannel2.end?.publish(context);
23564
+ throw error;
23565
+ }
23566
+ traced2 = Promise.resolve(originalResult).then(
23567
+ (result) => {
23568
+ context.result = result;
23569
+ tracingChannel2.asyncStart?.publish(context);
23570
+ tracingChannel2.asyncEnd?.publish(context);
23571
+ return result;
23572
+ },
23573
+ (error) => {
23574
+ context.error = normalizeError3(error);
23575
+ tracingChannel2.error?.publish(context);
23576
+ tracingChannel2.asyncStart?.publish(context);
23577
+ tracingChannel2.asyncEnd?.publish(context);
23578
+ throw error;
23579
+ }
23580
+ );
23581
+ };
23582
+ if (tracingChannel2.start?.runStores) {
23583
+ tracingChannel2.start.runStores(context, run);
23584
+ } else {
23585
+ tracingChannel2.start?.publish(context);
23586
+ run();
23587
+ }
23588
+ return { originalResult, traced: traced2 };
23589
+ }
23590
+ function normalizeError3(error) {
23591
+ return error instanceof Error ? error : new Error(String(error));
23592
+ }
23593
+ function preserveCallHandle(originalHandle, traced2) {
23594
+ if (!isFlueCallHandle(originalHandle)) {
23595
+ return traced2;
23596
+ }
23597
+ const handle = originalHandle;
23598
+ const wrapped = {
23599
+ get signal() {
23600
+ return handle.signal;
23601
+ },
23602
+ abort(reason) {
23603
+ return handle.abort(reason);
23604
+ },
23605
+ then(onfulfilled, onrejected) {
23606
+ return traced2.then(onfulfilled, onrejected);
23607
+ }
23608
+ };
23609
+ return wrapped;
23610
+ }
23611
+ function isPlausibleFlueHarness(value) {
23612
+ return !!value && typeof value === "object" && typeof value.session === "function";
23613
+ }
23614
+ function isFlueCallHandle(value) {
23615
+ return !!value && typeof value === "object" && typeof value.then === "function" && typeof value.abort === "function" && "signal" in value;
23616
+ }
23617
+
23618
+ // src/instrumentation/plugins/flue-plugin.ts
23619
+ var FluePlugin = class extends BasePlugin {
23620
+ activeOperationsById = /* @__PURE__ */ new Map();
23621
+ activeOperationsByScope = /* @__PURE__ */ new Map();
23622
+ compactionsByScope = /* @__PURE__ */ new Map();
23623
+ pendingOperationsByKey = /* @__PURE__ */ new Map();
23624
+ tasksById = /* @__PURE__ */ new Map();
23625
+ toolsById = /* @__PURE__ */ new Map();
23626
+ turnsByScope = /* @__PURE__ */ new Map();
23627
+ onEnable() {
23628
+ this.subscribeToContextCreation();
23629
+ this.subscribeToSessionCreation();
23630
+ this.subscribeToContextEvents();
23631
+ this.subscribeToSessionOperations();
23632
+ }
23633
+ onDisable() {
23634
+ for (const unsubscribe of this.unsubscribers) {
23635
+ unsubscribe();
23636
+ }
23637
+ this.unsubscribers = [];
23638
+ this.activeOperationsById.clear();
23639
+ this.activeOperationsByScope.clear();
23640
+ this.compactionsByScope.clear();
23641
+ this.pendingOperationsByKey.clear();
23642
+ this.tasksById.clear();
23643
+ this.toolsById.clear();
23644
+ this.turnsByScope.clear();
23645
+ }
23646
+ subscribeToContextCreation() {
23647
+ const channel2 = flueChannels.createContext.tracingChannel();
23648
+ const handlers = {
23649
+ end: (event) => {
23650
+ const ctx = event.result;
23651
+ if (!ctx) {
23652
+ return;
23653
+ }
23654
+ subscribeFlueContextEvents(ctx, { captureTurnSpans: false });
23655
+ patchFlueContextInPlace(ctx);
23656
+ },
23657
+ error: () => {
23658
+ }
23659
+ };
23660
+ channel2.subscribe(handlers);
23661
+ this.unsubscribers.push(() => {
23662
+ channel2.unsubscribe(handlers);
23663
+ });
23664
+ }
23665
+ subscribeToSessionCreation() {
23666
+ const channel2 = flueChannels.openSession.tracingChannel();
23667
+ const handlers = {
23668
+ asyncEnd: (event) => {
23669
+ if (event.result) {
23670
+ patchFlueSessionInPlace(
23671
+ event.result
23672
+ );
23673
+ }
23674
+ if (event.harness) {
23675
+ wrapFlueHarness(event.harness);
23676
+ }
23677
+ },
23678
+ error: () => {
23679
+ }
23680
+ };
23681
+ channel2.subscribe(handlers);
23682
+ this.unsubscribers.push(() => {
23683
+ channel2.unsubscribe(handlers);
23684
+ });
23685
+ }
23686
+ subscribeToSessionOperations() {
23687
+ this.subscribeToSessionOperation(flueChannels.prompt);
23688
+ this.subscribeToSessionOperation(flueChannels.skill);
23689
+ this.subscribeToSessionOperation(flueChannels.task);
23690
+ this.subscribeToCompact();
23691
+ }
23692
+ subscribeToSessionOperation(channel2) {
23693
+ const tracingChannel2 = channel2.tracingChannel();
23694
+ const states = /* @__PURE__ */ new WeakMap();
23695
+ const ensureState2 = (event) => {
23696
+ const existing = states.get(event);
23697
+ if (existing) {
23698
+ return existing;
23699
+ }
23700
+ const state = this.startOperationState({
23701
+ args: event.arguments,
23702
+ moduleVersion: typeof event.moduleVersion === "string" ? event.moduleVersion : void 0,
23703
+ operation: event.operation,
23704
+ session: event.session
23705
+ });
23706
+ states.set(event, state);
23707
+ return state;
23708
+ };
23709
+ const unbindCurrentSpanStore = this.bindCurrentSpanStoreToOperationStart(
23710
+ tracingChannel2,
23711
+ ensureState2
23712
+ );
23713
+ const handlers = {
23714
+ start: (event) => {
23715
+ ensureState2(event);
23716
+ },
23717
+ asyncEnd: (event) => {
23718
+ this.endOperationState(states.get(event), event.result);
23719
+ states.delete(event);
23720
+ },
23721
+ error: (event) => {
23722
+ const state = states.get(event);
23723
+ if (state && event.error) {
23724
+ safeLog3(state.span, { error: errorToString(event.error) });
23725
+ this.finishOperationState(state);
23726
+ }
23727
+ states.delete(event);
23728
+ }
23729
+ };
23730
+ tracingChannel2.subscribe(handlers);
23731
+ this.unsubscribers.push(() => {
23732
+ unbindCurrentSpanStore?.();
23733
+ tracingChannel2.unsubscribe(handlers);
23734
+ });
23735
+ }
23736
+ subscribeToCompact() {
23737
+ const tracingChannel2 = flueChannels.compact.tracingChannel();
23738
+ const states = /* @__PURE__ */ new WeakMap();
23739
+ const ensureState2 = (event) => {
23740
+ const existing = states.get(event);
23741
+ if (existing) {
23742
+ return existing;
23743
+ }
23744
+ const state = this.startOperationState({
23745
+ args: [],
23746
+ moduleVersion: typeof event.moduleVersion === "string" ? event.moduleVersion : void 0,
23747
+ operation: event.operation,
23748
+ session: event.session
23749
+ });
23750
+ states.set(event, state);
23751
+ return state;
23752
+ };
23753
+ const unbindCurrentSpanStore = this.bindCurrentSpanStoreToOperationStart(
23754
+ tracingChannel2,
23755
+ ensureState2
23756
+ );
23757
+ const handlers = {
23758
+ start: (event) => {
23759
+ ensureState2(event);
23760
+ },
23761
+ asyncEnd: (event) => {
23762
+ this.endOperationState(states.get(event), void 0);
23763
+ states.delete(event);
23764
+ },
23765
+ error: (event) => {
23766
+ const state = states.get(event);
23767
+ if (state && event.error) {
23768
+ safeLog3(state.span, { error: errorToString(event.error) });
23769
+ this.finishOperationState(state);
23770
+ }
23771
+ states.delete(event);
23772
+ }
23773
+ };
23774
+ tracingChannel2.subscribe(handlers);
23775
+ this.unsubscribers.push(() => {
23776
+ unbindCurrentSpanStore?.();
23777
+ tracingChannel2.unsubscribe(handlers);
23778
+ });
23779
+ }
23780
+ subscribeToContextEvents() {
23781
+ const channel2 = flueChannels.contextEvent.tracingChannel();
23782
+ const handlers = {
23783
+ start: (event) => {
23784
+ const flueEvent = event.arguments[0];
23785
+ if (!flueEvent) {
23786
+ return;
23787
+ }
23788
+ try {
23789
+ this.handleFlueEvent(flueEvent, {
23790
+ captureTurnSpans: event.captureTurnSpans !== false
23791
+ });
23792
+ } catch (error) {
23793
+ logInstrumentationError3("Flue event", error);
23794
+ }
23795
+ },
23796
+ error: () => {
23797
+ }
23798
+ };
23799
+ channel2.subscribe(handlers);
23800
+ this.unsubscribers.push(() => {
23801
+ channel2.unsubscribe(handlers);
23802
+ });
23803
+ }
23804
+ bindCurrentSpanStoreToOperationStart(tracingChannel2, ensureState2) {
23805
+ const state = _internalGetGlobalState();
23806
+ const startChannel = tracingChannel2.start;
23807
+ const contextManager = state?.contextManager;
23808
+ const currentSpanStore = contextManager ? contextManager[BRAINTRUST_CURRENT_SPAN_STORE] : void 0;
23809
+ if (!currentSpanStore || !startChannel) {
23810
+ return void 0;
23811
+ }
23812
+ startChannel.bindStore(currentSpanStore, (event) => {
23813
+ const operationState = ensureState2(event);
23814
+ return contextManager.wrapSpanForStore(operationState.span);
23815
+ });
23816
+ return () => {
23817
+ startChannel.unbindStore(currentSpanStore);
23818
+ };
23819
+ }
23820
+ startOperationState(args) {
23821
+ const sessionName = getSessionName(args.session);
23822
+ const metadata = {
23823
+ ...extractOperationInputMetadata(args.operation, args.args),
23824
+ ...extractSessionMetadata(args.session),
23825
+ "flue.operation": args.operation,
23826
+ provider: "flue",
23827
+ ...args.moduleVersion ? { "flue.version": args.moduleVersion } : {}
23828
+ };
23829
+ const span = startSpan({
23830
+ name: `flue.session.${args.operation}`,
23831
+ spanAttributes: { type: "task" /* TASK */ }
23832
+ });
23833
+ const state = {
23834
+ metadata,
23835
+ operation: args.operation,
23836
+ sessionName,
23837
+ span,
23838
+ startTime: getCurrentUnixTimestamp()
23839
+ };
23840
+ safeLog3(span, {
23841
+ input: extractOperationInput(args.operation, args.args),
23842
+ metadata
23843
+ });
23844
+ this.pendingOperationQueue(operationKey(sessionName, args.operation)).push(
23845
+ state
23846
+ );
23847
+ addOperationToScope(
23848
+ this.activeOperationsByScope,
23849
+ sessionName ?? "unknown",
23850
+ state
23851
+ );
23852
+ return state;
23853
+ }
23854
+ endOperationState(state, result) {
23855
+ if (!state) {
23856
+ return;
23857
+ }
23858
+ const metadata = {
23859
+ ...state.metadata,
23860
+ ...extractPromptResponseMetadata(result)
23861
+ };
23862
+ const metrics = {
23863
+ ...buildDurationMetrics3(state.startTime),
23864
+ ...metricsFromUsage(result?.usage)
23865
+ };
23866
+ safeLog3(state.span, {
23867
+ metadata,
23868
+ metrics,
23869
+ output: extractOperationOutput(result)
23870
+ });
23871
+ this.finishCompactionsForOperation(state);
23872
+ this.finishOperationState(state);
23873
+ }
23874
+ finishOperationState(state) {
23875
+ removePendingOperation(this.pendingOperationsByKey, state);
23876
+ if (state.operationId) {
23877
+ this.activeOperationsById.delete(state.operationId);
23878
+ }
23879
+ removeScopedOperation(this.activeOperationsByScope, state);
23880
+ state.span.end();
23881
+ }
23882
+ handleFlueEvent(event, options) {
23883
+ switch (event.type) {
23884
+ case "operation_start":
23885
+ this.handleOperationStart(event);
23886
+ return;
23887
+ case "operation":
23888
+ this.handleOperation(event);
23889
+ return;
23890
+ case "text_delta":
23891
+ if (!options.captureTurnSpans) {
23892
+ return;
23893
+ }
23894
+ this.ensureTurnState(event).text.push(
23895
+ typeof event.text === "string" ? event.text : ""
23896
+ );
23897
+ return;
23898
+ case "thinking_start":
23899
+ if (!options.captureTurnSpans) {
23900
+ return;
23901
+ }
23902
+ this.handleThinkingStart(event);
23903
+ return;
23904
+ case "thinking_delta":
23905
+ if (!options.captureTurnSpans) {
23906
+ return;
23907
+ }
23908
+ this.handleThinkingDelta(event);
23909
+ return;
23910
+ case "thinking_end":
23911
+ if (!options.captureTurnSpans) {
23912
+ return;
23913
+ }
23914
+ this.handleThinkingEnd(event);
23915
+ return;
23916
+ case "turn":
23917
+ if (!options.captureTurnSpans) {
23918
+ return;
23919
+ }
23920
+ this.handleTurn(event);
23921
+ return;
23922
+ case "tool_start":
23923
+ this.handleToolStart(event, options);
23924
+ return;
23925
+ case "tool_call":
23926
+ this.handleToolCall(event);
23927
+ return;
23928
+ case "task_start":
23929
+ this.handleTaskStart(event);
23930
+ return;
23931
+ case "task":
23932
+ this.handleTask(event);
23933
+ return;
23934
+ case "compaction_start":
23935
+ this.handleCompactionStart(event);
23936
+ return;
23937
+ case "compaction":
23938
+ this.handleCompaction(event);
23939
+ return;
23940
+ default:
23941
+ return;
23942
+ }
23943
+ }
23944
+ handleOperationStart(event) {
23945
+ if (!isInstrumentedOperation(event.operationKind)) {
23946
+ return;
23947
+ }
23948
+ const state = this.takePendingOperationForEvent(event);
23949
+ if (!state) {
23950
+ return;
23951
+ }
23952
+ state.operationId = event.operationId;
23953
+ this.activeOperationsById.set(event.operationId, state);
23954
+ addScopedOperation(this.activeOperationsByScope, event, state);
23955
+ state.metadata = {
23956
+ ...state.metadata,
23957
+ ...extractEventMetadata(event),
23958
+ "flue.operation_id": event.operationId
23959
+ };
23960
+ safeLog3(state.span, { metadata: state.metadata });
23961
+ }
23962
+ handleOperation(event) {
23963
+ const state = event.operationId ? this.activeOperationsById.get(event.operationId) : void 0;
23964
+ if (!state) {
23965
+ return;
23966
+ }
23967
+ const metadata = {
23968
+ ...state.metadata,
23969
+ ...extractEventMetadata(event),
23970
+ ...typeof event.durationMs === "number" ? { "flue.duration_ms": event.durationMs } : {},
23971
+ ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {}
23972
+ };
23973
+ const metrics = metricsFromUsage(event.usage);
23974
+ safeLog3(state.span, {
23975
+ ...event.error ? { error: errorToString(event.error) } : {},
23976
+ metadata,
23977
+ ...Object.keys(metrics).length ? { metrics } : {}
23978
+ });
23979
+ }
23980
+ ensureTurnState(event) {
23981
+ const scope = scopeKey(event);
23982
+ const existing = this.turnsByScope.get(scope);
23983
+ if (existing) {
23984
+ return existing;
23985
+ }
23986
+ const parent = this.parentSpanForEvent(event);
23987
+ const metadata = {
23988
+ ...extractEventMetadata(event),
23989
+ provider: "flue"
23990
+ };
23991
+ const span = startFlueSpan(parent, {
23992
+ name: "flue.turn",
23993
+ spanAttributes: { type: "llm" /* LLM */ }
23994
+ });
23995
+ const state = {
23996
+ metadata,
23997
+ span,
23998
+ hasThinking: false,
23999
+ startTime: getCurrentUnixTimestamp(),
24000
+ text: [],
24001
+ thinking: [],
24002
+ toolCalls: []
24003
+ };
24004
+ safeLog3(span, { metadata });
24005
+ this.turnsByScope.set(scope, state);
24006
+ return state;
24007
+ }
24008
+ handleTurn(event) {
24009
+ const scope = scopeKey(event);
24010
+ const state = this.ensureTurnState(event);
24011
+ const text = state.text.join("");
24012
+ const reasoning = state.finalThinking ?? state.thinking.join("");
24013
+ const outputReasoning = reasoning || (state.hasThinking ? "[reasoning stream present; content unavailable]" : void 0);
24014
+ const metadata = {
24015
+ ...state.metadata,
24016
+ ...extractEventMetadata(event),
24017
+ ...event.model ? { model: event.model, "flue.model": event.model } : {},
24018
+ ...event.stopReason ? { "flue.stop_reason": event.stopReason } : {},
24019
+ ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {},
24020
+ provider: "flue"
24021
+ };
24022
+ safeLog3(state.span, {
24023
+ ...event.error ? { error: errorToString(event.error) } : {},
24024
+ metadata,
24025
+ metrics: {
24026
+ ...durationMsMetrics(event.durationMs),
24027
+ ...metricsFromUsage(event.usage)
24028
+ },
24029
+ output: toAssistantOutput(
24030
+ text,
24031
+ event.stopReason,
24032
+ outputReasoning,
24033
+ state.toolCalls
24034
+ )
24035
+ });
24036
+ state.span.end();
24037
+ this.turnsByScope.delete(scope);
24038
+ }
24039
+ handleThinkingDelta(event) {
24040
+ const delta = event.delta;
24041
+ if (typeof delta !== "string" || !delta) {
24042
+ return;
24043
+ }
24044
+ const state = this.ensureTurnState(event);
24045
+ state.hasThinking = true;
24046
+ state.metadata["flue.thinking"] = true;
24047
+ state.thinking.push(delta);
24048
+ }
24049
+ handleThinkingStart(event) {
24050
+ const state = this.ensureTurnState(event);
24051
+ state.hasThinking = true;
24052
+ state.metadata["flue.thinking"] = true;
24053
+ }
24054
+ handleThinkingEnd(event) {
24055
+ const state = this.ensureTurnState(event);
24056
+ state.hasThinking = true;
24057
+ state.metadata["flue.thinking"] = true;
24058
+ if (typeof event.content === "string" && event.content) {
24059
+ state.finalThinking = event.content;
24060
+ }
24061
+ }
24062
+ handleToolStart(event, options) {
24063
+ const toolCallId = event.toolCallId;
24064
+ if (!toolCallId) {
24065
+ return;
24066
+ }
24067
+ const parent = this.parentSpanForEvent(event);
24068
+ const scope = scopeKey(event);
24069
+ let turnState = this.turnsByScope.get(scope);
24070
+ if (!turnState && parent && options.captureTurnSpans) {
24071
+ turnState = this.ensureTurnState(event);
24072
+ }
24073
+ const metadata = {
24074
+ ...extractEventMetadata(event),
24075
+ ...event.toolName ? { "flue.tool_name": event.toolName } : {},
24076
+ "flue.tool_call_id": toolCallId,
24077
+ provider: "flue"
24078
+ };
24079
+ const span = startFlueSpan(parent, {
24080
+ name: `tool: ${event.toolName ?? "unknown"}`,
24081
+ spanAttributes: { type: "tool" /* TOOL */ }
24082
+ });
24083
+ if (turnState) {
24084
+ turnState.toolCalls.push({
24085
+ args: event.args,
24086
+ toolCallId,
24087
+ toolName: event.toolName
24088
+ });
24089
+ }
24090
+ safeLog3(span, {
24091
+ input: event.args,
24092
+ metadata
24093
+ });
24094
+ this.toolsById.set(toolKey(event), {
24095
+ metadata,
24096
+ span,
24097
+ startTime: getCurrentUnixTimestamp()
24098
+ });
24099
+ }
24100
+ handleToolCall(event) {
24101
+ const key = toolKey(event);
24102
+ const state = this.toolsById.get(key) ?? this.startSyntheticToolState(event, event.toolName ?? "unknown");
24103
+ const metadata = {
24104
+ ...state.metadata,
24105
+ ...extractEventMetadata(event),
24106
+ ...event.toolName ? { "flue.tool_name": event.toolName } : {},
24107
+ ...event.toolCallId ? { "flue.tool_call_id": event.toolCallId } : {},
24108
+ ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {}
24109
+ };
24110
+ safeLog3(state.span, {
24111
+ ...event.isError ? { error: errorToString(event.result) } : {},
24112
+ metadata,
24113
+ metrics: durationMsMetrics(event.durationMs),
24114
+ output: event.result
24115
+ });
24116
+ state.span.end();
24117
+ this.toolsById.delete(key);
24118
+ }
24119
+ handleTaskStart(event) {
24120
+ const parent = this.parentSpanForEvent(event);
24121
+ const metadata = {
24122
+ ...extractEventMetadata(event),
24123
+ ...event.role ? { "flue.role": event.role } : {},
24124
+ ...event.cwd ? { "flue.cwd": event.cwd } : {},
24125
+ "flue.task_id": event.taskId,
24126
+ provider: "flue"
24127
+ };
24128
+ const span = startFlueSpan(parent, {
24129
+ name: "flue.task",
24130
+ spanAttributes: { type: "task" /* TASK */ }
24131
+ });
24132
+ safeLog3(span, {
24133
+ input: event.prompt,
24134
+ metadata
24135
+ });
24136
+ this.tasksById.set(event.taskId, {
24137
+ metadata,
24138
+ span,
24139
+ startTime: getCurrentUnixTimestamp()
24140
+ });
24141
+ }
24142
+ handleTask(event) {
24143
+ const state = this.tasksById.get(event.taskId);
24144
+ if (!state) {
24145
+ return;
24146
+ }
24147
+ safeLog3(state.span, {
24148
+ ...event.isError ? { error: errorToString(event.result) } : {},
24149
+ metadata: {
24150
+ ...state.metadata,
24151
+ ...extractEventMetadata(event),
24152
+ ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {}
24153
+ },
24154
+ metrics: durationMsMetrics(event.durationMs),
24155
+ output: event.result
24156
+ });
24157
+ state.span.end();
24158
+ this.tasksById.delete(event.taskId);
24159
+ }
24160
+ handleCompactionStart(event) {
24161
+ const operationState = this.operationStateForEvent(event);
24162
+ const parent = operationState?.span ?? this.parentSpanForEvent(event);
24163
+ const metadata = {
24164
+ ...extractEventMetadata(event),
24165
+ ...event.reason ? { "flue.compaction_reason": event.reason } : {},
24166
+ provider: "flue"
24167
+ };
24168
+ const input = {
24169
+ ...typeof event.estimatedTokens === "number" ? { estimatedTokens: event.estimatedTokens } : {},
24170
+ ...event.reason ? { reason: event.reason } : {}
24171
+ };
24172
+ const span = startFlueSpan(parent, {
24173
+ name: "flue.compaction",
24174
+ spanAttributes: { type: "task" /* TASK */ }
24175
+ });
24176
+ safeLog3(span, {
24177
+ input,
24178
+ metadata
24179
+ });
24180
+ this.compactionsByScope.set(scopeKey(event), {
24181
+ input,
24182
+ metadata,
24183
+ operationState,
24184
+ span,
24185
+ startTime: getCurrentUnixTimestamp()
24186
+ });
24187
+ }
24188
+ handleCompaction(event) {
24189
+ const key = scopeKey(event);
24190
+ const state = this.compactionsByScope.get(key) ?? this.findCompactionState(event);
24191
+ if (!state) {
24192
+ return;
24193
+ }
24194
+ safeLog3(state.span, {
24195
+ metadata: {
24196
+ ...state.metadata,
24197
+ ...extractEventMetadata(event),
24198
+ ...typeof event.messagesBefore === "number" ? { "flue.messages_before": event.messagesBefore } : {},
24199
+ ...typeof event.messagesAfter === "number" ? { "flue.messages_after": event.messagesAfter } : {}
24200
+ },
24201
+ metrics: {
24202
+ ...durationMsMetrics(event.durationMs),
24203
+ ...metricsFromUsage(event.usage)
24204
+ },
24205
+ output: {
24206
+ messagesAfter: event.messagesAfter,
24207
+ messagesBefore: event.messagesBefore
24208
+ }
24209
+ });
24210
+ state.span.end();
24211
+ this.deleteCompactionState(state);
24212
+ }
24213
+ findCompactionState(event) {
24214
+ const operationState = this.operationStateForEvent(event);
24215
+ for (const state of this.compactionsByScope.values()) {
24216
+ if (operationState && state.operationState === operationState) {
24217
+ return state;
24218
+ }
24219
+ }
24220
+ return void 0;
24221
+ }
24222
+ finishCompactionsForOperation(operationState) {
24223
+ for (const state of [...this.compactionsByScope.values()]) {
24224
+ if (state.operationState !== operationState) {
24225
+ continue;
24226
+ }
24227
+ safeLog3(state.span, {
24228
+ input: state.input,
24229
+ metadata: state.metadata,
24230
+ metrics: {
24231
+ ...buildDurationMetrics3(state.startTime)
24232
+ },
24233
+ output: { completed: true }
24234
+ });
24235
+ state.span.end();
24236
+ this.deleteCompactionState(state);
24237
+ }
24238
+ }
24239
+ deleteCompactionState(state) {
24240
+ for (const [key, candidate] of this.compactionsByScope) {
24241
+ if (candidate !== state) {
24242
+ continue;
24243
+ }
24244
+ this.compactionsByScope.delete(key);
24245
+ return;
24246
+ }
24247
+ }
24248
+ startSyntheticToolState(event, toolName) {
24249
+ const parent = this.parentSpanForEvent(event);
24250
+ const metadata = {
24251
+ ...extractEventMetadata(event),
24252
+ ...event.toolCallId ? { "flue.tool_call_id": event.toolCallId } : {},
24253
+ "flue.tool_name": toolName,
24254
+ provider: "flue"
24255
+ };
24256
+ const span = startFlueSpan(parent, {
24257
+ name: `tool: ${toolName}`,
24258
+ spanAttributes: { type: "tool" /* TOOL */ }
24259
+ });
24260
+ safeLog3(span, { metadata });
24261
+ return { metadata, span, startTime: getCurrentUnixTimestamp() };
24262
+ }
24263
+ operationStateForEvent(event) {
24264
+ if (event.operationId) {
24265
+ const operation = this.activeOperationsById.get(event.operationId) ?? this.promotePendingOperationForEvent(event);
24266
+ if (operation) {
24267
+ return operation;
24268
+ }
24269
+ }
24270
+ return this.activeOperationForEventScope(event) ?? this.pendingOperationForEventScope(event);
24271
+ }
24272
+ parentSpanForEvent(event) {
24273
+ if (event.operationId) {
24274
+ const operation = this.operationStateForEvent(event);
24275
+ if (operation) {
24276
+ return operation.span;
24277
+ }
24278
+ }
24279
+ if (event.taskId) {
24280
+ return this.tasksById.get(event.taskId)?.span;
24281
+ }
24282
+ return this.operationStateForEvent(event)?.span;
24283
+ }
24284
+ promotePendingOperationForEvent(event) {
24285
+ if (!event.operationId) {
24286
+ return void 0;
24287
+ }
24288
+ const scopePrefixes = operationScopePrefixes(event);
24289
+ for (const [candidateKey, candidateQueue] of this.pendingOperationsByKey) {
24290
+ if (!candidateQueue.length || !operationKeyMatchesScopes(candidateKey, scopePrefixes)) {
24291
+ continue;
24292
+ }
24293
+ const state = candidateQueue.shift();
24294
+ if (!state) {
24295
+ return void 0;
24296
+ }
24297
+ state.operationId = event.operationId;
24298
+ this.activeOperationsById.set(event.operationId, state);
24299
+ addScopedOperation(this.activeOperationsByScope, event, state);
24300
+ state.metadata = {
24301
+ ...state.metadata,
24302
+ ...extractEventMetadata(event),
24303
+ "flue.operation_id": event.operationId
24304
+ };
24305
+ safeLog3(state.span, { metadata: state.metadata });
24306
+ return state;
24307
+ }
24308
+ return void 0;
24309
+ }
24310
+ activeOperationForEventScope(event) {
24311
+ for (const scope of operationScopeNames(event)) {
24312
+ const operations = this.activeOperationsByScope.get(scope);
24313
+ if (operations?.length) {
24314
+ return operations[operations.length - 1];
24315
+ }
24316
+ }
24317
+ return void 0;
24318
+ }
24319
+ pendingOperationForEventScope(event) {
24320
+ const scopePrefixes = operationScopePrefixes(event);
24321
+ for (const [candidateKey, candidateQueue] of this.pendingOperationsByKey) {
24322
+ if (!candidateQueue.length || !operationKeyMatchesScopes(candidateKey, scopePrefixes)) {
24323
+ continue;
24324
+ }
24325
+ return candidateQueue[0];
24326
+ }
24327
+ return void 0;
24328
+ }
24329
+ takePendingOperationForEvent(event) {
24330
+ const key = operationKey(event.session, event.operationKind);
24331
+ const queue2 = this.pendingOperationsByKey.get(key);
24332
+ if (queue2?.length) {
24333
+ return queue2.shift();
24334
+ }
24335
+ for (const [candidateKey, candidateQueue] of this.pendingOperationsByKey) {
24336
+ if (candidateKey.endsWith(`::${event.operationKind}`) && candidateQueue.length) {
24337
+ return candidateQueue.shift();
24338
+ }
24339
+ }
24340
+ return void 0;
24341
+ }
24342
+ pendingOperationQueue(key) {
24343
+ const existing = this.pendingOperationsByKey.get(key);
24344
+ if (existing) {
24345
+ return existing;
24346
+ }
24347
+ const queue2 = [];
24348
+ this.pendingOperationsByKey.set(key, queue2);
24349
+ return queue2;
24350
+ }
24351
+ };
24352
+ function isInstrumentedOperation(operation) {
24353
+ return operation === "prompt" || operation === "skill" || operation === "task" || operation === "compact";
24354
+ }
24355
+ function getSessionName(session) {
24356
+ return typeof session?.name === "string" ? session.name : void 0;
24357
+ }
24358
+ function operationKey(sessionName, operation) {
24359
+ return `${sessionName ?? "unknown"}::${operation}`;
24360
+ }
24361
+ function operationScopePrefixes(event) {
24362
+ const scopes = /* @__PURE__ */ new Set();
24363
+ for (const scope of operationScopeNames(event)) {
24364
+ scopes.add(`${scope}::`);
24365
+ }
24366
+ return scopes;
24367
+ }
24368
+ function operationKeyMatchesScopes(key, scopes) {
24369
+ for (const scope of scopes) {
24370
+ if (key.startsWith(scope)) {
24371
+ return true;
24372
+ }
24373
+ }
24374
+ return false;
24375
+ }
24376
+ function operationScopeNames(event) {
24377
+ const scopes = /* @__PURE__ */ new Set();
24378
+ if (event.session) {
24379
+ scopes.add(event.session);
24380
+ }
24381
+ if (event.parentSession) {
24382
+ scopes.add(event.parentSession);
24383
+ }
24384
+ if (!scopes.size) {
24385
+ scopes.add("unknown");
24386
+ }
24387
+ return scopes;
24388
+ }
24389
+ function addScopedOperation(operationsByScope, event, state) {
24390
+ for (const scope of operationScopeNames(event)) {
24391
+ addOperationToScope(operationsByScope, scope, state);
24392
+ }
24393
+ }
24394
+ function addOperationToScope(operationsByScope, scope, state) {
24395
+ const operations = operationsByScope.get(scope);
24396
+ if (operations) {
24397
+ if (!operations.includes(state)) {
24398
+ operations.push(state);
24399
+ }
24400
+ } else {
24401
+ operationsByScope.set(scope, [state]);
24402
+ }
24403
+ }
24404
+ function removeScopedOperation(operationsByScope, state) {
24405
+ for (const [scope, operations] of operationsByScope) {
24406
+ const index = operations.indexOf(state);
24407
+ if (index === -1) {
24408
+ continue;
24409
+ }
24410
+ operations.splice(index, 1);
24411
+ if (operations.length === 0) {
24412
+ operationsByScope.delete(scope);
24413
+ }
24414
+ }
24415
+ }
24416
+ function removePendingOperation(pendingOperationsByKey, state) {
24417
+ for (const [key, queue2] of pendingOperationsByKey) {
24418
+ const index = queue2.indexOf(state);
24419
+ if (index === -1) {
24420
+ continue;
24421
+ }
24422
+ queue2.splice(index, 1);
24423
+ if (queue2.length === 0) {
24424
+ pendingOperationsByKey.delete(key);
24425
+ }
24426
+ return;
24427
+ }
24428
+ }
24429
+ function extractSessionMetadata(session) {
24430
+ const sessionName = getSessionName(session);
24431
+ return sessionName ? { "flue.session": sessionName } : {};
24432
+ }
24433
+ function extractEventMetadata(event) {
24434
+ return {
24435
+ ...event.runId ? { "flue.run_id": event.runId } : {},
24436
+ ...typeof event.eventIndex === "number" ? { "flue.event_index": event.eventIndex } : {},
24437
+ ...event.session ? { "flue.session": event.session } : {},
24438
+ ...event.parentSession ? { "flue.parent_session": event.parentSession } : {},
24439
+ ...event.harness ? { "flue.harness": event.harness } : {},
24440
+ ...event.taskId ? { "flue.task_id": event.taskId } : {},
24441
+ ...event.operationId ? { "flue.operation_id": event.operationId } : {}
24442
+ };
24443
+ }
24444
+ function extractOperationInput(operation, args) {
24445
+ switch (operation) {
24446
+ case "prompt":
24447
+ case "task":
24448
+ return args[0];
24449
+ case "skill":
24450
+ return {
24451
+ args: getOptionObject(args[1])?.args,
24452
+ name: args[0]
24453
+ };
24454
+ case "compact":
24455
+ return void 0;
24456
+ }
24457
+ }
24458
+ function extractOperationInputMetadata(operation, args) {
24459
+ const options = getOptionObject(args[1]);
24460
+ return {
24461
+ ...operation === "skill" && typeof args[0] === "string" ? { "flue.skill_name": args[0] } : {},
24462
+ ...options?.model ? { model: options.model, "flue.model": options.model } : {},
24463
+ ...options?.role ? { "flue.role": options.role } : {},
24464
+ ...options?.thinkingLevel ? { "flue.thinking_level": options.thinkingLevel } : {},
24465
+ ...typeof options?.cwd === "string" ? { "flue.cwd": options.cwd } : {},
24466
+ ...Array.isArray(options?.tools) ? {
24467
+ "flue.tools_count": options.tools.length,
24468
+ tools: summarizeTools(options.tools)
24469
+ } : {},
24470
+ ...Array.isArray(options?.images) ? { "flue.images_count": options.images.length } : {},
24471
+ ...options?.result || options?.schema ? { "flue.result_schema": true } : {}
24472
+ };
24473
+ }
24474
+ function getOptionObject(value) {
24475
+ return isObject(value) ? value : void 0;
24476
+ }
24477
+ function summarizeTools(tools) {
24478
+ return tools.flatMap((tool) => {
24479
+ if (!isObject(tool)) {
24480
+ return [];
24481
+ }
24482
+ const name = typeof tool.name === "string" ? tool.name : void 0;
24483
+ if (!name) {
24484
+ return [];
24485
+ }
24486
+ return [
24487
+ {
24488
+ function: {
24489
+ description: typeof tool.description === "string" ? tool.description : void 0,
24490
+ name,
24491
+ parameters: tool.parameters
24492
+ },
24493
+ type: "function"
24494
+ }
24495
+ ];
24496
+ });
24497
+ }
24498
+ function extractPromptResponseMetadata(result) {
24499
+ const modelId = result?.model && typeof result.model.id === "string" ? result.model.id : void 0;
24500
+ return modelId ? {
24501
+ model: modelId,
24502
+ "flue.model": modelId
24503
+ } : {};
24504
+ }
24505
+ function extractOperationOutput(result) {
24506
+ if (!result) {
24507
+ return void 0;
24508
+ }
24509
+ if ("data" in result) {
24510
+ return result.data;
24511
+ }
24512
+ if ("text" in result) {
24513
+ return result.text;
24514
+ }
24515
+ return result;
24516
+ }
24517
+ function metricsFromUsage(usage) {
24518
+ return {
24519
+ ...typeof usage?.input === "number" ? { prompt_tokens: usage.input } : {},
24520
+ ...typeof usage?.output === "number" ? { completion_tokens: usage.output } : {},
24521
+ ...typeof usage?.cacheRead === "number" ? { prompt_cached_tokens: usage.cacheRead } : {},
24522
+ ...typeof usage?.cacheWrite === "number" ? { prompt_cache_creation_tokens: usage.cacheWrite } : {},
24523
+ ...typeof usage?.totalTokens === "number" ? { tokens: usage.totalTokens } : {},
24524
+ ...typeof usage?.cost?.total === "number" ? { estimated_cost: usage.cost.total } : {}
24525
+ };
24526
+ }
24527
+ function buildDurationMetrics3(startTime) {
24528
+ return {
24529
+ duration_ms: Math.max(0, (getCurrentUnixTimestamp() - startTime) * 1e3)
24530
+ };
24531
+ }
24532
+ function durationMsMetrics(durationMs) {
24533
+ return typeof durationMs === "number" ? { duration_ms: durationMs } : {};
24534
+ }
24535
+ function scopeKey(event) {
24536
+ if (event.operationId) {
24537
+ return `operation:${event.operationId}`;
24538
+ }
24539
+ if (event.taskId) {
24540
+ return `task:${event.taskId}`;
24541
+ }
24542
+ if (event.session) {
24543
+ return `session:${event.session}`;
24544
+ }
24545
+ return "flue:unknown";
24546
+ }
24547
+ function toolKey(event) {
24548
+ return `${scopeKey(event)}::tool:${event.toolCallId ?? "unknown"}`;
24549
+ }
24550
+ function toAssistantOutput(text, finishReason, reasoning, toolCalls) {
24551
+ return [
24552
+ {
24553
+ finish_reason: finishReason ?? "stop",
24554
+ index: 0,
24555
+ message: {
24556
+ content: text,
24557
+ ...reasoning ? { reasoning } : {},
24558
+ role: "assistant",
24559
+ ...toolCalls?.length ? {
24560
+ tool_calls: toolCalls.map((toolCall) => ({
24561
+ function: {
24562
+ arguments: toolCall.args === void 0 ? "{}" : JSON.stringify(toolCall.args),
24563
+ name: toolCall.toolName ?? "unknown"
24564
+ },
24565
+ ...toolCall.toolCallId ? { id: toolCall.toolCallId } : {},
24566
+ type: "function"
24567
+ }))
24568
+ } : {}
24569
+ }
24570
+ }
24571
+ ];
24572
+ }
24573
+ function startFlueSpan(parent, args) {
24574
+ return parent ? withCurrent(parent, () => startSpan(args)) : startSpan(args);
24575
+ }
24576
+ function safeLog3(span, event) {
24577
+ try {
24578
+ span.log(event);
24579
+ } catch (error) {
24580
+ logInstrumentationError3("Flue span log", error);
24581
+ }
24582
+ }
24583
+ function errorToString(error) {
24584
+ if (error instanceof Error) {
24585
+ return error.message;
24586
+ }
24587
+ if (typeof error === "string") {
24588
+ return error;
24589
+ }
24590
+ try {
24591
+ return JSON.stringify(error);
24592
+ } catch {
24593
+ return String(error);
24594
+ }
24595
+ }
24596
+ function logInstrumentationError3(label, error) {
24597
+ console.error(`Error in ${label} instrumentation:`, error);
24598
+ }
24599
+
24600
+ // src/wrappers/langchain/callback-handler.ts
24601
+ var BRAINTRUST_LANGCHAIN_CALLBACK_HANDLER_NAME = "BraintrustCallbackHandler";
24602
+ var BraintrustLangChainCallbackHandler = class {
24603
+ name = BRAINTRUST_LANGCHAIN_CALLBACK_HANDLER_NAME;
24604
+ spans = /* @__PURE__ */ new Map();
24605
+ skippedRuns = /* @__PURE__ */ new Set();
24606
+ parent;
24607
+ rootRunId;
24608
+ options;
24609
+ startTimes = /* @__PURE__ */ new Map();
24610
+ firstTokenTimes = /* @__PURE__ */ new Map();
24611
+ ttftMs = /* @__PURE__ */ new Map();
24612
+ constructor(options) {
24613
+ this.parent = options?.parent;
24614
+ this.options = {
24615
+ debug: options?.debug ?? false,
24616
+ excludeMetadataProps: options?.excludeMetadataProps ?? /^(l[sc]_|langgraph_|__pregel_|checkpoint_ns)/,
24617
+ logger: options?.logger
24618
+ };
24619
+ }
24620
+ startSpan({
24621
+ runId,
24622
+ parentRunId,
24623
+ ...args
24624
+ }) {
24625
+ if (this.spans.has(runId)) {
24626
+ return;
24627
+ }
24628
+ if (!parentRunId) {
24629
+ this.rootRunId = runId;
24630
+ }
24631
+ const tags = args.event?.tags;
24632
+ const spanAttributes = args.spanAttributes || {};
24633
+ spanAttributes.type = args.type || spanAttributes.type || "task";
24634
+ args.type = spanAttributes.type;
24635
+ const currentParent = (typeof this.parent === "function" ? this.parent() : this.parent) ?? currentSpan();
24636
+ let parentSpan;
24637
+ if (parentRunId && this.spans.has(parentRunId)) {
24638
+ parentSpan = this.spans.get(parentRunId);
24639
+ } else if (!Object.is(currentParent, NOOP_SPAN)) {
24640
+ parentSpan = currentParent;
24641
+ } else if (this.options.logger) {
24642
+ parentSpan = this.options.logger;
24643
+ } else {
24644
+ parentSpan = { startSpan };
24645
+ }
24646
+ args.event = {
24647
+ ...args.event,
24648
+ tags: void 0,
24649
+ metadata: {
24650
+ ...tags ? { tags } : {},
24651
+ ...args.event?.metadata,
24652
+ braintrust: {
24653
+ integration_name: "langchain-js",
24654
+ sdk_language: "javascript"
24655
+ },
24656
+ run_id: runId,
24657
+ parent_run_id: parentRunId,
24658
+ ...this.options.debug ? { runId, parentRunId } : {}
24659
+ }
24660
+ };
24661
+ let span = parentSpan.startSpan(args);
24662
+ if (!Object.is(this.options.logger, NOOP_SPAN) && Object.is(span, NOOP_SPAN)) {
24663
+ span = initLogger().startSpan(args);
24664
+ }
24665
+ this.spans.set(runId, span);
24666
+ }
24667
+ endSpan({
24668
+ runId,
24669
+ parentRunId,
24670
+ tags,
24671
+ metadata,
24672
+ ...args
24673
+ }) {
24674
+ if (!this.spans.has(runId)) {
24675
+ return;
24676
+ }
24677
+ if (this.skippedRuns.has(runId)) {
24678
+ this.skippedRuns.delete(runId);
24679
+ return;
24680
+ }
24681
+ const span = this.spans.get(runId);
24682
+ this.spans.delete(runId);
24683
+ if (runId === this.rootRunId) {
24684
+ this.rootRunId = void 0;
24685
+ }
24686
+ span.log({ ...args, metadata: { tags, ...metadata } });
24687
+ span.end();
24688
+ }
24689
+ async handleLLMStart(llm, prompts, runId, parentRunId, extraParams, tags, metadata, runName) {
24690
+ this.startSpan({
24691
+ runId,
24692
+ parentRunId,
24693
+ name: runName ?? getSerializedName(llm) ?? "LLM",
24694
+ type: "llm",
24695
+ event: {
24696
+ input: prompts,
24697
+ tags,
24698
+ metadata: {
24699
+ serialized: llm,
24700
+ name: runName,
24701
+ metadata,
24702
+ ...extraParams
24703
+ }
24704
+ }
24705
+ });
24706
+ }
24707
+ async handleLLMError(err, runId, parentRunId, tags) {
24708
+ this.endSpan({ runId, parentRunId, error: err, tags });
24709
+ }
24710
+ async handleLLMEnd(output, runId, parentRunId, tags) {
24711
+ const metrics = getMetricsFromResponse(output);
24712
+ const modelName2 = getModelNameFromResponse(output);
24713
+ const ttft = this.ttftMs.get(runId);
24714
+ if (ttft !== void 0) {
24715
+ metrics.time_to_first_token = ttft;
24716
+ }
24717
+ this.startTimes.delete(runId);
24718
+ this.firstTokenTimes.delete(runId);
24719
+ this.ttftMs.delete(runId);
24720
+ this.endSpan({
24721
+ runId,
24722
+ parentRunId,
24723
+ output,
24724
+ metrics,
24725
+ tags,
24726
+ metadata: {
24727
+ model: modelName2
24728
+ }
24729
+ });
24730
+ }
24731
+ async handleChatModelStart(llm, messages, runId, parentRunId, extraParams, tags, metadata, runName) {
24732
+ this.startTimes.set(runId, Date.now());
24733
+ this.firstTokenTimes.delete(runId);
24734
+ this.ttftMs.delete(runId);
24735
+ this.startSpan({
24736
+ runId,
24737
+ parentRunId,
24738
+ name: runName ?? getSerializedName(llm) ?? "Chat Model",
24739
+ type: "llm",
24740
+ event: {
24741
+ input: messages,
24742
+ tags,
24743
+ metadata: {
24744
+ serialized: llm,
24745
+ name: runName,
24746
+ metadata,
24747
+ ...extraParams
24748
+ }
24749
+ }
24750
+ });
24751
+ }
24752
+ async handleChainStart(chain, inputs, runId, parentRunId, tags, metadata, runType, runName) {
24753
+ if (tags?.includes("langsmith:hidden")) {
24754
+ this.skippedRuns.add(runId);
24755
+ return;
24756
+ }
24757
+ this.startSpan({
24758
+ runId,
24759
+ parentRunId,
24760
+ name: runName ?? getSerializedName(chain) ?? "Chain",
24761
+ event: {
24762
+ input: inputs,
24763
+ tags,
24764
+ metadata: {
24765
+ serialized: chain,
24766
+ name: runName,
24767
+ metadata,
24768
+ run_type: runType
24769
+ }
24770
+ }
24771
+ });
24772
+ }
24773
+ async handleChainError(err, runId, parentRunId, tags, kwargs) {
24774
+ this.endSpan({ runId, parentRunId, error: err, tags, metadata: kwargs });
24775
+ }
24776
+ async handleChainEnd(outputs, runId, parentRunId, tags, kwargs) {
24777
+ this.endSpan({
24778
+ runId,
24779
+ parentRunId,
24780
+ tags,
24781
+ output: outputs,
24782
+ metadata: { ...kwargs }
24783
+ });
24784
+ }
24785
+ async handleToolStart(tool, input, runId, parentRunId, tags, metadata, runName) {
24786
+ this.startSpan({
24787
+ runId,
24788
+ parentRunId,
24789
+ name: runName ?? getSerializedName(tool) ?? "Tool",
24790
+ type: "llm",
24791
+ event: {
24792
+ input: safeJsonParse(input),
24793
+ tags,
24794
+ metadata: {
24795
+ metadata,
24796
+ serialized: tool,
24797
+ input_str: input,
24798
+ input: safeJsonParse(input),
24799
+ name: runName
24800
+ }
24801
+ }
24802
+ });
24803
+ }
24804
+ async handleToolError(err, runId, parentRunId, tags) {
24805
+ this.endSpan({ runId, parentRunId, error: err, tags });
24806
+ }
24807
+ async handleToolEnd(output, runId, parentRunId, tags) {
24808
+ this.endSpan({ runId, parentRunId, output, tags });
24809
+ }
24810
+ async handleAgentAction(action, runId, parentRunId, tags) {
24811
+ this.startSpan({
24812
+ runId,
24813
+ parentRunId,
24814
+ type: "llm",
24815
+ name: typeof action.tool === "string" ? action.tool : "Agent",
24816
+ event: {
24817
+ input: action,
24818
+ tags
24819
+ }
24820
+ });
24821
+ }
24822
+ async handleAgentEnd(action, runId, parentRunId, tags) {
24823
+ this.endSpan({ runId, parentRunId, output: action, tags });
24824
+ }
24825
+ async handleRetrieverStart(retriever, query, runId, parentRunId, tags, metadata, name) {
24826
+ this.startSpan({
24827
+ runId,
24828
+ parentRunId,
24829
+ name: name ?? getSerializedName(retriever) ?? "Retriever",
24830
+ type: "function",
24831
+ event: {
24832
+ input: query,
24833
+ tags,
24834
+ metadata: {
24835
+ serialized: retriever,
24836
+ metadata,
24837
+ name
24838
+ }
24839
+ }
24840
+ });
24841
+ }
24842
+ async handleRetrieverEnd(documents, runId, parentRunId, tags) {
24843
+ this.endSpan({ runId, parentRunId, output: documents, tags });
24844
+ }
24845
+ async handleRetrieverError(err, runId, parentRunId, tags) {
24846
+ this.endSpan({ runId, parentRunId, error: err, tags });
24847
+ }
24848
+ async handleLLMNewToken(_token, _idx, runId, _parentRunId, _tags) {
24849
+ if (!this.firstTokenTimes.has(runId)) {
24850
+ const now2 = Date.now();
24851
+ this.firstTokenTimes.set(runId, now2);
24852
+ const start = this.startTimes.get(runId);
24853
+ if (start !== void 0) {
24854
+ this.ttftMs.set(runId, (now2 - start) / 1e3);
24855
+ }
24856
+ }
24857
+ }
24858
+ };
24859
+ function getSerializedName(serialized) {
24860
+ if (typeof serialized.name === "string") {
24861
+ return serialized.name;
24862
+ }
24863
+ const lastIdPart = serialized.id?.at(-1);
24864
+ return typeof lastIdPart === "string" ? lastIdPart : void 0;
24865
+ }
24866
+ function cleanObject(obj) {
24867
+ return Object.fromEntries(
24868
+ Object.entries(obj).filter(([, value]) => {
24869
+ if (typeof value !== "number") {
24870
+ return false;
24871
+ }
24872
+ return Number.isFinite(value);
24873
+ })
24874
+ );
24875
+ }
24876
+ function walkGenerations(response) {
24877
+ const result = [];
24878
+ const generations = response.generations || [];
24879
+ for (const batch of generations) {
24880
+ if (Array.isArray(batch)) {
24881
+ for (const generation of batch) {
24882
+ if (isRecord(generation)) {
24883
+ result.push(generation);
24884
+ }
24885
+ }
24886
+ } else if (isRecord(batch)) {
24887
+ result.push(batch);
24888
+ }
24889
+ }
24890
+ return result;
24891
+ }
24892
+ function getModelNameFromResponse(response) {
24893
+ for (const generation of walkGenerations(response)) {
24894
+ const message = generation.message;
24895
+ if (!isRecord(message)) {
24896
+ continue;
24897
+ }
24898
+ const responseMetadata = message.response_metadata;
24899
+ if (!isRecord(responseMetadata)) {
24900
+ continue;
24901
+ }
24902
+ const modelName3 = responseMetadata.model_name ?? responseMetadata.model;
24903
+ if (typeof modelName3 === "string") {
24904
+ return modelName3;
24905
+ }
24906
+ }
24907
+ const llmOutput = response.llmOutput || {};
24908
+ const modelName2 = llmOutput.model_name ?? llmOutput.model;
24909
+ return typeof modelName2 === "string" ? modelName2 : void 0;
24910
+ }
24911
+ function getMetricsFromResponse(response) {
24912
+ for (const generation of walkGenerations(response)) {
24913
+ const message = generation.message;
24914
+ if (!isRecord(message)) {
24915
+ continue;
24916
+ }
24917
+ const usageMetadata = message.usage_metadata;
24918
+ if (!isRecord(usageMetadata)) {
24919
+ continue;
24920
+ }
24921
+ const inputTokenDetails = usageMetadata.input_token_details;
24922
+ return cleanObject({
24923
+ total_tokens: usageMetadata.total_tokens,
24924
+ prompt_tokens: usageMetadata.input_tokens,
24925
+ completion_tokens: usageMetadata.output_tokens,
24926
+ prompt_cache_creation_tokens: isRecord(inputTokenDetails) ? inputTokenDetails.cache_creation : void 0,
24927
+ prompt_cached_tokens: isRecord(inputTokenDetails) ? inputTokenDetails.cache_read : void 0
24928
+ });
24929
+ }
24930
+ const llmOutput = response.llmOutput || {};
24931
+ const tokenUsage = isRecord(llmOutput.tokenUsage) ? llmOutput.tokenUsage : isRecord(llmOutput.estimatedTokens) ? llmOutput.estimatedTokens : {};
24932
+ return cleanObject({
24933
+ total_tokens: tokenUsage.totalTokens,
24934
+ prompt_tokens: tokenUsage.promptTokens,
24935
+ completion_tokens: tokenUsage.completionTokens
24936
+ });
24937
+ }
24938
+ function safeJsonParse(input) {
24939
+ try {
24940
+ return JSON.parse(input);
24941
+ } catch {
24942
+ return input;
24943
+ }
24944
+ }
24945
+ function isRecord(value) {
24946
+ return typeof value === "object" && value !== null && !Array.isArray(value);
24947
+ }
24948
+
24949
+ // src/instrumentation/plugins/langchain-channels.ts
24950
+ var langChainChannels = defineChannels("@langchain/core", {
24951
+ configure: channel({
24952
+ channelName: "CallbackManager.configure",
24953
+ kind: "sync-stream"
24954
+ }),
24955
+ configureSync: channel({
24956
+ channelName: "CallbackManager._configureSync",
24957
+ kind: "sync-stream"
24958
+ })
24959
+ });
24960
+
24961
+ // src/instrumentation/plugins/langchain-plugin.ts
24962
+ var LangChainPlugin = class extends BasePlugin {
24963
+ injectedManagers = /* @__PURE__ */ new WeakSet();
24964
+ onEnable() {
24965
+ this.subscribeToConfigure(langChainChannels.configure);
24966
+ this.subscribeToConfigure(langChainChannels.configureSync);
24967
+ }
24968
+ onDisable() {
24969
+ for (const unsubscribe of this.unsubscribers) {
24970
+ unsubscribe();
24971
+ }
24972
+ this.unsubscribers = [];
24973
+ this.injectedManagers = /* @__PURE__ */ new WeakSet();
24974
+ }
24975
+ subscribeToConfigure(channel2) {
24976
+ const tracingChannel2 = channel2.tracingChannel();
24977
+ const handlers = {
24978
+ start: (event) => {
24979
+ injectHandlerIntoArguments(event.arguments);
24980
+ },
24981
+ end: (event) => {
24982
+ this.injectHandler(event.result);
24983
+ }
24984
+ };
24985
+ tracingChannel2.subscribe(handlers);
24986
+ this.unsubscribers.push(() => {
24987
+ tracingChannel2.unsubscribe(handlers);
24988
+ });
24989
+ }
24990
+ injectHandler(result) {
24991
+ if (!isCallbackManager(result)) {
24992
+ return;
24993
+ }
24994
+ if (this.injectedManagers.has(result) || hasBraintrustHandler(result)) {
24995
+ return;
24996
+ }
24997
+ try {
24998
+ result.addHandler(new BraintrustLangChainCallbackHandler(), true);
24999
+ this.injectedManagers.add(result);
25000
+ } catch {
25001
+ }
25002
+ }
25003
+ };
25004
+ function isCallbackManager(value) {
25005
+ if (typeof value !== "object" || value === null) {
25006
+ return false;
25007
+ }
25008
+ const maybeManager = value;
25009
+ return typeof maybeManager.addHandler === "function";
25010
+ }
25011
+ function hasBraintrustHandler(manager) {
25012
+ return manager.handlers?.some((handler) => {
25013
+ if (typeof handler !== "object" || handler === null) {
25014
+ return false;
25015
+ }
25016
+ const name = Reflect.get(handler, "name");
25017
+ return name === BRAINTRUST_LANGCHAIN_CALLBACK_HANDLER_NAME;
25018
+ }) ?? false;
25019
+ }
25020
+ function injectHandlerIntoArguments(args) {
25021
+ if (!isWritableArgumentsObject(args)) {
25022
+ return;
25023
+ }
25024
+ const inheritedHandlers = Reflect.get(args, "0");
25025
+ const handler = new BraintrustLangChainCallbackHandler();
25026
+ if (inheritedHandlers === void 0 || inheritedHandlers === null) {
25027
+ Reflect.set(args, "0", [handler]);
25028
+ return;
25029
+ }
25030
+ if (Array.isArray(inheritedHandlers)) {
25031
+ if (!inheritedHandlers.some(isBraintrustHandler)) {
25032
+ inheritedHandlers.push(handler);
25033
+ }
25034
+ }
25035
+ }
25036
+ function isWritableArgumentsObject(args) {
25037
+ return typeof args === "object" && args !== null;
25038
+ }
25039
+ function isBraintrustHandler(handler) {
25040
+ if (typeof handler !== "object" || handler === null) {
25041
+ return false;
25042
+ }
25043
+ return Reflect.get(handler, "name") === BRAINTRUST_LANGCHAIN_CALLBACK_HANDLER_NAME;
25044
+ }
25045
+
25046
+ // src/instrumentation/braintrust-plugin.ts
25047
+ function getIntegrationConfig(integrations, key) {
25048
+ return integrations[key];
25049
+ }
25050
+ var BraintrustPlugin = class extends BasePlugin {
25051
+ config;
25052
+ openaiPlugin = null;
25053
+ openAICodexPlugin = null;
25054
+ anthropicPlugin = null;
25055
+ aiSDKPlugin = null;
25056
+ claudeAgentSDKPlugin = null;
25057
+ cursorSDKPlugin = null;
25058
+ openAIAgentsPlugin = null;
25059
+ googleGenAIPlugin = null;
25060
+ huggingFacePlugin = null;
25061
+ openRouterPlugin = null;
25062
+ openRouterAgentPlugin = null;
25063
+ mistralPlugin = null;
25064
+ googleADKPlugin = null;
25065
+ coherePlugin = null;
25066
+ groqPlugin = null;
25067
+ genkitPlugin = null;
25068
+ gitHubCopilotPlugin = null;
25069
+ fluePlugin = null;
25070
+ langChainPlugin = null;
25071
+ constructor(config = {}) {
25072
+ super();
25073
+ this.config = config;
25074
+ }
25075
+ onEnable() {
25076
+ const integrations = this.config.integrations || {};
25077
+ if (integrations.openai !== false) {
25078
+ this.openaiPlugin = new OpenAIPlugin();
25079
+ this.openaiPlugin.enable();
22866
25080
  }
22867
25081
  if (integrations.openaiCodexSDK !== false) {
22868
25082
  this.openAICodexPlugin = new OpenAICodexPlugin();
@@ -22884,6 +25098,10 @@ var BraintrustPlugin = class extends BasePlugin {
22884
25098
  this.cursorSDKPlugin = new CursorSDKPlugin();
22885
25099
  this.cursorSDKPlugin.enable();
22886
25100
  }
25101
+ if (integrations.openAIAgents !== false) {
25102
+ this.openAIAgentsPlugin = new OpenAIAgentsPlugin();
25103
+ this.openAIAgentsPlugin.enable();
25104
+ }
22887
25105
  if (integrations.googleGenAI !== false && integrations.google !== false) {
22888
25106
  this.googleGenAIPlugin = new GoogleGenAIPlugin();
22889
25107
  this.googleGenAIPlugin.enable();
@@ -22924,6 +25142,14 @@ var BraintrustPlugin = class extends BasePlugin {
22924
25142
  this.gitHubCopilotPlugin = new GitHubCopilotPlugin();
22925
25143
  this.gitHubCopilotPlugin.enable();
22926
25144
  }
25145
+ if (getIntegrationConfig(integrations, "flue") !== false) {
25146
+ this.fluePlugin = new FluePlugin();
25147
+ this.fluePlugin.enable();
25148
+ }
25149
+ if (integrations.langchain !== false && integrations.langgraph !== false) {
25150
+ this.langChainPlugin = new LangChainPlugin();
25151
+ this.langChainPlugin.enable();
25152
+ }
22927
25153
  }
22928
25154
  onDisable() {
22929
25155
  if (this.openaiPlugin) {
@@ -22950,6 +25176,10 @@ var BraintrustPlugin = class extends BasePlugin {
22950
25176
  this.cursorSDKPlugin.disable();
22951
25177
  this.cursorSDKPlugin = null;
22952
25178
  }
25179
+ if (this.openAIAgentsPlugin) {
25180
+ this.openAIAgentsPlugin.disable();
25181
+ this.openAIAgentsPlugin = null;
25182
+ }
22953
25183
  if (this.googleGenAIPlugin) {
22954
25184
  this.googleGenAIPlugin.disable();
22955
25185
  this.googleGenAIPlugin = null;
@@ -22990,9 +25220,104 @@ var BraintrustPlugin = class extends BasePlugin {
22990
25220
  this.gitHubCopilotPlugin.disable();
22991
25221
  this.gitHubCopilotPlugin = null;
22992
25222
  }
25223
+ if (this.fluePlugin) {
25224
+ this.fluePlugin.disable();
25225
+ this.fluePlugin = null;
25226
+ }
25227
+ if (this.langChainPlugin) {
25228
+ this.langChainPlugin.disable();
25229
+ this.langChainPlugin = null;
25230
+ }
22993
25231
  }
22994
25232
  };
22995
25233
 
25234
+ // src/instrumentation/config.ts
25235
+ var envIntegrationAliases = {
25236
+ openai: "openai",
25237
+ "openai-codex": "openaiCodexSDK",
25238
+ "openai-codex-sdk": "openaiCodexSDK",
25239
+ openaicodexsdk: "openaiCodexSDK",
25240
+ codex: "openaiCodexSDK",
25241
+ "codex-sdk": "openaiCodexSDK",
25242
+ anthropic: "anthropic",
25243
+ aisdk: "aisdk",
25244
+ "ai-sdk": "aisdk",
25245
+ "vercel-ai": "aisdk",
25246
+ vercel: "vercel",
25247
+ claudeagentsdk: "claudeAgentSDK",
25248
+ "claude-agent-sdk": "claudeAgentSDK",
25249
+ cursor: "cursor",
25250
+ "cursor-sdk": "cursorSDK",
25251
+ cursorsdk: "cursorSDK",
25252
+ flue: "flue",
25253
+ "flue-runtime": "flue",
25254
+ "openai-agents": "openAIAgents",
25255
+ openaiagents: "openAIAgents",
25256
+ "openai-agents-core": "openAIAgents",
25257
+ openaiagentscore: "openAIAgents",
25258
+ google: "google",
25259
+ "google-genai": "googleGenAI",
25260
+ googlegenai: "googleGenAI",
25261
+ huggingface: "huggingface",
25262
+ openrouter: "openrouter",
25263
+ openrouteragent: "openrouterAgent",
25264
+ "openrouter-agent": "openrouterAgent",
25265
+ mistral: "mistral",
25266
+ googleadk: "googleADK",
25267
+ "google-adk": "googleADK",
25268
+ cohere: "cohere",
25269
+ groq: "groq",
25270
+ "groq-sdk": "groq",
25271
+ genkit: "genkit",
25272
+ "firebase-genkit": "genkit",
25273
+ githubcopilot: "gitHubCopilot",
25274
+ "github-copilot": "gitHubCopilot",
25275
+ "copilot-sdk": "gitHubCopilot",
25276
+ langchain: "langchain",
25277
+ "langchain-js": "langchain",
25278
+ "@langchain": "langchain",
25279
+ langgraph: "langgraph"
25280
+ };
25281
+ function getDefaultInstrumentationIntegrations() {
25282
+ return {
25283
+ openai: true,
25284
+ openaiCodexSDK: true,
25285
+ anthropic: true,
25286
+ vercel: true,
25287
+ aisdk: true,
25288
+ google: true,
25289
+ googleGenAI: true,
25290
+ googleADK: true,
25291
+ huggingface: true,
25292
+ claudeAgentSDK: true,
25293
+ cursor: true,
25294
+ cursorSDK: true,
25295
+ flue: true,
25296
+ openAIAgents: true,
25297
+ openrouter: true,
25298
+ openrouterAgent: true,
25299
+ mistral: true,
25300
+ cohere: true,
25301
+ groq: true,
25302
+ genkit: true,
25303
+ gitHubCopilot: true,
25304
+ langchain: true,
25305
+ langgraph: true
25306
+ };
25307
+ }
25308
+ function readDisabledInstrumentationEnvConfig(disabledList) {
25309
+ const integrations = {};
25310
+ if (disabledList) {
25311
+ for (const value of disabledList.split(",")) {
25312
+ const sdk = value.trim().toLowerCase();
25313
+ if (sdk.length > 0) {
25314
+ integrations[envIntegrationAliases[sdk] ?? sdk] = false;
25315
+ }
25316
+ }
25317
+ }
25318
+ return { integrations };
25319
+ }
25320
+
22996
25321
  // src/instrumentation/registry.ts
22997
25322
  var REGISTRY_STATE_KEY = /* @__PURE__ */ Symbol.for("braintrust.registry");
22998
25323
  function getSharedState() {
@@ -23071,50 +25396,16 @@ var PluginRegistry = class {
23071
25396
  * Get default configuration (all integrations enabled).
23072
25397
  */
23073
25398
  getDefaultConfig() {
23074
- return {
23075
- openai: true,
23076
- openaiCodexSDK: true,
23077
- anthropic: true,
23078
- vercel: true,
23079
- aisdk: true,
23080
- google: true,
23081
- googleGenAI: true,
23082
- googleADK: true,
23083
- huggingface: true,
23084
- claudeAgentSDK: true,
23085
- cursor: true,
23086
- cursorSDK: true,
23087
- openrouter: true,
23088
- openrouterAgent: true,
23089
- mistral: true,
23090
- cohere: true,
23091
- groq: true,
23092
- genkit: true,
23093
- gitHubCopilot: true
23094
- };
25399
+ return getDefaultInstrumentationIntegrations();
23095
25400
  }
23096
25401
  /**
23097
25402
  * Read configuration from environment variables.
23098
25403
  * Supports: BRAINTRUST_DISABLE_INSTRUMENTATION=openai,anthropic,...
23099
25404
  */
23100
25405
  readEnvConfig() {
23101
- const integrations = {};
23102
- const disabledList = isomorph_default.getEnv("BRAINTRUST_DISABLE_INSTRUMENTATION");
23103
- if (disabledList) {
23104
- const disabled = disabledList.split(",").map((s) => s.trim().toLowerCase()).filter((s) => s.length > 0);
23105
- for (const sdk of disabled) {
23106
- if (sdk === "cursor-sdk") {
23107
- integrations.cursorSDK = false;
23108
- } else if (sdk === "githubcopilot" || sdk === "github-copilot" || sdk === "copilot-sdk") {
23109
- integrations.gitHubCopilot = false;
23110
- } else if (sdk === "openai-codex-sdk") {
23111
- integrations.openaiCodexSDK = false;
23112
- } else {
23113
- integrations[sdk] = false;
23114
- }
23115
- }
23116
- }
23117
- return { integrations };
25406
+ return readDisabledInstrumentationEnvConfig(
25407
+ isomorph_default.getEnv("BRAINTRUST_DISABLE_INSTRUMENTATION")
25408
+ );
23118
25409
  }
23119
25410
  };
23120
25411
  var registry = new PluginRegistry();