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/index.mjs CHANGED
@@ -1,204 +1,42 @@
1
- var __defProp = Object.defineProperty;
2
- var __export = (target, all) => {
3
- for (var name in all)
4
- __defProp(target, name, { get: all[name], enumerable: true });
5
- };
1
+ import {
2
+ __export,
3
+ aiSDKChannels,
4
+ anthropicChannels,
5
+ claudeAgentSDKChannels,
6
+ cohereChannels,
7
+ cursorSDKChannels,
8
+ flueChannels,
9
+ genkitChannels,
10
+ genkitCoreChannels,
11
+ getDefaultInstrumentationIntegrations,
12
+ gitHubCopilotChannels,
13
+ googleADKChannels,
14
+ googleGenAIChannels,
15
+ groqChannels,
16
+ huggingFaceChannels,
17
+ isomorph_default,
18
+ langChainChannels,
19
+ mistralChannels,
20
+ openAIAgentsCoreChannels,
21
+ openAIChannels,
22
+ openAICodexChannels,
23
+ openRouterAgentChannels,
24
+ openRouterChannels,
25
+ patchTracingChannel,
26
+ readDisabledInstrumentationEnvConfig
27
+ } from "./chunk-75IQCUB2.mjs";
6
28
 
7
29
  // src/node/config.ts
8
30
  import { AsyncLocalStorage } from "node:async_hooks";
9
31
  import * as diagnostics_channel from "node:diagnostics_channel";
10
32
  import * as path from "node:path";
11
-
12
- // src/auto-instrumentations/patch-tracing-channel.ts
13
- function patchTracingChannel(tracingChannelFn) {
14
- const dummyChannel = tracingChannelFn("__braintrust_probe__");
15
- const TracingChannel = dummyChannel?.constructor;
16
- if (!TracingChannel?.prototype) {
17
- return;
18
- }
19
- if (!Object.getOwnPropertyDescriptor(TracingChannel.prototype, "hasSubscribers")) {
20
- Object.defineProperty(TracingChannel.prototype, "hasSubscribers", {
21
- configurable: true,
22
- enumerable: false,
23
- get() {
24
- return Boolean(
25
- this.start?.hasSubscribers || this.end?.hasSubscribers || this.asyncStart?.hasSubscribers || this.asyncEnd?.hasSubscribers || this.error?.hasSubscribers
26
- );
27
- }
28
- });
29
- }
30
- if (TracingChannel.prototype.tracePromise) {
31
- TracingChannel.prototype.tracePromise = function(fn, context = {}, thisArg, ...args) {
32
- const start = this.start;
33
- const end = this.end;
34
- const asyncStart = this.asyncStart;
35
- const asyncEnd = this.asyncEnd;
36
- const error = this.error;
37
- function publishRejected(err) {
38
- context.error = err;
39
- error?.publish(context);
40
- asyncStart?.publish(context);
41
- asyncEnd?.publish(context);
42
- }
43
- function publishResolved(result) {
44
- context.result = result;
45
- asyncStart?.publish(context);
46
- asyncEnd?.publish(context);
47
- }
48
- return start.runStores(context, () => {
49
- try {
50
- const result = Reflect.apply(fn, thisArg, args);
51
- end?.publish(context);
52
- if (result && (typeof result === "object" || typeof result === "function") && typeof result.then === "function") {
53
- if (result.constructor === Promise) {
54
- return result.then(
55
- (res) => {
56
- publishResolved(res);
57
- return res;
58
- },
59
- (err) => {
60
- publishRejected(err);
61
- return Promise.reject(err);
62
- }
63
- );
64
- }
65
- void result.then(
66
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
67
- (resolved) => {
68
- try {
69
- publishResolved(resolved);
70
- } catch {
71
- }
72
- },
73
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
74
- (err) => {
75
- try {
76
- publishRejected(err);
77
- } catch {
78
- }
79
- }
80
- );
81
- return result;
82
- }
83
- context.result = result;
84
- asyncStart?.publish(context);
85
- asyncEnd?.publish(context);
86
- return result;
87
- } catch (err) {
88
- context.error = err;
89
- error?.publish(context);
90
- end?.publish(context);
91
- throw err;
92
- }
93
- });
94
- };
95
- }
96
- }
97
-
98
- // src/node/config.ts
99
33
  import * as fs from "node:fs/promises";
100
34
  import * as os from "node:os";
101
35
  import * as fsSync from "node:fs";
102
36
  import * as crypto from "node:crypto";
103
37
  import { promisify } from "node:util";
104
38
  import * as zlib from "node:zlib";
105
-
106
- // src/isomorph.ts
107
- var DefaultAsyncLocalStorage = class {
108
- constructor() {
109
- }
110
- enterWith(_) {
111
- }
112
- run(_, callback) {
113
- return callback();
114
- }
115
- getStore() {
116
- return void 0;
117
- }
118
- };
119
- var DefaultChannel = class {
120
- constructor(name) {
121
- this.name = name;
122
- }
123
- hasSubscribers = false;
124
- subscribe(_subscription) {
125
- }
126
- unsubscribe(_subscription) {
127
- return false;
128
- }
129
- bindStore(_store, _transform) {
130
- }
131
- unbindStore(_store) {
132
- return false;
133
- }
134
- publish(_message) {
135
- }
136
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
137
- runStores(_message, fn, thisArg, ...args) {
138
- return fn.apply(thisArg, args);
139
- }
140
- };
141
- var DefaultTracingChannel = class {
142
- start;
143
- end;
144
- asyncStart;
145
- asyncEnd;
146
- error;
147
- constructor(nameOrChannels) {
148
- if (typeof nameOrChannels === "string") {
149
- this.start = new DefaultChannel(`tracing:${nameOrChannels}:start`);
150
- this.end = new DefaultChannel(`tracing:${nameOrChannels}:end`);
151
- this.asyncStart = new DefaultChannel(
152
- `tracing:${nameOrChannels}:asyncStart`
153
- );
154
- this.asyncEnd = new DefaultChannel(`tracing:${nameOrChannels}:asyncEnd`);
155
- this.error = new DefaultChannel(`tracing:${nameOrChannels}:error`);
156
- return;
157
- }
158
- this.start = nameOrChannels.start ?? new DefaultChannel("tracing:start");
159
- this.end = nameOrChannels.end ?? new DefaultChannel("tracing:end");
160
- this.asyncStart = nameOrChannels.asyncStart ?? new DefaultChannel("tracing:asyncStart");
161
- this.asyncEnd = nameOrChannels.asyncEnd ?? new DefaultChannel("tracing:asyncEnd");
162
- this.error = nameOrChannels.error ?? new DefaultChannel("tracing:error");
163
- }
164
- get hasSubscribers() {
165
- return this.start.hasSubscribers || this.end.hasSubscribers || this.asyncStart.hasSubscribers || this.asyncEnd.hasSubscribers || this.error.hasSubscribers;
166
- }
167
- subscribe(_handlers) {
168
- }
169
- unsubscribe(_handlers) {
170
- return false;
171
- }
172
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
173
- traceSync(fn, _message, thisArg, ...args) {
174
- return fn.apply(thisArg, args);
175
- }
176
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
177
- tracePromise(fn, _message, thisArg, ...args) {
178
- return fn.apply(thisArg, args);
179
- }
180
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
181
- traceCallback(fn, _position, _message, thisArg, ...args) {
182
- return fn.apply(thisArg, args);
183
- }
184
- };
185
- var iso = {
186
- buildType: "unknown",
187
- // Will be set by configureBrowser() or configureNode()
188
- getRepoInfo: async (_settings) => void 0,
189
- getPastNAncestors: async () => [],
190
- getEnv: (_name) => void 0,
191
- getCallerLocation: () => void 0,
192
- newAsyncLocalStorage: () => new DefaultAsyncLocalStorage(),
193
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
194
- newTracingChannel: (nameOrChannels) => new DefaultTracingChannel(nameOrChannels),
195
- processOn: (_0, _1) => {
196
- },
197
- basename: (filepath) => filepath.split(/[\\/]/).pop() || filepath,
198
- // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage.
199
- writeln: (text) => console.log(text)
200
- };
201
- var isomorph_default = iso;
39
+ import * as dotenv from "dotenv";
202
40
 
203
41
  // src/debug-logger.ts
204
42
  var PREFIX = "[braintrust]";
@@ -416,11 +254,11 @@ function truncateToByteLimit(s, byteLimit = 65536) {
416
254
  return new TextDecoder().decode(truncated);
417
255
  }
418
256
  async function getRepoInfo(settings) {
419
- if (settings && settings.collect === "none") {
257
+ if (!settings || settings.collect === "none") {
420
258
  return void 0;
421
259
  }
422
260
  const repo = await repoInfo();
423
- if (!repo || !settings || settings.collect === "all") {
261
+ if (!repo || settings.collect === "all") {
424
262
  return repo;
425
263
  }
426
264
  let sanitized = {};
@@ -1234,6 +1072,11 @@ function isPromiseLike(value) {
1234
1072
 
1235
1073
  // util/object_util.ts
1236
1074
  var SET_UNION_FIELDS = /* @__PURE__ */ new Set(["tags"]);
1075
+ var FORBIDDEN_MERGE_KEYS = /* @__PURE__ */ new Set([
1076
+ "__proto__",
1077
+ "constructor",
1078
+ "prototype"
1079
+ ]);
1237
1080
  function mergeDictsWithPaths({
1238
1081
  mergeInto,
1239
1082
  mergeFrom,
@@ -1256,6 +1099,7 @@ function mergeDictsWithPathsHelper({
1256
1099
  mergePaths
1257
1100
  }) {
1258
1101
  Object.entries(mergeFrom).forEach(([k, mergeFromV]) => {
1102
+ if (FORBIDDEN_MERGE_KEYS.has(k)) return;
1259
1103
  const fullPath = path2.concat([k]);
1260
1104
  const fullPathSerialized = JSON.stringify(fullPath);
1261
1105
  const mergeIntoV = recordFind(mergeInto, k);
@@ -5329,6 +5173,13 @@ var HTTPConnection = class _HTTPConnection {
5329
5173
  debugLogger.debug(
5330
5174
  `Retrying API request ${object_type} ${JSON.stringify(args)} ${e.status} ${e.text}`
5331
5175
  );
5176
+ const sleepTimeS = HTTP_RETRY_BASE_SLEEP_TIME_S * 2 ** i;
5177
+ debugLogger.info(
5178
+ `Sleeping for ${sleepTimeS}s before retrying API request`
5179
+ );
5180
+ await new Promise(
5181
+ (resolve) => setTimeout(resolve, sleepTimeS * 1e3)
5182
+ );
5332
5183
  continue;
5333
5184
  }
5334
5185
  throw e;
@@ -5730,6 +5581,19 @@ var JSONAttachment = class extends Attachment {
5730
5581
  */
5731
5582
  constructor(data, options) {
5732
5583
  const { filename = "data.json", pretty = false, state } = options ?? {};
5584
+ const deferredJsonAttachment = globalThis.__BT_DATASET_PIPELINE_DEFER_JSON_ATTACHMENT__;
5585
+ if (deferredJsonAttachment) {
5586
+ super({
5587
+ data: new Blob([]),
5588
+ filename,
5589
+ contentType: "application/json",
5590
+ state
5591
+ });
5592
+ return deferredJsonAttachment(data, {
5593
+ filename,
5594
+ pretty
5595
+ });
5596
+ }
5733
5597
  const jsonString = pretty ? JSON.stringify(data, null, 2) : JSON.stringify(data);
5734
5598
  const blob = new Blob([jsonString], { type: "application/json" });
5735
5599
  super({
@@ -5978,20 +5842,7 @@ function startSpanParentArgs(args) {
5978
5842
  `Mismatch between expected span parent object type ${args.parentObjectType} and provided type ${parentComponents.data.object_type}`
5979
5843
  );
5980
5844
  }
5981
- const parentComponentsObjectIdLambda = spanComponentsToObjectIdLambda(
5982
- args.state,
5983
- parentComponents
5984
- );
5985
- const computeParentObjectId = async () => {
5986
- const parentComponentsObjectId = await parentComponentsObjectIdLambda();
5987
- if (await args.parentObjectId.get() !== parentComponentsObjectId) {
5988
- throw new Error(
5989
- `Mismatch between expected span parent object id ${await args.parentObjectId.get()} and provided id ${parentComponentsObjectId}`
5990
- );
5991
- }
5992
- return await args.parentObjectId.get();
5993
- };
5994
- argParentObjectId = new LazyValue(computeParentObjectId);
5845
+ argParentObjectId = args.parentObjectId;
5995
5846
  if (parentComponents.data.row_id) {
5996
5847
  argParentSpanIds = {
5997
5848
  spanId: parentComponents.data.span_id,
@@ -6377,6 +6228,7 @@ var TestBackgroundLogger = class {
6377
6228
  }
6378
6229
  };
6379
6230
  var BACKGROUND_LOGGER_BASE_SLEEP_TIME_S = 1;
6231
+ var HTTP_RETRY_BASE_SLEEP_TIME_S = 1;
6380
6232
  var HTTPBackgroundLogger = class _HTTPBackgroundLogger {
6381
6233
  apiConn;
6382
6234
  queue;
@@ -7007,17 +6859,10 @@ function init(projectOrOptions, optionalOptions) {
7007
6859
  if (repoInfo2) {
7008
6860
  return repoInfo2;
7009
6861
  }
7010
- let mergedGitMetadataSettings = {
7011
- ...state.gitMetadataSettings || {
7012
- collect: "all"
7013
- }
7014
- };
7015
- if (gitMetadataSettings) {
7016
- mergedGitMetadataSettings = mergeGitMetadataSettings(
7017
- mergedGitMetadataSettings,
7018
- gitMetadataSettings
7019
- );
7020
- }
6862
+ const mergedGitMetadataSettings = state.gitMetadataSettings == null ? gitMetadataSettings ?? { collect: "none" } : mergeGitMetadataSettings(
6863
+ state.gitMetadataSettings,
6864
+ gitMetadataSettings ?? { collect: "all" }
6865
+ );
7021
6866
  return await isomorph_default.getRepoInfo(mergedGitMetadataSettings);
7022
6867
  })();
7023
6868
  if (repoInfoArg) {
@@ -7741,10 +7586,11 @@ async function login(options = {}) {
7741
7586
  async function loginToState(options = {}) {
7742
7587
  const {
7743
7588
  appUrl = isomorph_default.getEnv("BRAINTRUST_APP_URL") || "https://www.braintrust.dev",
7744
- apiKey = isomorph_default.getEnv("BRAINTRUST_API_KEY"),
7589
+ apiKey: apiKeyArg,
7745
7590
  orgName = isomorph_default.getEnv("BRAINTRUST_ORG_NAME"),
7746
7591
  fetch: fetch2 = globalThis.fetch
7747
7592
  } = options || {};
7593
+ const apiKey = apiKeyArg !== void 0 ? apiKeyArg : await isomorph_default.getBraintrustApiKey();
7748
7594
  const appPublicUrl = isomorph_default.getEnv("BRAINTRUST_APP_PUBLIC_URL") || appUrl;
7749
7595
  const state = new BraintrustState(options);
7750
7596
  state.resetLoginInfo();
@@ -8985,9 +8831,15 @@ var SpanImpl = class _SpanImpl {
8985
8831
  const cachedSpan = {
8986
8832
  input: partialRecord.input,
8987
8833
  output: partialRecord.output,
8834
+ expected: partialRecord.expected,
8835
+ error: partialRecord.error,
8836
+ scores: partialRecord.scores,
8837
+ metrics: partialRecord.metrics,
8988
8838
  metadata: partialRecord.metadata,
8839
+ tags: partialRecord.tags,
8989
8840
  span_id: this._spanId,
8990
8841
  span_parents: this._spanParents,
8842
+ is_root: this._spanId === this._rootSpanId,
8991
8843
  span_attributes: partialRecord.span_attributes
8992
8844
  };
8993
8845
  this._state.spanCache.queueWrite(
@@ -9323,6 +9175,7 @@ var Dataset2 = class extends ObjectFetcher {
9323
9175
  metadata,
9324
9176
  tags,
9325
9177
  output,
9178
+ origin,
9326
9179
  isMerge
9327
9180
  }) {
9328
9181
  return new LazyValue(async () => {
@@ -9337,6 +9190,7 @@ var Dataset2 = class extends ObjectFetcher {
9337
9190
  created: !isMerge ? (/* @__PURE__ */ new Date()).toISOString() : void 0,
9338
9191
  //if we're merging/updating an event we will not add this ts
9339
9192
  metadata,
9193
+ origin,
9340
9194
  ...!!isMerge ? {
9341
9195
  [IS_MERGE_FIELD]: true
9342
9196
  } : {}
@@ -9356,6 +9210,7 @@ var Dataset2 = class extends ObjectFetcher {
9356
9210
  * about anything else that's relevant, that you can use to help find and analyze examples later. For example, you could log the
9357
9211
  * `prompt`, example's `id`, or anything else that would be useful to slice/dice later. The values in `metadata` can be any
9358
9212
  * JSON-serializable type, but its keys must be strings.
9213
+ * @param event.origin (Optional) a reference to the source object this dataset record was derived from.
9359
9214
  * @param event.id (Optional) a unique identifier for the event. If you don't provide one, Braintrust will generate one for you.
9360
9215
  * @param event.output: (Deprecated) The output of your application. Use `expected` instead.
9361
9216
  * @returns The `id` of the logged record.
@@ -9366,7 +9221,8 @@ var Dataset2 = class extends ObjectFetcher {
9366
9221
  metadata,
9367
9222
  tags,
9368
9223
  id,
9369
- output
9224
+ output,
9225
+ origin
9370
9226
  }) {
9371
9227
  this.validateEvent({ metadata, expected, output, tags });
9372
9228
  const rowId = id || uuidv42();
@@ -9378,6 +9234,7 @@ var Dataset2 = class extends ObjectFetcher {
9378
9234
  metadata,
9379
9235
  tags,
9380
9236
  output,
9237
+ origin,
9381
9238
  isMerge: false
9382
9239
  })
9383
9240
  );
@@ -10408,15 +10265,15 @@ var BasePlugin = class {
10408
10265
  * @param handlers - Event handlers
10409
10266
  */
10410
10267
  subscribe(channelName, handlers) {
10411
- const channel2 = isomorph_default.newTracingChannel(channelName);
10412
- channel2.subscribe(handlers);
10268
+ const channel = isomorph_default.newTracingChannel(channelName);
10269
+ channel.subscribe(handlers);
10413
10270
  }
10414
10271
  /**
10415
10272
  * Subscribe to a channel for async methods (non-streaming).
10416
10273
  * Creates a span and logs input/output/metrics.
10417
10274
  */
10418
10275
  subscribeToChannel(channelName, config) {
10419
- const channel2 = isomorph_default.newTracingChannel(channelName);
10276
+ const channel = isomorph_default.newTracingChannel(channelName);
10420
10277
  const spans = /* @__PURE__ */ new WeakMap();
10421
10278
  const handlers = {
10422
10279
  start: (event) => {
@@ -10475,9 +10332,9 @@ var BasePlugin = class {
10475
10332
  spans.delete(event);
10476
10333
  }
10477
10334
  };
10478
- channel2.subscribe(handlers);
10335
+ channel.subscribe(handlers);
10479
10336
  this.unsubscribers.push(() => {
10480
- channel2.unsubscribe(handlers);
10337
+ channel.unsubscribe(handlers);
10481
10338
  });
10482
10339
  }
10483
10340
  /**
@@ -10485,7 +10342,7 @@ var BasePlugin = class {
10485
10342
  * Handles both streaming and non-streaming responses.
10486
10343
  */
10487
10344
  subscribeToStreamingChannel(channelName, config) {
10488
- const channel2 = isomorph_default.newTracingChannel(channelName);
10345
+ const channel = isomorph_default.newTracingChannel(channelName);
10489
10346
  const spans = /* @__PURE__ */ new WeakMap();
10490
10347
  const handlers = {
10491
10348
  start: (event) => {
@@ -10602,9 +10459,9 @@ var BasePlugin = class {
10602
10459
  spans.delete(event);
10603
10460
  }
10604
10461
  };
10605
- channel2.subscribe(handlers);
10462
+ channel.subscribe(handlers);
10606
10463
  this.unsubscribers.push(() => {
10607
- channel2.unsubscribe(handlers);
10464
+ channel.unsubscribe(handlers);
10608
10465
  });
10609
10466
  }
10610
10467
  /**
@@ -10612,7 +10469,7 @@ var BasePlugin = class {
10612
10469
  * Used for methods like beta.chat.completions.stream() and responses.stream().
10613
10470
  */
10614
10471
  subscribeToSyncStreamChannel(channelName, config) {
10615
- const channel2 = isomorph_default.newTracingChannel(channelName);
10472
+ const channel = isomorph_default.newTracingChannel(channelName);
10616
10473
  const spans = /* @__PURE__ */ new WeakMap();
10617
10474
  const handlers = {
10618
10475
  start: (event) => {
@@ -10714,9 +10571,9 @@ var BasePlugin = class {
10714
10571
  spans.delete(event);
10715
10572
  }
10716
10573
  };
10717
- channel2.subscribe(handlers);
10574
+ channel.subscribe(handlers);
10718
10575
  this.unsubscribers.push(() => {
10719
- channel2.unsubscribe(handlers);
10576
+ channel.unsubscribe(handlers);
10720
10577
  });
10721
10578
  }
10722
10579
  };
@@ -10821,10 +10678,10 @@ function runStreamingCompletionHook(args) {
10821
10678
  console.error(`Error in onComplete hook for ${args.channelName}:`, error);
10822
10679
  }
10823
10680
  }
10824
- function traceAsyncChannel(channel2, config) {
10825
- const tracingChannel2 = channel2.tracingChannel();
10681
+ function traceAsyncChannel(channel, config) {
10682
+ const tracingChannel2 = channel.tracingChannel();
10826
10683
  const states = /* @__PURE__ */ new WeakMap();
10827
- const channelName = channel2.channelName;
10684
+ const channelName = channel.channelName;
10828
10685
  const unbindCurrentSpanStore = bindCurrentSpanStoreToStart(
10829
10686
  tracingChannel2,
10830
10687
  states,
@@ -10883,10 +10740,10 @@ function traceAsyncChannel(channel2, config) {
10883
10740
  tracingChannel2.unsubscribe(handlers);
10884
10741
  };
10885
10742
  }
10886
- function traceStreamingChannel(channel2, config) {
10887
- const tracingChannel2 = channel2.tracingChannel();
10743
+ function traceStreamingChannel(channel, config) {
10744
+ const tracingChannel2 = channel.tracingChannel();
10888
10745
  const states = /* @__PURE__ */ new WeakMap();
10889
- const channelName = channel2.channelName;
10746
+ const channelName = channel.channelName;
10890
10747
  const unbindCurrentSpanStore = bindCurrentSpanStoreToStart(
10891
10748
  tracingChannel2,
10892
10749
  states,
@@ -11042,10 +10899,10 @@ function traceStreamingChannel(channel2, config) {
11042
10899
  tracingChannel2.unsubscribe(handlers);
11043
10900
  };
11044
10901
  }
11045
- function traceSyncStreamChannel(channel2, config) {
11046
- const tracingChannel2 = channel2.tracingChannel();
10902
+ function traceSyncStreamChannel(channel, config) {
10903
+ const tracingChannel2 = channel.tracingChannel();
11047
10904
  const states = /* @__PURE__ */ new WeakMap();
11048
- const channelName = channel2.channelName;
10905
+ const channelName = channel.channelName;
11049
10906
  const unbindCurrentSpanStore = bindCurrentSpanStoreToStart(
11050
10907
  tracingChannel2,
11051
10908
  states,
@@ -11324,92 +11181,6 @@ function processInputAttachments(input) {
11324
11181
  return processNode(input);
11325
11182
  }
11326
11183
 
11327
- // src/instrumentation/core/channel-definitions.ts
11328
- function channel(spec) {
11329
- return spec;
11330
- }
11331
- function defineChannels(pkg, channels) {
11332
- return Object.fromEntries(
11333
- Object.entries(channels).map(([key, spec]) => {
11334
- const fullChannelName = `orchestrion:${pkg}:${spec.channelName}`;
11335
- if (spec.kind === "async") {
11336
- const asyncSpec = spec;
11337
- const tracingChannel3 = () => isomorph_default.newTracingChannel(
11338
- fullChannelName
11339
- );
11340
- return [
11341
- key,
11342
- {
11343
- ...asyncSpec,
11344
- tracingChannel: tracingChannel3,
11345
- tracePromise: (fn, context) => tracingChannel3().tracePromise(
11346
- fn,
11347
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
11348
- context
11349
- )
11350
- }
11351
- ];
11352
- }
11353
- const syncSpec = spec;
11354
- const tracingChannel2 = () => isomorph_default.newTracingChannel(
11355
- fullChannelName
11356
- );
11357
- return [
11358
- key,
11359
- {
11360
- ...syncSpec,
11361
- tracingChannel: tracingChannel2,
11362
- traceSync: (fn, context) => tracingChannel2().traceSync(
11363
- fn,
11364
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
11365
- context
11366
- )
11367
- }
11368
- ];
11369
- })
11370
- );
11371
- }
11372
-
11373
- // src/instrumentation/plugins/openai-channels.ts
11374
- var openAIChannels = defineChannels("openai", {
11375
- chatCompletionsCreate: channel({
11376
- channelName: "chat.completions.create",
11377
- kind: "async"
11378
- }),
11379
- embeddingsCreate: channel({
11380
- channelName: "embeddings.create",
11381
- kind: "async"
11382
- }),
11383
- betaChatCompletionsParse: channel({
11384
- channelName: "beta.chat.completions.parse",
11385
- kind: "async"
11386
- }),
11387
- betaChatCompletionsStream: channel({
11388
- channelName: "beta.chat.completions.stream",
11389
- kind: "sync-stream"
11390
- }),
11391
- moderationsCreate: channel({
11392
- channelName: "moderations.create",
11393
- kind: "async"
11394
- }),
11395
- responsesCreate: channel({
11396
- channelName: "responses.create",
11397
- kind: "async"
11398
- }),
11399
- responsesStream: channel({
11400
- channelName: "responses.stream",
11401
- kind: "sync-stream"
11402
- }),
11403
- responsesParse: channel({
11404
- channelName: "responses.parse",
11405
- kind: "async"
11406
- }),
11407
- responsesCompact: channel({
11408
- channelName: "responses.compact",
11409
- kind: "async"
11410
- })
11411
- });
11412
-
11413
11184
  // src/openai-utils.ts
11414
11185
  var BRAINTRUST_CACHED_STREAM_METRIC = "__braintrust_cached_metric";
11415
11186
  var LEGACY_CACHED_HEADER = "x-cached";
@@ -11922,18 +11693,6 @@ function aggregateResponseStreamEvents(chunks, _streamResult, endEvent) {
11922
11693
  };
11923
11694
  }
11924
11695
 
11925
- // src/instrumentation/plugins/openai-codex-channels.ts
11926
- var openAICodexChannels = defineChannels("@openai/codex-sdk", {
11927
- run: channel({
11928
- channelName: "Thread.run",
11929
- kind: "async"
11930
- }),
11931
- runStreamed: channel({
11932
- channelName: "Thread.runStreamed",
11933
- kind: "async"
11934
- })
11935
- });
11936
-
11937
11696
  // src/instrumentation/plugins/openai-codex-plugin.ts
11938
11697
  var PATCHED_STREAMED_TURN = /* @__PURE__ */ Symbol.for(
11939
11698
  "braintrust.openai-codex.patched-streamed-turn"
@@ -11950,7 +11709,7 @@ var OpenAICodexPlugin = class extends BasePlugin {
11950
11709
  this.unsubscribers = [];
11951
11710
  }
11952
11711
  subscribeToRun() {
11953
- const channel2 = openAICodexChannels.run.tracingChannel();
11712
+ const channel = openAICodexChannels.run.tracingChannel();
11954
11713
  const states = /* @__PURE__ */ new WeakMap();
11955
11714
  const handlers = {
11956
11715
  start: (event) => {
@@ -11973,13 +11732,13 @@ var OpenAICodexPlugin = class extends BasePlugin {
11973
11732
  await finalizeCodexRun(state, { error: event.error });
11974
11733
  }
11975
11734
  };
11976
- channel2.subscribe(handlers);
11735
+ channel.subscribe(handlers);
11977
11736
  this.unsubscribers.push(() => {
11978
- channel2.unsubscribe(handlers);
11737
+ channel.unsubscribe(handlers);
11979
11738
  });
11980
11739
  }
11981
11740
  subscribeToRunStreamed() {
11982
- const channel2 = openAICodexChannels.runStreamed.tracingChannel();
11741
+ const channel = openAICodexChannels.runStreamed.tracingChannel();
11983
11742
  const states = /* @__PURE__ */ new WeakMap();
11984
11743
  const handlers = {
11985
11744
  start: (event) => {
@@ -12002,9 +11761,9 @@ var OpenAICodexPlugin = class extends BasePlugin {
12002
11761
  await finalizeCodexRun(state, { error: event.error });
12003
11762
  }
12004
11763
  };
12005
- channel2.subscribe(handlers);
11764
+ channel.subscribe(handlers);
12006
11765
  this.unsubscribers.push(() => {
12007
- channel2.unsubscribe(handlers);
11766
+ channel.unsubscribe(handlers);
12008
11767
  });
12009
11768
  }
12010
11769
  };
@@ -12577,22 +12336,6 @@ function extractAnthropicCacheTokens(cacheReadTokens = 0, cacheCreationTokens =
12577
12336
  return cacheTokens;
12578
12337
  }
12579
12338
 
12580
- // src/instrumentation/plugins/anthropic-channels.ts
12581
- var anthropicChannels = defineChannels("@anthropic-ai/sdk", {
12582
- messagesCreate: channel({
12583
- channelName: "messages.create",
12584
- kind: "async"
12585
- }),
12586
- betaMessagesCreate: channel({
12587
- channelName: "beta.messages.create",
12588
- kind: "async"
12589
- }),
12590
- betaMessagesToolRunner: channel({
12591
- channelName: "beta.messages.toolRunner",
12592
- kind: "sync-stream"
12593
- })
12594
- });
12595
-
12596
12339
  // src/instrumentation/plugins/anthropic-plugin.ts
12597
12340
  var ANTHROPIC_TOOL_RUNNER_TOOL_WRAPPED = /* @__PURE__ */ Symbol.for(
12598
12341
  "braintrust.anthropic_tool_runner_tool_wrapped"
@@ -13389,68 +13132,6 @@ function serializeAISDKToolsForLogging(tools) {
13389
13132
  return serialized;
13390
13133
  }
13391
13134
 
13392
- // src/instrumentation/plugins/ai-sdk-channels.ts
13393
- var aiSDKChannels = defineChannels("ai", {
13394
- generateText: channel({
13395
- channelName: "generateText",
13396
- kind: "async"
13397
- }),
13398
- streamText: channel({
13399
- channelName: "streamText",
13400
- kind: "async"
13401
- }),
13402
- streamTextSync: channel({
13403
- channelName: "streamText.sync",
13404
- kind: "sync-stream"
13405
- }),
13406
- generateObject: channel({
13407
- channelName: "generateObject",
13408
- kind: "async"
13409
- }),
13410
- streamObject: channel({
13411
- channelName: "streamObject",
13412
- kind: "async"
13413
- }),
13414
- streamObjectSync: channel({
13415
- channelName: "streamObject.sync",
13416
- kind: "sync-stream"
13417
- }),
13418
- embed: channel(
13419
- {
13420
- channelName: "embed",
13421
- kind: "async"
13422
- }
13423
- ),
13424
- embedMany: channel({
13425
- channelName: "embedMany",
13426
- kind: "async"
13427
- }),
13428
- rerank: channel({
13429
- channelName: "rerank",
13430
- kind: "async"
13431
- }),
13432
- agentGenerate: channel({
13433
- channelName: "Agent.generate",
13434
- kind: "async"
13435
- }),
13436
- agentStream: channel({
13437
- channelName: "Agent.stream",
13438
- kind: "async"
13439
- }),
13440
- agentStreamSync: channel({
13441
- channelName: "Agent.stream.sync",
13442
- kind: "sync-stream"
13443
- }),
13444
- toolLoopAgentGenerate: channel({
13445
- channelName: "ToolLoopAgent.generate",
13446
- kind: "async"
13447
- }),
13448
- toolLoopAgentStream: channel({
13449
- channelName: "ToolLoopAgent.stream",
13450
- kind: "async"
13451
- })
13452
- });
13453
-
13454
13135
  // src/instrumentation/plugins/ai-sdk-plugin.ts
13455
13136
  var DEFAULT_DENY_OUTPUT_PATHS = [
13456
13137
  // v3
@@ -13713,11 +13394,11 @@ function resolveDenyOutputPaths(event, defaultDenyOutputPaths) {
13713
13394
  if (Array.isArray(event?.denyOutputPaths)) {
13714
13395
  return event.denyOutputPaths;
13715
13396
  }
13716
- const firstArgument = event?.arguments && event.arguments.length > 0 ? event.arguments[0] : void 0;
13717
- if (!firstArgument || typeof firstArgument !== "object") {
13397
+ const firstArgument2 = event?.arguments && event.arguments.length > 0 ? event.arguments[0] : void 0;
13398
+ if (!firstArgument2 || typeof firstArgument2 !== "object") {
13718
13399
  return defaultDenyOutputPaths;
13719
13400
  }
13720
- const runtimeDenyOutputPaths = firstArgument[RUNTIME_DENY_OUTPUT_PATHS];
13401
+ const runtimeDenyOutputPaths = firstArgument2[RUNTIME_DENY_OUTPUT_PATHS];
13721
13402
  if (Array.isArray(runtimeDenyOutputPaths) && runtimeDenyOutputPaths.every((path2) => typeof path2 === "string")) {
13722
13403
  return runtimeDenyOutputPaths;
13723
13404
  }
@@ -15088,17 +14769,6 @@ function omit(obj, paths) {
15088
14769
  return result;
15089
14770
  }
15090
14771
 
15091
- // src/instrumentation/plugins/claude-agent-sdk-channels.ts
15092
- var claudeAgentSDKChannels = defineChannels(
15093
- "@anthropic-ai/claude-agent-sdk",
15094
- {
15095
- query: channel({
15096
- channelName: "query",
15097
- kind: "sync-stream"
15098
- })
15099
- }
15100
- );
15101
-
15102
14772
  // src/instrumentation/plugins/claude-agent-sdk-instrumentation-constants.ts
15103
14773
  var CLAUDE_AGENT_SDK_SKIP_LOCAL_TOOL_HOOKS_OPTION = "__braintrust_skip_local_tool_hooks";
15104
14774
 
@@ -16284,7 +15954,7 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
16284
15954
  this.unsubscribers = [];
16285
15955
  }
16286
15956
  subscribeToQuery() {
16287
- const channel2 = claudeAgentSDKChannels.query.tracingChannel();
15957
+ const channel = claudeAgentSDKChannels.query.tracingChannel();
16288
15958
  const spans = /* @__PURE__ */ new WeakMap();
16289
15959
  const handlers = {
16290
15960
  start: (event) => {
@@ -16491,33 +16161,13 @@ var ClaudeAgentSDKPlugin = class extends BasePlugin {
16491
16161
  spans.delete(event);
16492
16162
  }
16493
16163
  };
16494
- channel2.subscribe(handlers);
16164
+ channel.subscribe(handlers);
16495
16165
  this.unsubscribers.push(() => {
16496
- channel2.unsubscribe(handlers);
16166
+ channel.unsubscribe(handlers);
16497
16167
  });
16498
16168
  }
16499
16169
  };
16500
16170
 
16501
- // src/instrumentation/plugins/cursor-sdk-channels.ts
16502
- var cursorSDKChannels = defineChannels("@cursor/sdk", {
16503
- create: channel({
16504
- channelName: "Agent.create",
16505
- kind: "async"
16506
- }),
16507
- resume: channel({
16508
- channelName: "Agent.resume",
16509
- kind: "async"
16510
- }),
16511
- prompt: channel({
16512
- channelName: "Agent.prompt",
16513
- kind: "async"
16514
- }),
16515
- send: channel({
16516
- channelName: "agent.send",
16517
- kind: "async"
16518
- })
16519
- });
16520
-
16521
16171
  // src/instrumentation/plugins/cursor-sdk-plugin.ts
16522
16172
  var PATCHED_AGENT = /* @__PURE__ */ Symbol.for("braintrust.cursor-sdk.auto-patched-agent");
16523
16173
  var PATCHED_RUN = /* @__PURE__ */ Symbol.for("braintrust.cursor-sdk.patched-run");
@@ -16540,8 +16190,8 @@ var CursorSDKPlugin = class extends BasePlugin {
16540
16190
  this.subscribeToAgentFactory(cursorSDKChannels.create);
16541
16191
  this.subscribeToAgentFactory(cursorSDKChannels.resume);
16542
16192
  }
16543
- subscribeToAgentFactory(channel2) {
16544
- const tracingChannel2 = channel2.tracingChannel();
16193
+ subscribeToAgentFactory(channel) {
16194
+ const tracingChannel2 = channel.tracingChannel();
16545
16195
  const handlers = {
16546
16196
  asyncEnd: (event) => {
16547
16197
  patchCursorAgentInPlace(event.result);
@@ -16555,7 +16205,7 @@ var CursorSDKPlugin = class extends BasePlugin {
16555
16205
  });
16556
16206
  }
16557
16207
  subscribeToPrompt() {
16558
- const channel2 = cursorSDKChannels.prompt.tracingChannel();
16208
+ const channel = cursorSDKChannels.prompt.tracingChannel();
16559
16209
  const states = /* @__PURE__ */ new WeakMap();
16560
16210
  const handlers = {
16561
16211
  start: (event) => {
@@ -16610,13 +16260,13 @@ var CursorSDKPlugin = class extends BasePlugin {
16610
16260
  states.delete(event);
16611
16261
  }
16612
16262
  };
16613
- channel2.subscribe(handlers);
16263
+ channel.subscribe(handlers);
16614
16264
  this.unsubscribers.push(() => {
16615
- channel2.unsubscribe(handlers);
16265
+ channel.unsubscribe(handlers);
16616
16266
  });
16617
16267
  }
16618
16268
  subscribeToSend() {
16619
- const channel2 = cursorSDKChannels.send.tracingChannel();
16269
+ const channel = cursorSDKChannels.send.tracingChannel();
16620
16270
  const states = /* @__PURE__ */ new WeakMap();
16621
16271
  const handlers = {
16622
16272
  start: (event) => {
@@ -16690,9 +16340,9 @@ var CursorSDKPlugin = class extends BasePlugin {
16690
16340
  states.delete(event);
16691
16341
  }
16692
16342
  };
16693
- channel2.subscribe(handlers);
16343
+ channel.subscribe(handlers);
16694
16344
  this.unsubscribers.push(() => {
16695
- channel2.unsubscribe(handlers);
16345
+ channel.unsubscribe(handlers);
16696
16346
  });
16697
16347
  }
16698
16348
  };
@@ -17376,81 +17026,506 @@ function cleanMetrics2(metrics) {
17376
17026
  return cleaned;
17377
17027
  }
17378
17028
 
17379
- // src/instrumentation/plugins/google-genai-channels.ts
17380
- var googleGenAIChannels = defineChannels("@google/genai", {
17381
- generateContent: channel({
17382
- channelName: "models.generateContent",
17383
- kind: "async"
17384
- }),
17385
- generateContentStream: channel({
17386
- channelName: "models.generateContentStream",
17387
- kind: "async"
17388
- }),
17389
- embedContent: channel({
17390
- channelName: "models.embedContent",
17391
- kind: "async"
17392
- })
17393
- });
17394
-
17395
- // src/instrumentation/plugins/google-genai-plugin.ts
17396
- var GOOGLE_GENAI_INTERNAL_CONTEXT = {
17397
- caller_filename: "<node-internal>",
17398
- caller_functionname: "<node-internal>",
17399
- caller_lineno: 0
17400
- };
17401
- function createWrapperParityEvent(args) {
17402
- return {
17403
- context: GOOGLE_GENAI_INTERNAL_CONTEXT,
17404
- input: args.input,
17405
- metadata: args.metadata
17406
- };
17029
+ // src/instrumentation/plugins/openai-agents-trace-processor.ts
17030
+ function isSpanData(spanData, type) {
17031
+ return spanData.type === type;
17032
+ }
17033
+ function spanTypeFromAgents(span) {
17034
+ const spanType = span.spanData.type;
17035
+ if (spanType === "function" || spanType === "guardrail" || spanType === "mcp_tools") {
17036
+ return "tool" /* TOOL */;
17037
+ }
17038
+ if (spanType === "generation" || spanType === "response" || spanType === "transcription" || spanType === "speech") {
17039
+ return "llm" /* LLM */;
17040
+ }
17041
+ return "task" /* TASK */;
17042
+ }
17043
+ function spanNameFromAgents(span) {
17044
+ const spanData = span.spanData;
17045
+ if ("name" in spanData && spanData.name) {
17046
+ return spanData.name;
17047
+ }
17048
+ switch (spanData.type) {
17049
+ case "generation":
17050
+ return "Generation";
17051
+ case "response":
17052
+ return "Response";
17053
+ case "handoff":
17054
+ return "Handoff";
17055
+ case "mcp_tools":
17056
+ return isSpanData(spanData, "mcp_tools") && spanData.server ? `List Tools (${spanData.server})` : "MCP List Tools";
17057
+ case "transcription":
17058
+ return "Transcription";
17059
+ case "speech":
17060
+ return "Speech";
17061
+ case "speech_group":
17062
+ return "Speech Group";
17063
+ default:
17064
+ return "Unknown";
17065
+ }
17407
17066
  }
17408
- var GoogleGenAIPlugin = class extends BasePlugin {
17409
- onEnable() {
17410
- this.subscribeToGoogleGenAIChannels();
17067
+ function getTimeElapsed(end, start) {
17068
+ if (!start || !end) {
17069
+ return void 0;
17411
17070
  }
17412
- onDisable() {
17413
- this.unsubscribers = unsubscribeAll(this.unsubscribers);
17071
+ const startTime = new Date(start).getTime();
17072
+ const endTime = new Date(end).getTime();
17073
+ if (Number.isNaN(startTime) || Number.isNaN(endTime)) {
17074
+ return void 0;
17414
17075
  }
17415
- subscribeToGoogleGenAIChannels() {
17416
- this.subscribeToGenerateContentChannel();
17417
- this.subscribeToGenerateContentStreamChannel();
17418
- this.subscribeToEmbedContentChannel();
17076
+ return (endTime - startTime) / 1e3;
17077
+ }
17078
+ function getNumberProperty2(obj, key) {
17079
+ if (!isObject(obj) || !(key in obj)) {
17080
+ return void 0;
17419
17081
  }
17420
- subscribeToGenerateContentChannel() {
17421
- const tracingChannel2 = googleGenAIChannels.generateContent.tracingChannel();
17422
- const states = /* @__PURE__ */ new WeakMap();
17423
- const unbindCurrentSpanStore = bindCurrentSpanStoreToStart2(
17424
- tracingChannel2,
17425
- states,
17426
- (event) => {
17427
- const params = event.arguments[0];
17428
- const input = serializeGenerateContentInput(params);
17429
- const metadata = extractGenerateContentMetadata(params);
17430
- const span = startSpan({
17431
- name: "generate_content",
17432
- spanAttributes: {
17433
- type: "llm" /* LLM */
17434
- },
17435
- event: createWrapperParityEvent({ input, metadata })
17436
- });
17437
- return {
17438
- span,
17439
- startTime: getCurrentUnixTimestamp()
17440
- };
17082
+ const value = obj[key];
17083
+ return typeof value === "number" ? value : void 0;
17084
+ }
17085
+ function parseUsageMetrics(usage) {
17086
+ const metrics = {};
17087
+ if (!isObject(usage)) {
17088
+ return metrics;
17089
+ }
17090
+ const promptTokens = getNumberProperty2(usage, "prompt_tokens") ?? getNumberProperty2(usage, "input_tokens") ?? getNumberProperty2(usage, "promptTokens") ?? getNumberProperty2(usage, "inputTokens");
17091
+ const completionTokens = getNumberProperty2(usage, "completion_tokens") ?? getNumberProperty2(usage, "output_tokens") ?? getNumberProperty2(usage, "completionTokens") ?? getNumberProperty2(usage, "outputTokens");
17092
+ const totalTokens = getNumberProperty2(usage, "total_tokens") ?? getNumberProperty2(usage, "totalTokens");
17093
+ if (promptTokens !== void 0) {
17094
+ metrics.prompt_tokens = promptTokens;
17095
+ }
17096
+ if (completionTokens !== void 0) {
17097
+ metrics.completion_tokens = completionTokens;
17098
+ }
17099
+ if (totalTokens !== void 0) {
17100
+ metrics.tokens = totalTokens;
17101
+ } else if (promptTokens !== void 0 && completionTokens !== void 0) {
17102
+ metrics.tokens = promptTokens + completionTokens;
17103
+ }
17104
+ const inputDetails = usage.input_tokens_details;
17105
+ const cachedTokens = getNumberProperty2(inputDetails, "cached_tokens");
17106
+ const cacheWriteTokens = getNumberProperty2(
17107
+ inputDetails,
17108
+ "cache_write_tokens"
17109
+ );
17110
+ if (cachedTokens !== void 0) {
17111
+ metrics.prompt_cached_tokens = cachedTokens;
17112
+ }
17113
+ if (cacheWriteTokens !== void 0) {
17114
+ metrics.prompt_cache_creation_tokens = cacheWriteTokens;
17115
+ }
17116
+ return metrics;
17117
+ }
17118
+ var OpenAIAgentsTraceProcessor = class _OpenAIAgentsTraceProcessor {
17119
+ static DEFAULT_MAX_TRACES = 1e4;
17120
+ logger;
17121
+ maxTraces;
17122
+ traceSpans = /* @__PURE__ */ new Map();
17123
+ traceOrder = [];
17124
+ _traceSpans = this.traceSpans;
17125
+ constructor(options = {}) {
17126
+ this.logger = options.logger;
17127
+ this.maxTraces = options.maxTraces ?? _OpenAIAgentsTraceProcessor.DEFAULT_MAX_TRACES;
17128
+ }
17129
+ evictOldestTrace() {
17130
+ const oldestTraceId = this.traceOrder.shift();
17131
+ if (oldestTraceId) {
17132
+ this.traceSpans.delete(oldestTraceId);
17133
+ }
17134
+ }
17135
+ onTraceStart(trace) {
17136
+ if (!trace?.traceId) {
17137
+ return Promise.resolve();
17138
+ }
17139
+ if (this.traceOrder.length >= this.maxTraces) {
17140
+ this.evictOldestTrace();
17141
+ }
17142
+ const current = currentSpan();
17143
+ const span = current && current !== NOOP_SPAN ? current.startSpan({
17144
+ name: trace.name,
17145
+ type: "task" /* TASK */
17146
+ }) : this.logger ? this.logger.startSpan({
17147
+ name: trace.name,
17148
+ type: "task" /* TASK */
17149
+ }) : startSpan({
17150
+ name: trace.name,
17151
+ type: "task" /* TASK */
17152
+ });
17153
+ span.log({
17154
+ input: "Agent workflow started",
17155
+ metadata: {
17156
+ group_id: trace.groupId,
17157
+ ...trace.metadata || {}
17441
17158
  }
17442
- );
17443
- const handlers = {
17444
- start: (event) => {
17445
- ensureSpanState(states, event, () => {
17446
- const params = event.arguments[0];
17447
- const input = serializeGenerateContentInput(params);
17448
- const metadata = extractGenerateContentMetadata(params);
17449
- const span = startSpan({
17450
- name: "generate_content",
17451
- spanAttributes: {
17452
- type: "llm" /* LLM */
17453
- },
17159
+ });
17160
+ this.traceSpans.set(trace.traceId, {
17161
+ rootSpan: span,
17162
+ childSpans: /* @__PURE__ */ new Map(),
17163
+ metadata: {
17164
+ firstInput: null,
17165
+ lastOutput: null
17166
+ }
17167
+ });
17168
+ this.traceOrder.push(trace.traceId);
17169
+ return Promise.resolve();
17170
+ }
17171
+ async onTraceEnd(trace) {
17172
+ const traceData = this.traceSpans.get(trace?.traceId);
17173
+ if (!traceData) {
17174
+ return;
17175
+ }
17176
+ try {
17177
+ traceData.rootSpan.log({
17178
+ input: traceData.metadata.firstInput,
17179
+ output: traceData.metadata.lastOutput
17180
+ });
17181
+ traceData.rootSpan.end();
17182
+ await traceData.rootSpan.flush();
17183
+ } finally {
17184
+ this.traceSpans.delete(trace.traceId);
17185
+ const orderIndex = this.traceOrder.indexOf(trace.traceId);
17186
+ if (orderIndex > -1) {
17187
+ this.traceOrder.splice(orderIndex, 1);
17188
+ }
17189
+ }
17190
+ }
17191
+ onSpanStart(span) {
17192
+ if (!span?.spanId || !span.traceId) {
17193
+ return Promise.resolve();
17194
+ }
17195
+ const traceData = this.traceSpans.get(span.traceId);
17196
+ if (!traceData) {
17197
+ return Promise.resolve();
17198
+ }
17199
+ const parentSpan = span.parentId ? traceData.childSpans.get(span.parentId) : traceData.rootSpan;
17200
+ if (!parentSpan) {
17201
+ return Promise.resolve();
17202
+ }
17203
+ const childSpan = parentSpan.startSpan({
17204
+ name: spanNameFromAgents(span),
17205
+ type: spanTypeFromAgents(span)
17206
+ });
17207
+ traceData.childSpans.set(span.spanId, childSpan);
17208
+ return Promise.resolve();
17209
+ }
17210
+ onSpanEnd(span) {
17211
+ if (!span?.spanId || !span.traceId) {
17212
+ return Promise.resolve();
17213
+ }
17214
+ const traceData = this.traceSpans.get(span.traceId);
17215
+ if (!traceData) {
17216
+ return Promise.resolve();
17217
+ }
17218
+ const braintrustSpan = traceData.childSpans.get(span.spanId);
17219
+ if (!braintrustSpan) {
17220
+ return Promise.resolve();
17221
+ }
17222
+ const logData = this.extractLogData(span);
17223
+ braintrustSpan.log({
17224
+ error: span.error,
17225
+ ...logData
17226
+ });
17227
+ braintrustSpan.end();
17228
+ traceData.childSpans.delete(span.spanId);
17229
+ const input = logData.input;
17230
+ const output = logData.output;
17231
+ if (traceData.metadata.firstInput === null && input != null) {
17232
+ traceData.metadata.firstInput = input;
17233
+ }
17234
+ if (output != null) {
17235
+ traceData.metadata.lastOutput = output;
17236
+ }
17237
+ return Promise.resolve();
17238
+ }
17239
+ async shutdown() {
17240
+ if (this.logger && typeof this.logger.flush === "function") {
17241
+ await this.logger.flush();
17242
+ }
17243
+ }
17244
+ async forceFlush() {
17245
+ if (this.logger && typeof this.logger.flush === "function") {
17246
+ await this.logger.flush();
17247
+ }
17248
+ }
17249
+ extractLogData(span) {
17250
+ const spanData = span.spanData;
17251
+ switch (spanData.type) {
17252
+ case "agent":
17253
+ return this.extractAgentLogData(spanData);
17254
+ case "response":
17255
+ return this.extractResponseLogData(spanData, span);
17256
+ case "function":
17257
+ return this.extractFunctionLogData(spanData);
17258
+ case "handoff":
17259
+ return this.extractHandoffLogData(spanData);
17260
+ case "guardrail":
17261
+ return this.extractGuardrailLogData(spanData);
17262
+ case "generation":
17263
+ return this.extractGenerationLogData(spanData, span);
17264
+ case "custom":
17265
+ return this.extractCustomLogData(spanData);
17266
+ case "mcp_tools":
17267
+ return this.extractMCPListToolsLogData(spanData);
17268
+ case "transcription":
17269
+ return this.extractTranscriptionLogData(spanData);
17270
+ case "speech":
17271
+ return this.extractSpeechLogData(spanData);
17272
+ case "speech_group":
17273
+ return this.extractSpeechGroupLogData(spanData);
17274
+ default:
17275
+ return {};
17276
+ }
17277
+ }
17278
+ extractAgentLogData(spanData) {
17279
+ return {
17280
+ metadata: {
17281
+ tools: spanData.tools,
17282
+ handoffs: spanData.handoffs,
17283
+ output_type: spanData.output_type
17284
+ }
17285
+ };
17286
+ }
17287
+ extractResponseLogData(spanData, span) {
17288
+ const response = spanData._response;
17289
+ const output = isObject(response) ? response.output : void 0;
17290
+ const usage = isObject(response) ? response.usage : void 0;
17291
+ const metrics = {
17292
+ ...this.extractTimingMetrics(span),
17293
+ ...parseUsageMetrics(usage)
17294
+ };
17295
+ return {
17296
+ input: spanData._input,
17297
+ output,
17298
+ metadata: isObject(response) ? this.omitKeys(response, ["output", "usage"]) : {},
17299
+ metrics
17300
+ };
17301
+ }
17302
+ extractFunctionLogData(spanData) {
17303
+ return {
17304
+ input: spanData.input,
17305
+ output: spanData.output
17306
+ };
17307
+ }
17308
+ extractHandoffLogData(spanData) {
17309
+ return {
17310
+ metadata: {
17311
+ from_agent: spanData.from_agent,
17312
+ to_agent: spanData.to_agent
17313
+ }
17314
+ };
17315
+ }
17316
+ extractGuardrailLogData(spanData) {
17317
+ return {
17318
+ metadata: {
17319
+ triggered: spanData.triggered
17320
+ }
17321
+ };
17322
+ }
17323
+ extractGenerationLogData(spanData, span) {
17324
+ return {
17325
+ input: spanData.input,
17326
+ output: spanData.output,
17327
+ metadata: {
17328
+ model: spanData.model,
17329
+ model_config: spanData.model_config
17330
+ },
17331
+ metrics: {
17332
+ ...this.extractTimingMetrics(span),
17333
+ ...parseUsageMetrics(spanData.usage)
17334
+ }
17335
+ };
17336
+ }
17337
+ extractCustomLogData(spanData) {
17338
+ return spanData.data || {};
17339
+ }
17340
+ extractMCPListToolsLogData(spanData) {
17341
+ return {
17342
+ output: spanData.result,
17343
+ metadata: {
17344
+ server: spanData.server
17345
+ }
17346
+ };
17347
+ }
17348
+ extractTranscriptionLogData(spanData) {
17349
+ return {
17350
+ input: spanData.input,
17351
+ output: spanData.output,
17352
+ metadata: {
17353
+ model: spanData.model,
17354
+ model_config: spanData.model_config
17355
+ }
17356
+ };
17357
+ }
17358
+ extractSpeechLogData(spanData) {
17359
+ return {
17360
+ input: spanData.input,
17361
+ output: spanData.output,
17362
+ metadata: {
17363
+ model: spanData.model,
17364
+ model_config: spanData.model_config
17365
+ }
17366
+ };
17367
+ }
17368
+ extractSpeechGroupLogData(spanData) {
17369
+ return {
17370
+ input: spanData.input
17371
+ };
17372
+ }
17373
+ extractTimingMetrics(span) {
17374
+ const timeToFirstToken = getTimeElapsed(
17375
+ span.endedAt ?? void 0,
17376
+ span.startedAt ?? void 0
17377
+ );
17378
+ return timeToFirstToken === void 0 ? {} : { time_to_first_token: timeToFirstToken };
17379
+ }
17380
+ omitKeys(value, keys) {
17381
+ const result = {};
17382
+ for (const [key, fieldValue] of Object.entries(value)) {
17383
+ if (!keys.includes(key)) {
17384
+ result[key] = fieldValue;
17385
+ }
17386
+ }
17387
+ return result;
17388
+ }
17389
+ };
17390
+
17391
+ // src/instrumentation/plugins/openai-agents-plugin.ts
17392
+ function firstArgument(args) {
17393
+ if (Array.isArray(args)) {
17394
+ return args[0];
17395
+ }
17396
+ if (isObject(args) && "length" in args && typeof args.length === "number" && Number.isInteger(args.length) && args.length >= 0) {
17397
+ return Array.from(args)[0];
17398
+ }
17399
+ return void 0;
17400
+ }
17401
+ function isOpenAIAgentsTrace(value) {
17402
+ return isObject(value) && value.type === "trace" && typeof value.traceId === "string";
17403
+ }
17404
+ function isOpenAIAgentsSpan(value) {
17405
+ return isObject(value) && value.type === "trace.span" && typeof value.traceId === "string" && typeof value.spanId === "string";
17406
+ }
17407
+ var OpenAIAgentsPlugin = class extends BasePlugin {
17408
+ processor = new OpenAIAgentsTraceProcessor();
17409
+ onEnable() {
17410
+ this.subscribeToTraceLifecycle();
17411
+ }
17412
+ onDisable() {
17413
+ this.unsubscribers = unsubscribeAll(this.unsubscribers);
17414
+ void this.processor.shutdown();
17415
+ }
17416
+ subscribeToTraceLifecycle() {
17417
+ const traceStartChannel = openAIAgentsCoreChannels.onTraceStart.tracingChannel();
17418
+ const traceStartHandlers = {
17419
+ start: (event) => {
17420
+ const trace = firstArgument(event.arguments);
17421
+ if (isOpenAIAgentsTrace(trace)) {
17422
+ void this.processor.onTraceStart(trace);
17423
+ }
17424
+ }
17425
+ };
17426
+ traceStartChannel.subscribe(traceStartHandlers);
17427
+ this.unsubscribers.push(
17428
+ () => traceStartChannel.unsubscribe(traceStartHandlers)
17429
+ );
17430
+ const traceEndChannel = openAIAgentsCoreChannels.onTraceEnd.tracingChannel();
17431
+ const traceEndHandlers = {
17432
+ start: (event) => {
17433
+ const trace = firstArgument(event.arguments);
17434
+ if (isOpenAIAgentsTrace(trace)) {
17435
+ void this.processor.onTraceEnd(trace);
17436
+ }
17437
+ }
17438
+ };
17439
+ traceEndChannel.subscribe(traceEndHandlers);
17440
+ this.unsubscribers.push(
17441
+ () => traceEndChannel.unsubscribe(traceEndHandlers)
17442
+ );
17443
+ const spanStartChannel = openAIAgentsCoreChannels.onSpanStart.tracingChannel();
17444
+ const spanStartHandlers = {
17445
+ start: (event) => {
17446
+ const span = firstArgument(event.arguments);
17447
+ if (isOpenAIAgentsSpan(span)) {
17448
+ void this.processor.onSpanStart(span);
17449
+ }
17450
+ }
17451
+ };
17452
+ spanStartChannel.subscribe(spanStartHandlers);
17453
+ this.unsubscribers.push(
17454
+ () => spanStartChannel.unsubscribe(spanStartHandlers)
17455
+ );
17456
+ const spanEndChannel = openAIAgentsCoreChannels.onSpanEnd.tracingChannel();
17457
+ const spanEndHandlers = {
17458
+ start: (event) => {
17459
+ const span = firstArgument(event.arguments);
17460
+ if (isOpenAIAgentsSpan(span)) {
17461
+ void this.processor.onSpanEnd(span);
17462
+ }
17463
+ }
17464
+ };
17465
+ spanEndChannel.subscribe(spanEndHandlers);
17466
+ this.unsubscribers.push(() => spanEndChannel.unsubscribe(spanEndHandlers));
17467
+ }
17468
+ };
17469
+
17470
+ // src/instrumentation/plugins/google-genai-plugin.ts
17471
+ var GOOGLE_GENAI_INTERNAL_CONTEXT = {
17472
+ caller_filename: "<node-internal>",
17473
+ caller_functionname: "<node-internal>",
17474
+ caller_lineno: 0
17475
+ };
17476
+ function createWrapperParityEvent(args) {
17477
+ return {
17478
+ context: GOOGLE_GENAI_INTERNAL_CONTEXT,
17479
+ input: args.input,
17480
+ metadata: args.metadata
17481
+ };
17482
+ }
17483
+ var GoogleGenAIPlugin = class extends BasePlugin {
17484
+ onEnable() {
17485
+ this.subscribeToGoogleGenAIChannels();
17486
+ }
17487
+ onDisable() {
17488
+ this.unsubscribers = unsubscribeAll(this.unsubscribers);
17489
+ }
17490
+ subscribeToGoogleGenAIChannels() {
17491
+ this.subscribeToGenerateContentChannel();
17492
+ this.subscribeToGenerateContentStreamChannel();
17493
+ this.subscribeToEmbedContentChannel();
17494
+ }
17495
+ subscribeToGenerateContentChannel() {
17496
+ const tracingChannel2 = googleGenAIChannels.generateContent.tracingChannel();
17497
+ const states = /* @__PURE__ */ new WeakMap();
17498
+ const unbindCurrentSpanStore = bindCurrentSpanStoreToStart2(
17499
+ tracingChannel2,
17500
+ states,
17501
+ (event) => {
17502
+ const params = event.arguments[0];
17503
+ const input = serializeGenerateContentInput(params);
17504
+ const metadata = extractGenerateContentMetadata(params);
17505
+ const span = startSpan({
17506
+ name: "generate_content",
17507
+ spanAttributes: {
17508
+ type: "llm" /* LLM */
17509
+ },
17510
+ event: createWrapperParityEvent({ input, metadata })
17511
+ });
17512
+ return {
17513
+ span,
17514
+ startTime: getCurrentUnixTimestamp()
17515
+ };
17516
+ }
17517
+ );
17518
+ const handlers = {
17519
+ start: (event) => {
17520
+ ensureSpanState(states, event, () => {
17521
+ const params = event.arguments[0];
17522
+ const input = serializeGenerateContentInput(params);
17523
+ const metadata = extractGenerateContentMetadata(params);
17524
+ const span = startSpan({
17525
+ name: "generate_content",
17526
+ spanAttributes: {
17527
+ type: "llm" /* LLM */
17528
+ },
17454
17529
  event: createWrapperParityEvent({ input, metadata })
17455
17530
  });
17456
17531
  return {
@@ -18139,30 +18214,6 @@ function tryToDict(obj) {
18139
18214
  return null;
18140
18215
  }
18141
18216
 
18142
- // src/instrumentation/plugins/huggingface-channels.ts
18143
- var huggingFaceChannels = defineChannels("@huggingface/inference", {
18144
- chatCompletion: channel({
18145
- channelName: "chatCompletion",
18146
- kind: "async"
18147
- }),
18148
- chatCompletionStream: channel({
18149
- channelName: "chatCompletionStream",
18150
- kind: "sync-stream"
18151
- }),
18152
- textGeneration: channel({
18153
- channelName: "textGeneration",
18154
- kind: "async"
18155
- }),
18156
- textGenerationStream: channel({
18157
- channelName: "textGenerationStream",
18158
- kind: "sync-stream"
18159
- }),
18160
- featureExtraction: channel({
18161
- channelName: "featureExtraction",
18162
- kind: "async"
18163
- })
18164
- });
18165
-
18166
18217
  // src/instrumentation/plugins/huggingface-plugin.ts
18167
18218
  var REQUEST_METADATA_ALLOWLIST = /* @__PURE__ */ new Set([
18168
18219
  "dimensions",
@@ -18587,22 +18638,6 @@ function extractTextGenerationStreamMetadata(chunks) {
18587
18638
  return void 0;
18588
18639
  }
18589
18640
 
18590
- // src/instrumentation/plugins/openrouter-agent-channels.ts
18591
- var openRouterAgentChannels = defineChannels("@openrouter/agent", {
18592
- callModel: channel({
18593
- channelName: "callModel",
18594
- kind: "sync-stream"
18595
- }),
18596
- callModelTurn: channel({
18597
- channelName: "callModel.turn",
18598
- kind: "async"
18599
- }),
18600
- toolExecute: channel({
18601
- channelName: "tool.execute",
18602
- kind: "async"
18603
- })
18604
- });
18605
-
18606
18641
  // src/instrumentation/plugins/openrouter-agent-plugin.ts
18607
18642
  var OpenRouterAgentPlugin = class extends BasePlugin {
18608
18643
  onEnable() {
@@ -19372,40 +19407,6 @@ function normalizeError(error) {
19372
19407
  return error instanceof Error ? error : new Error(String(error));
19373
19408
  }
19374
19409
 
19375
- // src/instrumentation/plugins/openrouter-channels.ts
19376
- var openRouterChannels = defineChannels("@openrouter/sdk", {
19377
- chatSend: channel({
19378
- channelName: "chat.send",
19379
- kind: "async"
19380
- }),
19381
- embeddingsGenerate: channel({
19382
- channelName: "embeddings.generate",
19383
- kind: "async"
19384
- }),
19385
- rerankRerank: channel(
19386
- {
19387
- channelName: "rerank.rerank",
19388
- kind: "async"
19389
- }
19390
- ),
19391
- betaResponsesSend: channel({
19392
- channelName: "beta.responses.send",
19393
- kind: "async"
19394
- }),
19395
- callModel: channel({
19396
- channelName: "callModel",
19397
- kind: "sync-stream"
19398
- }),
19399
- callModelTurn: channel({
19400
- channelName: "callModel.turn",
19401
- kind: "async"
19402
- }),
19403
- toolExecute: channel({
19404
- channelName: "tool.execute",
19405
- kind: "async"
19406
- })
19407
- });
19408
-
19409
19410
  // src/instrumentation/plugins/openrouter-plugin.ts
19410
19411
  var OpenRouterPlugin = class extends BasePlugin {
19411
19412
  onEnable() {
@@ -20445,54 +20446,6 @@ function normalizeError2(error) {
20445
20446
  return error instanceof Error ? error : new Error(String(error));
20446
20447
  }
20447
20448
 
20448
- // src/instrumentation/plugins/mistral-channels.ts
20449
- var mistralChannels = defineChannels("@mistralai/mistralai", {
20450
- chatComplete: channel({
20451
- channelName: "chat.complete",
20452
- kind: "async"
20453
- }),
20454
- chatStream: channel({
20455
- channelName: "chat.stream",
20456
- kind: "async"
20457
- }),
20458
- embeddingsCreate: channel({
20459
- channelName: "embeddings.create",
20460
- kind: "async"
20461
- }),
20462
- classifiersModerate: channel({
20463
- channelName: "classifiers.moderate",
20464
- kind: "async"
20465
- }),
20466
- classifiersModerateChat: channel({
20467
- channelName: "classifiers.moderateChat",
20468
- kind: "async"
20469
- }),
20470
- classifiersClassify: channel({
20471
- channelName: "classifiers.classify",
20472
- kind: "async"
20473
- }),
20474
- classifiersClassifyChat: channel({
20475
- channelName: "classifiers.classifyChat",
20476
- kind: "async"
20477
- }),
20478
- fimComplete: channel({
20479
- channelName: "fim.complete",
20480
- kind: "async"
20481
- }),
20482
- fimStream: channel({
20483
- channelName: "fim.stream",
20484
- kind: "async"
20485
- }),
20486
- agentsComplete: channel({
20487
- channelName: "agents.complete",
20488
- kind: "async"
20489
- }),
20490
- agentsStream: channel({
20491
- channelName: "agents.stream",
20492
- kind: "async"
20493
- })
20494
- });
20495
-
20496
20449
  // src/instrumentation/plugins/mistral-plugin.ts
20497
20450
  var MistralPlugin = class extends BasePlugin {
20498
20451
  onEnable() {
@@ -21110,22 +21063,6 @@ function aggregateMistralStreamChunks(chunks) {
21110
21063
  };
21111
21064
  }
21112
21065
 
21113
- // src/instrumentation/plugins/google-adk-channels.ts
21114
- var googleADKChannels = defineChannels("@google/adk", {
21115
- runnerRunAsync: channel({
21116
- channelName: "runner.runAsync",
21117
- kind: "sync-stream"
21118
- }),
21119
- agentRunAsync: channel({
21120
- channelName: "agent.runAsync",
21121
- kind: "sync-stream"
21122
- }),
21123
- toolRunAsync: channel({
21124
- channelName: "tool.runAsync",
21125
- kind: "async"
21126
- })
21127
- });
21128
-
21129
21066
  // src/instrumentation/plugins/google-adk-plugin.ts
21130
21067
  var GoogleADKPlugin = class extends BasePlugin {
21131
21068
  activeRunnerSpans = /* @__PURE__ */ new Map();
@@ -21757,26 +21694,6 @@ function cleanMetrics4(metrics) {
21757
21694
  return cleaned;
21758
21695
  }
21759
21696
 
21760
- // src/instrumentation/plugins/cohere-channels.ts
21761
- var cohereChannels = defineChannels("cohere-ai", {
21762
- chat: channel({
21763
- channelName: "chat",
21764
- kind: "async"
21765
- }),
21766
- chatStream: channel({
21767
- channelName: "chatStream",
21768
- kind: "async"
21769
- }),
21770
- embed: channel({
21771
- channelName: "embed",
21772
- kind: "async"
21773
- }),
21774
- rerank: channel({
21775
- channelName: "rerank",
21776
- kind: "async"
21777
- })
21778
- });
21779
-
21780
21697
  // src/instrumentation/plugins/cohere-plugin.ts
21781
21698
  var CoherePlugin = class extends BasePlugin {
21782
21699
  onEnable() {
@@ -22443,20 +22360,6 @@ function aggregateCohereChatStreamChunks(chunks) {
22443
22360
  };
22444
22361
  }
22445
22362
 
22446
- // src/instrumentation/plugins/groq-channels.ts
22447
- var groqChannels = defineChannels("groq-sdk", {
22448
- chatCompletionsCreate: channel({
22449
- channelName: "chat.completions.create",
22450
- kind: "async"
22451
- }),
22452
- embeddingsCreate: channel(
22453
- {
22454
- channelName: "embeddings.create",
22455
- kind: "async"
22456
- }
22457
- )
22458
- });
22459
-
22460
22363
  // src/instrumentation/plugins/groq-plugin.ts
22461
22364
  var GroqPlugin = class extends BasePlugin {
22462
22365
  onEnable() {
@@ -22553,40 +22456,6 @@ function aggregateGroqReasoning(chunks) {
22553
22456
  return reasoning.length > 0 ? reasoning : void 0;
22554
22457
  }
22555
22458
 
22556
- // src/instrumentation/plugins/genkit-channels.ts
22557
- var genkitChannels = defineChannels("@genkit-ai/ai", {
22558
- generate: channel({
22559
- channelName: "generate",
22560
- kind: "async"
22561
- }),
22562
- generateStream: channel({
22563
- channelName: "generateStream",
22564
- kind: "sync-stream"
22565
- }),
22566
- embed: channel({
22567
- channelName: "embed",
22568
- kind: "async"
22569
- }),
22570
- embedMany: channel({
22571
- channelName: "embedMany",
22572
- kind: "async"
22573
- }),
22574
- actionRun: channel({
22575
- channelName: "action.run",
22576
- kind: "async"
22577
- }),
22578
- actionStream: channel({
22579
- channelName: "action.stream",
22580
- kind: "sync-stream"
22581
- })
22582
- });
22583
- var genkitCoreChannels = defineChannels("@genkit-ai/core", {
22584
- actionSpan: channel({
22585
- channelName: "action.span",
22586
- kind: "async"
22587
- })
22588
- });
22589
-
22590
22459
  // src/instrumentation/plugins/genkit-plugin.ts
22591
22460
  var GenkitPlugin = class extends BasePlugin {
22592
22461
  onEnable() {
@@ -23138,22 +23007,6 @@ function stringValue(value) {
23138
23007
  return typeof value === "string" ? value : void 0;
23139
23008
  }
23140
23009
 
23141
- // src/instrumentation/plugins/github-copilot-channels.ts
23142
- var gitHubCopilotChannels = defineChannels("@github/copilot-sdk", {
23143
- createSession: channel({
23144
- channelName: "client.createSession",
23145
- kind: "async"
23146
- }),
23147
- resumeSession: channel({
23148
- channelName: "client.resumeSession",
23149
- kind: "async"
23150
- }),
23151
- sendAndWait: channel({
23152
- channelName: "session.sendAndWait",
23153
- kind: "async"
23154
- })
23155
- });
23156
-
23157
23010
  // src/instrumentation/plugins/github-copilot-plugin.ts
23158
23011
  var ROOT_AGENT_KEY = "__root__";
23159
23012
  function agentKey(agentId) {
@@ -23523,150 +23376,1835 @@ async function dispatchEvent(state, event) {
23523
23376
  d.error ?? "sub-agent failed"
23524
23377
  );
23525
23378
  }
23526
- break;
23379
+ break;
23380
+ }
23381
+ case "session.usage_info": {
23382
+ const d = event.data;
23383
+ if (d && typeof d.currentTokens === "number") {
23384
+ state.session.span.log({
23385
+ metadata: {
23386
+ "github_copilot.context_window.limit": d.tokenLimit,
23387
+ "github_copilot.context_window.current": d.currentTokens,
23388
+ "github_copilot.context_window.messages": d.messagesLength
23389
+ }
23390
+ });
23391
+ }
23392
+ break;
23393
+ }
23394
+ }
23395
+ }
23396
+ function injectTracingHooks2(config, state) {
23397
+ const existingHooks = config.hooks ?? {};
23398
+ const onSessionEnd = async (input, invocation) => {
23399
+ try {
23400
+ await existingHooks.onSessionEnd?.(input, invocation);
23401
+ } finally {
23402
+ handleSessionEnd(state, input.reason, input.error);
23403
+ state.unsubscribeEvents?.();
23404
+ }
23405
+ };
23406
+ config.hooks = {
23407
+ ...existingHooks,
23408
+ onSessionEnd
23409
+ };
23410
+ }
23411
+ function attachSessionEventListener(session, state) {
23412
+ const handler = (event) => {
23413
+ state.processing = state.processing.then(() => dispatchEvent(state, event)).catch((err) => {
23414
+ console.error(
23415
+ "[Braintrust] Error processing GitHub Copilot SDK event:",
23416
+ err
23417
+ );
23418
+ });
23419
+ };
23420
+ state.unsubscribeEvents = session.on(
23421
+ handler
23422
+ );
23423
+ }
23424
+ function isGitHubCopilotSession(value) {
23425
+ return value !== null && typeof value === "object" && typeof value.on === "function";
23426
+ }
23427
+ function makeSessionHandlers(sessionStates, configArgIndex, includeProviderMetadata) {
23428
+ return {
23429
+ start: (event) => {
23430
+ const config = event.arguments[configArgIndex];
23431
+ if (!config || typeof config !== "object") {
23432
+ return;
23433
+ }
23434
+ const sessionSpan = startSpan({
23435
+ name: "Copilot Session",
23436
+ spanAttributes: { type: "task" /* TASK */ }
23437
+ });
23438
+ const metadata = {};
23439
+ if (config.model) {
23440
+ metadata["github_copilot.model"] = config.model;
23441
+ }
23442
+ if (includeProviderMetadata && config.provider?.type) {
23443
+ metadata["github_copilot.provider_type"] = config.provider.type;
23444
+ }
23445
+ if (Object.keys(metadata).length > 0) {
23446
+ sessionSpan.log({ metadata });
23447
+ }
23448
+ const state = {
23449
+ session: makeSpanWithId(sessionSpan),
23450
+ activeTurns: /* @__PURE__ */ new Map(),
23451
+ pendingUserMessages: /* @__PURE__ */ new Map(),
23452
+ currentMessageContent: /* @__PURE__ */ new Map(),
23453
+ activeTools: /* @__PURE__ */ new Map(),
23454
+ subAgents: /* @__PURE__ */ new Map(),
23455
+ agentIdToToolCallId: /* @__PURE__ */ new Map(),
23456
+ processing: Promise.resolve(),
23457
+ totalInputTokens: 0,
23458
+ totalOutputTokens: 0
23459
+ };
23460
+ injectTracingHooks2(config, state);
23461
+ sessionStates.set(event, state);
23462
+ },
23463
+ asyncEnd: (event) => {
23464
+ const state = sessionStates.get(event);
23465
+ if (!state) {
23466
+ return;
23467
+ }
23468
+ const session = event.result;
23469
+ if (isGitHubCopilotSession(session)) {
23470
+ attachSessionEventListener(session, state);
23471
+ } else {
23472
+ state.session.span.end();
23473
+ }
23474
+ sessionStates.delete(event);
23475
+ },
23476
+ error: (event) => {
23477
+ const state = sessionStates.get(event);
23478
+ if (!state || !event.error) {
23479
+ return;
23480
+ }
23481
+ state.session.span.log({ error: event.error.message });
23482
+ state.session.span.end();
23483
+ sessionStates.delete(event);
23484
+ }
23485
+ };
23486
+ }
23487
+ var GitHubCopilotPlugin = class extends BasePlugin {
23488
+ onEnable() {
23489
+ this.subscribeToSessionChannels();
23490
+ }
23491
+ onDisable() {
23492
+ for (const unsubscribe of this.unsubscribers) {
23493
+ unsubscribe();
23494
+ }
23495
+ this.unsubscribers = [];
23496
+ }
23497
+ subscribeToSessionChannels() {
23498
+ const createChannel = gitHubCopilotChannels.createSession.tracingChannel();
23499
+ const resumeChannel = gitHubCopilotChannels.resumeSession.tracingChannel();
23500
+ const sessionStates = /* @__PURE__ */ new WeakMap();
23501
+ const createHandlers = makeSessionHandlers(
23502
+ sessionStates,
23503
+ 0,
23504
+ // config is arg 0 of createSession(config)
23505
+ true
23506
+ // include provider metadata
23507
+ );
23508
+ const resumeHandlers = makeSessionHandlers(
23509
+ sessionStates,
23510
+ 1,
23511
+ // config is arg 1 of resumeSession(sessionId, config)
23512
+ false
23513
+ // resumeSession config has no provider field
23514
+ );
23515
+ createChannel.subscribe(createHandlers);
23516
+ resumeChannel.subscribe(resumeHandlers);
23517
+ this.unsubscribers.push(
23518
+ () => createChannel.unsubscribe(createHandlers),
23519
+ () => resumeChannel.unsubscribe(resumeHandlers)
23520
+ );
23521
+ }
23522
+ };
23523
+
23524
+ // src/wrappers/flue.ts
23525
+ var WRAPPED_FLUE_CONTEXT = /* @__PURE__ */ Symbol.for("braintrust.flue.wrapped-context");
23526
+ var WRAPPED_FLUE_HARNESS = /* @__PURE__ */ Symbol.for("braintrust.flue.wrapped-harness");
23527
+ var WRAPPED_FLUE_SESSION = /* @__PURE__ */ Symbol.for("braintrust.flue.wrapped-session");
23528
+ var SUBSCRIBED_FLUE_CONTEXT_EVENTS = /* @__PURE__ */ Symbol.for(
23529
+ "braintrust.flue.subscribed-context-events"
23530
+ );
23531
+ function wrapFlueContext(ctx) {
23532
+ if (!isPlausibleFlueContext(ctx)) {
23533
+ console.warn("Unsupported Flue context. Not wrapping.");
23534
+ return ctx;
23535
+ }
23536
+ const context = ctx;
23537
+ subscribeFlueContextEvents(context, { captureTurnSpans: true });
23538
+ return patchFlueContextInPlace(context);
23539
+ }
23540
+ function patchFlueContextInPlace(ctx) {
23541
+ const context = ctx;
23542
+ if (context[WRAPPED_FLUE_CONTEXT]) {
23543
+ return ctx;
23544
+ }
23545
+ const originalInit = context.init.bind(context);
23546
+ try {
23547
+ Object.defineProperty(context, WRAPPED_FLUE_CONTEXT, {
23548
+ configurable: false,
23549
+ enumerable: false,
23550
+ value: true
23551
+ });
23552
+ Object.defineProperty(context, "init", {
23553
+ configurable: true,
23554
+ value: async function wrappedFlueInit(options) {
23555
+ const harness = await originalInit(options);
23556
+ return wrapFlueHarness(harness);
23557
+ },
23558
+ writable: true
23559
+ });
23560
+ } catch {
23561
+ }
23562
+ return ctx;
23563
+ }
23564
+ function wrapFlueSession(session) {
23565
+ if (!isPlausibleFlueSession(session)) {
23566
+ console.warn("Unsupported Flue session. Not wrapping.");
23567
+ return session;
23568
+ }
23569
+ return patchFlueSessionInPlace(session);
23570
+ }
23571
+ function subscribeFlueContextEvents(ctx, options = {}) {
23572
+ if (!ctx || typeof ctx !== "object" || typeof ctx.subscribeEvent !== "function") {
23573
+ return void 0;
23574
+ }
23575
+ const context = ctx;
23576
+ const captureTurnSpans = options.captureTurnSpans ?? true;
23577
+ const existingSubscription = context[SUBSCRIBED_FLUE_CONTEXT_EVENTS];
23578
+ if (existingSubscription) {
23579
+ if (existingSubscription.captureTurnSpans || !captureTurnSpans) {
23580
+ return void 0;
23581
+ }
23582
+ try {
23583
+ existingSubscription.unsubscribe();
23584
+ } catch {
23585
+ }
23586
+ }
23587
+ try {
23588
+ const unsubscribe = ctx.subscribeEvent((event) => {
23589
+ flueChannels.contextEvent.traceSync(() => void 0, {
23590
+ arguments: [event],
23591
+ captureTurnSpans,
23592
+ context: ctx
23593
+ });
23594
+ });
23595
+ if (existingSubscription) {
23596
+ existingSubscription.captureTurnSpans = captureTurnSpans;
23597
+ existingSubscription.unsubscribe = unsubscribe;
23598
+ } else {
23599
+ Object.defineProperty(context, SUBSCRIBED_FLUE_CONTEXT_EVENTS, {
23600
+ configurable: false,
23601
+ enumerable: false,
23602
+ value: {
23603
+ captureTurnSpans,
23604
+ unsubscribe
23605
+ }
23606
+ });
23607
+ }
23608
+ return unsubscribe;
23609
+ } catch {
23610
+ return void 0;
23611
+ }
23612
+ }
23613
+ function wrapFlueHarness(harness) {
23614
+ if (!isPlausibleFlueHarness(harness)) {
23615
+ return harness;
23616
+ }
23617
+ const target = harness;
23618
+ if (target[WRAPPED_FLUE_HARNESS]) {
23619
+ return harness;
23620
+ }
23621
+ const originalSession = target.session.bind(target);
23622
+ try {
23623
+ Object.defineProperty(target, WRAPPED_FLUE_HARNESS, {
23624
+ configurable: false,
23625
+ enumerable: false,
23626
+ value: true
23627
+ });
23628
+ Object.defineProperty(target, "session", {
23629
+ configurable: true,
23630
+ value: async function wrappedFlueHarnessSession(name, options) {
23631
+ const session = await originalSession(name, options);
23632
+ return patchFlueSessionInPlace(session);
23633
+ },
23634
+ writable: true
23635
+ });
23636
+ const sessions = target.sessions;
23637
+ if (sessions && typeof sessions === "object") {
23638
+ patchFlueSessionFactory(sessions, "get");
23639
+ patchFlueSessionFactory(sessions, "create");
23640
+ }
23641
+ } catch {
23642
+ }
23643
+ return harness;
23644
+ }
23645
+ function patchFlueSessionInPlace(session) {
23646
+ if (session[WRAPPED_FLUE_SESSION]) {
23647
+ return session;
23648
+ }
23649
+ try {
23650
+ Object.defineProperty(session, WRAPPED_FLUE_SESSION, {
23651
+ configurable: false,
23652
+ enumerable: false,
23653
+ value: true
23654
+ });
23655
+ patchCallHandleMethod(session, "prompt", flueChannels.prompt);
23656
+ patchCallHandleMethod(session, "skill", flueChannels.skill);
23657
+ patchCallHandleMethod(session, "task", flueChannels.task);
23658
+ patchCompact(session);
23659
+ } catch {
23660
+ }
23661
+ return session;
23662
+ }
23663
+ function patchFlueSessionFactory(sessions, method) {
23664
+ const original = sessions[method];
23665
+ if (typeof original !== "function") {
23666
+ return;
23667
+ }
23668
+ const bound = original.bind(sessions);
23669
+ Object.defineProperty(sessions, method, {
23670
+ configurable: true,
23671
+ value: async function wrappedFlueSessionFactory(name, options) {
23672
+ const session = await bound(name, options);
23673
+ return patchFlueSessionInPlace(session);
23674
+ },
23675
+ writable: true
23676
+ });
23677
+ }
23678
+ function patchCallHandleMethod(session, method, channel) {
23679
+ const original = session[method];
23680
+ if (typeof original !== "function") {
23681
+ return;
23682
+ }
23683
+ const bound = original.bind(session);
23684
+ Object.defineProperty(session, method, {
23685
+ configurable: true,
23686
+ value(input, options) {
23687
+ const args = [input, options];
23688
+ const { originalResult, traced: traced2 } = traceFlueOperation(channel, {
23689
+ context: {
23690
+ arguments: args,
23691
+ operation: method,
23692
+ session
23693
+ },
23694
+ run: () => bound(input, options)
23695
+ });
23696
+ return preserveCallHandle(originalResult, traced2);
23697
+ },
23698
+ writable: true
23699
+ });
23700
+ }
23701
+ function patchCompact(session) {
23702
+ const original = session.compact;
23703
+ if (typeof original !== "function") {
23704
+ return;
23705
+ }
23706
+ const bound = original.bind(session);
23707
+ Object.defineProperty(session, "compact", {
23708
+ configurable: true,
23709
+ value() {
23710
+ const context = {
23711
+ arguments: [],
23712
+ operation: "compact",
23713
+ session
23714
+ };
23715
+ return flueChannels.compact.tracePromise(() => bound(), context);
23716
+ },
23717
+ writable: true
23718
+ });
23719
+ }
23720
+ function traceFlueOperation(channel, args) {
23721
+ const tracingChannel2 = channel.tracingChannel();
23722
+ const context = args.context;
23723
+ let originalResult;
23724
+ let traced2;
23725
+ const run = () => {
23726
+ try {
23727
+ originalResult = args.run();
23728
+ tracingChannel2.end?.publish(context);
23729
+ } catch (error) {
23730
+ context.error = normalizeError3(error);
23731
+ tracingChannel2.error?.publish(context);
23732
+ tracingChannel2.end?.publish(context);
23733
+ throw error;
23734
+ }
23735
+ traced2 = Promise.resolve(originalResult).then(
23736
+ (result) => {
23737
+ context.result = result;
23738
+ tracingChannel2.asyncStart?.publish(context);
23739
+ tracingChannel2.asyncEnd?.publish(context);
23740
+ return result;
23741
+ },
23742
+ (error) => {
23743
+ context.error = normalizeError3(error);
23744
+ tracingChannel2.error?.publish(context);
23745
+ tracingChannel2.asyncStart?.publish(context);
23746
+ tracingChannel2.asyncEnd?.publish(context);
23747
+ throw error;
23748
+ }
23749
+ );
23750
+ };
23751
+ if (tracingChannel2.start?.runStores) {
23752
+ tracingChannel2.start.runStores(context, run);
23753
+ } else {
23754
+ tracingChannel2.start?.publish(context);
23755
+ run();
23756
+ }
23757
+ return { originalResult, traced: traced2 };
23758
+ }
23759
+ function normalizeError3(error) {
23760
+ return error instanceof Error ? error : new Error(String(error));
23761
+ }
23762
+ function preserveCallHandle(originalHandle, traced2) {
23763
+ if (!isFlueCallHandle(originalHandle)) {
23764
+ return traced2;
23765
+ }
23766
+ const handle = originalHandle;
23767
+ const wrapped = {
23768
+ get signal() {
23769
+ return handle.signal;
23770
+ },
23771
+ abort(reason) {
23772
+ return handle.abort(reason);
23773
+ },
23774
+ then(onfulfilled, onrejected) {
23775
+ return traced2.then(onfulfilled, onrejected);
23776
+ }
23777
+ };
23778
+ return wrapped;
23779
+ }
23780
+ function isPlausibleFlueContext(value) {
23781
+ return !!value && typeof value === "object" && typeof value.init === "function";
23782
+ }
23783
+ function isPlausibleFlueHarness(value) {
23784
+ return !!value && typeof value === "object" && typeof value.session === "function";
23785
+ }
23786
+ function isPlausibleFlueSession(value) {
23787
+ return !!value && typeof value === "object" && typeof value.prompt === "function" && typeof value.skill === "function" && typeof value.task === "function" && typeof value.compact === "function";
23788
+ }
23789
+ function isFlueCallHandle(value) {
23790
+ return !!value && typeof value === "object" && typeof value.then === "function" && typeof value.abort === "function" && "signal" in value;
23791
+ }
23792
+
23793
+ // src/instrumentation/plugins/flue-plugin.ts
23794
+ var FluePlugin = class extends BasePlugin {
23795
+ activeOperationsById = /* @__PURE__ */ new Map();
23796
+ activeOperationsByScope = /* @__PURE__ */ new Map();
23797
+ compactionsByScope = /* @__PURE__ */ new Map();
23798
+ pendingOperationsByKey = /* @__PURE__ */ new Map();
23799
+ tasksById = /* @__PURE__ */ new Map();
23800
+ toolsById = /* @__PURE__ */ new Map();
23801
+ turnsByScope = /* @__PURE__ */ new Map();
23802
+ onEnable() {
23803
+ this.subscribeToContextCreation();
23804
+ this.subscribeToSessionCreation();
23805
+ this.subscribeToContextEvents();
23806
+ this.subscribeToSessionOperations();
23807
+ }
23808
+ onDisable() {
23809
+ for (const unsubscribe of this.unsubscribers) {
23810
+ unsubscribe();
23811
+ }
23812
+ this.unsubscribers = [];
23813
+ this.activeOperationsById.clear();
23814
+ this.activeOperationsByScope.clear();
23815
+ this.compactionsByScope.clear();
23816
+ this.pendingOperationsByKey.clear();
23817
+ this.tasksById.clear();
23818
+ this.toolsById.clear();
23819
+ this.turnsByScope.clear();
23820
+ }
23821
+ subscribeToContextCreation() {
23822
+ const channel = flueChannels.createContext.tracingChannel();
23823
+ const handlers = {
23824
+ end: (event) => {
23825
+ const ctx = event.result;
23826
+ if (!ctx) {
23827
+ return;
23828
+ }
23829
+ subscribeFlueContextEvents(ctx, { captureTurnSpans: false });
23830
+ patchFlueContextInPlace(ctx);
23831
+ },
23832
+ error: () => {
23833
+ }
23834
+ };
23835
+ channel.subscribe(handlers);
23836
+ this.unsubscribers.push(() => {
23837
+ channel.unsubscribe(handlers);
23838
+ });
23839
+ }
23840
+ subscribeToSessionCreation() {
23841
+ const channel = flueChannels.openSession.tracingChannel();
23842
+ const handlers = {
23843
+ asyncEnd: (event) => {
23844
+ if (event.result) {
23845
+ patchFlueSessionInPlace(
23846
+ event.result
23847
+ );
23848
+ }
23849
+ if (event.harness) {
23850
+ wrapFlueHarness(event.harness);
23851
+ }
23852
+ },
23853
+ error: () => {
23854
+ }
23855
+ };
23856
+ channel.subscribe(handlers);
23857
+ this.unsubscribers.push(() => {
23858
+ channel.unsubscribe(handlers);
23859
+ });
23860
+ }
23861
+ subscribeToSessionOperations() {
23862
+ this.subscribeToSessionOperation(flueChannels.prompt);
23863
+ this.subscribeToSessionOperation(flueChannels.skill);
23864
+ this.subscribeToSessionOperation(flueChannels.task);
23865
+ this.subscribeToCompact();
23866
+ }
23867
+ subscribeToSessionOperation(channel) {
23868
+ const tracingChannel2 = channel.tracingChannel();
23869
+ const states = /* @__PURE__ */ new WeakMap();
23870
+ const ensureState2 = (event) => {
23871
+ const existing = states.get(event);
23872
+ if (existing) {
23873
+ return existing;
23874
+ }
23875
+ const state = this.startOperationState({
23876
+ args: event.arguments,
23877
+ moduleVersion: typeof event.moduleVersion === "string" ? event.moduleVersion : void 0,
23878
+ operation: event.operation,
23879
+ session: event.session
23880
+ });
23881
+ states.set(event, state);
23882
+ return state;
23883
+ };
23884
+ const unbindCurrentSpanStore = this.bindCurrentSpanStoreToOperationStart(
23885
+ tracingChannel2,
23886
+ ensureState2
23887
+ );
23888
+ const handlers = {
23889
+ start: (event) => {
23890
+ ensureState2(event);
23891
+ },
23892
+ asyncEnd: (event) => {
23893
+ this.endOperationState(states.get(event), event.result);
23894
+ states.delete(event);
23895
+ },
23896
+ error: (event) => {
23897
+ const state = states.get(event);
23898
+ if (state && event.error) {
23899
+ safeLog3(state.span, { error: errorToString(event.error) });
23900
+ this.finishOperationState(state);
23901
+ }
23902
+ states.delete(event);
23903
+ }
23904
+ };
23905
+ tracingChannel2.subscribe(handlers);
23906
+ this.unsubscribers.push(() => {
23907
+ unbindCurrentSpanStore?.();
23908
+ tracingChannel2.unsubscribe(handlers);
23909
+ });
23910
+ }
23911
+ subscribeToCompact() {
23912
+ const tracingChannel2 = flueChannels.compact.tracingChannel();
23913
+ const states = /* @__PURE__ */ new WeakMap();
23914
+ const ensureState2 = (event) => {
23915
+ const existing = states.get(event);
23916
+ if (existing) {
23917
+ return existing;
23918
+ }
23919
+ const state = this.startOperationState({
23920
+ args: [],
23921
+ moduleVersion: typeof event.moduleVersion === "string" ? event.moduleVersion : void 0,
23922
+ operation: event.operation,
23923
+ session: event.session
23924
+ });
23925
+ states.set(event, state);
23926
+ return state;
23927
+ };
23928
+ const unbindCurrentSpanStore = this.bindCurrentSpanStoreToOperationStart(
23929
+ tracingChannel2,
23930
+ ensureState2
23931
+ );
23932
+ const handlers = {
23933
+ start: (event) => {
23934
+ ensureState2(event);
23935
+ },
23936
+ asyncEnd: (event) => {
23937
+ this.endOperationState(states.get(event), void 0);
23938
+ states.delete(event);
23939
+ },
23940
+ error: (event) => {
23941
+ const state = states.get(event);
23942
+ if (state && event.error) {
23943
+ safeLog3(state.span, { error: errorToString(event.error) });
23944
+ this.finishOperationState(state);
23945
+ }
23946
+ states.delete(event);
23947
+ }
23948
+ };
23949
+ tracingChannel2.subscribe(handlers);
23950
+ this.unsubscribers.push(() => {
23951
+ unbindCurrentSpanStore?.();
23952
+ tracingChannel2.unsubscribe(handlers);
23953
+ });
23954
+ }
23955
+ subscribeToContextEvents() {
23956
+ const channel = flueChannels.contextEvent.tracingChannel();
23957
+ const handlers = {
23958
+ start: (event) => {
23959
+ const flueEvent = event.arguments[0];
23960
+ if (!flueEvent) {
23961
+ return;
23962
+ }
23963
+ try {
23964
+ this.handleFlueEvent(flueEvent, {
23965
+ captureTurnSpans: event.captureTurnSpans !== false
23966
+ });
23967
+ } catch (error) {
23968
+ logInstrumentationError3("Flue event", error);
23969
+ }
23970
+ },
23971
+ error: () => {
23972
+ }
23973
+ };
23974
+ channel.subscribe(handlers);
23975
+ this.unsubscribers.push(() => {
23976
+ channel.unsubscribe(handlers);
23977
+ });
23978
+ }
23979
+ bindCurrentSpanStoreToOperationStart(tracingChannel2, ensureState2) {
23980
+ const state = _internalGetGlobalState();
23981
+ const startChannel = tracingChannel2.start;
23982
+ const contextManager = state?.contextManager;
23983
+ const currentSpanStore = contextManager ? contextManager[BRAINTRUST_CURRENT_SPAN_STORE] : void 0;
23984
+ if (!currentSpanStore || !startChannel) {
23985
+ return void 0;
23986
+ }
23987
+ startChannel.bindStore(currentSpanStore, (event) => {
23988
+ const operationState = ensureState2(event);
23989
+ return contextManager.wrapSpanForStore(operationState.span);
23990
+ });
23991
+ return () => {
23992
+ startChannel.unbindStore(currentSpanStore);
23993
+ };
23994
+ }
23995
+ startOperationState(args) {
23996
+ const sessionName = getSessionName(args.session);
23997
+ const metadata = {
23998
+ ...extractOperationInputMetadata(args.operation, args.args),
23999
+ ...extractSessionMetadata(args.session),
24000
+ "flue.operation": args.operation,
24001
+ provider: "flue",
24002
+ ...args.moduleVersion ? { "flue.version": args.moduleVersion } : {}
24003
+ };
24004
+ const span = startSpan({
24005
+ name: `flue.session.${args.operation}`,
24006
+ spanAttributes: { type: "task" /* TASK */ }
24007
+ });
24008
+ const state = {
24009
+ metadata,
24010
+ operation: args.operation,
24011
+ sessionName,
24012
+ span,
24013
+ startTime: getCurrentUnixTimestamp()
24014
+ };
24015
+ safeLog3(span, {
24016
+ input: extractOperationInput(args.operation, args.args),
24017
+ metadata
24018
+ });
24019
+ this.pendingOperationQueue(operationKey(sessionName, args.operation)).push(
24020
+ state
24021
+ );
24022
+ addOperationToScope(
24023
+ this.activeOperationsByScope,
24024
+ sessionName ?? "unknown",
24025
+ state
24026
+ );
24027
+ return state;
24028
+ }
24029
+ endOperationState(state, result) {
24030
+ if (!state) {
24031
+ return;
24032
+ }
24033
+ const metadata = {
24034
+ ...state.metadata,
24035
+ ...extractPromptResponseMetadata(result)
24036
+ };
24037
+ const metrics = {
24038
+ ...buildDurationMetrics3(state.startTime),
24039
+ ...metricsFromUsage(result?.usage)
24040
+ };
24041
+ safeLog3(state.span, {
24042
+ metadata,
24043
+ metrics,
24044
+ output: extractOperationOutput(result)
24045
+ });
24046
+ this.finishCompactionsForOperation(state);
24047
+ this.finishOperationState(state);
24048
+ }
24049
+ finishOperationState(state) {
24050
+ removePendingOperation(this.pendingOperationsByKey, state);
24051
+ if (state.operationId) {
24052
+ this.activeOperationsById.delete(state.operationId);
24053
+ }
24054
+ removeScopedOperation(this.activeOperationsByScope, state);
24055
+ state.span.end();
24056
+ }
24057
+ handleFlueEvent(event, options) {
24058
+ switch (event.type) {
24059
+ case "operation_start":
24060
+ this.handleOperationStart(event);
24061
+ return;
24062
+ case "operation":
24063
+ this.handleOperation(event);
24064
+ return;
24065
+ case "text_delta":
24066
+ if (!options.captureTurnSpans) {
24067
+ return;
24068
+ }
24069
+ this.ensureTurnState(event).text.push(
24070
+ typeof event.text === "string" ? event.text : ""
24071
+ );
24072
+ return;
24073
+ case "thinking_start":
24074
+ if (!options.captureTurnSpans) {
24075
+ return;
24076
+ }
24077
+ this.handleThinkingStart(event);
24078
+ return;
24079
+ case "thinking_delta":
24080
+ if (!options.captureTurnSpans) {
24081
+ return;
24082
+ }
24083
+ this.handleThinkingDelta(event);
24084
+ return;
24085
+ case "thinking_end":
24086
+ if (!options.captureTurnSpans) {
24087
+ return;
24088
+ }
24089
+ this.handleThinkingEnd(event);
24090
+ return;
24091
+ case "turn":
24092
+ if (!options.captureTurnSpans) {
24093
+ return;
24094
+ }
24095
+ this.handleTurn(event);
24096
+ return;
24097
+ case "tool_start":
24098
+ this.handleToolStart(event, options);
24099
+ return;
24100
+ case "tool_call":
24101
+ this.handleToolCall(event);
24102
+ return;
24103
+ case "task_start":
24104
+ this.handleTaskStart(event);
24105
+ return;
24106
+ case "task":
24107
+ this.handleTask(event);
24108
+ return;
24109
+ case "compaction_start":
24110
+ this.handleCompactionStart(event);
24111
+ return;
24112
+ case "compaction":
24113
+ this.handleCompaction(event);
24114
+ return;
24115
+ default:
24116
+ return;
24117
+ }
24118
+ }
24119
+ handleOperationStart(event) {
24120
+ if (!isInstrumentedOperation(event.operationKind)) {
24121
+ return;
24122
+ }
24123
+ const state = this.takePendingOperationForEvent(event);
24124
+ if (!state) {
24125
+ return;
24126
+ }
24127
+ state.operationId = event.operationId;
24128
+ this.activeOperationsById.set(event.operationId, state);
24129
+ addScopedOperation(this.activeOperationsByScope, event, state);
24130
+ state.metadata = {
24131
+ ...state.metadata,
24132
+ ...extractEventMetadata(event),
24133
+ "flue.operation_id": event.operationId
24134
+ };
24135
+ safeLog3(state.span, { metadata: state.metadata });
24136
+ }
24137
+ handleOperation(event) {
24138
+ const state = event.operationId ? this.activeOperationsById.get(event.operationId) : void 0;
24139
+ if (!state) {
24140
+ return;
24141
+ }
24142
+ const metadata = {
24143
+ ...state.metadata,
24144
+ ...extractEventMetadata(event),
24145
+ ...typeof event.durationMs === "number" ? { "flue.duration_ms": event.durationMs } : {},
24146
+ ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {}
24147
+ };
24148
+ const metrics = metricsFromUsage(event.usage);
24149
+ safeLog3(state.span, {
24150
+ ...event.error ? { error: errorToString(event.error) } : {},
24151
+ metadata,
24152
+ ...Object.keys(metrics).length ? { metrics } : {}
24153
+ });
24154
+ }
24155
+ ensureTurnState(event) {
24156
+ const scope = scopeKey(event);
24157
+ const existing = this.turnsByScope.get(scope);
24158
+ if (existing) {
24159
+ return existing;
24160
+ }
24161
+ const parent = this.parentSpanForEvent(event);
24162
+ const metadata = {
24163
+ ...extractEventMetadata(event),
24164
+ provider: "flue"
24165
+ };
24166
+ const span = startFlueSpan(parent, {
24167
+ name: "flue.turn",
24168
+ spanAttributes: { type: "llm" /* LLM */ }
24169
+ });
24170
+ const state = {
24171
+ metadata,
24172
+ span,
24173
+ hasThinking: false,
24174
+ startTime: getCurrentUnixTimestamp(),
24175
+ text: [],
24176
+ thinking: [],
24177
+ toolCalls: []
24178
+ };
24179
+ safeLog3(span, { metadata });
24180
+ this.turnsByScope.set(scope, state);
24181
+ return state;
24182
+ }
24183
+ handleTurn(event) {
24184
+ const scope = scopeKey(event);
24185
+ const state = this.ensureTurnState(event);
24186
+ const text = state.text.join("");
24187
+ const reasoning = state.finalThinking ?? state.thinking.join("");
24188
+ const outputReasoning = reasoning || (state.hasThinking ? "[reasoning stream present; content unavailable]" : void 0);
24189
+ const metadata = {
24190
+ ...state.metadata,
24191
+ ...extractEventMetadata(event),
24192
+ ...event.model ? { model: event.model, "flue.model": event.model } : {},
24193
+ ...event.stopReason ? { "flue.stop_reason": event.stopReason } : {},
24194
+ ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {},
24195
+ provider: "flue"
24196
+ };
24197
+ safeLog3(state.span, {
24198
+ ...event.error ? { error: errorToString(event.error) } : {},
24199
+ metadata,
24200
+ metrics: {
24201
+ ...durationMsMetrics(event.durationMs),
24202
+ ...metricsFromUsage(event.usage)
24203
+ },
24204
+ output: toAssistantOutput(
24205
+ text,
24206
+ event.stopReason,
24207
+ outputReasoning,
24208
+ state.toolCalls
24209
+ )
24210
+ });
24211
+ state.span.end();
24212
+ this.turnsByScope.delete(scope);
24213
+ }
24214
+ handleThinkingDelta(event) {
24215
+ const delta = event.delta;
24216
+ if (typeof delta !== "string" || !delta) {
24217
+ return;
24218
+ }
24219
+ const state = this.ensureTurnState(event);
24220
+ state.hasThinking = true;
24221
+ state.metadata["flue.thinking"] = true;
24222
+ state.thinking.push(delta);
24223
+ }
24224
+ handleThinkingStart(event) {
24225
+ const state = this.ensureTurnState(event);
24226
+ state.hasThinking = true;
24227
+ state.metadata["flue.thinking"] = true;
24228
+ }
24229
+ handleThinkingEnd(event) {
24230
+ const state = this.ensureTurnState(event);
24231
+ state.hasThinking = true;
24232
+ state.metadata["flue.thinking"] = true;
24233
+ if (typeof event.content === "string" && event.content) {
24234
+ state.finalThinking = event.content;
24235
+ }
24236
+ }
24237
+ handleToolStart(event, options) {
24238
+ const toolCallId = event.toolCallId;
24239
+ if (!toolCallId) {
24240
+ return;
24241
+ }
24242
+ const parent = this.parentSpanForEvent(event);
24243
+ const scope = scopeKey(event);
24244
+ let turnState = this.turnsByScope.get(scope);
24245
+ if (!turnState && parent && options.captureTurnSpans) {
24246
+ turnState = this.ensureTurnState(event);
24247
+ }
24248
+ const metadata = {
24249
+ ...extractEventMetadata(event),
24250
+ ...event.toolName ? { "flue.tool_name": event.toolName } : {},
24251
+ "flue.tool_call_id": toolCallId,
24252
+ provider: "flue"
24253
+ };
24254
+ const span = startFlueSpan(parent, {
24255
+ name: `tool: ${event.toolName ?? "unknown"}`,
24256
+ spanAttributes: { type: "tool" /* TOOL */ }
24257
+ });
24258
+ if (turnState) {
24259
+ turnState.toolCalls.push({
24260
+ args: event.args,
24261
+ toolCallId,
24262
+ toolName: event.toolName
24263
+ });
24264
+ }
24265
+ safeLog3(span, {
24266
+ input: event.args,
24267
+ metadata
24268
+ });
24269
+ this.toolsById.set(toolKey(event), {
24270
+ metadata,
24271
+ span,
24272
+ startTime: getCurrentUnixTimestamp()
24273
+ });
24274
+ }
24275
+ handleToolCall(event) {
24276
+ const key = toolKey(event);
24277
+ const state = this.toolsById.get(key) ?? this.startSyntheticToolState(event, event.toolName ?? "unknown");
24278
+ const metadata = {
24279
+ ...state.metadata,
24280
+ ...extractEventMetadata(event),
24281
+ ...event.toolName ? { "flue.tool_name": event.toolName } : {},
24282
+ ...event.toolCallId ? { "flue.tool_call_id": event.toolCallId } : {},
24283
+ ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {}
24284
+ };
24285
+ safeLog3(state.span, {
24286
+ ...event.isError ? { error: errorToString(event.result) } : {},
24287
+ metadata,
24288
+ metrics: durationMsMetrics(event.durationMs),
24289
+ output: event.result
24290
+ });
24291
+ state.span.end();
24292
+ this.toolsById.delete(key);
24293
+ }
24294
+ handleTaskStart(event) {
24295
+ const parent = this.parentSpanForEvent(event);
24296
+ const metadata = {
24297
+ ...extractEventMetadata(event),
24298
+ ...event.role ? { "flue.role": event.role } : {},
24299
+ ...event.cwd ? { "flue.cwd": event.cwd } : {},
24300
+ "flue.task_id": event.taskId,
24301
+ provider: "flue"
24302
+ };
24303
+ const span = startFlueSpan(parent, {
24304
+ name: "flue.task",
24305
+ spanAttributes: { type: "task" /* TASK */ }
24306
+ });
24307
+ safeLog3(span, {
24308
+ input: event.prompt,
24309
+ metadata
24310
+ });
24311
+ this.tasksById.set(event.taskId, {
24312
+ metadata,
24313
+ span,
24314
+ startTime: getCurrentUnixTimestamp()
24315
+ });
24316
+ }
24317
+ handleTask(event) {
24318
+ const state = this.tasksById.get(event.taskId);
24319
+ if (!state) {
24320
+ return;
24321
+ }
24322
+ safeLog3(state.span, {
24323
+ ...event.isError ? { error: errorToString(event.result) } : {},
24324
+ metadata: {
24325
+ ...state.metadata,
24326
+ ...extractEventMetadata(event),
24327
+ ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {}
24328
+ },
24329
+ metrics: durationMsMetrics(event.durationMs),
24330
+ output: event.result
24331
+ });
24332
+ state.span.end();
24333
+ this.tasksById.delete(event.taskId);
24334
+ }
24335
+ handleCompactionStart(event) {
24336
+ const operationState = this.operationStateForEvent(event);
24337
+ const parent = operationState?.span ?? this.parentSpanForEvent(event);
24338
+ const metadata = {
24339
+ ...extractEventMetadata(event),
24340
+ ...event.reason ? { "flue.compaction_reason": event.reason } : {},
24341
+ provider: "flue"
24342
+ };
24343
+ const input = {
24344
+ ...typeof event.estimatedTokens === "number" ? { estimatedTokens: event.estimatedTokens } : {},
24345
+ ...event.reason ? { reason: event.reason } : {}
24346
+ };
24347
+ const span = startFlueSpan(parent, {
24348
+ name: "flue.compaction",
24349
+ spanAttributes: { type: "task" /* TASK */ }
24350
+ });
24351
+ safeLog3(span, {
24352
+ input,
24353
+ metadata
24354
+ });
24355
+ this.compactionsByScope.set(scopeKey(event), {
24356
+ input,
24357
+ metadata,
24358
+ operationState,
24359
+ span,
24360
+ startTime: getCurrentUnixTimestamp()
24361
+ });
24362
+ }
24363
+ handleCompaction(event) {
24364
+ const key = scopeKey(event);
24365
+ const state = this.compactionsByScope.get(key) ?? this.findCompactionState(event);
24366
+ if (!state) {
24367
+ return;
24368
+ }
24369
+ safeLog3(state.span, {
24370
+ metadata: {
24371
+ ...state.metadata,
24372
+ ...extractEventMetadata(event),
24373
+ ...typeof event.messagesBefore === "number" ? { "flue.messages_before": event.messagesBefore } : {},
24374
+ ...typeof event.messagesAfter === "number" ? { "flue.messages_after": event.messagesAfter } : {}
24375
+ },
24376
+ metrics: {
24377
+ ...durationMsMetrics(event.durationMs),
24378
+ ...metricsFromUsage(event.usage)
24379
+ },
24380
+ output: {
24381
+ messagesAfter: event.messagesAfter,
24382
+ messagesBefore: event.messagesBefore
24383
+ }
24384
+ });
24385
+ state.span.end();
24386
+ this.deleteCompactionState(state);
24387
+ }
24388
+ findCompactionState(event) {
24389
+ const operationState = this.operationStateForEvent(event);
24390
+ for (const state of this.compactionsByScope.values()) {
24391
+ if (operationState && state.operationState === operationState) {
24392
+ return state;
24393
+ }
24394
+ }
24395
+ return void 0;
24396
+ }
24397
+ finishCompactionsForOperation(operationState) {
24398
+ for (const state of [...this.compactionsByScope.values()]) {
24399
+ if (state.operationState !== operationState) {
24400
+ continue;
24401
+ }
24402
+ safeLog3(state.span, {
24403
+ input: state.input,
24404
+ metadata: state.metadata,
24405
+ metrics: {
24406
+ ...buildDurationMetrics3(state.startTime)
24407
+ },
24408
+ output: { completed: true }
24409
+ });
24410
+ state.span.end();
24411
+ this.deleteCompactionState(state);
24412
+ }
24413
+ }
24414
+ deleteCompactionState(state) {
24415
+ for (const [key, candidate] of this.compactionsByScope) {
24416
+ if (candidate !== state) {
24417
+ continue;
24418
+ }
24419
+ this.compactionsByScope.delete(key);
24420
+ return;
24421
+ }
24422
+ }
24423
+ startSyntheticToolState(event, toolName) {
24424
+ const parent = this.parentSpanForEvent(event);
24425
+ const metadata = {
24426
+ ...extractEventMetadata(event),
24427
+ ...event.toolCallId ? { "flue.tool_call_id": event.toolCallId } : {},
24428
+ "flue.tool_name": toolName,
24429
+ provider: "flue"
24430
+ };
24431
+ const span = startFlueSpan(parent, {
24432
+ name: `tool: ${toolName}`,
24433
+ spanAttributes: { type: "tool" /* TOOL */ }
24434
+ });
24435
+ safeLog3(span, { metadata });
24436
+ return { metadata, span, startTime: getCurrentUnixTimestamp() };
24437
+ }
24438
+ operationStateForEvent(event) {
24439
+ if (event.operationId) {
24440
+ const operation = this.activeOperationsById.get(event.operationId) ?? this.promotePendingOperationForEvent(event);
24441
+ if (operation) {
24442
+ return operation;
24443
+ }
24444
+ }
24445
+ return this.activeOperationForEventScope(event) ?? this.pendingOperationForEventScope(event);
24446
+ }
24447
+ parentSpanForEvent(event) {
24448
+ if (event.operationId) {
24449
+ const operation = this.operationStateForEvent(event);
24450
+ if (operation) {
24451
+ return operation.span;
24452
+ }
24453
+ }
24454
+ if (event.taskId) {
24455
+ return this.tasksById.get(event.taskId)?.span;
24456
+ }
24457
+ return this.operationStateForEvent(event)?.span;
24458
+ }
24459
+ promotePendingOperationForEvent(event) {
24460
+ if (!event.operationId) {
24461
+ return void 0;
24462
+ }
24463
+ const scopePrefixes = operationScopePrefixes(event);
24464
+ for (const [candidateKey, candidateQueue] of this.pendingOperationsByKey) {
24465
+ if (!candidateQueue.length || !operationKeyMatchesScopes(candidateKey, scopePrefixes)) {
24466
+ continue;
24467
+ }
24468
+ const state = candidateQueue.shift();
24469
+ if (!state) {
24470
+ return void 0;
24471
+ }
24472
+ state.operationId = event.operationId;
24473
+ this.activeOperationsById.set(event.operationId, state);
24474
+ addScopedOperation(this.activeOperationsByScope, event, state);
24475
+ state.metadata = {
24476
+ ...state.metadata,
24477
+ ...extractEventMetadata(event),
24478
+ "flue.operation_id": event.operationId
24479
+ };
24480
+ safeLog3(state.span, { metadata: state.metadata });
24481
+ return state;
24482
+ }
24483
+ return void 0;
24484
+ }
24485
+ activeOperationForEventScope(event) {
24486
+ for (const scope of operationScopeNames(event)) {
24487
+ const operations = this.activeOperationsByScope.get(scope);
24488
+ if (operations?.length) {
24489
+ return operations[operations.length - 1];
24490
+ }
24491
+ }
24492
+ return void 0;
24493
+ }
24494
+ pendingOperationForEventScope(event) {
24495
+ const scopePrefixes = operationScopePrefixes(event);
24496
+ for (const [candidateKey, candidateQueue] of this.pendingOperationsByKey) {
24497
+ if (!candidateQueue.length || !operationKeyMatchesScopes(candidateKey, scopePrefixes)) {
24498
+ continue;
24499
+ }
24500
+ return candidateQueue[0];
24501
+ }
24502
+ return void 0;
24503
+ }
24504
+ takePendingOperationForEvent(event) {
24505
+ const key = operationKey(event.session, event.operationKind);
24506
+ const queue2 = this.pendingOperationsByKey.get(key);
24507
+ if (queue2?.length) {
24508
+ return queue2.shift();
24509
+ }
24510
+ for (const [candidateKey, candidateQueue] of this.pendingOperationsByKey) {
24511
+ if (candidateKey.endsWith(`::${event.operationKind}`) && candidateQueue.length) {
24512
+ return candidateQueue.shift();
24513
+ }
24514
+ }
24515
+ return void 0;
24516
+ }
24517
+ pendingOperationQueue(key) {
24518
+ const existing = this.pendingOperationsByKey.get(key);
24519
+ if (existing) {
24520
+ return existing;
24521
+ }
24522
+ const queue2 = [];
24523
+ this.pendingOperationsByKey.set(key, queue2);
24524
+ return queue2;
24525
+ }
24526
+ };
24527
+ function isInstrumentedOperation(operation) {
24528
+ return operation === "prompt" || operation === "skill" || operation === "task" || operation === "compact";
24529
+ }
24530
+ function getSessionName(session) {
24531
+ return typeof session?.name === "string" ? session.name : void 0;
24532
+ }
24533
+ function operationKey(sessionName, operation) {
24534
+ return `${sessionName ?? "unknown"}::${operation}`;
24535
+ }
24536
+ function operationScopePrefixes(event) {
24537
+ const scopes = /* @__PURE__ */ new Set();
24538
+ for (const scope of operationScopeNames(event)) {
24539
+ scopes.add(`${scope}::`);
24540
+ }
24541
+ return scopes;
24542
+ }
24543
+ function operationKeyMatchesScopes(key, scopes) {
24544
+ for (const scope of scopes) {
24545
+ if (key.startsWith(scope)) {
24546
+ return true;
24547
+ }
24548
+ }
24549
+ return false;
24550
+ }
24551
+ function operationScopeNames(event) {
24552
+ const scopes = /* @__PURE__ */ new Set();
24553
+ if (event.session) {
24554
+ scopes.add(event.session);
24555
+ }
24556
+ if (event.parentSession) {
24557
+ scopes.add(event.parentSession);
24558
+ }
24559
+ if (!scopes.size) {
24560
+ scopes.add("unknown");
24561
+ }
24562
+ return scopes;
24563
+ }
24564
+ function addScopedOperation(operationsByScope, event, state) {
24565
+ for (const scope of operationScopeNames(event)) {
24566
+ addOperationToScope(operationsByScope, scope, state);
24567
+ }
24568
+ }
24569
+ function addOperationToScope(operationsByScope, scope, state) {
24570
+ const operations = operationsByScope.get(scope);
24571
+ if (operations) {
24572
+ if (!operations.includes(state)) {
24573
+ operations.push(state);
24574
+ }
24575
+ } else {
24576
+ operationsByScope.set(scope, [state]);
24577
+ }
24578
+ }
24579
+ function removeScopedOperation(operationsByScope, state) {
24580
+ for (const [scope, operations] of operationsByScope) {
24581
+ const index = operations.indexOf(state);
24582
+ if (index === -1) {
24583
+ continue;
24584
+ }
24585
+ operations.splice(index, 1);
24586
+ if (operations.length === 0) {
24587
+ operationsByScope.delete(scope);
24588
+ }
24589
+ }
24590
+ }
24591
+ function removePendingOperation(pendingOperationsByKey, state) {
24592
+ for (const [key, queue2] of pendingOperationsByKey) {
24593
+ const index = queue2.indexOf(state);
24594
+ if (index === -1) {
24595
+ continue;
24596
+ }
24597
+ queue2.splice(index, 1);
24598
+ if (queue2.length === 0) {
24599
+ pendingOperationsByKey.delete(key);
24600
+ }
24601
+ return;
24602
+ }
24603
+ }
24604
+ function extractSessionMetadata(session) {
24605
+ const sessionName = getSessionName(session);
24606
+ return sessionName ? { "flue.session": sessionName } : {};
24607
+ }
24608
+ function extractEventMetadata(event) {
24609
+ return {
24610
+ ...event.runId ? { "flue.run_id": event.runId } : {},
24611
+ ...typeof event.eventIndex === "number" ? { "flue.event_index": event.eventIndex } : {},
24612
+ ...event.session ? { "flue.session": event.session } : {},
24613
+ ...event.parentSession ? { "flue.parent_session": event.parentSession } : {},
24614
+ ...event.harness ? { "flue.harness": event.harness } : {},
24615
+ ...event.taskId ? { "flue.task_id": event.taskId } : {},
24616
+ ...event.operationId ? { "flue.operation_id": event.operationId } : {}
24617
+ };
24618
+ }
24619
+ function extractOperationInput(operation, args) {
24620
+ switch (operation) {
24621
+ case "prompt":
24622
+ case "task":
24623
+ return args[0];
24624
+ case "skill":
24625
+ return {
24626
+ args: getOptionObject(args[1])?.args,
24627
+ name: args[0]
24628
+ };
24629
+ case "compact":
24630
+ return void 0;
24631
+ }
24632
+ }
24633
+ function extractOperationInputMetadata(operation, args) {
24634
+ const options = getOptionObject(args[1]);
24635
+ return {
24636
+ ...operation === "skill" && typeof args[0] === "string" ? { "flue.skill_name": args[0] } : {},
24637
+ ...options?.model ? { model: options.model, "flue.model": options.model } : {},
24638
+ ...options?.role ? { "flue.role": options.role } : {},
24639
+ ...options?.thinkingLevel ? { "flue.thinking_level": options.thinkingLevel } : {},
24640
+ ...typeof options?.cwd === "string" ? { "flue.cwd": options.cwd } : {},
24641
+ ...Array.isArray(options?.tools) ? {
24642
+ "flue.tools_count": options.tools.length,
24643
+ tools: summarizeTools(options.tools)
24644
+ } : {},
24645
+ ...Array.isArray(options?.images) ? { "flue.images_count": options.images.length } : {},
24646
+ ...options?.result || options?.schema ? { "flue.result_schema": true } : {}
24647
+ };
24648
+ }
24649
+ function getOptionObject(value) {
24650
+ return isObject(value) ? value : void 0;
24651
+ }
24652
+ function summarizeTools(tools) {
24653
+ return tools.flatMap((tool) => {
24654
+ if (!isObject(tool)) {
24655
+ return [];
24656
+ }
24657
+ const name = typeof tool.name === "string" ? tool.name : void 0;
24658
+ if (!name) {
24659
+ return [];
24660
+ }
24661
+ return [
24662
+ {
24663
+ function: {
24664
+ description: typeof tool.description === "string" ? tool.description : void 0,
24665
+ name,
24666
+ parameters: tool.parameters
24667
+ },
24668
+ type: "function"
24669
+ }
24670
+ ];
24671
+ });
24672
+ }
24673
+ function extractPromptResponseMetadata(result) {
24674
+ const modelId = result?.model && typeof result.model.id === "string" ? result.model.id : void 0;
24675
+ return modelId ? {
24676
+ model: modelId,
24677
+ "flue.model": modelId
24678
+ } : {};
24679
+ }
24680
+ function extractOperationOutput(result) {
24681
+ if (!result) {
24682
+ return void 0;
24683
+ }
24684
+ if ("data" in result) {
24685
+ return result.data;
24686
+ }
24687
+ if ("text" in result) {
24688
+ return result.text;
24689
+ }
24690
+ return result;
24691
+ }
24692
+ function metricsFromUsage(usage) {
24693
+ return {
24694
+ ...typeof usage?.input === "number" ? { prompt_tokens: usage.input } : {},
24695
+ ...typeof usage?.output === "number" ? { completion_tokens: usage.output } : {},
24696
+ ...typeof usage?.cacheRead === "number" ? { prompt_cached_tokens: usage.cacheRead } : {},
24697
+ ...typeof usage?.cacheWrite === "number" ? { prompt_cache_creation_tokens: usage.cacheWrite } : {},
24698
+ ...typeof usage?.totalTokens === "number" ? { tokens: usage.totalTokens } : {},
24699
+ ...typeof usage?.cost?.total === "number" ? { estimated_cost: usage.cost.total } : {}
24700
+ };
24701
+ }
24702
+ function buildDurationMetrics3(startTime) {
24703
+ return {
24704
+ duration_ms: Math.max(0, (getCurrentUnixTimestamp() - startTime) * 1e3)
24705
+ };
24706
+ }
24707
+ function durationMsMetrics(durationMs) {
24708
+ return typeof durationMs === "number" ? { duration_ms: durationMs } : {};
24709
+ }
24710
+ function scopeKey(event) {
24711
+ if (event.operationId) {
24712
+ return `operation:${event.operationId}`;
24713
+ }
24714
+ if (event.taskId) {
24715
+ return `task:${event.taskId}`;
24716
+ }
24717
+ if (event.session) {
24718
+ return `session:${event.session}`;
24719
+ }
24720
+ return "flue:unknown";
24721
+ }
24722
+ function toolKey(event) {
24723
+ return `${scopeKey(event)}::tool:${event.toolCallId ?? "unknown"}`;
24724
+ }
24725
+ function toAssistantOutput(text, finishReason, reasoning, toolCalls) {
24726
+ return [
24727
+ {
24728
+ finish_reason: finishReason ?? "stop",
24729
+ index: 0,
24730
+ message: {
24731
+ content: text,
24732
+ ...reasoning ? { reasoning } : {},
24733
+ role: "assistant",
24734
+ ...toolCalls?.length ? {
24735
+ tool_calls: toolCalls.map((toolCall) => ({
24736
+ function: {
24737
+ arguments: toolCall.args === void 0 ? "{}" : JSON.stringify(toolCall.args),
24738
+ name: toolCall.toolName ?? "unknown"
24739
+ },
24740
+ ...toolCall.toolCallId ? { id: toolCall.toolCallId } : {},
24741
+ type: "function"
24742
+ }))
24743
+ } : {}
24744
+ }
24745
+ }
24746
+ ];
24747
+ }
24748
+ function startFlueSpan(parent, args) {
24749
+ return parent ? withCurrent(parent, () => startSpan(args)) : startSpan(args);
24750
+ }
24751
+ function safeLog3(span, event) {
24752
+ try {
24753
+ span.log(event);
24754
+ } catch (error) {
24755
+ logInstrumentationError3("Flue span log", error);
24756
+ }
24757
+ }
24758
+ function errorToString(error) {
24759
+ if (error instanceof Error) {
24760
+ return error.message;
24761
+ }
24762
+ if (typeof error === "string") {
24763
+ return error;
24764
+ }
24765
+ try {
24766
+ return JSON.stringify(error);
24767
+ } catch {
24768
+ return String(error);
24769
+ }
24770
+ }
24771
+ function logInstrumentationError3(label, error) {
24772
+ console.error(`Error in ${label} instrumentation:`, error);
24773
+ }
24774
+
24775
+ // src/wrappers/langchain/callback-handler.ts
24776
+ var BRAINTRUST_LANGCHAIN_CALLBACK_HANDLER_NAME = "BraintrustCallbackHandler";
24777
+ var BraintrustLangChainCallbackHandler = class {
24778
+ name = BRAINTRUST_LANGCHAIN_CALLBACK_HANDLER_NAME;
24779
+ spans = /* @__PURE__ */ new Map();
24780
+ skippedRuns = /* @__PURE__ */ new Set();
24781
+ parent;
24782
+ rootRunId;
24783
+ options;
24784
+ startTimes = /* @__PURE__ */ new Map();
24785
+ firstTokenTimes = /* @__PURE__ */ new Map();
24786
+ ttftMs = /* @__PURE__ */ new Map();
24787
+ constructor(options) {
24788
+ this.parent = options?.parent;
24789
+ this.options = {
24790
+ debug: options?.debug ?? false,
24791
+ excludeMetadataProps: options?.excludeMetadataProps ?? /^(l[sc]_|langgraph_|__pregel_|checkpoint_ns)/,
24792
+ logger: options?.logger
24793
+ };
24794
+ }
24795
+ startSpan({
24796
+ runId,
24797
+ parentRunId,
24798
+ ...args
24799
+ }) {
24800
+ if (this.spans.has(runId)) {
24801
+ return;
24802
+ }
24803
+ if (!parentRunId) {
24804
+ this.rootRunId = runId;
24805
+ }
24806
+ const tags = args.event?.tags;
24807
+ const spanAttributes = args.spanAttributes || {};
24808
+ spanAttributes.type = args.type || spanAttributes.type || "task";
24809
+ args.type = spanAttributes.type;
24810
+ const currentParent = (typeof this.parent === "function" ? this.parent() : this.parent) ?? currentSpan();
24811
+ let parentSpan;
24812
+ if (parentRunId && this.spans.has(parentRunId)) {
24813
+ parentSpan = this.spans.get(parentRunId);
24814
+ } else if (!Object.is(currentParent, NOOP_SPAN)) {
24815
+ parentSpan = currentParent;
24816
+ } else if (this.options.logger) {
24817
+ parentSpan = this.options.logger;
24818
+ } else {
24819
+ parentSpan = { startSpan };
24820
+ }
24821
+ args.event = {
24822
+ ...args.event,
24823
+ tags: void 0,
24824
+ metadata: {
24825
+ ...tags ? { tags } : {},
24826
+ ...args.event?.metadata,
24827
+ braintrust: {
24828
+ integration_name: "langchain-js",
24829
+ sdk_language: "javascript"
24830
+ },
24831
+ run_id: runId,
24832
+ parent_run_id: parentRunId,
24833
+ ...this.options.debug ? { runId, parentRunId } : {}
24834
+ }
24835
+ };
24836
+ let span = parentSpan.startSpan(args);
24837
+ if (!Object.is(this.options.logger, NOOP_SPAN) && Object.is(span, NOOP_SPAN)) {
24838
+ span = initLogger().startSpan(args);
24839
+ }
24840
+ this.spans.set(runId, span);
24841
+ }
24842
+ endSpan({
24843
+ runId,
24844
+ parentRunId,
24845
+ tags,
24846
+ metadata,
24847
+ ...args
24848
+ }) {
24849
+ if (!this.spans.has(runId)) {
24850
+ return;
24851
+ }
24852
+ if (this.skippedRuns.has(runId)) {
24853
+ this.skippedRuns.delete(runId);
24854
+ return;
24855
+ }
24856
+ const span = this.spans.get(runId);
24857
+ this.spans.delete(runId);
24858
+ if (runId === this.rootRunId) {
24859
+ this.rootRunId = void 0;
24860
+ }
24861
+ span.log({ ...args, metadata: { tags, ...metadata } });
24862
+ span.end();
24863
+ }
24864
+ async handleLLMStart(llm, prompts, runId, parentRunId, extraParams, tags, metadata, runName) {
24865
+ this.startSpan({
24866
+ runId,
24867
+ parentRunId,
24868
+ name: runName ?? getSerializedName(llm) ?? "LLM",
24869
+ type: "llm",
24870
+ event: {
24871
+ input: prompts,
24872
+ tags,
24873
+ metadata: {
24874
+ serialized: llm,
24875
+ name: runName,
24876
+ metadata,
24877
+ ...extraParams
24878
+ }
24879
+ }
24880
+ });
24881
+ }
24882
+ async handleLLMError(err, runId, parentRunId, tags) {
24883
+ this.endSpan({ runId, parentRunId, error: err, tags });
24884
+ }
24885
+ async handleLLMEnd(output, runId, parentRunId, tags) {
24886
+ const metrics = getMetricsFromResponse(output);
24887
+ const modelName2 = getModelNameFromResponse(output);
24888
+ const ttft = this.ttftMs.get(runId);
24889
+ if (ttft !== void 0) {
24890
+ metrics.time_to_first_token = ttft;
24891
+ }
24892
+ this.startTimes.delete(runId);
24893
+ this.firstTokenTimes.delete(runId);
24894
+ this.ttftMs.delete(runId);
24895
+ this.endSpan({
24896
+ runId,
24897
+ parentRunId,
24898
+ output,
24899
+ metrics,
24900
+ tags,
24901
+ metadata: {
24902
+ model: modelName2
24903
+ }
24904
+ });
24905
+ }
24906
+ async handleChatModelStart(llm, messages, runId, parentRunId, extraParams, tags, metadata, runName) {
24907
+ this.startTimes.set(runId, Date.now());
24908
+ this.firstTokenTimes.delete(runId);
24909
+ this.ttftMs.delete(runId);
24910
+ this.startSpan({
24911
+ runId,
24912
+ parentRunId,
24913
+ name: runName ?? getSerializedName(llm) ?? "Chat Model",
24914
+ type: "llm",
24915
+ event: {
24916
+ input: messages,
24917
+ tags,
24918
+ metadata: {
24919
+ serialized: llm,
24920
+ name: runName,
24921
+ metadata,
24922
+ ...extraParams
24923
+ }
24924
+ }
24925
+ });
24926
+ }
24927
+ async handleChainStart(chain, inputs, runId, parentRunId, tags, metadata, runType, runName) {
24928
+ if (tags?.includes("langsmith:hidden")) {
24929
+ this.skippedRuns.add(runId);
24930
+ return;
24931
+ }
24932
+ this.startSpan({
24933
+ runId,
24934
+ parentRunId,
24935
+ name: runName ?? getSerializedName(chain) ?? "Chain",
24936
+ event: {
24937
+ input: inputs,
24938
+ tags,
24939
+ metadata: {
24940
+ serialized: chain,
24941
+ name: runName,
24942
+ metadata,
24943
+ run_type: runType
24944
+ }
24945
+ }
24946
+ });
24947
+ }
24948
+ async handleChainError(err, runId, parentRunId, tags, kwargs) {
24949
+ this.endSpan({ runId, parentRunId, error: err, tags, metadata: kwargs });
24950
+ }
24951
+ async handleChainEnd(outputs, runId, parentRunId, tags, kwargs) {
24952
+ this.endSpan({
24953
+ runId,
24954
+ parentRunId,
24955
+ tags,
24956
+ output: outputs,
24957
+ metadata: { ...kwargs }
24958
+ });
24959
+ }
24960
+ async handleToolStart(tool, input, runId, parentRunId, tags, metadata, runName) {
24961
+ this.startSpan({
24962
+ runId,
24963
+ parentRunId,
24964
+ name: runName ?? getSerializedName(tool) ?? "Tool",
24965
+ type: "llm",
24966
+ event: {
24967
+ input: safeJsonParse(input),
24968
+ tags,
24969
+ metadata: {
24970
+ metadata,
24971
+ serialized: tool,
24972
+ input_str: input,
24973
+ input: safeJsonParse(input),
24974
+ name: runName
24975
+ }
24976
+ }
24977
+ });
24978
+ }
24979
+ async handleToolError(err, runId, parentRunId, tags) {
24980
+ this.endSpan({ runId, parentRunId, error: err, tags });
24981
+ }
24982
+ async handleToolEnd(output, runId, parentRunId, tags) {
24983
+ this.endSpan({ runId, parentRunId, output, tags });
24984
+ }
24985
+ async handleAgentAction(action, runId, parentRunId, tags) {
24986
+ this.startSpan({
24987
+ runId,
24988
+ parentRunId,
24989
+ type: "llm",
24990
+ name: typeof action.tool === "string" ? action.tool : "Agent",
24991
+ event: {
24992
+ input: action,
24993
+ tags
24994
+ }
24995
+ });
24996
+ }
24997
+ async handleAgentEnd(action, runId, parentRunId, tags) {
24998
+ this.endSpan({ runId, parentRunId, output: action, tags });
24999
+ }
25000
+ async handleRetrieverStart(retriever, query, runId, parentRunId, tags, metadata, name) {
25001
+ this.startSpan({
25002
+ runId,
25003
+ parentRunId,
25004
+ name: name ?? getSerializedName(retriever) ?? "Retriever",
25005
+ type: "function",
25006
+ event: {
25007
+ input: query,
25008
+ tags,
25009
+ metadata: {
25010
+ serialized: retriever,
25011
+ metadata,
25012
+ name
25013
+ }
25014
+ }
25015
+ });
25016
+ }
25017
+ async handleRetrieverEnd(documents, runId, parentRunId, tags) {
25018
+ this.endSpan({ runId, parentRunId, output: documents, tags });
25019
+ }
25020
+ async handleRetrieverError(err, runId, parentRunId, tags) {
25021
+ this.endSpan({ runId, parentRunId, error: err, tags });
25022
+ }
25023
+ async handleLLMNewToken(_token, _idx, runId, _parentRunId, _tags) {
25024
+ if (!this.firstTokenTimes.has(runId)) {
25025
+ const now2 = Date.now();
25026
+ this.firstTokenTimes.set(runId, now2);
25027
+ const start = this.startTimes.get(runId);
25028
+ if (start !== void 0) {
25029
+ this.ttftMs.set(runId, (now2 - start) / 1e3);
25030
+ }
23527
25031
  }
23528
- case "session.usage_info": {
23529
- const d = event.data;
23530
- if (d && typeof d.currentTokens === "number") {
23531
- state.session.span.log({
23532
- metadata: {
23533
- "github_copilot.context_window.limit": d.tokenLimit,
23534
- "github_copilot.context_window.current": d.currentTokens,
23535
- "github_copilot.context_window.messages": d.messagesLength
23536
- }
23537
- });
25032
+ }
25033
+ };
25034
+ function getSerializedName(serialized) {
25035
+ if (typeof serialized.name === "string") {
25036
+ return serialized.name;
25037
+ }
25038
+ const lastIdPart = serialized.id?.at(-1);
25039
+ return typeof lastIdPart === "string" ? lastIdPart : void 0;
25040
+ }
25041
+ function cleanObject(obj) {
25042
+ return Object.fromEntries(
25043
+ Object.entries(obj).filter(([, value]) => {
25044
+ if (typeof value !== "number") {
25045
+ return false;
23538
25046
  }
23539
- break;
25047
+ return Number.isFinite(value);
25048
+ })
25049
+ );
25050
+ }
25051
+ function walkGenerations(response) {
25052
+ const result = [];
25053
+ const generations = response.generations || [];
25054
+ for (const batch of generations) {
25055
+ if (Array.isArray(batch)) {
25056
+ for (const generation of batch) {
25057
+ if (isRecord(generation)) {
25058
+ result.push(generation);
25059
+ }
25060
+ }
25061
+ } else if (isRecord(batch)) {
25062
+ result.push(batch);
23540
25063
  }
23541
25064
  }
25065
+ return result;
23542
25066
  }
23543
- function injectTracingHooks2(config, state) {
23544
- const existingHooks = config.hooks ?? {};
23545
- const onSessionEnd = async (input, invocation) => {
23546
- try {
23547
- await existingHooks.onSessionEnd?.(input, invocation);
23548
- } finally {
23549
- handleSessionEnd(state, input.reason, input.error);
23550
- state.unsubscribeEvents?.();
25067
+ function getModelNameFromResponse(response) {
25068
+ for (const generation of walkGenerations(response)) {
25069
+ const message = generation.message;
25070
+ if (!isRecord(message)) {
25071
+ continue;
23551
25072
  }
23552
- };
23553
- config.hooks = {
23554
- ...existingHooks,
23555
- onSessionEnd
23556
- };
25073
+ const responseMetadata = message.response_metadata;
25074
+ if (!isRecord(responseMetadata)) {
25075
+ continue;
25076
+ }
25077
+ const modelName3 = responseMetadata.model_name ?? responseMetadata.model;
25078
+ if (typeof modelName3 === "string") {
25079
+ return modelName3;
25080
+ }
25081
+ }
25082
+ const llmOutput = response.llmOutput || {};
25083
+ const modelName2 = llmOutput.model_name ?? llmOutput.model;
25084
+ return typeof modelName2 === "string" ? modelName2 : void 0;
23557
25085
  }
23558
- function attachSessionEventListener(session, state) {
23559
- const handler = (event) => {
23560
- state.processing = state.processing.then(() => dispatchEvent(state, event)).catch((err) => {
23561
- console.error(
23562
- "[Braintrust] Error processing GitHub Copilot SDK event:",
23563
- err
23564
- );
25086
+ function getMetricsFromResponse(response) {
25087
+ for (const generation of walkGenerations(response)) {
25088
+ const message = generation.message;
25089
+ if (!isRecord(message)) {
25090
+ continue;
25091
+ }
25092
+ const usageMetadata = message.usage_metadata;
25093
+ if (!isRecord(usageMetadata)) {
25094
+ continue;
25095
+ }
25096
+ const inputTokenDetails = usageMetadata.input_token_details;
25097
+ return cleanObject({
25098
+ total_tokens: usageMetadata.total_tokens,
25099
+ prompt_tokens: usageMetadata.input_tokens,
25100
+ completion_tokens: usageMetadata.output_tokens,
25101
+ prompt_cache_creation_tokens: isRecord(inputTokenDetails) ? inputTokenDetails.cache_creation : void 0,
25102
+ prompt_cached_tokens: isRecord(inputTokenDetails) ? inputTokenDetails.cache_read : void 0
23565
25103
  });
23566
- };
23567
- state.unsubscribeEvents = session.on(
23568
- handler
23569
- );
25104
+ }
25105
+ const llmOutput = response.llmOutput || {};
25106
+ const tokenUsage = isRecord(llmOutput.tokenUsage) ? llmOutput.tokenUsage : isRecord(llmOutput.estimatedTokens) ? llmOutput.estimatedTokens : {};
25107
+ return cleanObject({
25108
+ total_tokens: tokenUsage.totalTokens,
25109
+ prompt_tokens: tokenUsage.promptTokens,
25110
+ completion_tokens: tokenUsage.completionTokens
25111
+ });
23570
25112
  }
23571
- function isGitHubCopilotSession(value) {
23572
- return value !== null && typeof value === "object" && typeof value.on === "function";
25113
+ function safeJsonParse(input) {
25114
+ try {
25115
+ return JSON.parse(input);
25116
+ } catch {
25117
+ return input;
25118
+ }
23573
25119
  }
23574
- function makeSessionHandlers(sessionStates, configArgIndex, includeProviderMetadata) {
23575
- return {
23576
- start: (event) => {
23577
- const config = event.arguments[configArgIndex];
23578
- if (!config || typeof config !== "object") {
23579
- return;
23580
- }
23581
- const sessionSpan = startSpan({
23582
- name: "Copilot Session",
23583
- spanAttributes: { type: "task" /* TASK */ }
23584
- });
23585
- const metadata = {};
23586
- if (config.model) {
23587
- metadata["github_copilot.model"] = config.model;
23588
- }
23589
- if (includeProviderMetadata && config.provider?.type) {
23590
- metadata["github_copilot.provider_type"] = config.provider.type;
23591
- }
23592
- if (Object.keys(metadata).length > 0) {
23593
- sessionSpan.log({ metadata });
23594
- }
23595
- const state = {
23596
- session: makeSpanWithId(sessionSpan),
23597
- activeTurns: /* @__PURE__ */ new Map(),
23598
- pendingUserMessages: /* @__PURE__ */ new Map(),
23599
- currentMessageContent: /* @__PURE__ */ new Map(),
23600
- activeTools: /* @__PURE__ */ new Map(),
23601
- subAgents: /* @__PURE__ */ new Map(),
23602
- agentIdToToolCallId: /* @__PURE__ */ new Map(),
23603
- processing: Promise.resolve(),
23604
- totalInputTokens: 0,
23605
- totalOutputTokens: 0
23606
- };
23607
- injectTracingHooks2(config, state);
23608
- sessionStates.set(event, state);
23609
- },
23610
- asyncEnd: (event) => {
23611
- const state = sessionStates.get(event);
23612
- if (!state) {
23613
- return;
23614
- }
23615
- const session = event.result;
23616
- if (isGitHubCopilotSession(session)) {
23617
- attachSessionEventListener(session, state);
23618
- } else {
23619
- state.session.span.end();
23620
- }
23621
- sessionStates.delete(event);
23622
- },
23623
- error: (event) => {
23624
- const state = sessionStates.get(event);
23625
- if (!state || !event.error) {
23626
- return;
23627
- }
23628
- state.session.span.log({ error: event.error.message });
23629
- state.session.span.end();
23630
- sessionStates.delete(event);
23631
- }
23632
- };
25120
+ function isRecord(value) {
25121
+ return typeof value === "object" && value !== null && !Array.isArray(value);
23633
25122
  }
23634
- var GitHubCopilotPlugin = class extends BasePlugin {
25123
+
25124
+ // src/instrumentation/plugins/langchain-plugin.ts
25125
+ var LangChainPlugin = class extends BasePlugin {
25126
+ injectedManagers = /* @__PURE__ */ new WeakSet();
23635
25127
  onEnable() {
23636
- this.subscribeToSessionChannels();
25128
+ this.subscribeToConfigure(langChainChannels.configure);
25129
+ this.subscribeToConfigure(langChainChannels.configureSync);
23637
25130
  }
23638
25131
  onDisable() {
23639
25132
  for (const unsubscribe of this.unsubscribers) {
23640
25133
  unsubscribe();
23641
25134
  }
23642
25135
  this.unsubscribers = [];
25136
+ this.injectedManagers = /* @__PURE__ */ new WeakSet();
23643
25137
  }
23644
- subscribeToSessionChannels() {
23645
- const createChannel = gitHubCopilotChannels.createSession.tracingChannel();
23646
- const resumeChannel = gitHubCopilotChannels.resumeSession.tracingChannel();
23647
- const sessionStates = /* @__PURE__ */ new WeakMap();
23648
- const createHandlers = makeSessionHandlers(
23649
- sessionStates,
23650
- 0,
23651
- // config is arg 0 of createSession(config)
23652
- true
23653
- // include provider metadata
23654
- );
23655
- const resumeHandlers = makeSessionHandlers(
23656
- sessionStates,
23657
- 1,
23658
- // config is arg 1 of resumeSession(sessionId, config)
23659
- false
23660
- // resumeSession config has no provider field
23661
- );
23662
- createChannel.subscribe(createHandlers);
23663
- resumeChannel.subscribe(resumeHandlers);
23664
- this.unsubscribers.push(
23665
- () => createChannel.unsubscribe(createHandlers),
23666
- () => resumeChannel.unsubscribe(resumeHandlers)
23667
- );
25138
+ subscribeToConfigure(channel) {
25139
+ const tracingChannel2 = channel.tracingChannel();
25140
+ const handlers = {
25141
+ start: (event) => {
25142
+ injectHandlerIntoArguments(event.arguments);
25143
+ },
25144
+ end: (event) => {
25145
+ this.injectHandler(event.result);
25146
+ }
25147
+ };
25148
+ tracingChannel2.subscribe(handlers);
25149
+ this.unsubscribers.push(() => {
25150
+ tracingChannel2.unsubscribe(handlers);
25151
+ });
25152
+ }
25153
+ injectHandler(result) {
25154
+ if (!isCallbackManager(result)) {
25155
+ return;
25156
+ }
25157
+ if (this.injectedManagers.has(result) || hasBraintrustHandler(result)) {
25158
+ return;
25159
+ }
25160
+ try {
25161
+ result.addHandler(new BraintrustLangChainCallbackHandler(), true);
25162
+ this.injectedManagers.add(result);
25163
+ } catch {
25164
+ }
23668
25165
  }
23669
25166
  };
25167
+ function isCallbackManager(value) {
25168
+ if (typeof value !== "object" || value === null) {
25169
+ return false;
25170
+ }
25171
+ const maybeManager = value;
25172
+ return typeof maybeManager.addHandler === "function";
25173
+ }
25174
+ function hasBraintrustHandler(manager) {
25175
+ return manager.handlers?.some((handler) => {
25176
+ if (typeof handler !== "object" || handler === null) {
25177
+ return false;
25178
+ }
25179
+ const name = Reflect.get(handler, "name");
25180
+ return name === BRAINTRUST_LANGCHAIN_CALLBACK_HANDLER_NAME;
25181
+ }) ?? false;
25182
+ }
25183
+ function injectHandlerIntoArguments(args) {
25184
+ if (!isWritableArgumentsObject(args)) {
25185
+ return;
25186
+ }
25187
+ const inheritedHandlers = Reflect.get(args, "0");
25188
+ const handler = new BraintrustLangChainCallbackHandler();
25189
+ if (inheritedHandlers === void 0 || inheritedHandlers === null) {
25190
+ Reflect.set(args, "0", [handler]);
25191
+ return;
25192
+ }
25193
+ if (Array.isArray(inheritedHandlers)) {
25194
+ if (!inheritedHandlers.some(isBraintrustHandler)) {
25195
+ inheritedHandlers.push(handler);
25196
+ }
25197
+ }
25198
+ }
25199
+ function isWritableArgumentsObject(args) {
25200
+ return typeof args === "object" && args !== null;
25201
+ }
25202
+ function isBraintrustHandler(handler) {
25203
+ if (typeof handler !== "object" || handler === null) {
25204
+ return false;
25205
+ }
25206
+ return Reflect.get(handler, "name") === BRAINTRUST_LANGCHAIN_CALLBACK_HANDLER_NAME;
25207
+ }
23670
25208
 
23671
25209
  // src/instrumentation/braintrust-plugin.ts
23672
25210
  function getIntegrationConfig(integrations, key) {
@@ -23680,6 +25218,7 @@ var BraintrustPlugin = class extends BasePlugin {
23680
25218
  aiSDKPlugin = null;
23681
25219
  claudeAgentSDKPlugin = null;
23682
25220
  cursorSDKPlugin = null;
25221
+ openAIAgentsPlugin = null;
23683
25222
  googleGenAIPlugin = null;
23684
25223
  huggingFacePlugin = null;
23685
25224
  openRouterPlugin = null;
@@ -23690,6 +25229,8 @@ var BraintrustPlugin = class extends BasePlugin {
23690
25229
  groqPlugin = null;
23691
25230
  genkitPlugin = null;
23692
25231
  gitHubCopilotPlugin = null;
25232
+ fluePlugin = null;
25233
+ langChainPlugin = null;
23693
25234
  constructor(config = {}) {
23694
25235
  super();
23695
25236
  this.config = config;
@@ -23720,6 +25261,10 @@ var BraintrustPlugin = class extends BasePlugin {
23720
25261
  this.cursorSDKPlugin = new CursorSDKPlugin();
23721
25262
  this.cursorSDKPlugin.enable();
23722
25263
  }
25264
+ if (integrations.openAIAgents !== false) {
25265
+ this.openAIAgentsPlugin = new OpenAIAgentsPlugin();
25266
+ this.openAIAgentsPlugin.enable();
25267
+ }
23723
25268
  if (integrations.googleGenAI !== false && integrations.google !== false) {
23724
25269
  this.googleGenAIPlugin = new GoogleGenAIPlugin();
23725
25270
  this.googleGenAIPlugin.enable();
@@ -23760,6 +25305,14 @@ var BraintrustPlugin = class extends BasePlugin {
23760
25305
  this.gitHubCopilotPlugin = new GitHubCopilotPlugin();
23761
25306
  this.gitHubCopilotPlugin.enable();
23762
25307
  }
25308
+ if (getIntegrationConfig(integrations, "flue") !== false) {
25309
+ this.fluePlugin = new FluePlugin();
25310
+ this.fluePlugin.enable();
25311
+ }
25312
+ if (integrations.langchain !== false && integrations.langgraph !== false) {
25313
+ this.langChainPlugin = new LangChainPlugin();
25314
+ this.langChainPlugin.enable();
25315
+ }
23763
25316
  }
23764
25317
  onDisable() {
23765
25318
  if (this.openaiPlugin) {
@@ -23786,6 +25339,10 @@ var BraintrustPlugin = class extends BasePlugin {
23786
25339
  this.cursorSDKPlugin.disable();
23787
25340
  this.cursorSDKPlugin = null;
23788
25341
  }
25342
+ if (this.openAIAgentsPlugin) {
25343
+ this.openAIAgentsPlugin.disable();
25344
+ this.openAIAgentsPlugin = null;
25345
+ }
23789
25346
  if (this.googleGenAIPlugin) {
23790
25347
  this.googleGenAIPlugin.disable();
23791
25348
  this.googleGenAIPlugin = null;
@@ -23826,6 +25383,14 @@ var BraintrustPlugin = class extends BasePlugin {
23826
25383
  this.gitHubCopilotPlugin.disable();
23827
25384
  this.gitHubCopilotPlugin = null;
23828
25385
  }
25386
+ if (this.fluePlugin) {
25387
+ this.fluePlugin.disable();
25388
+ this.fluePlugin = null;
25389
+ }
25390
+ if (this.langChainPlugin) {
25391
+ this.langChainPlugin.disable();
25392
+ this.langChainPlugin = null;
25393
+ }
23829
25394
  }
23830
25395
  };
23831
25396
 
@@ -23907,50 +25472,16 @@ var PluginRegistry = class {
23907
25472
  * Get default configuration (all integrations enabled).
23908
25473
  */
23909
25474
  getDefaultConfig() {
23910
- return {
23911
- openai: true,
23912
- openaiCodexSDK: true,
23913
- anthropic: true,
23914
- vercel: true,
23915
- aisdk: true,
23916
- google: true,
23917
- googleGenAI: true,
23918
- googleADK: true,
23919
- huggingface: true,
23920
- claudeAgentSDK: true,
23921
- cursor: true,
23922
- cursorSDK: true,
23923
- openrouter: true,
23924
- openrouterAgent: true,
23925
- mistral: true,
23926
- cohere: true,
23927
- groq: true,
23928
- genkit: true,
23929
- gitHubCopilot: true
23930
- };
25475
+ return getDefaultInstrumentationIntegrations();
23931
25476
  }
23932
25477
  /**
23933
25478
  * Read configuration from environment variables.
23934
25479
  * Supports: BRAINTRUST_DISABLE_INSTRUMENTATION=openai,anthropic,...
23935
25480
  */
23936
25481
  readEnvConfig() {
23937
- const integrations = {};
23938
- const disabledList = isomorph_default.getEnv("BRAINTRUST_DISABLE_INSTRUMENTATION");
23939
- if (disabledList) {
23940
- const disabled = disabledList.split(",").map((s) => s.trim().toLowerCase()).filter((s) => s.length > 0);
23941
- for (const sdk of disabled) {
23942
- if (sdk === "cursor-sdk") {
23943
- integrations.cursorSDK = false;
23944
- } else if (sdk === "githubcopilot" || sdk === "github-copilot" || sdk === "copilot-sdk") {
23945
- integrations.gitHubCopilot = false;
23946
- } else if (sdk === "openai-codex-sdk") {
23947
- integrations.openaiCodexSDK = false;
23948
- } else {
23949
- integrations[sdk] = false;
23950
- }
23951
- }
23952
- }
23953
- return { integrations };
25482
+ return readDisabledInstrumentationEnvConfig(
25483
+ isomorph_default.getEnv("BRAINTRUST_DISABLE_INSTRUMENTATION")
25484
+ );
23954
25485
  }
23955
25486
  };
23956
25487
  var registry = new PluginRegistry();
@@ -23959,11 +25490,60 @@ function configureInstrumentation(config) {
23959
25490
  }
23960
25491
 
23961
25492
  // src/node/config.ts
25493
+ var BRAINTRUST_ENV_SEARCH_PARENT_LIMIT = 64;
23962
25494
  function configureNode() {
23963
25495
  isomorph_default.buildType = "node";
23964
25496
  isomorph_default.getRepoInfo = getRepoInfo;
23965
25497
  isomorph_default.getPastNAncestors = getPastNAncestors;
23966
- isomorph_default.getEnv = (name) => process.env[name];
25498
+ isomorph_default.getEnv = (name) => {
25499
+ const value = process.env[name];
25500
+ return name === "BRAINTRUST_API_KEY" && !value?.trim() ? void 0 : value;
25501
+ };
25502
+ isomorph_default.getBraintrustApiKey = async () => {
25503
+ const value = process.env.BRAINTRUST_API_KEY;
25504
+ if (value?.trim()) {
25505
+ return value;
25506
+ }
25507
+ const envPaths = [];
25508
+ for (let dir2 = process.cwd(), depth = 0; depth <= BRAINTRUST_ENV_SEARCH_PARENT_LIMIT; dir2 = path.dirname(dir2), depth++) {
25509
+ envPaths.push(path.join(dir2, ".env.braintrust"));
25510
+ if (path.dirname(dir2) === dir2) {
25511
+ break;
25512
+ }
25513
+ }
25514
+ const pending = /* @__PURE__ */ new Map();
25515
+ envPaths.forEach((envPath, index) => {
25516
+ pending.set(
25517
+ index,
25518
+ fs.readFile(envPath, "utf8").then(
25519
+ (contents) => ({ contents, envPath, index }),
25520
+ (error) => ({ error, envPath, index })
25521
+ )
25522
+ );
25523
+ });
25524
+ const results = [];
25525
+ let nearestUnresolvedIndex = 0;
25526
+ while (pending.size > 0) {
25527
+ const result = await Promise.race(pending.values());
25528
+ pending.delete(result.index);
25529
+ results[result.index] = result;
25530
+ while (results[nearestUnresolvedIndex]) {
25531
+ const nearestResult = results[nearestUnresolvedIndex];
25532
+ if ("contents" in nearestResult) {
25533
+ const parsed = dotenv.parse(nearestResult.contents);
25534
+ const apiKey = parsed.BRAINTRUST_API_KEY;
25535
+ return apiKey?.trim() ? apiKey : void 0;
25536
+ }
25537
+ const e = nearestResult.error;
25538
+ if (typeof e === "object" && e !== null && "code" in e && e.code === "ENOENT") {
25539
+ nearestUnresolvedIndex++;
25540
+ continue;
25541
+ }
25542
+ return void 0;
25543
+ }
25544
+ }
25545
+ return void 0;
25546
+ };
23967
25547
  isomorph_default.getCallerLocation = getCallerLocation;
23968
25548
  isomorph_default.newAsyncLocalStorage = () => new AsyncLocalStorage();
23969
25549
  isomorph_default.newTracingChannel = (nameOrChannels) => diagnostics_channel.tracingChannel(nameOrChannels);
@@ -24003,8 +25583,10 @@ __export(exports_exports, {
24003
25583
  Attachment: () => Attachment,
24004
25584
  AttachmentReference: () => AttachmentReference,
24005
25585
  BRAINTRUST_CURRENT_SPAN_STORE: () => BRAINTRUST_CURRENT_SPAN_STORE,
25586
+ BRAINTRUST_LANGCHAIN_CALLBACK_HANDLER_NAME: () => BRAINTRUST_LANGCHAIN_CALLBACK_HANDLER_NAME,
24006
25587
  BaseAttachment: () => BaseAttachment,
24007
25588
  BaseExperiment: () => BaseExperiment,
25589
+ BraintrustLangChainCallbackHandler: () => BraintrustLangChainCallbackHandler,
24008
25590
  BraintrustMiddleware: () => BraintrustMiddleware,
24009
25591
  BraintrustState: () => BraintrustState,
24010
25592
  BraintrustStream: () => BraintrustStream,
@@ -24015,6 +25597,7 @@ __export(exports_exports, {
24015
25597
  DEFAULT_FETCH_BATCH_SIZE: () => DEFAULT_FETCH_BATCH_SIZE,
24016
25598
  DEFAULT_MAX_REQUEST_SIZE: () => DEFAULT_MAX_REQUEST_SIZE,
24017
25599
  Dataset: () => Dataset2,
25600
+ DatasetPipeline: () => DatasetPipeline,
24018
25601
  ERR_PERMALINK: () => ERR_PERMALINK,
24019
25602
  Eval: () => Eval,
24020
25603
  EvalResultWithSummary: () => EvalResultWithSummary,
@@ -24130,6 +25713,8 @@ __export(exports_exports, {
24130
25713
  wrapCohere: () => wrapCohere,
24131
25714
  wrapCopilotClient: () => wrapCopilotClient,
24132
25715
  wrapCursorSDK: () => wrapCursorSDK,
25716
+ wrapFlueContext: () => wrapFlueContext,
25717
+ wrapFlueSession: () => wrapFlueSession,
24133
25718
  wrapGenkit: () => wrapGenkit,
24134
25719
  wrapGoogleADK: () => wrapGoogleADK,
24135
25720
  wrapGoogleGenAI: () => wrapGoogleGenAI,
@@ -24357,11 +25942,11 @@ function createChannelContext(_channel, params, span_info) {
24357
25942
  span_info
24358
25943
  };
24359
25944
  }
24360
- async function tracePromiseWithResponse(channel2, traceContext, apiPromise) {
25945
+ async function tracePromiseWithResponse(channel, traceContext, apiPromise) {
24361
25946
  let enhancedResponse;
24362
25947
  const tracePromise = (
24363
25948
  // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
24364
- channel2.tracePromise
25949
+ channel.tracePromise
24365
25950
  );
24366
25951
  const data = await tracePromise(async () => {
24367
25952
  enhancedResponse = await apiPromise.withResponse();
@@ -24424,16 +26009,16 @@ function responsesProxy(openai) {
24424
26009
  }
24425
26010
  });
24426
26011
  }
24427
- function wrapResponsesAsync(target, channel2) {
26012
+ function wrapResponsesAsync(target, channel) {
24428
26013
  return (allParams, options) => {
24429
26014
  const { span_info, params } = splitSpanInfo(allParams);
24430
26015
  let executionPromise = null;
24431
26016
  const ensureExecuted = () => {
24432
26017
  if (!executionPromise) {
24433
26018
  executionPromise = (async () => {
24434
- const traceContext = createChannelContext(channel2, params, span_info);
26019
+ const traceContext = createChannelContext(channel, params, span_info);
24435
26020
  const apiPromise = target(params, options);
24436
- return tracePromiseWithResponse(channel2, traceContext, apiPromise);
26021
+ return tracePromiseWithResponse(channel, traceContext, apiPromise);
24437
26022
  })();
24438
26023
  }
24439
26024
  return executionPromise;
@@ -24441,10 +26026,10 @@ function wrapResponsesAsync(target, channel2) {
24441
26026
  return createLazyAPIPromise(ensureExecuted);
24442
26027
  };
24443
26028
  }
24444
- function wrapResponsesSyncStream(target, channel2) {
26029
+ function wrapResponsesSyncStream(target, channel) {
24445
26030
  return (allParams, options) => {
24446
26031
  const { span_info, params } = splitSpanInfo(allParams);
24447
- return channel2.traceSync(() => target(params, options), {
26032
+ return channel.traceSync(() => target(params, options), {
24448
26033
  arguments: [params],
24449
26034
  span_info
24450
26035
  });
@@ -24632,16 +26217,16 @@ function createEndpointProxy(target, wrapperFn) {
24632
26217
  }
24633
26218
  });
24634
26219
  }
24635
- function wrapApiCreateWithChannel(create, channel2) {
26220
+ function wrapApiCreateWithChannel(create, channel) {
24636
26221
  return (allParams, options) => {
24637
26222
  const { span_info, params } = splitSpanInfo(allParams);
24638
26223
  let executionPromise = null;
24639
26224
  const ensureExecuted = () => {
24640
26225
  if (!executionPromise) {
24641
26226
  executionPromise = (async () => {
24642
- const traceContext = createChannelContext(channel2, params, span_info);
26227
+ const traceContext = createChannelContext(channel, params, span_info);
24643
26228
  return tracePromiseWithResponse(
24644
- channel2,
26229
+ channel,
24645
26230
  traceContext,
24646
26231
  create(params, options)
24647
26232
  );
@@ -24763,11 +26348,11 @@ var wrapAgentStream = (stream, instance, options = {}) => {
24763
26348
  options
24764
26349
  )({ ...instance.settings, ...params });
24765
26350
  };
24766
- var makeGenerateTextWrapper = (channel2, name, generateText, contextOptions = {}, options = {}) => {
26351
+ var makeGenerateTextWrapper = (channel, name, generateText, contextOptions = {}, options = {}) => {
24767
26352
  const wrapper = async function(allParams) {
24768
26353
  const { span_info, ...params } = allParams;
24769
26354
  const tracedParams = { ...params };
24770
- return channel2.tracePromise(
26355
+ return channel.tracePromise(
24771
26356
  () => generateText(tracedParams),
24772
26357
  createAISDKChannelContext(tracedParams, {
24773
26358
  aiSDK: contextOptions.aiSDK,
@@ -24801,11 +26386,11 @@ var wrapGenerateObject = (generateObject, options = {}, aiSDK) => {
24801
26386
  options
24802
26387
  );
24803
26388
  };
24804
- var makeEmbedWrapper = (channel2, name, embed, contextOptions = {}, options = {}) => {
26389
+ var makeEmbedWrapper = (channel, name, embed, contextOptions = {}, options = {}) => {
24805
26390
  const wrapper = async function(allParams) {
24806
26391
  const { span_info, ...params } = allParams;
24807
26392
  const tracedParams = { ...params };
24808
- return channel2.tracePromise(
26393
+ return channel.tracePromise(
24809
26394
  () => embed(tracedParams),
24810
26395
  createAISDKChannelContext(tracedParams, {
24811
26396
  aiSDK: contextOptions.aiSDK,
@@ -24862,7 +26447,7 @@ var makeRerankWrapper = (rerank, contextOptions = {}, options = {}) => {
24862
26447
  var wrapRerank = (rerank, options = {}, aiSDK) => {
24863
26448
  return makeRerankWrapper(rerank, { aiSDK }, options);
24864
26449
  };
24865
- var makeStreamWrapper = (channel2, name, streamText, contextOptions = {}, options = {}) => {
26450
+ var makeStreamWrapper = (channel, name, streamText, contextOptions = {}, options = {}) => {
24866
26451
  const wrapper = function(allParams) {
24867
26452
  const { span_info, ...params } = allParams;
24868
26453
  const tracedParams = { ...params };
@@ -24875,7 +26460,7 @@ var makeStreamWrapper = (channel2, name, streamText, contextOptions = {}, option
24875
26460
  spanType: contextOptions.spanType
24876
26461
  })
24877
26462
  });
24878
- return channel2.tracePromise(() => streamText(tracedParams), context);
26463
+ return channel.tracePromise(() => streamText(tracedParams), context);
24879
26464
  };
24880
26465
  Object.defineProperty(wrapper, "name", { value: name, writable: false });
24881
26466
  return wrapper;
@@ -25229,7 +26814,7 @@ function extractModelParameters(params, excludeKeys) {
25229
26814
  }
25230
26815
  return modelParams;
25231
26816
  }
25232
- function getNumberProperty2(obj, key) {
26817
+ function getNumberProperty3(obj, key) {
25233
26818
  if (!obj || typeof obj !== "object" || !(key in obj)) {
25234
26819
  return void 0;
25235
26820
  }
@@ -25238,31 +26823,31 @@ function getNumberProperty2(obj, key) {
25238
26823
  }
25239
26824
  function normalizeUsageMetrics(usage, provider, providerMetadata) {
25240
26825
  const metrics = {};
25241
- const inputTokens = getNumberProperty2(usage, "inputTokens");
26826
+ const inputTokens = getNumberProperty3(usage, "inputTokens");
25242
26827
  if (inputTokens !== void 0) {
25243
26828
  metrics.prompt_tokens = inputTokens;
25244
26829
  }
25245
- const outputTokens = getNumberProperty2(usage, "outputTokens");
26830
+ const outputTokens = getNumberProperty3(usage, "outputTokens");
25246
26831
  if (outputTokens !== void 0) {
25247
26832
  metrics.completion_tokens = outputTokens;
25248
26833
  }
25249
- const totalTokens = getNumberProperty2(usage, "totalTokens");
26834
+ const totalTokens = getNumberProperty3(usage, "totalTokens");
25250
26835
  if (totalTokens !== void 0) {
25251
26836
  metrics.tokens = totalTokens;
25252
26837
  }
25253
- const reasoningTokens = getNumberProperty2(usage, "reasoningTokens");
26838
+ const reasoningTokens = getNumberProperty3(usage, "reasoningTokens");
25254
26839
  if (reasoningTokens !== void 0) {
25255
26840
  metrics.completion_reasoning_tokens = reasoningTokens;
25256
26841
  }
25257
- const cachedInputTokens = getNumberProperty2(usage, "cachedInputTokens");
26842
+ const cachedInputTokens = getNumberProperty3(usage, "cachedInputTokens");
25258
26843
  if (cachedInputTokens !== void 0) {
25259
26844
  metrics.prompt_cached_tokens = cachedInputTokens;
25260
26845
  }
25261
26846
  if (provider === "anthropic") {
25262
26847
  const anthropicMetadata = providerMetadata?.anthropic;
25263
26848
  if (anthropicMetadata) {
25264
- const cacheReadTokens = getNumberProperty2(anthropicMetadata.usage, "cache_read_input_tokens") || 0;
25265
- const cacheCreationTokens = getNumberProperty2(
26849
+ const cacheReadTokens = getNumberProperty3(anthropicMetadata.usage, "cache_read_input_tokens") || 0;
26850
+ const cacheCreationTokens = getNumberProperty3(
25266
26851
  anthropicMetadata.usage,
25267
26852
  "cache_creation_input_tokens"
25268
26853
  ) || 0;
@@ -25585,10 +27170,10 @@ function betaMessagesProxy(messages, anthropic) {
25585
27170
  }
25586
27171
  });
25587
27172
  }
25588
- function createProxy(create, channel2) {
27173
+ function createProxy(create, channel) {
25589
27174
  return new TypedApplyProxy(create, {
25590
27175
  apply(target, thisArg, argArray) {
25591
- return channel2.tracePromise(
27176
+ return channel.tracePromise(
25592
27177
  () => Reflect.apply(target, thisArg, argArray),
25593
27178
  {
25594
27179
  arguments: argArray
@@ -25597,7 +27182,7 @@ function createProxy(create, channel2) {
25597
27182
  }
25598
27183
  });
25599
27184
  }
25600
- function toolRunnerProxy(toolRunner, anthropic, channel2) {
27185
+ function toolRunnerProxy(toolRunner, anthropic, channel) {
25601
27186
  return new TypedApplyProxy(toolRunner, {
25602
27187
  apply(target, thisArg, argArray) {
25603
27188
  const invocationTarget = thisArg && typeof thisArg === "object" ? new Proxy(thisArg, {
@@ -25608,7 +27193,7 @@ function toolRunnerProxy(toolRunner, anthropic, channel2) {
25608
27193
  return Reflect.get(currentTarget, prop, receiver);
25609
27194
  }
25610
27195
  }) : { _client: anthropic };
25611
- return channel2.traceSync(
27196
+ return channel.traceSync(
25612
27197
  () => Reflect.apply(target, invocationTarget, argArray),
25613
27198
  {
25614
27199
  arguments: argArray
@@ -26237,17 +27822,17 @@ function wrapGenkit(genkit) {
26237
27822
  console.warn("Unsupported Genkit object. Not wrapping.");
26238
27823
  return genkit;
26239
27824
  }
26240
- function isRecord(value) {
27825
+ function isRecord2(value) {
26241
27826
  return typeof value === "object" && value !== null;
26242
27827
  }
26243
27828
  function isPropertyBag(value) {
26244
- return isRecord(value) || typeof value === "function";
27829
+ return isRecord2(value) || typeof value === "function";
26245
27830
  }
26246
27831
  function hasFunction(value, methodName) {
26247
27832
  return isPropertyBag(value) && methodName in value && typeof value[methodName] === "function";
26248
27833
  }
26249
27834
  function isGenkitInstance(value) {
26250
- return isRecord(value) && (hasFunction(value, "generate") || hasFunction(value, "generateStream") || hasFunction(value, "defineFlow") || hasFunction(value, "defineTool"));
27835
+ return isRecord2(value) && (hasFunction(value, "generate") || hasFunction(value, "generateStream") || hasFunction(value, "defineFlow") || hasFunction(value, "defineTool"));
26251
27836
  }
26252
27837
  function isGenkitModule(value) {
26253
27838
  return hasFunction(value, "genkit");
@@ -26301,7 +27886,7 @@ function patchGenkitRegistry(instance) {
26301
27886
  patchGenkitRegistryConstructor(registry2);
26302
27887
  }
26303
27888
  function patchGenkitRegistryLookup(registry2) {
26304
- if (!isRecord(registry2) || hasRegistryPatchedFlag(registry2) || !hasFunction(registry2, "lookupAction")) {
27889
+ if (!isRecord2(registry2) || hasRegistryPatchedFlag(registry2) || !hasFunction(registry2, "lookupAction")) {
26305
27890
  return;
26306
27891
  }
26307
27892
  const originalLookupAction = registry2.lookupAction;
@@ -26327,7 +27912,7 @@ function patchGenkitRegistryLookup(registry2) {
26327
27912
  }
26328
27913
  }
26329
27914
  function patchGenkitRegistryConstructor(registry2) {
26330
- if (!isRecord(registry2)) {
27915
+ if (!isRecord2(registry2)) {
26331
27916
  return;
26332
27917
  }
26333
27918
  const constructor = registry2.constructor;
@@ -26343,7 +27928,7 @@ function patchGenkitRegistryConstructor(registry2) {
26343
27928
  configurable: true,
26344
27929
  value: (...args) => {
26345
27930
  const childRegistry = originalWithParent.apply(constructor, args);
26346
- if (args.some((arg) => isRecord(arg) && hasRegistryPatchedFlag(arg))) {
27931
+ if (args.some((arg) => isRecord2(arg) && hasRegistryPatchedFlag(arg))) {
26347
27932
  patchGenkitRegistryLookup(childRegistry);
26348
27933
  patchGenkitRegistryConstructor(childRegistry);
26349
27934
  }
@@ -26442,7 +28027,7 @@ function hasRegistryConstructorPatchedFlag(value) {
26442
28027
  );
26443
28028
  }
26444
28029
  function isPromiseLike2(value) {
26445
- return isRecord(value) && "then" in value && typeof value.then === "function";
28030
+ return isRecord2(value) && "then" in value && typeof value.then === "function";
26446
28031
  }
26447
28032
 
26448
28033
  // src/wrappers/huggingface.ts
@@ -26805,14 +28390,14 @@ function wrapMistral(mistral) {
26805
28390
  console.warn("Unsupported Mistral library. Not wrapping.");
26806
28391
  return mistral;
26807
28392
  }
26808
- function isRecord2(value) {
28393
+ function isRecord3(value) {
26809
28394
  return typeof value === "object" && value !== null;
26810
28395
  }
26811
28396
  function hasFunction3(value, methodName) {
26812
- return isRecord2(value) && methodName in value && typeof value[methodName] === "function";
28397
+ return isRecord3(value) && methodName in value && typeof value[methodName] === "function";
26813
28398
  }
26814
28399
  function isSupportedMistralClient(value) {
26815
- if (!isRecord2(value)) {
28400
+ if (!isRecord3(value)) {
26816
28401
  return false;
26817
28402
  }
26818
28403
  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);
@@ -26996,14 +28581,14 @@ function wrapCohere(cohere) {
26996
28581
  return cohere;
26997
28582
  }
26998
28583
  var cohereProxyCache = /* @__PURE__ */ new WeakMap();
26999
- function isRecord3(value) {
28584
+ function isRecord4(value) {
27000
28585
  return typeof value === "object" && value !== null;
27001
28586
  }
27002
28587
  function hasFunction4(value, methodName) {
27003
- return isRecord3(value) && methodName in value && typeof value[methodName] === "function";
28588
+ return isRecord4(value) && methodName in value && typeof value[methodName] === "function";
27004
28589
  }
27005
28590
  function isSupportedCohereClient(value) {
27006
- if (!isRecord3(value)) {
28591
+ if (!isRecord4(value)) {
27007
28592
  return false;
27008
28593
  }
27009
28594
  return hasFunction4(value, "chat") || hasFunction4(value, "chatStream") || hasFunction4(value, "embed") || hasFunction4(value, "rerank");
@@ -27063,20 +28648,20 @@ function wrapGroq(groq) {
27063
28648
  console.warn("Unsupported Groq library. Not wrapping.");
27064
28649
  return groq;
27065
28650
  }
27066
- function isRecord4(value) {
28651
+ function isRecord5(value) {
27067
28652
  return typeof value === "object" && value !== null;
27068
28653
  }
27069
28654
  function hasFunction5(value, methodName) {
27070
- return isRecord4(value) && methodName in value && typeof value[methodName] === "function";
28655
+ return isRecord5(value) && methodName in value && typeof value[methodName] === "function";
27071
28656
  }
27072
28657
  function hasChat2(value) {
27073
- return isRecord4(value) && isRecord4(value.completions) && hasFunction5(value.completions, "create");
28658
+ return isRecord5(value) && isRecord5(value.completions) && hasFunction5(value.completions, "create");
27074
28659
  }
27075
28660
  function hasEmbeddings2(value) {
27076
28661
  return hasFunction5(value, "create");
27077
28662
  }
27078
28663
  function isSupportedGroqClient(value) {
27079
- return isRecord4(value) && (value.chat !== void 0 && hasChat2(value.chat) || value.embeddings !== void 0 && hasEmbeddings2(value.embeddings));
28664
+ return isRecord5(value) && (value.chat !== void 0 && hasChat2(value.chat) || value.embeddings !== void 0 && hasEmbeddings2(value.embeddings));
27080
28665
  }
27081
28666
  function groqProxy(groq) {
27082
28667
  const privateMethodWorkaroundCache = /* @__PURE__ */ new WeakMap();
@@ -27271,10 +28856,12 @@ function formatExperimentSummary(summary) {
27271
28856
  // src/wrappers/shared/flush.ts
27272
28857
  async function summarizeAndFlush(experiment, options) {
27273
28858
  const shouldDisplay = options.displaySummary ?? true;
27274
- const summary = await experiment.summarize();
27275
- if (shouldDisplay) {
27276
- console.log(formatExperimentSummary(summary));
28859
+ if (!shouldDisplay) {
28860
+ await experiment.flush();
28861
+ return;
27277
28862
  }
28863
+ const summary = await experiment.summarize();
28864
+ console.log(formatExperimentSummary(summary));
27278
28865
  }
27279
28866
 
27280
28867
  // src/wrappers/vitest/flush-manager.ts
@@ -29138,8 +30725,12 @@ var waterfall$1 = awaitify(waterfall);
29138
30725
 
29139
30726
  // src/trace.ts
29140
30727
  var SpanFetcher = class _SpanFetcher extends ObjectFetcher {
29141
- constructor(objectType, _objectId, rootSpanId, _state, spanTypeFilter) {
29142
- const filterExpr = _SpanFetcher.buildFilter(rootSpanId, spanTypeFilter);
30728
+ constructor(objectType, _objectId, rootSpanId, _state, spanTypeFilter, includeScorers = false) {
30729
+ const filterExpr = _SpanFetcher.buildFilter(
30730
+ rootSpanId,
30731
+ spanTypeFilter,
30732
+ includeScorers
30733
+ );
29143
30734
  super(objectType, void 0, void 0, {
29144
30735
  filter: filterExpr
29145
30736
  });
@@ -29148,16 +30739,17 @@ var SpanFetcher = class _SpanFetcher extends ObjectFetcher {
29148
30739
  this._state = _state;
29149
30740
  this.spanTypeFilter = spanTypeFilter;
29150
30741
  }
29151
- static buildFilter(rootSpanId, spanTypeFilter) {
30742
+ static buildFilter(rootSpanId, spanTypeFilter, includeScorers = false) {
29152
30743
  const children = [
29153
30744
  // Base filter: root_span_id = 'value'
29154
30745
  {
29155
30746
  op: "eq",
29156
30747
  left: { op: "ident", name: ["root_span_id"] },
29157
30748
  right: { op: "literal", value: rootSpanId }
29158
- },
29159
- // Exclude span_attributes.purpose = 'score'
29160
- {
30749
+ }
30750
+ ];
30751
+ if (!includeScorers) {
30752
+ children.push({
29161
30753
  op: "or",
29162
30754
  children: [
29163
30755
  {
@@ -29170,8 +30762,8 @@ var SpanFetcher = class _SpanFetcher extends ObjectFetcher {
29170
30762
  right: { op: "literal", value: "scorer" }
29171
30763
  }
29172
30764
  ]
29173
- }
29174
- ];
30765
+ });
30766
+ }
29175
30767
  if (spanTypeFilter && spanTypeFilter.length > 0) {
29176
30768
  children.push({
29177
30769
  op: "in",
@@ -29197,35 +30789,49 @@ var CachedSpanFetcher = class {
29197
30789
  fetchFn;
29198
30790
  constructor(objectTypeOrFetchFn, objectId, rootSpanId, getState) {
29199
30791
  if (typeof objectTypeOrFetchFn === "function") {
29200
- this.fetchFn = objectTypeOrFetchFn;
30792
+ this.fetchFn = (spanType) => objectTypeOrFetchFn(spanType);
29201
30793
  } else {
29202
30794
  const objectType = objectTypeOrFetchFn;
29203
- this.fetchFn = async (spanType) => {
30795
+ this.fetchFn = async (spanType, includeScorers) => {
29204
30796
  const state = await getState();
29205
30797
  const fetcher = new SpanFetcher(
29206
30798
  objectType,
29207
30799
  objectId,
29208
30800
  rootSpanId,
29209
30801
  state,
29210
- spanType
30802
+ spanType,
30803
+ includeScorers
29211
30804
  );
29212
30805
  const rows = await fetcher.fetchedData();
29213
- return rows.filter((row) => row.span_attributes?.purpose !== "scorer").map((row) => ({
30806
+ return rows.map((row) => ({
29214
30807
  input: row.input,
29215
30808
  output: row.output,
30809
+ expected: row.expected,
30810
+ error: row.error,
30811
+ scores: row.scores,
30812
+ metrics: row.metrics,
29216
30813
  metadata: row.metadata,
29217
30814
  span_id: row.span_id,
29218
30815
  span_parents: row.span_parents,
30816
+ is_root: row.is_root,
29219
30817
  span_attributes: row.span_attributes,
29220
30818
  id: row.id,
29221
30819
  _xact_id: row._xact_id,
29222
30820
  _pagination_key: row._pagination_key,
29223
- root_span_id: row.root_span_id
30821
+ root_span_id: row.root_span_id,
30822
+ created: row.created,
30823
+ tags: row.tags
29224
30824
  }));
29225
30825
  };
29226
30826
  }
29227
30827
  }
29228
- async getSpans({ spanType } = {}) {
30828
+ async getSpans({
30829
+ spanType,
30830
+ includeScorers = false
30831
+ } = {}) {
30832
+ if (includeScorers) {
30833
+ return this.fetchFn(spanType, true);
30834
+ }
29229
30835
  if (this.allFetched) {
29230
30836
  return this.getFromCache(spanType);
29231
30837
  }
@@ -29242,7 +30848,7 @@ var CachedSpanFetcher = class {
29242
30848
  return this.getFromCache(spanType);
29243
30849
  }
29244
30850
  async fetchSpans(spanType) {
29245
- const spans = await this.fetchFn(spanType);
30851
+ const spans = await this.fetchFn(spanType, false);
29246
30852
  for (const span of spans) {
29247
30853
  const type = span.span_attributes?.type ?? "";
29248
30854
  const existing = this.spanCache.get(type) ?? [];
@@ -29320,10 +30926,13 @@ var LocalTrace = class {
29320
30926
  * First checks the local span cache for recently logged spans, then falls
29321
30927
  * back to CachedSpanFetcher which handles BTQL fetching and caching.
29322
30928
  */
29323
- async getSpans({ spanType } = {}) {
30929
+ async getSpans({
30930
+ spanType,
30931
+ includeScorers = false
30932
+ } = {}) {
29324
30933
  const cachedSpans = this.state.spanCache.getByRootSpanId(this.rootSpanId);
29325
30934
  if (cachedSpans && cachedSpans.length > 0) {
29326
- let spans = cachedSpans.filter(
30935
+ let spans = includeScorers ? cachedSpans : cachedSpans.filter(
29327
30936
  (span) => span.span_attributes?.purpose !== "scorer"
29328
30937
  );
29329
30938
  if (spanType && spanType.length > 0) {
@@ -29334,13 +30943,19 @@ var LocalTrace = class {
29334
30943
  return spans.map((span) => ({
29335
30944
  input: span.input,
29336
30945
  output: span.output,
30946
+ expected: span.expected,
30947
+ error: span.error,
30948
+ scores: span.scores,
30949
+ metrics: span.metrics,
29337
30950
  metadata: span.metadata,
29338
30951
  span_id: span.span_id,
29339
30952
  span_parents: span.span_parents,
29340
- span_attributes: span.span_attributes
30953
+ is_root: span.is_root,
30954
+ span_attributes: span.span_attributes,
30955
+ tags: span.tags
29341
30956
  }));
29342
30957
  }
29343
- return this.cachedFetcher.getSpans({ spanType });
30958
+ return this.cachedFetcher.getSpans({ spanType, includeScorers });
29344
30959
  }
29345
30960
  /**
29346
30961
  * Get the thread (preprocessed messages) for this trace.
@@ -30529,6 +32144,34 @@ var defaultReporter = {
30529
32144
  }
30530
32145
  };
30531
32146
 
32147
+ // src/dataset-pipeline.ts
32148
+ function DatasetPipeline(definition) {
32149
+ if (!globalThis.__braintrust_dataset_pipelines) {
32150
+ globalThis.__braintrust_dataset_pipelines = [];
32151
+ }
32152
+ const storedDefinition = {
32153
+ name: definition.name,
32154
+ source: {
32155
+ projectId: definition.source.projectId,
32156
+ projectName: definition.source.projectName,
32157
+ orgName: definition.source.orgName,
32158
+ filter: definition.source.filter,
32159
+ scope: definition.source.scope ?? "span"
32160
+ },
32161
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions, @typescript-eslint/no-explicit-any
32162
+ transform: definition.transform,
32163
+ target: {
32164
+ projectId: definition.target.projectId,
32165
+ projectName: definition.target.projectName,
32166
+ orgName: definition.target.orgName,
32167
+ datasetName: definition.target.datasetName,
32168
+ description: definition.target.description,
32169
+ metadata: definition.target.metadata
32170
+ }
32171
+ };
32172
+ globalThis.__braintrust_dataset_pipelines.push(storedDefinition);
32173
+ }
32174
+
30532
32175
  // src/framework2.ts
30533
32176
  import { z as z12 } from "zod/v3";
30534
32177
  var currentFilename = typeof __filename !== "undefined" ? __filename : "unknown";
@@ -31054,8 +32697,10 @@ export {
31054
32697
  Attachment,
31055
32698
  AttachmentReference,
31056
32699
  BRAINTRUST_CURRENT_SPAN_STORE,
32700
+ BRAINTRUST_LANGCHAIN_CALLBACK_HANDLER_NAME,
31057
32701
  BaseAttachment,
31058
32702
  BaseExperiment,
32703
+ BraintrustLangChainCallbackHandler,
31059
32704
  BraintrustMiddleware,
31060
32705
  BraintrustState,
31061
32706
  BraintrustStream,
@@ -31066,6 +32711,7 @@ export {
31066
32711
  DEFAULT_FETCH_BATCH_SIZE,
31067
32712
  DEFAULT_MAX_REQUEST_SIZE,
31068
32713
  Dataset2 as Dataset,
32714
+ DatasetPipeline,
31069
32715
  ERR_PERMALINK,
31070
32716
  Eval,
31071
32717
  EvalResultWithSummary,
@@ -31182,6 +32828,8 @@ export {
31182
32828
  wrapCohere,
31183
32829
  wrapCopilotClient,
31184
32830
  wrapCursorSDK,
32831
+ wrapFlueContext,
32832
+ wrapFlueSession,
31185
32833
  wrapGenkit,
31186
32834
  wrapGoogleADK,
31187
32835
  wrapGoogleGenAI,