braintrust 3.11.0 → 3.13.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 (77) hide show
  1. package/README.md +8 -8
  2. package/dev/dist/index.d.mts +26 -7
  3. package/dev/dist/index.d.ts +26 -7
  4. package/dev/dist/index.js +2717 -335
  5. package/dev/dist/index.mjs +2499 -117
  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 +1803 -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 +3269 -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 +1803 -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 +1803 -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 +1861 -1308
  31. package/dist/auto-instrumentations/bundler/webpack-loader.d.ts +3 -3
  32. package/dist/auto-instrumentations/bundler/webpack.cjs +1803 -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-E5DUYJWK.mjs} +338 -1
  37. package/dist/auto-instrumentations/chunk-GJOO4ESL.mjs +300 -0
  38. package/dist/auto-instrumentations/chunk-WFEUJACP.mjs +18 -0
  39. package/dist/auto-instrumentations/hook.mjs +1713 -1460
  40. package/dist/auto-instrumentations/index.cjs +94 -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 +264 -47
  48. package/dist/browser.d.ts +264 -47
  49. package/dist/browser.js +2521 -159
  50. package/dist/browser.mjs +2521 -159
  51. package/dist/chunk-26JGOELH.js +817 -0
  52. package/dist/chunk-75IQCUB2.mjs +817 -0
  53. package/dist/cli.js +2510 -122
  54. package/dist/edge-light.d.mts +1 -1
  55. package/dist/edge-light.d.ts +1 -1
  56. package/dist/edge-light.js +2521 -159
  57. package/dist/edge-light.mjs +2521 -159
  58. package/dist/index.d.mts +264 -47
  59. package/dist/index.d.ts +264 -47
  60. package/dist/index.js +3498 -1850
  61. package/dist/index.mjs +2635 -987
  62. package/dist/instrumentation/index.d.mts +7897 -48
  63. package/dist/instrumentation/index.d.ts +7897 -48
  64. package/dist/instrumentation/index.js +2408 -95
  65. package/dist/instrumentation/index.mjs +2407 -95
  66. package/dist/workerd.d.mts +1 -1
  67. package/dist/workerd.d.ts +1 -1
  68. package/dist/workerd.js +2521 -159
  69. package/dist/workerd.mjs +2521 -159
  70. package/package.json +23 -17
  71. package/util/dist/index.d.mts +3 -1
  72. package/util/dist/index.d.ts +3 -1
  73. package/util/dist/index.js +6 -0
  74. package/util/dist/index.mjs +6 -0
  75. package/dist/auto-instrumentations/chunk-G6ZWXGZB.mjs +0 -116
  76. package/dist/auto-instrumentations/plugin-Df3qKIl2.d.mts +0 -22
  77. package/dist/auto-instrumentations/plugin-Df3qKIl2.d.ts +0 -22
package/dist/browser.mjs CHANGED
@@ -92,6 +92,7 @@ var iso = {
92
92
  getRepoInfo: async (_settings) => void 0,
93
93
  getPastNAncestors: async () => [],
94
94
  getEnv: (_name) => void 0,
95
+ getBraintrustApiKey: async () => void 0,
95
96
  getCallerLocation: () => void 0,
96
97
  newAsyncLocalStorage: () => new DefaultAsyncLocalStorage(),
97
98
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -924,6 +925,11 @@ function isPromiseLike(value) {
924
925
 
925
926
  // util/object_util.ts
926
927
  var SET_UNION_FIELDS = /* @__PURE__ */ new Set(["tags"]);
928
+ var FORBIDDEN_MERGE_KEYS = /* @__PURE__ */ new Set([
929
+ "__proto__",
930
+ "constructor",
931
+ "prototype"
932
+ ]);
927
933
  function mergeDictsWithPaths({
928
934
  mergeInto,
929
935
  mergeFrom,
@@ -946,6 +952,7 @@ function mergeDictsWithPathsHelper({
946
952
  mergePaths
947
953
  }) {
948
954
  Object.entries(mergeFrom).forEach(([k, mergeFromV]) => {
955
+ if (FORBIDDEN_MERGE_KEYS.has(k)) return;
949
956
  const fullPath = path.concat([k]);
950
957
  const fullPathSerialized = JSON.stringify(fullPath);
951
958
  const mergeIntoV = recordFind(mergeInto, k);
@@ -5019,6 +5026,13 @@ var HTTPConnection = class _HTTPConnection {
5019
5026
  debugLogger.debug(
5020
5027
  `Retrying API request ${object_type} ${JSON.stringify(args)} ${e.status} ${e.text}`
5021
5028
  );
5029
+ const sleepTimeS = HTTP_RETRY_BASE_SLEEP_TIME_S * 2 ** i;
5030
+ debugLogger.info(
5031
+ `Sleeping for ${sleepTimeS}s before retrying API request`
5032
+ );
5033
+ await new Promise(
5034
+ (resolve) => setTimeout(resolve, sleepTimeS * 1e3)
5035
+ );
5022
5036
  continue;
5023
5037
  }
5024
5038
  throw e;
@@ -5420,6 +5434,19 @@ var JSONAttachment = class extends Attachment {
5420
5434
  */
5421
5435
  constructor(data, options) {
5422
5436
  const { filename = "data.json", pretty = false, state } = options ?? {};
5437
+ const deferredJsonAttachment = globalThis.__BT_DATASET_PIPELINE_DEFER_JSON_ATTACHMENT__;
5438
+ if (deferredJsonAttachment) {
5439
+ super({
5440
+ data: new Blob([]),
5441
+ filename,
5442
+ contentType: "application/json",
5443
+ state
5444
+ });
5445
+ return deferredJsonAttachment(data, {
5446
+ filename,
5447
+ pretty
5448
+ });
5449
+ }
5423
5450
  const jsonString = pretty ? JSON.stringify(data, null, 2) : JSON.stringify(data);
5424
5451
  const blob = new Blob([jsonString], { type: "application/json" });
5425
5452
  super({
@@ -5668,20 +5695,7 @@ function startSpanParentArgs(args) {
5668
5695
  `Mismatch between expected span parent object type ${args.parentObjectType} and provided type ${parentComponents.data.object_type}`
5669
5696
  );
5670
5697
  }
5671
- const parentComponentsObjectIdLambda = spanComponentsToObjectIdLambda(
5672
- args.state,
5673
- parentComponents
5674
- );
5675
- const computeParentObjectId = async () => {
5676
- const parentComponentsObjectId = await parentComponentsObjectIdLambda();
5677
- if (await args.parentObjectId.get() !== parentComponentsObjectId) {
5678
- throw new Error(
5679
- `Mismatch between expected span parent object id ${await args.parentObjectId.get()} and provided id ${parentComponentsObjectId}`
5680
- );
5681
- }
5682
- return await args.parentObjectId.get();
5683
- };
5684
- argParentObjectId = new LazyValue(computeParentObjectId);
5698
+ argParentObjectId = args.parentObjectId;
5685
5699
  if (parentComponents.data.row_id) {
5686
5700
  argParentSpanIds = {
5687
5701
  spanId: parentComponents.data.span_id,
@@ -6067,6 +6081,7 @@ var TestBackgroundLogger = class {
6067
6081
  }
6068
6082
  };
6069
6083
  var BACKGROUND_LOGGER_BASE_SLEEP_TIME_S = 1;
6084
+ var HTTP_RETRY_BASE_SLEEP_TIME_S = 1;
6070
6085
  var HTTPBackgroundLogger = class _HTTPBackgroundLogger {
6071
6086
  apiConn;
6072
6087
  queue;
@@ -6697,17 +6712,10 @@ function init(projectOrOptions, optionalOptions) {
6697
6712
  if (repoInfo) {
6698
6713
  return repoInfo;
6699
6714
  }
6700
- let mergedGitMetadataSettings = {
6701
- ...state.gitMetadataSettings || {
6702
- collect: "all"
6703
- }
6704
- };
6705
- if (gitMetadataSettings) {
6706
- mergedGitMetadataSettings = mergeGitMetadataSettings(
6707
- mergedGitMetadataSettings,
6708
- gitMetadataSettings
6709
- );
6710
- }
6715
+ const mergedGitMetadataSettings = state.gitMetadataSettings == null ? gitMetadataSettings ?? { collect: "none" } : mergeGitMetadataSettings(
6716
+ state.gitMetadataSettings,
6717
+ gitMetadataSettings ?? { collect: "all" }
6718
+ );
6711
6719
  return await isomorph_default.getRepoInfo(mergedGitMetadataSettings);
6712
6720
  })();
6713
6721
  if (repoInfoArg) {
@@ -7431,10 +7439,11 @@ async function login(options = {}) {
7431
7439
  async function loginToState(options = {}) {
7432
7440
  const {
7433
7441
  appUrl = isomorph_default.getEnv("BRAINTRUST_APP_URL") || "https://www.braintrust.dev",
7434
- apiKey = isomorph_default.getEnv("BRAINTRUST_API_KEY"),
7442
+ apiKey: apiKeyArg,
7435
7443
  orgName = isomorph_default.getEnv("BRAINTRUST_ORG_NAME"),
7436
7444
  fetch: fetch2 = globalThis.fetch
7437
7445
  } = options || {};
7446
+ const apiKey = apiKeyArg !== void 0 ? apiKeyArg : await isomorph_default.getBraintrustApiKey();
7438
7447
  const appPublicUrl = isomorph_default.getEnv("BRAINTRUST_APP_PUBLIC_URL") || appUrl;
7439
7448
  const state = new BraintrustState(options);
7440
7449
  state.resetLoginInfo();
@@ -8675,9 +8684,15 @@ var SpanImpl = class _SpanImpl {
8675
8684
  const cachedSpan = {
8676
8685
  input: partialRecord.input,
8677
8686
  output: partialRecord.output,
8687
+ expected: partialRecord.expected,
8688
+ error: partialRecord.error,
8689
+ scores: partialRecord.scores,
8690
+ metrics: partialRecord.metrics,
8678
8691
  metadata: partialRecord.metadata,
8692
+ tags: partialRecord.tags,
8679
8693
  span_id: this._spanId,
8680
8694
  span_parents: this._spanParents,
8695
+ is_root: this._spanId === this._rootSpanId,
8681
8696
  span_attributes: partialRecord.span_attributes
8682
8697
  };
8683
8698
  this._state.spanCache.queueWrite(
@@ -9013,6 +9028,7 @@ var Dataset2 = class extends ObjectFetcher {
9013
9028
  metadata,
9014
9029
  tags,
9015
9030
  output,
9031
+ origin,
9016
9032
  isMerge
9017
9033
  }) {
9018
9034
  return new LazyValue(async () => {
@@ -9027,6 +9043,7 @@ var Dataset2 = class extends ObjectFetcher {
9027
9043
  created: !isMerge ? (/* @__PURE__ */ new Date()).toISOString() : void 0,
9028
9044
  //if we're merging/updating an event we will not add this ts
9029
9045
  metadata,
9046
+ origin,
9030
9047
  ...!!isMerge ? {
9031
9048
  [IS_MERGE_FIELD]: true
9032
9049
  } : {}
@@ -9046,6 +9063,7 @@ var Dataset2 = class extends ObjectFetcher {
9046
9063
  * about anything else that's relevant, that you can use to help find and analyze examples later. For example, you could log the
9047
9064
  * `prompt`, example's `id`, or anything else that would be useful to slice/dice later. The values in `metadata` can be any
9048
9065
  * JSON-serializable type, but its keys must be strings.
9066
+ * @param event.origin (Optional) a reference to the source object this dataset record was derived from.
9049
9067
  * @param event.id (Optional) a unique identifier for the event. If you don't provide one, Braintrust will generate one for you.
9050
9068
  * @param event.output: (Deprecated) The output of your application. Use `expected` instead.
9051
9069
  * @returns The `id` of the logged record.
@@ -9056,7 +9074,8 @@ var Dataset2 = class extends ObjectFetcher {
9056
9074
  metadata,
9057
9075
  tags,
9058
9076
  id,
9059
- output
9077
+ output,
9078
+ origin
9060
9079
  }) {
9061
9080
  this.validateEvent({ metadata, expected, output, tags });
9062
9081
  const rowId = id || uuidv42();
@@ -9068,6 +9087,7 @@ var Dataset2 = class extends ObjectFetcher {
9068
9087
  metadata,
9069
9088
  tags,
9070
9089
  output,
9090
+ origin,
9071
9091
  isMerge: false
9072
9092
  })
9073
9093
  );
@@ -13403,11 +13423,11 @@ function resolveDenyOutputPaths(event, defaultDenyOutputPaths) {
13403
13423
  if (Array.isArray(event?.denyOutputPaths)) {
13404
13424
  return event.denyOutputPaths;
13405
13425
  }
13406
- const firstArgument = event?.arguments && event.arguments.length > 0 ? event.arguments[0] : void 0;
13407
- if (!firstArgument || typeof firstArgument !== "object") {
13426
+ const firstArgument2 = event?.arguments && event.arguments.length > 0 ? event.arguments[0] : void 0;
13427
+ if (!firstArgument2 || typeof firstArgument2 !== "object") {
13408
13428
  return defaultDenyOutputPaths;
13409
13429
  }
13410
- const runtimeDenyOutputPaths = firstArgument[RUNTIME_DENY_OUTPUT_PATHS];
13430
+ const runtimeDenyOutputPaths = firstArgument2[RUNTIME_DENY_OUTPUT_PATHS];
13411
13431
  if (Array.isArray(runtimeDenyOutputPaths) && runtimeDenyOutputPaths.every((path) => typeof path === "string")) {
13412
13432
  return runtimeDenyOutputPaths;
13413
13433
  }
@@ -17066,6 +17086,467 @@ function cleanMetrics2(metrics) {
17066
17086
  return cleaned;
17067
17087
  }
17068
17088
 
17089
+ // src/instrumentation/plugins/openai-agents-channels.ts
17090
+ var openAIAgentsCoreChannels = defineChannels("@openai/agents-core", {
17091
+ onTraceStart: channel({
17092
+ channelName: "tracing.processor.onTraceStart",
17093
+ kind: "async"
17094
+ }),
17095
+ onTraceEnd: channel({
17096
+ channelName: "tracing.processor.onTraceEnd",
17097
+ kind: "async"
17098
+ }),
17099
+ onSpanStart: channel({
17100
+ channelName: "tracing.processor.onSpanStart",
17101
+ kind: "async"
17102
+ }),
17103
+ onSpanEnd: channel({
17104
+ channelName: "tracing.processor.onSpanEnd",
17105
+ kind: "async"
17106
+ })
17107
+ });
17108
+
17109
+ // src/instrumentation/plugins/openai-agents-trace-processor.ts
17110
+ function isSpanData(spanData, type) {
17111
+ return spanData.type === type;
17112
+ }
17113
+ function spanTypeFromAgents(span) {
17114
+ const spanType = span.spanData.type;
17115
+ if (spanType === "function" || spanType === "guardrail" || spanType === "mcp_tools") {
17116
+ return "tool" /* TOOL */;
17117
+ }
17118
+ if (spanType === "generation" || spanType === "response" || spanType === "transcription" || spanType === "speech") {
17119
+ return "llm" /* LLM */;
17120
+ }
17121
+ return "task" /* TASK */;
17122
+ }
17123
+ function spanNameFromAgents(span) {
17124
+ const spanData = span.spanData;
17125
+ if ("name" in spanData && spanData.name) {
17126
+ return spanData.name;
17127
+ }
17128
+ switch (spanData.type) {
17129
+ case "generation":
17130
+ return "Generation";
17131
+ case "response":
17132
+ return "Response";
17133
+ case "handoff":
17134
+ return "Handoff";
17135
+ case "mcp_tools":
17136
+ return isSpanData(spanData, "mcp_tools") && spanData.server ? `List Tools (${spanData.server})` : "MCP List Tools";
17137
+ case "transcription":
17138
+ return "Transcription";
17139
+ case "speech":
17140
+ return "Speech";
17141
+ case "speech_group":
17142
+ return "Speech Group";
17143
+ default:
17144
+ return "Unknown";
17145
+ }
17146
+ }
17147
+ function getTimeElapsed(end, start) {
17148
+ if (!start || !end) {
17149
+ return void 0;
17150
+ }
17151
+ const startTime = new Date(start).getTime();
17152
+ const endTime = new Date(end).getTime();
17153
+ if (Number.isNaN(startTime) || Number.isNaN(endTime)) {
17154
+ return void 0;
17155
+ }
17156
+ return (endTime - startTime) / 1e3;
17157
+ }
17158
+ function getNumberProperty2(obj, key) {
17159
+ if (!isObject(obj) || !(key in obj)) {
17160
+ return void 0;
17161
+ }
17162
+ const value = obj[key];
17163
+ return typeof value === "number" ? value : void 0;
17164
+ }
17165
+ function parseUsageMetrics(usage) {
17166
+ const metrics = {};
17167
+ if (!isObject(usage)) {
17168
+ return metrics;
17169
+ }
17170
+ const promptTokens = getNumberProperty2(usage, "prompt_tokens") ?? getNumberProperty2(usage, "input_tokens") ?? getNumberProperty2(usage, "promptTokens") ?? getNumberProperty2(usage, "inputTokens");
17171
+ const completionTokens = getNumberProperty2(usage, "completion_tokens") ?? getNumberProperty2(usage, "output_tokens") ?? getNumberProperty2(usage, "completionTokens") ?? getNumberProperty2(usage, "outputTokens");
17172
+ const totalTokens = getNumberProperty2(usage, "total_tokens") ?? getNumberProperty2(usage, "totalTokens");
17173
+ if (promptTokens !== void 0) {
17174
+ metrics.prompt_tokens = promptTokens;
17175
+ }
17176
+ if (completionTokens !== void 0) {
17177
+ metrics.completion_tokens = completionTokens;
17178
+ }
17179
+ if (totalTokens !== void 0) {
17180
+ metrics.tokens = totalTokens;
17181
+ } else if (promptTokens !== void 0 && completionTokens !== void 0) {
17182
+ metrics.tokens = promptTokens + completionTokens;
17183
+ }
17184
+ const inputDetails = usage.input_tokens_details;
17185
+ const cachedTokens = getNumberProperty2(inputDetails, "cached_tokens");
17186
+ const cacheWriteTokens = getNumberProperty2(
17187
+ inputDetails,
17188
+ "cache_write_tokens"
17189
+ );
17190
+ if (cachedTokens !== void 0) {
17191
+ metrics.prompt_cached_tokens = cachedTokens;
17192
+ }
17193
+ if (cacheWriteTokens !== void 0) {
17194
+ metrics.prompt_cache_creation_tokens = cacheWriteTokens;
17195
+ }
17196
+ return metrics;
17197
+ }
17198
+ var OpenAIAgentsTraceProcessor = class _OpenAIAgentsTraceProcessor {
17199
+ static DEFAULT_MAX_TRACES = 1e4;
17200
+ logger;
17201
+ maxTraces;
17202
+ traceSpans = /* @__PURE__ */ new Map();
17203
+ traceOrder = [];
17204
+ _traceSpans = this.traceSpans;
17205
+ constructor(options = {}) {
17206
+ this.logger = options.logger;
17207
+ this.maxTraces = options.maxTraces ?? _OpenAIAgentsTraceProcessor.DEFAULT_MAX_TRACES;
17208
+ }
17209
+ evictOldestTrace() {
17210
+ const oldestTraceId = this.traceOrder.shift();
17211
+ if (oldestTraceId) {
17212
+ this.traceSpans.delete(oldestTraceId);
17213
+ }
17214
+ }
17215
+ onTraceStart(trace) {
17216
+ if (!trace?.traceId) {
17217
+ return Promise.resolve();
17218
+ }
17219
+ if (this.traceOrder.length >= this.maxTraces) {
17220
+ this.evictOldestTrace();
17221
+ }
17222
+ const current = currentSpan();
17223
+ const span = current && current !== NOOP_SPAN ? current.startSpan({
17224
+ name: trace.name,
17225
+ type: "task" /* TASK */
17226
+ }) : this.logger ? this.logger.startSpan({
17227
+ name: trace.name,
17228
+ type: "task" /* TASK */
17229
+ }) : startSpan({
17230
+ name: trace.name,
17231
+ type: "task" /* TASK */
17232
+ });
17233
+ span.log({
17234
+ input: "Agent workflow started",
17235
+ metadata: {
17236
+ group_id: trace.groupId,
17237
+ ...trace.metadata || {}
17238
+ }
17239
+ });
17240
+ this.traceSpans.set(trace.traceId, {
17241
+ rootSpan: span,
17242
+ childSpans: /* @__PURE__ */ new Map(),
17243
+ metadata: {
17244
+ firstInput: null,
17245
+ lastOutput: null
17246
+ }
17247
+ });
17248
+ this.traceOrder.push(trace.traceId);
17249
+ return Promise.resolve();
17250
+ }
17251
+ async onTraceEnd(trace) {
17252
+ const traceData = this.traceSpans.get(trace?.traceId);
17253
+ if (!traceData) {
17254
+ return;
17255
+ }
17256
+ try {
17257
+ traceData.rootSpan.log({
17258
+ input: traceData.metadata.firstInput,
17259
+ output: traceData.metadata.lastOutput
17260
+ });
17261
+ traceData.rootSpan.end();
17262
+ await traceData.rootSpan.flush();
17263
+ } finally {
17264
+ this.traceSpans.delete(trace.traceId);
17265
+ const orderIndex = this.traceOrder.indexOf(trace.traceId);
17266
+ if (orderIndex > -1) {
17267
+ this.traceOrder.splice(orderIndex, 1);
17268
+ }
17269
+ }
17270
+ }
17271
+ onSpanStart(span) {
17272
+ if (!span?.spanId || !span.traceId) {
17273
+ return Promise.resolve();
17274
+ }
17275
+ const traceData = this.traceSpans.get(span.traceId);
17276
+ if (!traceData) {
17277
+ return Promise.resolve();
17278
+ }
17279
+ const parentSpan = span.parentId ? traceData.childSpans.get(span.parentId) : traceData.rootSpan;
17280
+ if (!parentSpan) {
17281
+ return Promise.resolve();
17282
+ }
17283
+ const childSpan = parentSpan.startSpan({
17284
+ name: spanNameFromAgents(span),
17285
+ type: spanTypeFromAgents(span)
17286
+ });
17287
+ traceData.childSpans.set(span.spanId, childSpan);
17288
+ return Promise.resolve();
17289
+ }
17290
+ onSpanEnd(span) {
17291
+ if (!span?.spanId || !span.traceId) {
17292
+ return Promise.resolve();
17293
+ }
17294
+ const traceData = this.traceSpans.get(span.traceId);
17295
+ if (!traceData) {
17296
+ return Promise.resolve();
17297
+ }
17298
+ const braintrustSpan = traceData.childSpans.get(span.spanId);
17299
+ if (!braintrustSpan) {
17300
+ return Promise.resolve();
17301
+ }
17302
+ const logData = this.extractLogData(span);
17303
+ braintrustSpan.log({
17304
+ error: span.error,
17305
+ ...logData
17306
+ });
17307
+ braintrustSpan.end();
17308
+ traceData.childSpans.delete(span.spanId);
17309
+ const input = logData.input;
17310
+ const output = logData.output;
17311
+ if (traceData.metadata.firstInput === null && input != null) {
17312
+ traceData.metadata.firstInput = input;
17313
+ }
17314
+ if (output != null) {
17315
+ traceData.metadata.lastOutput = output;
17316
+ }
17317
+ return Promise.resolve();
17318
+ }
17319
+ async shutdown() {
17320
+ if (this.logger && typeof this.logger.flush === "function") {
17321
+ await this.logger.flush();
17322
+ }
17323
+ }
17324
+ async forceFlush() {
17325
+ if (this.logger && typeof this.logger.flush === "function") {
17326
+ await this.logger.flush();
17327
+ }
17328
+ }
17329
+ extractLogData(span) {
17330
+ const spanData = span.spanData;
17331
+ switch (spanData.type) {
17332
+ case "agent":
17333
+ return this.extractAgentLogData(spanData);
17334
+ case "response":
17335
+ return this.extractResponseLogData(spanData, span);
17336
+ case "function":
17337
+ return this.extractFunctionLogData(spanData);
17338
+ case "handoff":
17339
+ return this.extractHandoffLogData(spanData);
17340
+ case "guardrail":
17341
+ return this.extractGuardrailLogData(spanData);
17342
+ case "generation":
17343
+ return this.extractGenerationLogData(spanData, span);
17344
+ case "custom":
17345
+ return this.extractCustomLogData(spanData);
17346
+ case "mcp_tools":
17347
+ return this.extractMCPListToolsLogData(spanData);
17348
+ case "transcription":
17349
+ return this.extractTranscriptionLogData(spanData);
17350
+ case "speech":
17351
+ return this.extractSpeechLogData(spanData);
17352
+ case "speech_group":
17353
+ return this.extractSpeechGroupLogData(spanData);
17354
+ default:
17355
+ return {};
17356
+ }
17357
+ }
17358
+ extractAgentLogData(spanData) {
17359
+ return {
17360
+ metadata: {
17361
+ tools: spanData.tools,
17362
+ handoffs: spanData.handoffs,
17363
+ output_type: spanData.output_type
17364
+ }
17365
+ };
17366
+ }
17367
+ extractResponseLogData(spanData, span) {
17368
+ const response = spanData._response;
17369
+ const output = isObject(response) ? response.output : void 0;
17370
+ const usage = isObject(response) ? response.usage : void 0;
17371
+ const metrics = {
17372
+ ...this.extractTimingMetrics(span),
17373
+ ...parseUsageMetrics(usage)
17374
+ };
17375
+ return {
17376
+ input: spanData._input,
17377
+ output,
17378
+ metadata: isObject(response) ? this.omitKeys(response, ["output", "usage"]) : {},
17379
+ metrics
17380
+ };
17381
+ }
17382
+ extractFunctionLogData(spanData) {
17383
+ return {
17384
+ input: spanData.input,
17385
+ output: spanData.output
17386
+ };
17387
+ }
17388
+ extractHandoffLogData(spanData) {
17389
+ return {
17390
+ metadata: {
17391
+ from_agent: spanData.from_agent,
17392
+ to_agent: spanData.to_agent
17393
+ }
17394
+ };
17395
+ }
17396
+ extractGuardrailLogData(spanData) {
17397
+ return {
17398
+ metadata: {
17399
+ triggered: spanData.triggered
17400
+ }
17401
+ };
17402
+ }
17403
+ extractGenerationLogData(spanData, span) {
17404
+ return {
17405
+ input: spanData.input,
17406
+ output: spanData.output,
17407
+ metadata: {
17408
+ model: spanData.model,
17409
+ model_config: spanData.model_config
17410
+ },
17411
+ metrics: {
17412
+ ...this.extractTimingMetrics(span),
17413
+ ...parseUsageMetrics(spanData.usage)
17414
+ }
17415
+ };
17416
+ }
17417
+ extractCustomLogData(spanData) {
17418
+ return spanData.data || {};
17419
+ }
17420
+ extractMCPListToolsLogData(spanData) {
17421
+ return {
17422
+ output: spanData.result,
17423
+ metadata: {
17424
+ server: spanData.server
17425
+ }
17426
+ };
17427
+ }
17428
+ extractTranscriptionLogData(spanData) {
17429
+ return {
17430
+ input: spanData.input,
17431
+ output: spanData.output,
17432
+ metadata: {
17433
+ model: spanData.model,
17434
+ model_config: spanData.model_config
17435
+ }
17436
+ };
17437
+ }
17438
+ extractSpeechLogData(spanData) {
17439
+ return {
17440
+ input: spanData.input,
17441
+ output: spanData.output,
17442
+ metadata: {
17443
+ model: spanData.model,
17444
+ model_config: spanData.model_config
17445
+ }
17446
+ };
17447
+ }
17448
+ extractSpeechGroupLogData(spanData) {
17449
+ return {
17450
+ input: spanData.input
17451
+ };
17452
+ }
17453
+ extractTimingMetrics(span) {
17454
+ const timeToFirstToken = getTimeElapsed(
17455
+ span.endedAt ?? void 0,
17456
+ span.startedAt ?? void 0
17457
+ );
17458
+ return timeToFirstToken === void 0 ? {} : { time_to_first_token: timeToFirstToken };
17459
+ }
17460
+ omitKeys(value, keys) {
17461
+ const result = {};
17462
+ for (const [key, fieldValue] of Object.entries(value)) {
17463
+ if (!keys.includes(key)) {
17464
+ result[key] = fieldValue;
17465
+ }
17466
+ }
17467
+ return result;
17468
+ }
17469
+ };
17470
+
17471
+ // src/instrumentation/plugins/openai-agents-plugin.ts
17472
+ function firstArgument(args) {
17473
+ if (Array.isArray(args)) {
17474
+ return args[0];
17475
+ }
17476
+ if (isObject(args) && "length" in args && typeof args.length === "number" && Number.isInteger(args.length) && args.length >= 0) {
17477
+ return Array.from(args)[0];
17478
+ }
17479
+ return void 0;
17480
+ }
17481
+ function isOpenAIAgentsTrace(value) {
17482
+ return isObject(value) && value.type === "trace" && typeof value.traceId === "string";
17483
+ }
17484
+ function isOpenAIAgentsSpan(value) {
17485
+ return isObject(value) && value.type === "trace.span" && typeof value.traceId === "string" && typeof value.spanId === "string";
17486
+ }
17487
+ var OpenAIAgentsPlugin = class extends BasePlugin {
17488
+ processor = new OpenAIAgentsTraceProcessor();
17489
+ onEnable() {
17490
+ this.subscribeToTraceLifecycle();
17491
+ }
17492
+ onDisable() {
17493
+ this.unsubscribers = unsubscribeAll(this.unsubscribers);
17494
+ void this.processor.shutdown();
17495
+ }
17496
+ subscribeToTraceLifecycle() {
17497
+ const traceStartChannel = openAIAgentsCoreChannels.onTraceStart.tracingChannel();
17498
+ const traceStartHandlers = {
17499
+ start: (event) => {
17500
+ const trace = firstArgument(event.arguments);
17501
+ if (isOpenAIAgentsTrace(trace)) {
17502
+ void this.processor.onTraceStart(trace);
17503
+ }
17504
+ }
17505
+ };
17506
+ traceStartChannel.subscribe(traceStartHandlers);
17507
+ this.unsubscribers.push(
17508
+ () => traceStartChannel.unsubscribe(traceStartHandlers)
17509
+ );
17510
+ const traceEndChannel = openAIAgentsCoreChannels.onTraceEnd.tracingChannel();
17511
+ const traceEndHandlers = {
17512
+ start: (event) => {
17513
+ const trace = firstArgument(event.arguments);
17514
+ if (isOpenAIAgentsTrace(trace)) {
17515
+ void this.processor.onTraceEnd(trace);
17516
+ }
17517
+ }
17518
+ };
17519
+ traceEndChannel.subscribe(traceEndHandlers);
17520
+ this.unsubscribers.push(
17521
+ () => traceEndChannel.unsubscribe(traceEndHandlers)
17522
+ );
17523
+ const spanStartChannel = openAIAgentsCoreChannels.onSpanStart.tracingChannel();
17524
+ const spanStartHandlers = {
17525
+ start: (event) => {
17526
+ const span = firstArgument(event.arguments);
17527
+ if (isOpenAIAgentsSpan(span)) {
17528
+ void this.processor.onSpanStart(span);
17529
+ }
17530
+ }
17531
+ };
17532
+ spanStartChannel.subscribe(spanStartHandlers);
17533
+ this.unsubscribers.push(
17534
+ () => spanStartChannel.unsubscribe(spanStartHandlers)
17535
+ );
17536
+ const spanEndChannel = openAIAgentsCoreChannels.onSpanEnd.tracingChannel();
17537
+ const spanEndHandlers = {
17538
+ start: (event) => {
17539
+ const span = firstArgument(event.arguments);
17540
+ if (isOpenAIAgentsSpan(span)) {
17541
+ void this.processor.onSpanEnd(span);
17542
+ }
17543
+ }
17544
+ };
17545
+ spanEndChannel.subscribe(spanEndHandlers);
17546
+ this.unsubscribers.push(() => spanEndChannel.unsubscribe(spanEndHandlers));
17547
+ }
17548
+ };
17549
+
17069
17550
  // src/instrumentation/plugins/google-genai-channels.ts
17070
17551
  var googleGenAIChannels = defineChannels("@google/genai", {
17071
17552
  generateContent: channel({
@@ -23358,58 +23839,1794 @@ var GitHubCopilotPlugin = class extends BasePlugin {
23358
23839
  }
23359
23840
  };
23360
23841
 
23361
- // src/instrumentation/braintrust-plugin.ts
23362
- function getIntegrationConfig(integrations, key) {
23363
- return integrations[key];
23842
+ // src/instrumentation/plugins/flue-channels.ts
23843
+ var flueChannels = defineChannels("@flue/runtime", {
23844
+ createContext: channel({
23845
+ channelName: "createFlueContext",
23846
+ kind: "sync-stream"
23847
+ }),
23848
+ openSession: channel({
23849
+ channelName: "Harness.openSession",
23850
+ kind: "async"
23851
+ }),
23852
+ contextEvent: channel({
23853
+ channelName: "context.event",
23854
+ kind: "sync-stream"
23855
+ }),
23856
+ prompt: channel({
23857
+ channelName: "session.prompt",
23858
+ kind: "async"
23859
+ }),
23860
+ skill: channel({
23861
+ channelName: "session.skill",
23862
+ kind: "async"
23863
+ }),
23864
+ task: channel({
23865
+ channelName: "session.task",
23866
+ kind: "async"
23867
+ }),
23868
+ compact: channel({
23869
+ channelName: "session.compact",
23870
+ kind: "async"
23871
+ })
23872
+ });
23873
+
23874
+ // src/wrappers/flue.ts
23875
+ var WRAPPED_FLUE_CONTEXT = /* @__PURE__ */ Symbol.for("braintrust.flue.wrapped-context");
23876
+ var WRAPPED_FLUE_HARNESS = /* @__PURE__ */ Symbol.for("braintrust.flue.wrapped-harness");
23877
+ var WRAPPED_FLUE_SESSION = /* @__PURE__ */ Symbol.for("braintrust.flue.wrapped-session");
23878
+ var SUBSCRIBED_FLUE_CONTEXT_EVENTS = /* @__PURE__ */ Symbol.for(
23879
+ "braintrust.flue.subscribed-context-events"
23880
+ );
23881
+ function wrapFlueContext(ctx) {
23882
+ if (!isPlausibleFlueContext(ctx)) {
23883
+ console.warn("Unsupported Flue context. Not wrapping.");
23884
+ return ctx;
23885
+ }
23886
+ const context = ctx;
23887
+ subscribeFlueContextEvents(context, { captureTurnSpans: true });
23888
+ return patchFlueContextInPlace(context);
23364
23889
  }
23365
- var BraintrustPlugin = class extends BasePlugin {
23366
- config;
23367
- openaiPlugin = null;
23368
- openAICodexPlugin = null;
23369
- anthropicPlugin = null;
23370
- aiSDKPlugin = null;
23371
- claudeAgentSDKPlugin = null;
23372
- cursorSDKPlugin = null;
23373
- googleGenAIPlugin = null;
23374
- huggingFacePlugin = null;
23375
- openRouterPlugin = null;
23376
- openRouterAgentPlugin = null;
23377
- mistralPlugin = null;
23378
- googleADKPlugin = null;
23379
- coherePlugin = null;
23380
- groqPlugin = null;
23381
- genkitPlugin = null;
23382
- gitHubCopilotPlugin = null;
23383
- constructor(config = {}) {
23384
- super();
23385
- this.config = config;
23890
+ function patchFlueContextInPlace(ctx) {
23891
+ const context = ctx;
23892
+ if (context[WRAPPED_FLUE_CONTEXT]) {
23893
+ return ctx;
23386
23894
  }
23387
- onEnable() {
23388
- const integrations = this.config.integrations || {};
23389
- if (integrations.openai !== false) {
23390
- this.openaiPlugin = new OpenAIPlugin();
23391
- this.openaiPlugin.enable();
23392
- }
23393
- if (integrations.openaiCodexSDK !== false) {
23394
- this.openAICodexPlugin = new OpenAICodexPlugin();
23395
- this.openAICodexPlugin.enable();
23396
- }
23397
- if (integrations.anthropic !== false) {
23398
- this.anthropicPlugin = new AnthropicPlugin();
23399
- this.anthropicPlugin.enable();
23400
- }
23401
- if (integrations.aisdk !== false && integrations.vercel !== false) {
23402
- this.aiSDKPlugin = new AISDKPlugin();
23403
- this.aiSDKPlugin.enable();
23404
- }
23405
- if (integrations.claudeAgentSDK !== false) {
23406
- this.claudeAgentSDKPlugin = new ClaudeAgentSDKPlugin();
23895
+ const originalInit = context.init.bind(context);
23896
+ try {
23897
+ Object.defineProperty(context, WRAPPED_FLUE_CONTEXT, {
23898
+ configurable: false,
23899
+ enumerable: false,
23900
+ value: true
23901
+ });
23902
+ Object.defineProperty(context, "init", {
23903
+ configurable: true,
23904
+ value: async function wrappedFlueInit(options) {
23905
+ const harness = await originalInit(options);
23906
+ return wrapFlueHarness(harness);
23907
+ },
23908
+ writable: true
23909
+ });
23910
+ } catch {
23911
+ }
23912
+ return ctx;
23913
+ }
23914
+ function wrapFlueSession(session) {
23915
+ if (!isPlausibleFlueSession(session)) {
23916
+ console.warn("Unsupported Flue session. Not wrapping.");
23917
+ return session;
23918
+ }
23919
+ return patchFlueSessionInPlace(session);
23920
+ }
23921
+ function subscribeFlueContextEvents(ctx, options = {}) {
23922
+ if (!ctx || typeof ctx !== "object" || typeof ctx.subscribeEvent !== "function") {
23923
+ return void 0;
23924
+ }
23925
+ const context = ctx;
23926
+ const captureTurnSpans = options.captureTurnSpans ?? true;
23927
+ const existingSubscription = context[SUBSCRIBED_FLUE_CONTEXT_EVENTS];
23928
+ if (existingSubscription) {
23929
+ if (existingSubscription.captureTurnSpans || !captureTurnSpans) {
23930
+ return void 0;
23931
+ }
23932
+ try {
23933
+ existingSubscription.unsubscribe();
23934
+ } catch {
23935
+ }
23936
+ }
23937
+ try {
23938
+ const unsubscribe = ctx.subscribeEvent((event) => {
23939
+ flueChannels.contextEvent.traceSync(() => void 0, {
23940
+ arguments: [event],
23941
+ captureTurnSpans,
23942
+ context: ctx
23943
+ });
23944
+ });
23945
+ if (existingSubscription) {
23946
+ existingSubscription.captureTurnSpans = captureTurnSpans;
23947
+ existingSubscription.unsubscribe = unsubscribe;
23948
+ } else {
23949
+ Object.defineProperty(context, SUBSCRIBED_FLUE_CONTEXT_EVENTS, {
23950
+ configurable: false,
23951
+ enumerable: false,
23952
+ value: {
23953
+ captureTurnSpans,
23954
+ unsubscribe
23955
+ }
23956
+ });
23957
+ }
23958
+ return unsubscribe;
23959
+ } catch {
23960
+ return void 0;
23961
+ }
23962
+ }
23963
+ function wrapFlueHarness(harness) {
23964
+ if (!isPlausibleFlueHarness(harness)) {
23965
+ return harness;
23966
+ }
23967
+ const target = harness;
23968
+ if (target[WRAPPED_FLUE_HARNESS]) {
23969
+ return harness;
23970
+ }
23971
+ const originalSession = target.session.bind(target);
23972
+ try {
23973
+ Object.defineProperty(target, WRAPPED_FLUE_HARNESS, {
23974
+ configurable: false,
23975
+ enumerable: false,
23976
+ value: true
23977
+ });
23978
+ Object.defineProperty(target, "session", {
23979
+ configurable: true,
23980
+ value: async function wrappedFlueHarnessSession(name, options) {
23981
+ const session = await originalSession(name, options);
23982
+ return patchFlueSessionInPlace(session);
23983
+ },
23984
+ writable: true
23985
+ });
23986
+ const sessions = target.sessions;
23987
+ if (sessions && typeof sessions === "object") {
23988
+ patchFlueSessionFactory(sessions, "get");
23989
+ patchFlueSessionFactory(sessions, "create");
23990
+ }
23991
+ } catch {
23992
+ }
23993
+ return harness;
23994
+ }
23995
+ function patchFlueSessionInPlace(session) {
23996
+ if (session[WRAPPED_FLUE_SESSION]) {
23997
+ return session;
23998
+ }
23999
+ try {
24000
+ Object.defineProperty(session, WRAPPED_FLUE_SESSION, {
24001
+ configurable: false,
24002
+ enumerable: false,
24003
+ value: true
24004
+ });
24005
+ patchCallHandleMethod(session, "prompt", flueChannels.prompt);
24006
+ patchCallHandleMethod(session, "skill", flueChannels.skill);
24007
+ patchCallHandleMethod(session, "task", flueChannels.task);
24008
+ patchCompact(session);
24009
+ } catch {
24010
+ }
24011
+ return session;
24012
+ }
24013
+ function patchFlueSessionFactory(sessions, method) {
24014
+ const original = sessions[method];
24015
+ if (typeof original !== "function") {
24016
+ return;
24017
+ }
24018
+ const bound = original.bind(sessions);
24019
+ Object.defineProperty(sessions, method, {
24020
+ configurable: true,
24021
+ value: async function wrappedFlueSessionFactory(name, options) {
24022
+ const session = await bound(name, options);
24023
+ return patchFlueSessionInPlace(session);
24024
+ },
24025
+ writable: true
24026
+ });
24027
+ }
24028
+ function patchCallHandleMethod(session, method, channel2) {
24029
+ const original = session[method];
24030
+ if (typeof original !== "function") {
24031
+ return;
24032
+ }
24033
+ const bound = original.bind(session);
24034
+ Object.defineProperty(session, method, {
24035
+ configurable: true,
24036
+ value(input, options) {
24037
+ const args = [input, options];
24038
+ const { originalResult, traced: traced2 } = traceFlueOperation(channel2, {
24039
+ context: {
24040
+ arguments: args,
24041
+ operation: method,
24042
+ session
24043
+ },
24044
+ run: () => bound(input, options)
24045
+ });
24046
+ return preserveCallHandle(originalResult, traced2);
24047
+ },
24048
+ writable: true
24049
+ });
24050
+ }
24051
+ function patchCompact(session) {
24052
+ const original = session.compact;
24053
+ if (typeof original !== "function") {
24054
+ return;
24055
+ }
24056
+ const bound = original.bind(session);
24057
+ Object.defineProperty(session, "compact", {
24058
+ configurable: true,
24059
+ value() {
24060
+ const context = {
24061
+ arguments: [],
24062
+ operation: "compact",
24063
+ session
24064
+ };
24065
+ return flueChannels.compact.tracePromise(() => bound(), context);
24066
+ },
24067
+ writable: true
24068
+ });
24069
+ }
24070
+ function traceFlueOperation(channel2, args) {
24071
+ const tracingChannel2 = channel2.tracingChannel();
24072
+ const context = args.context;
24073
+ let originalResult;
24074
+ let traced2;
24075
+ const run = () => {
24076
+ try {
24077
+ originalResult = args.run();
24078
+ tracingChannel2.end?.publish(context);
24079
+ } catch (error) {
24080
+ context.error = normalizeError3(error);
24081
+ tracingChannel2.error?.publish(context);
24082
+ tracingChannel2.end?.publish(context);
24083
+ throw error;
24084
+ }
24085
+ traced2 = Promise.resolve(originalResult).then(
24086
+ (result) => {
24087
+ context.result = result;
24088
+ tracingChannel2.asyncStart?.publish(context);
24089
+ tracingChannel2.asyncEnd?.publish(context);
24090
+ return result;
24091
+ },
24092
+ (error) => {
24093
+ context.error = normalizeError3(error);
24094
+ tracingChannel2.error?.publish(context);
24095
+ tracingChannel2.asyncStart?.publish(context);
24096
+ tracingChannel2.asyncEnd?.publish(context);
24097
+ throw error;
24098
+ }
24099
+ );
24100
+ };
24101
+ if (tracingChannel2.start?.runStores) {
24102
+ tracingChannel2.start.runStores(context, run);
24103
+ } else {
24104
+ tracingChannel2.start?.publish(context);
24105
+ run();
24106
+ }
24107
+ return { originalResult, traced: traced2 };
24108
+ }
24109
+ function normalizeError3(error) {
24110
+ return error instanceof Error ? error : new Error(String(error));
24111
+ }
24112
+ function preserveCallHandle(originalHandle, traced2) {
24113
+ if (!isFlueCallHandle(originalHandle)) {
24114
+ return traced2;
24115
+ }
24116
+ const handle = originalHandle;
24117
+ const wrapped = {
24118
+ get signal() {
24119
+ return handle.signal;
24120
+ },
24121
+ abort(reason) {
24122
+ return handle.abort(reason);
24123
+ },
24124
+ then(onfulfilled, onrejected) {
24125
+ return traced2.then(onfulfilled, onrejected);
24126
+ }
24127
+ };
24128
+ return wrapped;
24129
+ }
24130
+ function isPlausibleFlueContext(value) {
24131
+ return !!value && typeof value === "object" && typeof value.init === "function";
24132
+ }
24133
+ function isPlausibleFlueHarness(value) {
24134
+ return !!value && typeof value === "object" && typeof value.session === "function";
24135
+ }
24136
+ function isPlausibleFlueSession(value) {
24137
+ return !!value && typeof value === "object" && typeof value.prompt === "function" && typeof value.skill === "function" && typeof value.task === "function" && typeof value.compact === "function";
24138
+ }
24139
+ function isFlueCallHandle(value) {
24140
+ return !!value && typeof value === "object" && typeof value.then === "function" && typeof value.abort === "function" && "signal" in value;
24141
+ }
24142
+
24143
+ // src/instrumentation/plugins/flue-plugin.ts
24144
+ var FluePlugin = class extends BasePlugin {
24145
+ activeOperationsById = /* @__PURE__ */ new Map();
24146
+ activeOperationsByScope = /* @__PURE__ */ new Map();
24147
+ compactionsByScope = /* @__PURE__ */ new Map();
24148
+ pendingOperationsByKey = /* @__PURE__ */ new Map();
24149
+ tasksById = /* @__PURE__ */ new Map();
24150
+ toolsById = /* @__PURE__ */ new Map();
24151
+ turnsByScope = /* @__PURE__ */ new Map();
24152
+ onEnable() {
24153
+ this.subscribeToContextCreation();
24154
+ this.subscribeToSessionCreation();
24155
+ this.subscribeToContextEvents();
24156
+ this.subscribeToSessionOperations();
24157
+ }
24158
+ onDisable() {
24159
+ for (const unsubscribe of this.unsubscribers) {
24160
+ unsubscribe();
24161
+ }
24162
+ this.unsubscribers = [];
24163
+ this.activeOperationsById.clear();
24164
+ this.activeOperationsByScope.clear();
24165
+ this.compactionsByScope.clear();
24166
+ this.pendingOperationsByKey.clear();
24167
+ this.tasksById.clear();
24168
+ this.toolsById.clear();
24169
+ this.turnsByScope.clear();
24170
+ }
24171
+ subscribeToContextCreation() {
24172
+ const channel2 = flueChannels.createContext.tracingChannel();
24173
+ const handlers = {
24174
+ end: (event) => {
24175
+ const ctx = event.result;
24176
+ if (!ctx) {
24177
+ return;
24178
+ }
24179
+ subscribeFlueContextEvents(ctx, { captureTurnSpans: false });
24180
+ patchFlueContextInPlace(ctx);
24181
+ },
24182
+ error: () => {
24183
+ }
24184
+ };
24185
+ channel2.subscribe(handlers);
24186
+ this.unsubscribers.push(() => {
24187
+ channel2.unsubscribe(handlers);
24188
+ });
24189
+ }
24190
+ subscribeToSessionCreation() {
24191
+ const channel2 = flueChannels.openSession.tracingChannel();
24192
+ const handlers = {
24193
+ asyncEnd: (event) => {
24194
+ if (event.result) {
24195
+ patchFlueSessionInPlace(
24196
+ event.result
24197
+ );
24198
+ }
24199
+ if (event.harness) {
24200
+ wrapFlueHarness(event.harness);
24201
+ }
24202
+ },
24203
+ error: () => {
24204
+ }
24205
+ };
24206
+ channel2.subscribe(handlers);
24207
+ this.unsubscribers.push(() => {
24208
+ channel2.unsubscribe(handlers);
24209
+ });
24210
+ }
24211
+ subscribeToSessionOperations() {
24212
+ this.subscribeToSessionOperation(flueChannels.prompt);
24213
+ this.subscribeToSessionOperation(flueChannels.skill);
24214
+ this.subscribeToSessionOperation(flueChannels.task);
24215
+ this.subscribeToCompact();
24216
+ }
24217
+ subscribeToSessionOperation(channel2) {
24218
+ const tracingChannel2 = channel2.tracingChannel();
24219
+ const states = /* @__PURE__ */ new WeakMap();
24220
+ const ensureState2 = (event) => {
24221
+ const existing = states.get(event);
24222
+ if (existing) {
24223
+ return existing;
24224
+ }
24225
+ const state = this.startOperationState({
24226
+ args: event.arguments,
24227
+ moduleVersion: typeof event.moduleVersion === "string" ? event.moduleVersion : void 0,
24228
+ operation: event.operation,
24229
+ session: event.session
24230
+ });
24231
+ states.set(event, state);
24232
+ return state;
24233
+ };
24234
+ const unbindCurrentSpanStore = this.bindCurrentSpanStoreToOperationStart(
24235
+ tracingChannel2,
24236
+ ensureState2
24237
+ );
24238
+ const handlers = {
24239
+ start: (event) => {
24240
+ ensureState2(event);
24241
+ },
24242
+ asyncEnd: (event) => {
24243
+ this.endOperationState(states.get(event), event.result);
24244
+ states.delete(event);
24245
+ },
24246
+ error: (event) => {
24247
+ const state = states.get(event);
24248
+ if (state && event.error) {
24249
+ safeLog3(state.span, { error: errorToString(event.error) });
24250
+ this.finishOperationState(state);
24251
+ }
24252
+ states.delete(event);
24253
+ }
24254
+ };
24255
+ tracingChannel2.subscribe(handlers);
24256
+ this.unsubscribers.push(() => {
24257
+ unbindCurrentSpanStore?.();
24258
+ tracingChannel2.unsubscribe(handlers);
24259
+ });
24260
+ }
24261
+ subscribeToCompact() {
24262
+ const tracingChannel2 = flueChannels.compact.tracingChannel();
24263
+ const states = /* @__PURE__ */ new WeakMap();
24264
+ const ensureState2 = (event) => {
24265
+ const existing = states.get(event);
24266
+ if (existing) {
24267
+ return existing;
24268
+ }
24269
+ const state = this.startOperationState({
24270
+ args: [],
24271
+ moduleVersion: typeof event.moduleVersion === "string" ? event.moduleVersion : void 0,
24272
+ operation: event.operation,
24273
+ session: event.session
24274
+ });
24275
+ states.set(event, state);
24276
+ return state;
24277
+ };
24278
+ const unbindCurrentSpanStore = this.bindCurrentSpanStoreToOperationStart(
24279
+ tracingChannel2,
24280
+ ensureState2
24281
+ );
24282
+ const handlers = {
24283
+ start: (event) => {
24284
+ ensureState2(event);
24285
+ },
24286
+ asyncEnd: (event) => {
24287
+ this.endOperationState(states.get(event), void 0);
24288
+ states.delete(event);
24289
+ },
24290
+ error: (event) => {
24291
+ const state = states.get(event);
24292
+ if (state && event.error) {
24293
+ safeLog3(state.span, { error: errorToString(event.error) });
24294
+ this.finishOperationState(state);
24295
+ }
24296
+ states.delete(event);
24297
+ }
24298
+ };
24299
+ tracingChannel2.subscribe(handlers);
24300
+ this.unsubscribers.push(() => {
24301
+ unbindCurrentSpanStore?.();
24302
+ tracingChannel2.unsubscribe(handlers);
24303
+ });
24304
+ }
24305
+ subscribeToContextEvents() {
24306
+ const channel2 = flueChannels.contextEvent.tracingChannel();
24307
+ const handlers = {
24308
+ start: (event) => {
24309
+ const flueEvent = event.arguments[0];
24310
+ if (!flueEvent) {
24311
+ return;
24312
+ }
24313
+ try {
24314
+ this.handleFlueEvent(flueEvent, {
24315
+ captureTurnSpans: event.captureTurnSpans !== false
24316
+ });
24317
+ } catch (error) {
24318
+ logInstrumentationError3("Flue event", error);
24319
+ }
24320
+ },
24321
+ error: () => {
24322
+ }
24323
+ };
24324
+ channel2.subscribe(handlers);
24325
+ this.unsubscribers.push(() => {
24326
+ channel2.unsubscribe(handlers);
24327
+ });
24328
+ }
24329
+ bindCurrentSpanStoreToOperationStart(tracingChannel2, ensureState2) {
24330
+ const state = _internalGetGlobalState();
24331
+ const startChannel = tracingChannel2.start;
24332
+ const contextManager = state?.contextManager;
24333
+ const currentSpanStore = contextManager ? contextManager[BRAINTRUST_CURRENT_SPAN_STORE] : void 0;
24334
+ if (!currentSpanStore || !startChannel) {
24335
+ return void 0;
24336
+ }
24337
+ startChannel.bindStore(currentSpanStore, (event) => {
24338
+ const operationState = ensureState2(event);
24339
+ return contextManager.wrapSpanForStore(operationState.span);
24340
+ });
24341
+ return () => {
24342
+ startChannel.unbindStore(currentSpanStore);
24343
+ };
24344
+ }
24345
+ startOperationState(args) {
24346
+ const sessionName = getSessionName(args.session);
24347
+ const metadata = {
24348
+ ...extractOperationInputMetadata(args.operation, args.args),
24349
+ ...extractSessionMetadata(args.session),
24350
+ "flue.operation": args.operation,
24351
+ provider: "flue",
24352
+ ...args.moduleVersion ? { "flue.version": args.moduleVersion } : {}
24353
+ };
24354
+ const span = startSpan({
24355
+ name: `flue.session.${args.operation}`,
24356
+ spanAttributes: { type: "task" /* TASK */ }
24357
+ });
24358
+ const state = {
24359
+ metadata,
24360
+ operation: args.operation,
24361
+ sessionName,
24362
+ span,
24363
+ startTime: getCurrentUnixTimestamp()
24364
+ };
24365
+ safeLog3(span, {
24366
+ input: extractOperationInput(args.operation, args.args),
24367
+ metadata
24368
+ });
24369
+ this.pendingOperationQueue(operationKey(sessionName, args.operation)).push(
24370
+ state
24371
+ );
24372
+ addOperationToScope(
24373
+ this.activeOperationsByScope,
24374
+ sessionName ?? "unknown",
24375
+ state
24376
+ );
24377
+ return state;
24378
+ }
24379
+ endOperationState(state, result) {
24380
+ if (!state) {
24381
+ return;
24382
+ }
24383
+ const metadata = {
24384
+ ...state.metadata,
24385
+ ...extractPromptResponseMetadata(result)
24386
+ };
24387
+ const metrics = {
24388
+ ...buildDurationMetrics3(state.startTime),
24389
+ ...metricsFromUsage(result?.usage)
24390
+ };
24391
+ safeLog3(state.span, {
24392
+ metadata,
24393
+ metrics,
24394
+ output: extractOperationOutput(result)
24395
+ });
24396
+ this.finishCompactionsForOperation(state);
24397
+ this.finishOperationState(state);
24398
+ }
24399
+ finishOperationState(state) {
24400
+ removePendingOperation(this.pendingOperationsByKey, state);
24401
+ if (state.operationId) {
24402
+ this.activeOperationsById.delete(state.operationId);
24403
+ }
24404
+ removeScopedOperation(this.activeOperationsByScope, state);
24405
+ state.span.end();
24406
+ }
24407
+ handleFlueEvent(event, options) {
24408
+ switch (event.type) {
24409
+ case "operation_start":
24410
+ this.handleOperationStart(event);
24411
+ return;
24412
+ case "operation":
24413
+ this.handleOperation(event);
24414
+ return;
24415
+ case "text_delta":
24416
+ if (!options.captureTurnSpans) {
24417
+ return;
24418
+ }
24419
+ this.ensureTurnState(event).text.push(
24420
+ typeof event.text === "string" ? event.text : ""
24421
+ );
24422
+ return;
24423
+ case "thinking_start":
24424
+ if (!options.captureTurnSpans) {
24425
+ return;
24426
+ }
24427
+ this.handleThinkingStart(event);
24428
+ return;
24429
+ case "thinking_delta":
24430
+ if (!options.captureTurnSpans) {
24431
+ return;
24432
+ }
24433
+ this.handleThinkingDelta(event);
24434
+ return;
24435
+ case "thinking_end":
24436
+ if (!options.captureTurnSpans) {
24437
+ return;
24438
+ }
24439
+ this.handleThinkingEnd(event);
24440
+ return;
24441
+ case "turn":
24442
+ if (!options.captureTurnSpans) {
24443
+ return;
24444
+ }
24445
+ this.handleTurn(event);
24446
+ return;
24447
+ case "tool_start":
24448
+ this.handleToolStart(event, options);
24449
+ return;
24450
+ case "tool_call":
24451
+ this.handleToolCall(event);
24452
+ return;
24453
+ case "task_start":
24454
+ this.handleTaskStart(event);
24455
+ return;
24456
+ case "task":
24457
+ this.handleTask(event);
24458
+ return;
24459
+ case "compaction_start":
24460
+ this.handleCompactionStart(event);
24461
+ return;
24462
+ case "compaction":
24463
+ this.handleCompaction(event);
24464
+ return;
24465
+ default:
24466
+ return;
24467
+ }
24468
+ }
24469
+ handleOperationStart(event) {
24470
+ if (!isInstrumentedOperation(event.operationKind)) {
24471
+ return;
24472
+ }
24473
+ const state = this.takePendingOperationForEvent(event);
24474
+ if (!state) {
24475
+ return;
24476
+ }
24477
+ state.operationId = event.operationId;
24478
+ this.activeOperationsById.set(event.operationId, state);
24479
+ addScopedOperation(this.activeOperationsByScope, event, state);
24480
+ state.metadata = {
24481
+ ...state.metadata,
24482
+ ...extractEventMetadata(event),
24483
+ "flue.operation_id": event.operationId
24484
+ };
24485
+ safeLog3(state.span, { metadata: state.metadata });
24486
+ }
24487
+ handleOperation(event) {
24488
+ const state = event.operationId ? this.activeOperationsById.get(event.operationId) : void 0;
24489
+ if (!state) {
24490
+ return;
24491
+ }
24492
+ const metadata = {
24493
+ ...state.metadata,
24494
+ ...extractEventMetadata(event),
24495
+ ...typeof event.durationMs === "number" ? { "flue.duration_ms": event.durationMs } : {},
24496
+ ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {}
24497
+ };
24498
+ const metrics = metricsFromUsage(event.usage);
24499
+ safeLog3(state.span, {
24500
+ ...event.error ? { error: errorToString(event.error) } : {},
24501
+ metadata,
24502
+ ...Object.keys(metrics).length ? { metrics } : {}
24503
+ });
24504
+ }
24505
+ ensureTurnState(event) {
24506
+ const scope = scopeKey(event);
24507
+ const existing = this.turnsByScope.get(scope);
24508
+ if (existing) {
24509
+ return existing;
24510
+ }
24511
+ const parent = this.parentSpanForEvent(event);
24512
+ const metadata = {
24513
+ ...extractEventMetadata(event),
24514
+ provider: "flue"
24515
+ };
24516
+ const span = startFlueSpan(parent, {
24517
+ name: "flue.turn",
24518
+ spanAttributes: { type: "llm" /* LLM */ }
24519
+ });
24520
+ const state = {
24521
+ metadata,
24522
+ span,
24523
+ hasThinking: false,
24524
+ startTime: getCurrentUnixTimestamp(),
24525
+ text: [],
24526
+ thinking: [],
24527
+ toolCalls: []
24528
+ };
24529
+ safeLog3(span, { metadata });
24530
+ this.turnsByScope.set(scope, state);
24531
+ return state;
24532
+ }
24533
+ handleTurn(event) {
24534
+ const scope = scopeKey(event);
24535
+ const state = this.ensureTurnState(event);
24536
+ const text = state.text.join("");
24537
+ const reasoning = state.finalThinking ?? state.thinking.join("");
24538
+ const outputReasoning = reasoning || (state.hasThinking ? "[reasoning stream present; content unavailable]" : void 0);
24539
+ const metadata = {
24540
+ ...state.metadata,
24541
+ ...extractEventMetadata(event),
24542
+ ...event.model ? { model: event.model, "flue.model": event.model } : {},
24543
+ ...event.stopReason ? { "flue.stop_reason": event.stopReason } : {},
24544
+ ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {},
24545
+ provider: "flue"
24546
+ };
24547
+ safeLog3(state.span, {
24548
+ ...event.error ? { error: errorToString(event.error) } : {},
24549
+ metadata,
24550
+ metrics: {
24551
+ ...durationMsMetrics(event.durationMs),
24552
+ ...metricsFromUsage(event.usage)
24553
+ },
24554
+ output: toAssistantOutput(
24555
+ text,
24556
+ event.stopReason,
24557
+ outputReasoning,
24558
+ state.toolCalls
24559
+ )
24560
+ });
24561
+ state.span.end();
24562
+ this.turnsByScope.delete(scope);
24563
+ }
24564
+ handleThinkingDelta(event) {
24565
+ const delta = event.delta;
24566
+ if (typeof delta !== "string" || !delta) {
24567
+ return;
24568
+ }
24569
+ const state = this.ensureTurnState(event);
24570
+ state.hasThinking = true;
24571
+ state.metadata["flue.thinking"] = true;
24572
+ state.thinking.push(delta);
24573
+ }
24574
+ handleThinkingStart(event) {
24575
+ const state = this.ensureTurnState(event);
24576
+ state.hasThinking = true;
24577
+ state.metadata["flue.thinking"] = true;
24578
+ }
24579
+ handleThinkingEnd(event) {
24580
+ const state = this.ensureTurnState(event);
24581
+ state.hasThinking = true;
24582
+ state.metadata["flue.thinking"] = true;
24583
+ if (typeof event.content === "string" && event.content) {
24584
+ state.finalThinking = event.content;
24585
+ }
24586
+ }
24587
+ handleToolStart(event, options) {
24588
+ const toolCallId = event.toolCallId;
24589
+ if (!toolCallId) {
24590
+ return;
24591
+ }
24592
+ const parent = this.parentSpanForEvent(event);
24593
+ const scope = scopeKey(event);
24594
+ let turnState = this.turnsByScope.get(scope);
24595
+ if (!turnState && parent && options.captureTurnSpans) {
24596
+ turnState = this.ensureTurnState(event);
24597
+ }
24598
+ const metadata = {
24599
+ ...extractEventMetadata(event),
24600
+ ...event.toolName ? { "flue.tool_name": event.toolName } : {},
24601
+ "flue.tool_call_id": toolCallId,
24602
+ provider: "flue"
24603
+ };
24604
+ const span = startFlueSpan(parent, {
24605
+ name: `tool: ${event.toolName ?? "unknown"}`,
24606
+ spanAttributes: { type: "tool" /* TOOL */ }
24607
+ });
24608
+ if (turnState) {
24609
+ turnState.toolCalls.push({
24610
+ args: event.args,
24611
+ toolCallId,
24612
+ toolName: event.toolName
24613
+ });
24614
+ }
24615
+ safeLog3(span, {
24616
+ input: event.args,
24617
+ metadata
24618
+ });
24619
+ this.toolsById.set(toolKey(event), {
24620
+ metadata,
24621
+ span,
24622
+ startTime: getCurrentUnixTimestamp()
24623
+ });
24624
+ }
24625
+ handleToolCall(event) {
24626
+ const key = toolKey(event);
24627
+ const state = this.toolsById.get(key) ?? this.startSyntheticToolState(event, event.toolName ?? "unknown");
24628
+ const metadata = {
24629
+ ...state.metadata,
24630
+ ...extractEventMetadata(event),
24631
+ ...event.toolName ? { "flue.tool_name": event.toolName } : {},
24632
+ ...event.toolCallId ? { "flue.tool_call_id": event.toolCallId } : {},
24633
+ ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {}
24634
+ };
24635
+ safeLog3(state.span, {
24636
+ ...event.isError ? { error: errorToString(event.result) } : {},
24637
+ metadata,
24638
+ metrics: durationMsMetrics(event.durationMs),
24639
+ output: event.result
24640
+ });
24641
+ state.span.end();
24642
+ this.toolsById.delete(key);
24643
+ }
24644
+ handleTaskStart(event) {
24645
+ const parent = this.parentSpanForEvent(event);
24646
+ const metadata = {
24647
+ ...extractEventMetadata(event),
24648
+ ...event.role ? { "flue.role": event.role } : {},
24649
+ ...event.cwd ? { "flue.cwd": event.cwd } : {},
24650
+ "flue.task_id": event.taskId,
24651
+ provider: "flue"
24652
+ };
24653
+ const span = startFlueSpan(parent, {
24654
+ name: "flue.task",
24655
+ spanAttributes: { type: "task" /* TASK */ }
24656
+ });
24657
+ safeLog3(span, {
24658
+ input: event.prompt,
24659
+ metadata
24660
+ });
24661
+ this.tasksById.set(event.taskId, {
24662
+ metadata,
24663
+ span,
24664
+ startTime: getCurrentUnixTimestamp()
24665
+ });
24666
+ }
24667
+ handleTask(event) {
24668
+ const state = this.tasksById.get(event.taskId);
24669
+ if (!state) {
24670
+ return;
24671
+ }
24672
+ safeLog3(state.span, {
24673
+ ...event.isError ? { error: errorToString(event.result) } : {},
24674
+ metadata: {
24675
+ ...state.metadata,
24676
+ ...extractEventMetadata(event),
24677
+ ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {}
24678
+ },
24679
+ metrics: durationMsMetrics(event.durationMs),
24680
+ output: event.result
24681
+ });
24682
+ state.span.end();
24683
+ this.tasksById.delete(event.taskId);
24684
+ }
24685
+ handleCompactionStart(event) {
24686
+ const operationState = this.operationStateForEvent(event);
24687
+ const parent = operationState?.span ?? this.parentSpanForEvent(event);
24688
+ const metadata = {
24689
+ ...extractEventMetadata(event),
24690
+ ...event.reason ? { "flue.compaction_reason": event.reason } : {},
24691
+ provider: "flue"
24692
+ };
24693
+ const input = {
24694
+ ...typeof event.estimatedTokens === "number" ? { estimatedTokens: event.estimatedTokens } : {},
24695
+ ...event.reason ? { reason: event.reason } : {}
24696
+ };
24697
+ const span = startFlueSpan(parent, {
24698
+ name: "flue.compaction",
24699
+ spanAttributes: { type: "task" /* TASK */ }
24700
+ });
24701
+ safeLog3(span, {
24702
+ input,
24703
+ metadata
24704
+ });
24705
+ this.compactionsByScope.set(scopeKey(event), {
24706
+ input,
24707
+ metadata,
24708
+ operationState,
24709
+ span,
24710
+ startTime: getCurrentUnixTimestamp()
24711
+ });
24712
+ }
24713
+ handleCompaction(event) {
24714
+ const key = scopeKey(event);
24715
+ const state = this.compactionsByScope.get(key) ?? this.findCompactionState(event);
24716
+ if (!state) {
24717
+ return;
24718
+ }
24719
+ safeLog3(state.span, {
24720
+ metadata: {
24721
+ ...state.metadata,
24722
+ ...extractEventMetadata(event),
24723
+ ...typeof event.messagesBefore === "number" ? { "flue.messages_before": event.messagesBefore } : {},
24724
+ ...typeof event.messagesAfter === "number" ? { "flue.messages_after": event.messagesAfter } : {}
24725
+ },
24726
+ metrics: {
24727
+ ...durationMsMetrics(event.durationMs),
24728
+ ...metricsFromUsage(event.usage)
24729
+ },
24730
+ output: {
24731
+ messagesAfter: event.messagesAfter,
24732
+ messagesBefore: event.messagesBefore
24733
+ }
24734
+ });
24735
+ state.span.end();
24736
+ this.deleteCompactionState(state);
24737
+ }
24738
+ findCompactionState(event) {
24739
+ const operationState = this.operationStateForEvent(event);
24740
+ for (const state of this.compactionsByScope.values()) {
24741
+ if (operationState && state.operationState === operationState) {
24742
+ return state;
24743
+ }
24744
+ }
24745
+ return void 0;
24746
+ }
24747
+ finishCompactionsForOperation(operationState) {
24748
+ for (const state of [...this.compactionsByScope.values()]) {
24749
+ if (state.operationState !== operationState) {
24750
+ continue;
24751
+ }
24752
+ safeLog3(state.span, {
24753
+ input: state.input,
24754
+ metadata: state.metadata,
24755
+ metrics: {
24756
+ ...buildDurationMetrics3(state.startTime)
24757
+ },
24758
+ output: { completed: true }
24759
+ });
24760
+ state.span.end();
24761
+ this.deleteCompactionState(state);
24762
+ }
24763
+ }
24764
+ deleteCompactionState(state) {
24765
+ for (const [key, candidate] of this.compactionsByScope) {
24766
+ if (candidate !== state) {
24767
+ continue;
24768
+ }
24769
+ this.compactionsByScope.delete(key);
24770
+ return;
24771
+ }
24772
+ }
24773
+ startSyntheticToolState(event, toolName) {
24774
+ const parent = this.parentSpanForEvent(event);
24775
+ const metadata = {
24776
+ ...extractEventMetadata(event),
24777
+ ...event.toolCallId ? { "flue.tool_call_id": event.toolCallId } : {},
24778
+ "flue.tool_name": toolName,
24779
+ provider: "flue"
24780
+ };
24781
+ const span = startFlueSpan(parent, {
24782
+ name: `tool: ${toolName}`,
24783
+ spanAttributes: { type: "tool" /* TOOL */ }
24784
+ });
24785
+ safeLog3(span, { metadata });
24786
+ return { metadata, span, startTime: getCurrentUnixTimestamp() };
24787
+ }
24788
+ operationStateForEvent(event) {
24789
+ if (event.operationId) {
24790
+ const operation = this.activeOperationsById.get(event.operationId) ?? this.promotePendingOperationForEvent(event);
24791
+ if (operation) {
24792
+ return operation;
24793
+ }
24794
+ }
24795
+ return this.activeOperationForEventScope(event) ?? this.pendingOperationForEventScope(event);
24796
+ }
24797
+ parentSpanForEvent(event) {
24798
+ if (event.operationId) {
24799
+ const operation = this.operationStateForEvent(event);
24800
+ if (operation) {
24801
+ return operation.span;
24802
+ }
24803
+ }
24804
+ if (event.taskId) {
24805
+ return this.tasksById.get(event.taskId)?.span;
24806
+ }
24807
+ return this.operationStateForEvent(event)?.span;
24808
+ }
24809
+ promotePendingOperationForEvent(event) {
24810
+ if (!event.operationId) {
24811
+ return void 0;
24812
+ }
24813
+ const scopePrefixes = operationScopePrefixes(event);
24814
+ for (const [candidateKey, candidateQueue] of this.pendingOperationsByKey) {
24815
+ if (!candidateQueue.length || !operationKeyMatchesScopes(candidateKey, scopePrefixes)) {
24816
+ continue;
24817
+ }
24818
+ const state = candidateQueue.shift();
24819
+ if (!state) {
24820
+ return void 0;
24821
+ }
24822
+ state.operationId = event.operationId;
24823
+ this.activeOperationsById.set(event.operationId, state);
24824
+ addScopedOperation(this.activeOperationsByScope, event, state);
24825
+ state.metadata = {
24826
+ ...state.metadata,
24827
+ ...extractEventMetadata(event),
24828
+ "flue.operation_id": event.operationId
24829
+ };
24830
+ safeLog3(state.span, { metadata: state.metadata });
24831
+ return state;
24832
+ }
24833
+ return void 0;
24834
+ }
24835
+ activeOperationForEventScope(event) {
24836
+ for (const scope of operationScopeNames(event)) {
24837
+ const operations = this.activeOperationsByScope.get(scope);
24838
+ if (operations?.length) {
24839
+ return operations[operations.length - 1];
24840
+ }
24841
+ }
24842
+ return void 0;
24843
+ }
24844
+ pendingOperationForEventScope(event) {
24845
+ const scopePrefixes = operationScopePrefixes(event);
24846
+ for (const [candidateKey, candidateQueue] of this.pendingOperationsByKey) {
24847
+ if (!candidateQueue.length || !operationKeyMatchesScopes(candidateKey, scopePrefixes)) {
24848
+ continue;
24849
+ }
24850
+ return candidateQueue[0];
24851
+ }
24852
+ return void 0;
24853
+ }
24854
+ takePendingOperationForEvent(event) {
24855
+ const key = operationKey(event.session, event.operationKind);
24856
+ const queue2 = this.pendingOperationsByKey.get(key);
24857
+ if (queue2?.length) {
24858
+ return queue2.shift();
24859
+ }
24860
+ for (const [candidateKey, candidateQueue] of this.pendingOperationsByKey) {
24861
+ if (candidateKey.endsWith(`::${event.operationKind}`) && candidateQueue.length) {
24862
+ return candidateQueue.shift();
24863
+ }
24864
+ }
24865
+ return void 0;
24866
+ }
24867
+ pendingOperationQueue(key) {
24868
+ const existing = this.pendingOperationsByKey.get(key);
24869
+ if (existing) {
24870
+ return existing;
24871
+ }
24872
+ const queue2 = [];
24873
+ this.pendingOperationsByKey.set(key, queue2);
24874
+ return queue2;
24875
+ }
24876
+ };
24877
+ function isInstrumentedOperation(operation) {
24878
+ return operation === "prompt" || operation === "skill" || operation === "task" || operation === "compact";
24879
+ }
24880
+ function getSessionName(session) {
24881
+ return typeof session?.name === "string" ? session.name : void 0;
24882
+ }
24883
+ function operationKey(sessionName, operation) {
24884
+ return `${sessionName ?? "unknown"}::${operation}`;
24885
+ }
24886
+ function operationScopePrefixes(event) {
24887
+ const scopes = /* @__PURE__ */ new Set();
24888
+ for (const scope of operationScopeNames(event)) {
24889
+ scopes.add(`${scope}::`);
24890
+ }
24891
+ return scopes;
24892
+ }
24893
+ function operationKeyMatchesScopes(key, scopes) {
24894
+ for (const scope of scopes) {
24895
+ if (key.startsWith(scope)) {
24896
+ return true;
24897
+ }
24898
+ }
24899
+ return false;
24900
+ }
24901
+ function operationScopeNames(event) {
24902
+ const scopes = /* @__PURE__ */ new Set();
24903
+ if (event.session) {
24904
+ scopes.add(event.session);
24905
+ }
24906
+ if (event.parentSession) {
24907
+ scopes.add(event.parentSession);
24908
+ }
24909
+ if (!scopes.size) {
24910
+ scopes.add("unknown");
24911
+ }
24912
+ return scopes;
24913
+ }
24914
+ function addScopedOperation(operationsByScope, event, state) {
24915
+ for (const scope of operationScopeNames(event)) {
24916
+ addOperationToScope(operationsByScope, scope, state);
24917
+ }
24918
+ }
24919
+ function addOperationToScope(operationsByScope, scope, state) {
24920
+ const operations = operationsByScope.get(scope);
24921
+ if (operations) {
24922
+ if (!operations.includes(state)) {
24923
+ operations.push(state);
24924
+ }
24925
+ } else {
24926
+ operationsByScope.set(scope, [state]);
24927
+ }
24928
+ }
24929
+ function removeScopedOperation(operationsByScope, state) {
24930
+ for (const [scope, operations] of operationsByScope) {
24931
+ const index = operations.indexOf(state);
24932
+ if (index === -1) {
24933
+ continue;
24934
+ }
24935
+ operations.splice(index, 1);
24936
+ if (operations.length === 0) {
24937
+ operationsByScope.delete(scope);
24938
+ }
24939
+ }
24940
+ }
24941
+ function removePendingOperation(pendingOperationsByKey, state) {
24942
+ for (const [key, queue2] of pendingOperationsByKey) {
24943
+ const index = queue2.indexOf(state);
24944
+ if (index === -1) {
24945
+ continue;
24946
+ }
24947
+ queue2.splice(index, 1);
24948
+ if (queue2.length === 0) {
24949
+ pendingOperationsByKey.delete(key);
24950
+ }
24951
+ return;
24952
+ }
24953
+ }
24954
+ function extractSessionMetadata(session) {
24955
+ const sessionName = getSessionName(session);
24956
+ return sessionName ? { "flue.session": sessionName } : {};
24957
+ }
24958
+ function extractEventMetadata(event) {
24959
+ return {
24960
+ ...event.runId ? { "flue.run_id": event.runId } : {},
24961
+ ...typeof event.eventIndex === "number" ? { "flue.event_index": event.eventIndex } : {},
24962
+ ...event.session ? { "flue.session": event.session } : {},
24963
+ ...event.parentSession ? { "flue.parent_session": event.parentSession } : {},
24964
+ ...event.harness ? { "flue.harness": event.harness } : {},
24965
+ ...event.taskId ? { "flue.task_id": event.taskId } : {},
24966
+ ...event.operationId ? { "flue.operation_id": event.operationId } : {}
24967
+ };
24968
+ }
24969
+ function extractOperationInput(operation, args) {
24970
+ switch (operation) {
24971
+ case "prompt":
24972
+ case "task":
24973
+ return args[0];
24974
+ case "skill":
24975
+ return {
24976
+ args: getOptionObject(args[1])?.args,
24977
+ name: args[0]
24978
+ };
24979
+ case "compact":
24980
+ return void 0;
24981
+ }
24982
+ }
24983
+ function extractOperationInputMetadata(operation, args) {
24984
+ const options = getOptionObject(args[1]);
24985
+ return {
24986
+ ...operation === "skill" && typeof args[0] === "string" ? { "flue.skill_name": args[0] } : {},
24987
+ ...options?.model ? { model: options.model, "flue.model": options.model } : {},
24988
+ ...options?.role ? { "flue.role": options.role } : {},
24989
+ ...options?.thinkingLevel ? { "flue.thinking_level": options.thinkingLevel } : {},
24990
+ ...typeof options?.cwd === "string" ? { "flue.cwd": options.cwd } : {},
24991
+ ...Array.isArray(options?.tools) ? {
24992
+ "flue.tools_count": options.tools.length,
24993
+ tools: summarizeTools(options.tools)
24994
+ } : {},
24995
+ ...Array.isArray(options?.images) ? { "flue.images_count": options.images.length } : {},
24996
+ ...options?.result || options?.schema ? { "flue.result_schema": true } : {}
24997
+ };
24998
+ }
24999
+ function getOptionObject(value) {
25000
+ return isObject(value) ? value : void 0;
25001
+ }
25002
+ function summarizeTools(tools) {
25003
+ return tools.flatMap((tool) => {
25004
+ if (!isObject(tool)) {
25005
+ return [];
25006
+ }
25007
+ const name = typeof tool.name === "string" ? tool.name : void 0;
25008
+ if (!name) {
25009
+ return [];
25010
+ }
25011
+ return [
25012
+ {
25013
+ function: {
25014
+ description: typeof tool.description === "string" ? tool.description : void 0,
25015
+ name,
25016
+ parameters: tool.parameters
25017
+ },
25018
+ type: "function"
25019
+ }
25020
+ ];
25021
+ });
25022
+ }
25023
+ function extractPromptResponseMetadata(result) {
25024
+ const modelId = result?.model && typeof result.model.id === "string" ? result.model.id : void 0;
25025
+ return modelId ? {
25026
+ model: modelId,
25027
+ "flue.model": modelId
25028
+ } : {};
25029
+ }
25030
+ function extractOperationOutput(result) {
25031
+ if (!result) {
25032
+ return void 0;
25033
+ }
25034
+ if ("data" in result) {
25035
+ return result.data;
25036
+ }
25037
+ if ("text" in result) {
25038
+ return result.text;
25039
+ }
25040
+ return result;
25041
+ }
25042
+ function metricsFromUsage(usage) {
25043
+ return {
25044
+ ...typeof usage?.input === "number" ? { prompt_tokens: usage.input } : {},
25045
+ ...typeof usage?.output === "number" ? { completion_tokens: usage.output } : {},
25046
+ ...typeof usage?.cacheRead === "number" ? { prompt_cached_tokens: usage.cacheRead } : {},
25047
+ ...typeof usage?.cacheWrite === "number" ? { prompt_cache_creation_tokens: usage.cacheWrite } : {},
25048
+ ...typeof usage?.totalTokens === "number" ? { tokens: usage.totalTokens } : {},
25049
+ ...typeof usage?.cost?.total === "number" ? { estimated_cost: usage.cost.total } : {}
25050
+ };
25051
+ }
25052
+ function buildDurationMetrics3(startTime) {
25053
+ return {
25054
+ duration_ms: Math.max(0, (getCurrentUnixTimestamp() - startTime) * 1e3)
25055
+ };
25056
+ }
25057
+ function durationMsMetrics(durationMs) {
25058
+ return typeof durationMs === "number" ? { duration_ms: durationMs } : {};
25059
+ }
25060
+ function scopeKey(event) {
25061
+ if (event.operationId) {
25062
+ return `operation:${event.operationId}`;
25063
+ }
25064
+ if (event.taskId) {
25065
+ return `task:${event.taskId}`;
25066
+ }
25067
+ if (event.session) {
25068
+ return `session:${event.session}`;
25069
+ }
25070
+ return "flue:unknown";
25071
+ }
25072
+ function toolKey(event) {
25073
+ return `${scopeKey(event)}::tool:${event.toolCallId ?? "unknown"}`;
25074
+ }
25075
+ function toAssistantOutput(text, finishReason, reasoning, toolCalls) {
25076
+ return [
25077
+ {
25078
+ finish_reason: finishReason ?? "stop",
25079
+ index: 0,
25080
+ message: {
25081
+ content: text,
25082
+ ...reasoning ? { reasoning } : {},
25083
+ role: "assistant",
25084
+ ...toolCalls?.length ? {
25085
+ tool_calls: toolCalls.map((toolCall) => ({
25086
+ function: {
25087
+ arguments: toolCall.args === void 0 ? "{}" : JSON.stringify(toolCall.args),
25088
+ name: toolCall.toolName ?? "unknown"
25089
+ },
25090
+ ...toolCall.toolCallId ? { id: toolCall.toolCallId } : {},
25091
+ type: "function"
25092
+ }))
25093
+ } : {}
25094
+ }
25095
+ }
25096
+ ];
25097
+ }
25098
+ function startFlueSpan(parent, args) {
25099
+ return parent ? withCurrent(parent, () => startSpan(args)) : startSpan(args);
25100
+ }
25101
+ function safeLog3(span, event) {
25102
+ try {
25103
+ span.log(event);
25104
+ } catch (error) {
25105
+ logInstrumentationError3("Flue span log", error);
25106
+ }
25107
+ }
25108
+ function errorToString(error) {
25109
+ if (error instanceof Error) {
25110
+ return error.message;
25111
+ }
25112
+ if (typeof error === "string") {
25113
+ return error;
25114
+ }
25115
+ try {
25116
+ return JSON.stringify(error);
25117
+ } catch {
25118
+ return String(error);
25119
+ }
25120
+ }
25121
+ function logInstrumentationError3(label, error) {
25122
+ console.error(`Error in ${label} instrumentation:`, error);
25123
+ }
25124
+
25125
+ // src/wrappers/langchain/callback-handler.ts
25126
+ var BRAINTRUST_LANGCHAIN_CALLBACK_HANDLER_NAME = "BraintrustCallbackHandler";
25127
+ var BraintrustLangChainCallbackHandler = class {
25128
+ name = BRAINTRUST_LANGCHAIN_CALLBACK_HANDLER_NAME;
25129
+ spans = /* @__PURE__ */ new Map();
25130
+ skippedRuns = /* @__PURE__ */ new Set();
25131
+ parent;
25132
+ rootRunId;
25133
+ options;
25134
+ startTimes = /* @__PURE__ */ new Map();
25135
+ firstTokenTimes = /* @__PURE__ */ new Map();
25136
+ ttftMs = /* @__PURE__ */ new Map();
25137
+ constructor(options) {
25138
+ this.parent = options?.parent;
25139
+ this.options = {
25140
+ debug: options?.debug ?? false,
25141
+ excludeMetadataProps: options?.excludeMetadataProps ?? /^(l[sc]_|langgraph_|__pregel_|checkpoint_ns)/,
25142
+ logger: options?.logger
25143
+ };
25144
+ }
25145
+ startSpan({
25146
+ runId,
25147
+ parentRunId,
25148
+ ...args
25149
+ }) {
25150
+ if (this.spans.has(runId)) {
25151
+ return;
25152
+ }
25153
+ if (!parentRunId) {
25154
+ this.rootRunId = runId;
25155
+ }
25156
+ const tags = args.event?.tags;
25157
+ const spanAttributes = args.spanAttributes || {};
25158
+ spanAttributes.type = args.type || spanAttributes.type || "task";
25159
+ args.type = spanAttributes.type;
25160
+ const currentParent = (typeof this.parent === "function" ? this.parent() : this.parent) ?? currentSpan();
25161
+ let parentSpan;
25162
+ if (parentRunId && this.spans.has(parentRunId)) {
25163
+ parentSpan = this.spans.get(parentRunId);
25164
+ } else if (!Object.is(currentParent, NOOP_SPAN)) {
25165
+ parentSpan = currentParent;
25166
+ } else if (this.options.logger) {
25167
+ parentSpan = this.options.logger;
25168
+ } else {
25169
+ parentSpan = { startSpan };
25170
+ }
25171
+ args.event = {
25172
+ ...args.event,
25173
+ tags: void 0,
25174
+ metadata: {
25175
+ ...tags ? { tags } : {},
25176
+ ...args.event?.metadata,
25177
+ braintrust: {
25178
+ integration_name: "langchain-js",
25179
+ sdk_language: "javascript"
25180
+ },
25181
+ run_id: runId,
25182
+ parent_run_id: parentRunId,
25183
+ ...this.options.debug ? { runId, parentRunId } : {}
25184
+ }
25185
+ };
25186
+ let span = parentSpan.startSpan(args);
25187
+ if (!Object.is(this.options.logger, NOOP_SPAN) && Object.is(span, NOOP_SPAN)) {
25188
+ span = initLogger().startSpan(args);
25189
+ }
25190
+ this.spans.set(runId, span);
25191
+ }
25192
+ endSpan({
25193
+ runId,
25194
+ parentRunId,
25195
+ tags,
25196
+ metadata,
25197
+ ...args
25198
+ }) {
25199
+ if (!this.spans.has(runId)) {
25200
+ return;
25201
+ }
25202
+ if (this.skippedRuns.has(runId)) {
25203
+ this.skippedRuns.delete(runId);
25204
+ return;
25205
+ }
25206
+ const span = this.spans.get(runId);
25207
+ this.spans.delete(runId);
25208
+ if (runId === this.rootRunId) {
25209
+ this.rootRunId = void 0;
25210
+ }
25211
+ span.log({ ...args, metadata: { tags, ...metadata } });
25212
+ span.end();
25213
+ }
25214
+ async handleLLMStart(llm, prompts, runId, parentRunId, extraParams, tags, metadata, runName) {
25215
+ this.startSpan({
25216
+ runId,
25217
+ parentRunId,
25218
+ name: runName ?? getSerializedName(llm) ?? "LLM",
25219
+ type: "llm",
25220
+ event: {
25221
+ input: prompts,
25222
+ tags,
25223
+ metadata: {
25224
+ serialized: llm,
25225
+ name: runName,
25226
+ metadata,
25227
+ ...extraParams
25228
+ }
25229
+ }
25230
+ });
25231
+ }
25232
+ async handleLLMError(err, runId, parentRunId, tags) {
25233
+ this.endSpan({ runId, parentRunId, error: err, tags });
25234
+ }
25235
+ async handleLLMEnd(output, runId, parentRunId, tags) {
25236
+ const metrics = getMetricsFromResponse(output);
25237
+ const modelName2 = getModelNameFromResponse(output);
25238
+ const ttft = this.ttftMs.get(runId);
25239
+ if (ttft !== void 0) {
25240
+ metrics.time_to_first_token = ttft;
25241
+ }
25242
+ this.startTimes.delete(runId);
25243
+ this.firstTokenTimes.delete(runId);
25244
+ this.ttftMs.delete(runId);
25245
+ this.endSpan({
25246
+ runId,
25247
+ parentRunId,
25248
+ output,
25249
+ metrics,
25250
+ tags,
25251
+ metadata: {
25252
+ model: modelName2
25253
+ }
25254
+ });
25255
+ }
25256
+ async handleChatModelStart(llm, messages, runId, parentRunId, extraParams, tags, metadata, runName) {
25257
+ this.startTimes.set(runId, Date.now());
25258
+ this.firstTokenTimes.delete(runId);
25259
+ this.ttftMs.delete(runId);
25260
+ this.startSpan({
25261
+ runId,
25262
+ parentRunId,
25263
+ name: runName ?? getSerializedName(llm) ?? "Chat Model",
25264
+ type: "llm",
25265
+ event: {
25266
+ input: messages,
25267
+ tags,
25268
+ metadata: {
25269
+ serialized: llm,
25270
+ name: runName,
25271
+ metadata,
25272
+ ...extraParams
25273
+ }
25274
+ }
25275
+ });
25276
+ }
25277
+ async handleChainStart(chain, inputs, runId, parentRunId, tags, metadata, runType, runName) {
25278
+ if (tags?.includes("langsmith:hidden")) {
25279
+ this.skippedRuns.add(runId);
25280
+ return;
25281
+ }
25282
+ this.startSpan({
25283
+ runId,
25284
+ parentRunId,
25285
+ name: runName ?? getSerializedName(chain) ?? "Chain",
25286
+ event: {
25287
+ input: inputs,
25288
+ tags,
25289
+ metadata: {
25290
+ serialized: chain,
25291
+ name: runName,
25292
+ metadata,
25293
+ run_type: runType
25294
+ }
25295
+ }
25296
+ });
25297
+ }
25298
+ async handleChainError(err, runId, parentRunId, tags, kwargs) {
25299
+ this.endSpan({ runId, parentRunId, error: err, tags, metadata: kwargs });
25300
+ }
25301
+ async handleChainEnd(outputs, runId, parentRunId, tags, kwargs) {
25302
+ this.endSpan({
25303
+ runId,
25304
+ parentRunId,
25305
+ tags,
25306
+ output: outputs,
25307
+ metadata: { ...kwargs }
25308
+ });
25309
+ }
25310
+ async handleToolStart(tool, input, runId, parentRunId, tags, metadata, runName) {
25311
+ this.startSpan({
25312
+ runId,
25313
+ parentRunId,
25314
+ name: runName ?? getSerializedName(tool) ?? "Tool",
25315
+ type: "llm",
25316
+ event: {
25317
+ input: safeJsonParse(input),
25318
+ tags,
25319
+ metadata: {
25320
+ metadata,
25321
+ serialized: tool,
25322
+ input_str: input,
25323
+ input: safeJsonParse(input),
25324
+ name: runName
25325
+ }
25326
+ }
25327
+ });
25328
+ }
25329
+ async handleToolError(err, runId, parentRunId, tags) {
25330
+ this.endSpan({ runId, parentRunId, error: err, tags });
25331
+ }
25332
+ async handleToolEnd(output, runId, parentRunId, tags) {
25333
+ this.endSpan({ runId, parentRunId, output, tags });
25334
+ }
25335
+ async handleAgentAction(action, runId, parentRunId, tags) {
25336
+ this.startSpan({
25337
+ runId,
25338
+ parentRunId,
25339
+ type: "llm",
25340
+ name: typeof action.tool === "string" ? action.tool : "Agent",
25341
+ event: {
25342
+ input: action,
25343
+ tags
25344
+ }
25345
+ });
25346
+ }
25347
+ async handleAgentEnd(action, runId, parentRunId, tags) {
25348
+ this.endSpan({ runId, parentRunId, output: action, tags });
25349
+ }
25350
+ async handleRetrieverStart(retriever, query, runId, parentRunId, tags, metadata, name) {
25351
+ this.startSpan({
25352
+ runId,
25353
+ parentRunId,
25354
+ name: name ?? getSerializedName(retriever) ?? "Retriever",
25355
+ type: "function",
25356
+ event: {
25357
+ input: query,
25358
+ tags,
25359
+ metadata: {
25360
+ serialized: retriever,
25361
+ metadata,
25362
+ name
25363
+ }
25364
+ }
25365
+ });
25366
+ }
25367
+ async handleRetrieverEnd(documents, runId, parentRunId, tags) {
25368
+ this.endSpan({ runId, parentRunId, output: documents, tags });
25369
+ }
25370
+ async handleRetrieverError(err, runId, parentRunId, tags) {
25371
+ this.endSpan({ runId, parentRunId, error: err, tags });
25372
+ }
25373
+ async handleLLMNewToken(_token, _idx, runId, _parentRunId, _tags) {
25374
+ if (!this.firstTokenTimes.has(runId)) {
25375
+ const now2 = Date.now();
25376
+ this.firstTokenTimes.set(runId, now2);
25377
+ const start = this.startTimes.get(runId);
25378
+ if (start !== void 0) {
25379
+ this.ttftMs.set(runId, (now2 - start) / 1e3);
25380
+ }
25381
+ }
25382
+ }
25383
+ };
25384
+ function getSerializedName(serialized) {
25385
+ if (typeof serialized.name === "string") {
25386
+ return serialized.name;
25387
+ }
25388
+ const lastIdPart = serialized.id?.at(-1);
25389
+ return typeof lastIdPart === "string" ? lastIdPart : void 0;
25390
+ }
25391
+ function cleanObject(obj) {
25392
+ return Object.fromEntries(
25393
+ Object.entries(obj).filter(([, value]) => {
25394
+ if (typeof value !== "number") {
25395
+ return false;
25396
+ }
25397
+ return Number.isFinite(value);
25398
+ })
25399
+ );
25400
+ }
25401
+ function walkGenerations(response) {
25402
+ const result = [];
25403
+ const generations = response.generations || [];
25404
+ for (const batch of generations) {
25405
+ if (Array.isArray(batch)) {
25406
+ for (const generation of batch) {
25407
+ if (isRecord(generation)) {
25408
+ result.push(generation);
25409
+ }
25410
+ }
25411
+ } else if (isRecord(batch)) {
25412
+ result.push(batch);
25413
+ }
25414
+ }
25415
+ return result;
25416
+ }
25417
+ function getModelNameFromResponse(response) {
25418
+ for (const generation of walkGenerations(response)) {
25419
+ const message = generation.message;
25420
+ if (!isRecord(message)) {
25421
+ continue;
25422
+ }
25423
+ const responseMetadata = message.response_metadata;
25424
+ if (!isRecord(responseMetadata)) {
25425
+ continue;
25426
+ }
25427
+ const modelName3 = responseMetadata.model_name ?? responseMetadata.model;
25428
+ if (typeof modelName3 === "string") {
25429
+ return modelName3;
25430
+ }
25431
+ }
25432
+ const llmOutput = response.llmOutput || {};
25433
+ const modelName2 = llmOutput.model_name ?? llmOutput.model;
25434
+ return typeof modelName2 === "string" ? modelName2 : void 0;
25435
+ }
25436
+ function getMetricsFromResponse(response) {
25437
+ for (const generation of walkGenerations(response)) {
25438
+ const message = generation.message;
25439
+ if (!isRecord(message)) {
25440
+ continue;
25441
+ }
25442
+ const usageMetadata = message.usage_metadata;
25443
+ if (!isRecord(usageMetadata)) {
25444
+ continue;
25445
+ }
25446
+ const inputTokenDetails = usageMetadata.input_token_details;
25447
+ return cleanObject({
25448
+ total_tokens: usageMetadata.total_tokens,
25449
+ prompt_tokens: usageMetadata.input_tokens,
25450
+ completion_tokens: usageMetadata.output_tokens,
25451
+ prompt_cache_creation_tokens: isRecord(inputTokenDetails) ? inputTokenDetails.cache_creation : void 0,
25452
+ prompt_cached_tokens: isRecord(inputTokenDetails) ? inputTokenDetails.cache_read : void 0
25453
+ });
25454
+ }
25455
+ const llmOutput = response.llmOutput || {};
25456
+ const tokenUsage = isRecord(llmOutput.tokenUsage) ? llmOutput.tokenUsage : isRecord(llmOutput.estimatedTokens) ? llmOutput.estimatedTokens : {};
25457
+ return cleanObject({
25458
+ total_tokens: tokenUsage.totalTokens,
25459
+ prompt_tokens: tokenUsage.promptTokens,
25460
+ completion_tokens: tokenUsage.completionTokens
25461
+ });
25462
+ }
25463
+ function safeJsonParse(input) {
25464
+ try {
25465
+ return JSON.parse(input);
25466
+ } catch {
25467
+ return input;
25468
+ }
25469
+ }
25470
+ function isRecord(value) {
25471
+ return typeof value === "object" && value !== null && !Array.isArray(value);
25472
+ }
25473
+
25474
+ // src/instrumentation/plugins/langchain-channels.ts
25475
+ var langChainChannels = defineChannels("@langchain/core", {
25476
+ configure: channel({
25477
+ channelName: "CallbackManager.configure",
25478
+ kind: "sync-stream"
25479
+ }),
25480
+ configureSync: channel({
25481
+ channelName: "CallbackManager._configureSync",
25482
+ kind: "sync-stream"
25483
+ })
25484
+ });
25485
+
25486
+ // src/instrumentation/plugins/langchain-plugin.ts
25487
+ var LangChainPlugin = class extends BasePlugin {
25488
+ injectedManagers = /* @__PURE__ */ new WeakSet();
25489
+ onEnable() {
25490
+ this.subscribeToConfigure(langChainChannels.configure);
25491
+ this.subscribeToConfigure(langChainChannels.configureSync);
25492
+ }
25493
+ onDisable() {
25494
+ for (const unsubscribe of this.unsubscribers) {
25495
+ unsubscribe();
25496
+ }
25497
+ this.unsubscribers = [];
25498
+ this.injectedManagers = /* @__PURE__ */ new WeakSet();
25499
+ }
25500
+ subscribeToConfigure(channel2) {
25501
+ const tracingChannel2 = channel2.tracingChannel();
25502
+ const handlers = {
25503
+ start: (event) => {
25504
+ injectHandlerIntoArguments(event.arguments);
25505
+ },
25506
+ end: (event) => {
25507
+ this.injectHandler(event.result);
25508
+ }
25509
+ };
25510
+ tracingChannel2.subscribe(handlers);
25511
+ this.unsubscribers.push(() => {
25512
+ tracingChannel2.unsubscribe(handlers);
25513
+ });
25514
+ }
25515
+ injectHandler(result) {
25516
+ if (!isCallbackManager(result)) {
25517
+ return;
25518
+ }
25519
+ if (this.injectedManagers.has(result) || hasBraintrustHandler(result)) {
25520
+ return;
25521
+ }
25522
+ try {
25523
+ result.addHandler(new BraintrustLangChainCallbackHandler(), true);
25524
+ this.injectedManagers.add(result);
25525
+ } catch {
25526
+ }
25527
+ }
25528
+ };
25529
+ function isCallbackManager(value) {
25530
+ if (typeof value !== "object" || value === null) {
25531
+ return false;
25532
+ }
25533
+ const maybeManager = value;
25534
+ return typeof maybeManager.addHandler === "function";
25535
+ }
25536
+ function hasBraintrustHandler(manager) {
25537
+ return manager.handlers?.some((handler) => {
25538
+ if (typeof handler !== "object" || handler === null) {
25539
+ return false;
25540
+ }
25541
+ const name = Reflect.get(handler, "name");
25542
+ return name === BRAINTRUST_LANGCHAIN_CALLBACK_HANDLER_NAME;
25543
+ }) ?? false;
25544
+ }
25545
+ function injectHandlerIntoArguments(args) {
25546
+ if (!isWritableArgumentsObject(args)) {
25547
+ return;
25548
+ }
25549
+ const inheritedHandlers = Reflect.get(args, "0");
25550
+ const handler = new BraintrustLangChainCallbackHandler();
25551
+ if (inheritedHandlers === void 0 || inheritedHandlers === null) {
25552
+ Reflect.set(args, "0", [handler]);
25553
+ return;
25554
+ }
25555
+ if (Array.isArray(inheritedHandlers)) {
25556
+ if (!inheritedHandlers.some(isBraintrustHandler)) {
25557
+ inheritedHandlers.push(handler);
25558
+ }
25559
+ }
25560
+ }
25561
+ function isWritableArgumentsObject(args) {
25562
+ return typeof args === "object" && args !== null;
25563
+ }
25564
+ function isBraintrustHandler(handler) {
25565
+ if (typeof handler !== "object" || handler === null) {
25566
+ return false;
25567
+ }
25568
+ return Reflect.get(handler, "name") === BRAINTRUST_LANGCHAIN_CALLBACK_HANDLER_NAME;
25569
+ }
25570
+
25571
+ // src/instrumentation/braintrust-plugin.ts
25572
+ function getIntegrationConfig(integrations, key) {
25573
+ return integrations[key];
25574
+ }
25575
+ var BraintrustPlugin = class extends BasePlugin {
25576
+ config;
25577
+ openaiPlugin = null;
25578
+ openAICodexPlugin = null;
25579
+ anthropicPlugin = null;
25580
+ aiSDKPlugin = null;
25581
+ claudeAgentSDKPlugin = null;
25582
+ cursorSDKPlugin = null;
25583
+ openAIAgentsPlugin = null;
25584
+ googleGenAIPlugin = null;
25585
+ huggingFacePlugin = null;
25586
+ openRouterPlugin = null;
25587
+ openRouterAgentPlugin = null;
25588
+ mistralPlugin = null;
25589
+ googleADKPlugin = null;
25590
+ coherePlugin = null;
25591
+ groqPlugin = null;
25592
+ genkitPlugin = null;
25593
+ gitHubCopilotPlugin = null;
25594
+ fluePlugin = null;
25595
+ langChainPlugin = null;
25596
+ constructor(config = {}) {
25597
+ super();
25598
+ this.config = config;
25599
+ }
25600
+ onEnable() {
25601
+ const integrations = this.config.integrations || {};
25602
+ if (integrations.openai !== false) {
25603
+ this.openaiPlugin = new OpenAIPlugin();
25604
+ this.openaiPlugin.enable();
25605
+ }
25606
+ if (integrations.openaiCodexSDK !== false) {
25607
+ this.openAICodexPlugin = new OpenAICodexPlugin();
25608
+ this.openAICodexPlugin.enable();
25609
+ }
25610
+ if (integrations.anthropic !== false) {
25611
+ this.anthropicPlugin = new AnthropicPlugin();
25612
+ this.anthropicPlugin.enable();
25613
+ }
25614
+ if (integrations.aisdk !== false && integrations.vercel !== false) {
25615
+ this.aiSDKPlugin = new AISDKPlugin();
25616
+ this.aiSDKPlugin.enable();
25617
+ }
25618
+ if (integrations.claudeAgentSDK !== false) {
25619
+ this.claudeAgentSDKPlugin = new ClaudeAgentSDKPlugin();
23407
25620
  this.claudeAgentSDKPlugin.enable();
23408
25621
  }
23409
25622
  if (integrations.cursorSDK !== false && integrations.cursor !== false) {
23410
25623
  this.cursorSDKPlugin = new CursorSDKPlugin();
23411
25624
  this.cursorSDKPlugin.enable();
23412
25625
  }
25626
+ if (integrations.openAIAgents !== false) {
25627
+ this.openAIAgentsPlugin = new OpenAIAgentsPlugin();
25628
+ this.openAIAgentsPlugin.enable();
25629
+ }
23413
25630
  if (integrations.googleGenAI !== false && integrations.google !== false) {
23414
25631
  this.googleGenAIPlugin = new GoogleGenAIPlugin();
23415
25632
  this.googleGenAIPlugin.enable();
@@ -23450,6 +25667,14 @@ var BraintrustPlugin = class extends BasePlugin {
23450
25667
  this.gitHubCopilotPlugin = new GitHubCopilotPlugin();
23451
25668
  this.gitHubCopilotPlugin.enable();
23452
25669
  }
25670
+ if (getIntegrationConfig(integrations, "flue") !== false) {
25671
+ this.fluePlugin = new FluePlugin();
25672
+ this.fluePlugin.enable();
25673
+ }
25674
+ if (integrations.langchain !== false && integrations.langgraph !== false) {
25675
+ this.langChainPlugin = new LangChainPlugin();
25676
+ this.langChainPlugin.enable();
25677
+ }
23453
25678
  }
23454
25679
  onDisable() {
23455
25680
  if (this.openaiPlugin) {
@@ -23476,6 +25701,10 @@ var BraintrustPlugin = class extends BasePlugin {
23476
25701
  this.cursorSDKPlugin.disable();
23477
25702
  this.cursorSDKPlugin = null;
23478
25703
  }
25704
+ if (this.openAIAgentsPlugin) {
25705
+ this.openAIAgentsPlugin.disable();
25706
+ this.openAIAgentsPlugin = null;
25707
+ }
23479
25708
  if (this.googleGenAIPlugin) {
23480
25709
  this.googleGenAIPlugin.disable();
23481
25710
  this.googleGenAIPlugin = null;
@@ -23516,9 +25745,104 @@ var BraintrustPlugin = class extends BasePlugin {
23516
25745
  this.gitHubCopilotPlugin.disable();
23517
25746
  this.gitHubCopilotPlugin = null;
23518
25747
  }
25748
+ if (this.fluePlugin) {
25749
+ this.fluePlugin.disable();
25750
+ this.fluePlugin = null;
25751
+ }
25752
+ if (this.langChainPlugin) {
25753
+ this.langChainPlugin.disable();
25754
+ this.langChainPlugin = null;
25755
+ }
23519
25756
  }
23520
25757
  };
23521
25758
 
25759
+ // src/instrumentation/config.ts
25760
+ var envIntegrationAliases = {
25761
+ openai: "openai",
25762
+ "openai-codex": "openaiCodexSDK",
25763
+ "openai-codex-sdk": "openaiCodexSDK",
25764
+ openaicodexsdk: "openaiCodexSDK",
25765
+ codex: "openaiCodexSDK",
25766
+ "codex-sdk": "openaiCodexSDK",
25767
+ anthropic: "anthropic",
25768
+ aisdk: "aisdk",
25769
+ "ai-sdk": "aisdk",
25770
+ "vercel-ai": "aisdk",
25771
+ vercel: "vercel",
25772
+ claudeagentsdk: "claudeAgentSDK",
25773
+ "claude-agent-sdk": "claudeAgentSDK",
25774
+ cursor: "cursor",
25775
+ "cursor-sdk": "cursorSDK",
25776
+ cursorsdk: "cursorSDK",
25777
+ flue: "flue",
25778
+ "flue-runtime": "flue",
25779
+ "openai-agents": "openAIAgents",
25780
+ openaiagents: "openAIAgents",
25781
+ "openai-agents-core": "openAIAgents",
25782
+ openaiagentscore: "openAIAgents",
25783
+ google: "google",
25784
+ "google-genai": "googleGenAI",
25785
+ googlegenai: "googleGenAI",
25786
+ huggingface: "huggingface",
25787
+ openrouter: "openrouter",
25788
+ openrouteragent: "openrouterAgent",
25789
+ "openrouter-agent": "openrouterAgent",
25790
+ mistral: "mistral",
25791
+ googleadk: "googleADK",
25792
+ "google-adk": "googleADK",
25793
+ cohere: "cohere",
25794
+ groq: "groq",
25795
+ "groq-sdk": "groq",
25796
+ genkit: "genkit",
25797
+ "firebase-genkit": "genkit",
25798
+ githubcopilot: "gitHubCopilot",
25799
+ "github-copilot": "gitHubCopilot",
25800
+ "copilot-sdk": "gitHubCopilot",
25801
+ langchain: "langchain",
25802
+ "langchain-js": "langchain",
25803
+ "@langchain": "langchain",
25804
+ langgraph: "langgraph"
25805
+ };
25806
+ function getDefaultInstrumentationIntegrations() {
25807
+ return {
25808
+ openai: true,
25809
+ openaiCodexSDK: true,
25810
+ anthropic: true,
25811
+ vercel: true,
25812
+ aisdk: true,
25813
+ google: true,
25814
+ googleGenAI: true,
25815
+ googleADK: true,
25816
+ huggingface: true,
25817
+ claudeAgentSDK: true,
25818
+ cursor: true,
25819
+ cursorSDK: true,
25820
+ flue: true,
25821
+ openAIAgents: true,
25822
+ openrouter: true,
25823
+ openrouterAgent: true,
25824
+ mistral: true,
25825
+ cohere: true,
25826
+ groq: true,
25827
+ genkit: true,
25828
+ gitHubCopilot: true,
25829
+ langchain: true,
25830
+ langgraph: true
25831
+ };
25832
+ }
25833
+ function readDisabledInstrumentationEnvConfig(disabledList) {
25834
+ const integrations = {};
25835
+ if (disabledList) {
25836
+ for (const value of disabledList.split(",")) {
25837
+ const sdk = value.trim().toLowerCase();
25838
+ if (sdk.length > 0) {
25839
+ integrations[envIntegrationAliases[sdk] ?? sdk] = false;
25840
+ }
25841
+ }
25842
+ }
25843
+ return { integrations };
25844
+ }
25845
+
23522
25846
  // src/instrumentation/registry.ts
23523
25847
  var REGISTRY_STATE_KEY = /* @__PURE__ */ Symbol.for("braintrust.registry");
23524
25848
  function getSharedState() {
@@ -23597,50 +25921,16 @@ var PluginRegistry = class {
23597
25921
  * Get default configuration (all integrations enabled).
23598
25922
  */
23599
25923
  getDefaultConfig() {
23600
- return {
23601
- openai: true,
23602
- openaiCodexSDK: true,
23603
- anthropic: true,
23604
- vercel: true,
23605
- aisdk: true,
23606
- google: true,
23607
- googleGenAI: true,
23608
- googleADK: true,
23609
- huggingface: true,
23610
- claudeAgentSDK: true,
23611
- cursor: true,
23612
- cursorSDK: true,
23613
- openrouter: true,
23614
- openrouterAgent: true,
23615
- mistral: true,
23616
- cohere: true,
23617
- groq: true,
23618
- genkit: true,
23619
- gitHubCopilot: true
23620
- };
25924
+ return getDefaultInstrumentationIntegrations();
23621
25925
  }
23622
25926
  /**
23623
25927
  * Read configuration from environment variables.
23624
25928
  * Supports: BRAINTRUST_DISABLE_INSTRUMENTATION=openai,anthropic,...
23625
25929
  */
23626
25930
  readEnvConfig() {
23627
- const integrations = {};
23628
- const disabledList = isomorph_default.getEnv("BRAINTRUST_DISABLE_INSTRUMENTATION");
23629
- if (disabledList) {
23630
- const disabled = disabledList.split(",").map((s) => s.trim().toLowerCase()).filter((s) => s.length > 0);
23631
- for (const sdk of disabled) {
23632
- if (sdk === "cursor-sdk") {
23633
- integrations.cursorSDK = false;
23634
- } else if (sdk === "githubcopilot" || sdk === "github-copilot" || sdk === "copilot-sdk") {
23635
- integrations.gitHubCopilot = false;
23636
- } else if (sdk === "openai-codex-sdk") {
23637
- integrations.openaiCodexSDK = false;
23638
- } else {
23639
- integrations[sdk] = false;
23640
- }
23641
- }
23642
- }
23643
- return { integrations };
25931
+ return readDisabledInstrumentationEnvConfig(
25932
+ isomorph_default.getEnv("BRAINTRUST_DISABLE_INSTRUMENTATION")
25933
+ );
23644
25934
  }
23645
25935
  };
23646
25936
  var registry = new PluginRegistry();
@@ -23755,6 +26045,10 @@ function configureBrowser() {
23755
26045
  }
23756
26046
  return process.env[name];
23757
26047
  };
26048
+ isomorph_default.getBraintrustApiKey = async () => {
26049
+ const value = isomorph_default.getEnv("BRAINTRUST_API_KEY");
26050
+ return value?.trim() ? value : void 0;
26051
+ };
23758
26052
  isomorph_default.hash = (data) => {
23759
26053
  let hash = 0;
23760
26054
  for (let i = 0; i < data.length; i++) {
@@ -23776,8 +26070,10 @@ __export(exports_exports, {
23776
26070
  Attachment: () => Attachment,
23777
26071
  AttachmentReference: () => AttachmentReference,
23778
26072
  BRAINTRUST_CURRENT_SPAN_STORE: () => BRAINTRUST_CURRENT_SPAN_STORE,
26073
+ BRAINTRUST_LANGCHAIN_CALLBACK_HANDLER_NAME: () => BRAINTRUST_LANGCHAIN_CALLBACK_HANDLER_NAME,
23779
26074
  BaseAttachment: () => BaseAttachment,
23780
26075
  BaseExperiment: () => BaseExperiment,
26076
+ BraintrustLangChainCallbackHandler: () => BraintrustLangChainCallbackHandler,
23781
26077
  BraintrustMiddleware: () => BraintrustMiddleware,
23782
26078
  BraintrustState: () => BraintrustState,
23783
26079
  BraintrustStream: () => BraintrustStream,
@@ -23788,6 +26084,7 @@ __export(exports_exports, {
23788
26084
  DEFAULT_FETCH_BATCH_SIZE: () => DEFAULT_FETCH_BATCH_SIZE,
23789
26085
  DEFAULT_MAX_REQUEST_SIZE: () => DEFAULT_MAX_REQUEST_SIZE,
23790
26086
  Dataset: () => Dataset2,
26087
+ DatasetPipeline: () => DatasetPipeline,
23791
26088
  ERR_PERMALINK: () => ERR_PERMALINK,
23792
26089
  Eval: () => Eval,
23793
26090
  EvalResultWithSummary: () => EvalResultWithSummary,
@@ -23903,6 +26200,8 @@ __export(exports_exports, {
23903
26200
  wrapCohere: () => wrapCohere,
23904
26201
  wrapCopilotClient: () => wrapCopilotClient,
23905
26202
  wrapCursorSDK: () => wrapCursorSDK,
26203
+ wrapFlueContext: () => wrapFlueContext,
26204
+ wrapFlueSession: () => wrapFlueSession,
23906
26205
  wrapGenkit: () => wrapGenkit,
23907
26206
  wrapGoogleADK: () => wrapGoogleADK,
23908
26207
  wrapGoogleGenAI: () => wrapGoogleGenAI,
@@ -25002,7 +27301,7 @@ function extractModelParameters(params, excludeKeys) {
25002
27301
  }
25003
27302
  return modelParams;
25004
27303
  }
25005
- function getNumberProperty2(obj, key) {
27304
+ function getNumberProperty3(obj, key) {
25006
27305
  if (!obj || typeof obj !== "object" || !(key in obj)) {
25007
27306
  return void 0;
25008
27307
  }
@@ -25011,31 +27310,31 @@ function getNumberProperty2(obj, key) {
25011
27310
  }
25012
27311
  function normalizeUsageMetrics(usage, provider, providerMetadata) {
25013
27312
  const metrics = {};
25014
- const inputTokens = getNumberProperty2(usage, "inputTokens");
27313
+ const inputTokens = getNumberProperty3(usage, "inputTokens");
25015
27314
  if (inputTokens !== void 0) {
25016
27315
  metrics.prompt_tokens = inputTokens;
25017
27316
  }
25018
- const outputTokens = getNumberProperty2(usage, "outputTokens");
27317
+ const outputTokens = getNumberProperty3(usage, "outputTokens");
25019
27318
  if (outputTokens !== void 0) {
25020
27319
  metrics.completion_tokens = outputTokens;
25021
27320
  }
25022
- const totalTokens = getNumberProperty2(usage, "totalTokens");
27321
+ const totalTokens = getNumberProperty3(usage, "totalTokens");
25023
27322
  if (totalTokens !== void 0) {
25024
27323
  metrics.tokens = totalTokens;
25025
27324
  }
25026
- const reasoningTokens = getNumberProperty2(usage, "reasoningTokens");
27325
+ const reasoningTokens = getNumberProperty3(usage, "reasoningTokens");
25027
27326
  if (reasoningTokens !== void 0) {
25028
27327
  metrics.completion_reasoning_tokens = reasoningTokens;
25029
27328
  }
25030
- const cachedInputTokens = getNumberProperty2(usage, "cachedInputTokens");
27329
+ const cachedInputTokens = getNumberProperty3(usage, "cachedInputTokens");
25031
27330
  if (cachedInputTokens !== void 0) {
25032
27331
  metrics.prompt_cached_tokens = cachedInputTokens;
25033
27332
  }
25034
27333
  if (provider === "anthropic") {
25035
27334
  const anthropicMetadata = providerMetadata?.anthropic;
25036
27335
  if (anthropicMetadata) {
25037
- const cacheReadTokens = getNumberProperty2(anthropicMetadata.usage, "cache_read_input_tokens") || 0;
25038
- const cacheCreationTokens = getNumberProperty2(
27336
+ const cacheReadTokens = getNumberProperty3(anthropicMetadata.usage, "cache_read_input_tokens") || 0;
27337
+ const cacheCreationTokens = getNumberProperty3(
25039
27338
  anthropicMetadata.usage,
25040
27339
  "cache_creation_input_tokens"
25041
27340
  ) || 0;
@@ -26010,17 +28309,17 @@ function wrapGenkit(genkit) {
26010
28309
  console.warn("Unsupported Genkit object. Not wrapping.");
26011
28310
  return genkit;
26012
28311
  }
26013
- function isRecord(value) {
28312
+ function isRecord2(value) {
26014
28313
  return typeof value === "object" && value !== null;
26015
28314
  }
26016
28315
  function isPropertyBag(value) {
26017
- return isRecord(value) || typeof value === "function";
28316
+ return isRecord2(value) || typeof value === "function";
26018
28317
  }
26019
28318
  function hasFunction(value, methodName) {
26020
28319
  return isPropertyBag(value) && methodName in value && typeof value[methodName] === "function";
26021
28320
  }
26022
28321
  function isGenkitInstance(value) {
26023
- return isRecord(value) && (hasFunction(value, "generate") || hasFunction(value, "generateStream") || hasFunction(value, "defineFlow") || hasFunction(value, "defineTool"));
28322
+ return isRecord2(value) && (hasFunction(value, "generate") || hasFunction(value, "generateStream") || hasFunction(value, "defineFlow") || hasFunction(value, "defineTool"));
26024
28323
  }
26025
28324
  function isGenkitModule(value) {
26026
28325
  return hasFunction(value, "genkit");
@@ -26074,7 +28373,7 @@ function patchGenkitRegistry(instance) {
26074
28373
  patchGenkitRegistryConstructor(registry2);
26075
28374
  }
26076
28375
  function patchGenkitRegistryLookup(registry2) {
26077
- if (!isRecord(registry2) || hasRegistryPatchedFlag(registry2) || !hasFunction(registry2, "lookupAction")) {
28376
+ if (!isRecord2(registry2) || hasRegistryPatchedFlag(registry2) || !hasFunction(registry2, "lookupAction")) {
26078
28377
  return;
26079
28378
  }
26080
28379
  const originalLookupAction = registry2.lookupAction;
@@ -26100,7 +28399,7 @@ function patchGenkitRegistryLookup(registry2) {
26100
28399
  }
26101
28400
  }
26102
28401
  function patchGenkitRegistryConstructor(registry2) {
26103
- if (!isRecord(registry2)) {
28402
+ if (!isRecord2(registry2)) {
26104
28403
  return;
26105
28404
  }
26106
28405
  const constructor = registry2.constructor;
@@ -26116,7 +28415,7 @@ function patchGenkitRegistryConstructor(registry2) {
26116
28415
  configurable: true,
26117
28416
  value: (...args) => {
26118
28417
  const childRegistry = originalWithParent.apply(constructor, args);
26119
- if (args.some((arg) => isRecord(arg) && hasRegistryPatchedFlag(arg))) {
28418
+ if (args.some((arg) => isRecord2(arg) && hasRegistryPatchedFlag(arg))) {
26120
28419
  patchGenkitRegistryLookup(childRegistry);
26121
28420
  patchGenkitRegistryConstructor(childRegistry);
26122
28421
  }
@@ -26215,7 +28514,7 @@ function hasRegistryConstructorPatchedFlag(value) {
26215
28514
  );
26216
28515
  }
26217
28516
  function isPromiseLike2(value) {
26218
- return isRecord(value) && "then" in value && typeof value.then === "function";
28517
+ return isRecord2(value) && "then" in value && typeof value.then === "function";
26219
28518
  }
26220
28519
 
26221
28520
  // src/wrappers/huggingface.ts
@@ -26578,14 +28877,14 @@ function wrapMistral(mistral) {
26578
28877
  console.warn("Unsupported Mistral library. Not wrapping.");
26579
28878
  return mistral;
26580
28879
  }
26581
- function isRecord2(value) {
28880
+ function isRecord3(value) {
26582
28881
  return typeof value === "object" && value !== null;
26583
28882
  }
26584
28883
  function hasFunction3(value, methodName) {
26585
- return isRecord2(value) && methodName in value && typeof value[methodName] === "function";
28884
+ return isRecord3(value) && methodName in value && typeof value[methodName] === "function";
26586
28885
  }
26587
28886
  function isSupportedMistralClient(value) {
26588
- if (!isRecord2(value)) {
28887
+ if (!isRecord3(value)) {
26589
28888
  return false;
26590
28889
  }
26591
28890
  return value.chat !== void 0 && hasChat(value.chat) || value.embeddings !== void 0 && hasEmbeddings(value.embeddings) || value.fim !== void 0 && hasFim(value.fim) || value.agents !== void 0 && hasAgents(value.agents) || value.classifiers !== void 0 && hasClassifiers(value.classifiers);
@@ -26769,14 +29068,14 @@ function wrapCohere(cohere) {
26769
29068
  return cohere;
26770
29069
  }
26771
29070
  var cohereProxyCache = /* @__PURE__ */ new WeakMap();
26772
- function isRecord3(value) {
29071
+ function isRecord4(value) {
26773
29072
  return typeof value === "object" && value !== null;
26774
29073
  }
26775
29074
  function hasFunction4(value, methodName) {
26776
- return isRecord3(value) && methodName in value && typeof value[methodName] === "function";
29075
+ return isRecord4(value) && methodName in value && typeof value[methodName] === "function";
26777
29076
  }
26778
29077
  function isSupportedCohereClient(value) {
26779
- if (!isRecord3(value)) {
29078
+ if (!isRecord4(value)) {
26780
29079
  return false;
26781
29080
  }
26782
29081
  return hasFunction4(value, "chat") || hasFunction4(value, "chatStream") || hasFunction4(value, "embed") || hasFunction4(value, "rerank");
@@ -26836,20 +29135,20 @@ function wrapGroq(groq) {
26836
29135
  console.warn("Unsupported Groq library. Not wrapping.");
26837
29136
  return groq;
26838
29137
  }
26839
- function isRecord4(value) {
29138
+ function isRecord5(value) {
26840
29139
  return typeof value === "object" && value !== null;
26841
29140
  }
26842
29141
  function hasFunction5(value, methodName) {
26843
- return isRecord4(value) && methodName in value && typeof value[methodName] === "function";
29142
+ return isRecord5(value) && methodName in value && typeof value[methodName] === "function";
26844
29143
  }
26845
29144
  function hasChat2(value) {
26846
- return isRecord4(value) && isRecord4(value.completions) && hasFunction5(value.completions, "create");
29145
+ return isRecord5(value) && isRecord5(value.completions) && hasFunction5(value.completions, "create");
26847
29146
  }
26848
29147
  function hasEmbeddings2(value) {
26849
29148
  return hasFunction5(value, "create");
26850
29149
  }
26851
29150
  function isSupportedGroqClient(value) {
26852
- return isRecord4(value) && (value.chat !== void 0 && hasChat2(value.chat) || value.embeddings !== void 0 && hasEmbeddings2(value.embeddings));
29151
+ return isRecord5(value) && (value.chat !== void 0 && hasChat2(value.chat) || value.embeddings !== void 0 && hasEmbeddings2(value.embeddings));
26853
29152
  }
26854
29153
  function groqProxy(groq) {
26855
29154
  const privateMethodWorkaroundCache = /* @__PURE__ */ new WeakMap();
@@ -27044,10 +29343,12 @@ function formatExperimentSummary(summary) {
27044
29343
  // src/wrappers/shared/flush.ts
27045
29344
  async function summarizeAndFlush(experiment, options) {
27046
29345
  const shouldDisplay = options.displaySummary ?? true;
27047
- const summary = await experiment.summarize();
27048
- if (shouldDisplay) {
27049
- console.log(formatExperimentSummary(summary));
29346
+ if (!shouldDisplay) {
29347
+ await experiment.flush();
29348
+ return;
27050
29349
  }
29350
+ const summary = await experiment.summarize();
29351
+ console.log(formatExperimentSummary(summary));
27051
29352
  }
27052
29353
 
27053
29354
  // src/wrappers/vitest/flush-manager.ts
@@ -28911,8 +31212,12 @@ var waterfall$1 = awaitify(waterfall);
28911
31212
 
28912
31213
  // src/trace.ts
28913
31214
  var SpanFetcher = class _SpanFetcher extends ObjectFetcher {
28914
- constructor(objectType, _objectId, rootSpanId, _state, spanTypeFilter) {
28915
- const filterExpr = _SpanFetcher.buildFilter(rootSpanId, spanTypeFilter);
31215
+ constructor(objectType, _objectId, rootSpanId, _state, spanTypeFilter, includeScorers = false) {
31216
+ const filterExpr = _SpanFetcher.buildFilter(
31217
+ rootSpanId,
31218
+ spanTypeFilter,
31219
+ includeScorers
31220
+ );
28916
31221
  super(objectType, void 0, void 0, {
28917
31222
  filter: filterExpr
28918
31223
  });
@@ -28921,16 +31226,17 @@ var SpanFetcher = class _SpanFetcher extends ObjectFetcher {
28921
31226
  this._state = _state;
28922
31227
  this.spanTypeFilter = spanTypeFilter;
28923
31228
  }
28924
- static buildFilter(rootSpanId, spanTypeFilter) {
31229
+ static buildFilter(rootSpanId, spanTypeFilter, includeScorers = false) {
28925
31230
  const children = [
28926
31231
  // Base filter: root_span_id = 'value'
28927
31232
  {
28928
31233
  op: "eq",
28929
31234
  left: { op: "ident", name: ["root_span_id"] },
28930
31235
  right: { op: "literal", value: rootSpanId }
28931
- },
28932
- // Exclude span_attributes.purpose = 'score'
28933
- {
31236
+ }
31237
+ ];
31238
+ if (!includeScorers) {
31239
+ children.push({
28934
31240
  op: "or",
28935
31241
  children: [
28936
31242
  {
@@ -28943,8 +31249,8 @@ var SpanFetcher = class _SpanFetcher extends ObjectFetcher {
28943
31249
  right: { op: "literal", value: "scorer" }
28944
31250
  }
28945
31251
  ]
28946
- }
28947
- ];
31252
+ });
31253
+ }
28948
31254
  if (spanTypeFilter && spanTypeFilter.length > 0) {
28949
31255
  children.push({
28950
31256
  op: "in",
@@ -28970,35 +31276,49 @@ var CachedSpanFetcher = class {
28970
31276
  fetchFn;
28971
31277
  constructor(objectTypeOrFetchFn, objectId, rootSpanId, getState) {
28972
31278
  if (typeof objectTypeOrFetchFn === "function") {
28973
- this.fetchFn = objectTypeOrFetchFn;
31279
+ this.fetchFn = (spanType) => objectTypeOrFetchFn(spanType);
28974
31280
  } else {
28975
31281
  const objectType = objectTypeOrFetchFn;
28976
- this.fetchFn = async (spanType) => {
31282
+ this.fetchFn = async (spanType, includeScorers) => {
28977
31283
  const state = await getState();
28978
31284
  const fetcher = new SpanFetcher(
28979
31285
  objectType,
28980
31286
  objectId,
28981
31287
  rootSpanId,
28982
31288
  state,
28983
- spanType
31289
+ spanType,
31290
+ includeScorers
28984
31291
  );
28985
31292
  const rows = await fetcher.fetchedData();
28986
- return rows.filter((row) => row.span_attributes?.purpose !== "scorer").map((row) => ({
31293
+ return rows.map((row) => ({
28987
31294
  input: row.input,
28988
31295
  output: row.output,
31296
+ expected: row.expected,
31297
+ error: row.error,
31298
+ scores: row.scores,
31299
+ metrics: row.metrics,
28989
31300
  metadata: row.metadata,
28990
31301
  span_id: row.span_id,
28991
31302
  span_parents: row.span_parents,
31303
+ is_root: row.is_root,
28992
31304
  span_attributes: row.span_attributes,
28993
31305
  id: row.id,
28994
31306
  _xact_id: row._xact_id,
28995
31307
  _pagination_key: row._pagination_key,
28996
- root_span_id: row.root_span_id
31308
+ root_span_id: row.root_span_id,
31309
+ created: row.created,
31310
+ tags: row.tags
28997
31311
  }));
28998
31312
  };
28999
31313
  }
29000
31314
  }
29001
- async getSpans({ spanType } = {}) {
31315
+ async getSpans({
31316
+ spanType,
31317
+ includeScorers = false
31318
+ } = {}) {
31319
+ if (includeScorers) {
31320
+ return this.fetchFn(spanType, true);
31321
+ }
29002
31322
  if (this.allFetched) {
29003
31323
  return this.getFromCache(spanType);
29004
31324
  }
@@ -29015,7 +31335,7 @@ var CachedSpanFetcher = class {
29015
31335
  return this.getFromCache(spanType);
29016
31336
  }
29017
31337
  async fetchSpans(spanType) {
29018
- const spans = await this.fetchFn(spanType);
31338
+ const spans = await this.fetchFn(spanType, false);
29019
31339
  for (const span of spans) {
29020
31340
  const type = span.span_attributes?.type ?? "";
29021
31341
  const existing = this.spanCache.get(type) ?? [];
@@ -29093,10 +31413,13 @@ var LocalTrace = class {
29093
31413
  * First checks the local span cache for recently logged spans, then falls
29094
31414
  * back to CachedSpanFetcher which handles BTQL fetching and caching.
29095
31415
  */
29096
- async getSpans({ spanType } = {}) {
31416
+ async getSpans({
31417
+ spanType,
31418
+ includeScorers = false
31419
+ } = {}) {
29097
31420
  const cachedSpans = this.state.spanCache.getByRootSpanId(this.rootSpanId);
29098
31421
  if (cachedSpans && cachedSpans.length > 0) {
29099
- let spans = cachedSpans.filter(
31422
+ let spans = includeScorers ? cachedSpans : cachedSpans.filter(
29100
31423
  (span) => span.span_attributes?.purpose !== "scorer"
29101
31424
  );
29102
31425
  if (spanType && spanType.length > 0) {
@@ -29107,13 +31430,19 @@ var LocalTrace = class {
29107
31430
  return spans.map((span) => ({
29108
31431
  input: span.input,
29109
31432
  output: span.output,
31433
+ expected: span.expected,
31434
+ error: span.error,
31435
+ scores: span.scores,
31436
+ metrics: span.metrics,
29110
31437
  metadata: span.metadata,
29111
31438
  span_id: span.span_id,
29112
31439
  span_parents: span.span_parents,
29113
- span_attributes: span.span_attributes
31440
+ is_root: span.is_root,
31441
+ span_attributes: span.span_attributes,
31442
+ tags: span.tags
29114
31443
  }));
29115
31444
  }
29116
- return this.cachedFetcher.getSpans({ spanType });
31445
+ return this.cachedFetcher.getSpans({ spanType, includeScorers });
29117
31446
  }
29118
31447
  /**
29119
31448
  * Get the thread (preprocessed messages) for this trace.
@@ -30302,6 +32631,34 @@ var defaultReporter = {
30302
32631
  }
30303
32632
  };
30304
32633
 
32634
+ // src/dataset-pipeline.ts
32635
+ function DatasetPipeline(definition) {
32636
+ if (!globalThis.__braintrust_dataset_pipelines) {
32637
+ globalThis.__braintrust_dataset_pipelines = [];
32638
+ }
32639
+ const storedDefinition = {
32640
+ name: definition.name,
32641
+ source: {
32642
+ projectId: definition.source.projectId,
32643
+ projectName: definition.source.projectName,
32644
+ orgName: definition.source.orgName,
32645
+ filter: definition.source.filter,
32646
+ scope: definition.source.scope ?? "span"
32647
+ },
32648
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions, @typescript-eslint/no-explicit-any
32649
+ transform: definition.transform,
32650
+ target: {
32651
+ projectId: definition.target.projectId,
32652
+ projectName: definition.target.projectName,
32653
+ orgName: definition.target.orgName,
32654
+ datasetName: definition.target.datasetName,
32655
+ description: definition.target.description,
32656
+ metadata: definition.target.metadata
32657
+ }
32658
+ };
32659
+ globalThis.__braintrust_dataset_pipelines.push(storedDefinition);
32660
+ }
32661
+
30305
32662
  // src/framework2.ts
30306
32663
  import { z as z12 } from "zod/v3";
30307
32664
  var currentFilename = typeof __filename !== "undefined" ? __filename : "unknown";
@@ -30827,8 +33184,10 @@ export {
30827
33184
  Attachment,
30828
33185
  AttachmentReference,
30829
33186
  BRAINTRUST_CURRENT_SPAN_STORE,
33187
+ BRAINTRUST_LANGCHAIN_CALLBACK_HANDLER_NAME,
30830
33188
  BaseAttachment,
30831
33189
  BaseExperiment,
33190
+ BraintrustLangChainCallbackHandler,
30832
33191
  BraintrustMiddleware,
30833
33192
  BraintrustState,
30834
33193
  BraintrustStream,
@@ -30839,6 +33198,7 @@ export {
30839
33198
  DEFAULT_FETCH_BATCH_SIZE,
30840
33199
  DEFAULT_MAX_REQUEST_SIZE,
30841
33200
  Dataset2 as Dataset,
33201
+ DatasetPipeline,
30842
33202
  ERR_PERMALINK,
30843
33203
  Eval,
30844
33204
  EvalResultWithSummary,
@@ -30955,6 +33315,8 @@ export {
30955
33315
  wrapCohere,
30956
33316
  wrapCopilotClient,
30957
33317
  wrapCursorSDK,
33318
+ wrapFlueContext,
33319
+ wrapFlueSession,
30958
33320
  wrapGenkit,
30959
33321
  wrapGoogleADK,
30960
33322
  wrapGoogleGenAI,