braintrust 3.11.0 → 3.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/README.md +8 -8
  2. package/dev/dist/index.d.mts +26 -7
  3. package/dev/dist/index.d.ts +26 -7
  4. package/dev/dist/index.js +2717 -335
  5. package/dev/dist/index.mjs +2499 -117
  6. package/dist/apply-auto-instrumentation.browser.d.mts +2 -0
  7. package/dist/apply-auto-instrumentation.browser.d.ts +2 -0
  8. package/dist/apply-auto-instrumentation.browser.js +18 -0
  9. package/dist/apply-auto-instrumentation.browser.mjs +0 -0
  10. package/dist/apply-auto-instrumentation.d.mts +2 -0
  11. package/dist/apply-auto-instrumentation.d.ts +2 -0
  12. package/dist/apply-auto-instrumentation.js +2534 -0
  13. package/dist/apply-auto-instrumentation.mjs +2534 -0
  14. package/dist/auto-instrumentations/bundler/esbuild.cjs +1803 -1283
  15. package/dist/auto-instrumentations/bundler/esbuild.d.mts +9 -5
  16. package/dist/auto-instrumentations/bundler/esbuild.d.ts +9 -5
  17. package/dist/auto-instrumentations/bundler/esbuild.mjs +10 -2
  18. package/dist/auto-instrumentations/bundler/next.cjs +3269 -0
  19. package/dist/auto-instrumentations/bundler/next.d.mts +3 -0
  20. package/dist/auto-instrumentations/bundler/next.d.ts +3 -0
  21. package/dist/auto-instrumentations/bundler/next.mjs +189 -0
  22. package/dist/auto-instrumentations/bundler/rollup.cjs +1803 -1283
  23. package/dist/auto-instrumentations/bundler/rollup.d.mts +9 -5
  24. package/dist/auto-instrumentations/bundler/rollup.d.ts +9 -5
  25. package/dist/auto-instrumentations/bundler/rollup.mjs +10 -2
  26. package/dist/auto-instrumentations/bundler/vite.cjs +1803 -1283
  27. package/dist/auto-instrumentations/bundler/vite.d.mts +9 -5
  28. package/dist/auto-instrumentations/bundler/vite.d.ts +9 -5
  29. package/dist/auto-instrumentations/bundler/vite.mjs +10 -2
  30. package/dist/auto-instrumentations/bundler/webpack-loader.cjs +1861 -1308
  31. package/dist/auto-instrumentations/bundler/webpack-loader.d.ts +3 -3
  32. package/dist/auto-instrumentations/bundler/webpack.cjs +1803 -1283
  33. package/dist/auto-instrumentations/bundler/webpack.d.mts +9 -5
  34. package/dist/auto-instrumentations/bundler/webpack.d.ts +9 -5
  35. package/dist/auto-instrumentations/bundler/webpack.mjs +6 -6
  36. package/dist/auto-instrumentations/{chunk-DIV5TO4S.mjs → chunk-E5DUYJWK.mjs} +338 -1
  37. package/dist/auto-instrumentations/chunk-GJOO4ESL.mjs +300 -0
  38. package/dist/auto-instrumentations/chunk-WFEUJACP.mjs +18 -0
  39. package/dist/auto-instrumentations/hook.mjs +1713 -1460
  40. package/dist/auto-instrumentations/index.cjs +94 -0
  41. package/dist/auto-instrumentations/index.d.mts +5 -1
  42. package/dist/auto-instrumentations/index.d.ts +5 -1
  43. package/dist/auto-instrumentations/index.mjs +6 -247
  44. package/dist/auto-instrumentations/loader/esm-hook.mjs +19 -2
  45. package/dist/auto-instrumentations/plugin-D7nDswtC.d.mts +44 -0
  46. package/dist/auto-instrumentations/plugin-D7nDswtC.d.ts +44 -0
  47. package/dist/browser.d.mts +264 -47
  48. package/dist/browser.d.ts +264 -47
  49. package/dist/browser.js +2521 -159
  50. package/dist/browser.mjs +2521 -159
  51. package/dist/chunk-26JGOELH.js +817 -0
  52. package/dist/chunk-75IQCUB2.mjs +817 -0
  53. package/dist/cli.js +2510 -122
  54. package/dist/edge-light.d.mts +1 -1
  55. package/dist/edge-light.d.ts +1 -1
  56. package/dist/edge-light.js +2521 -159
  57. package/dist/edge-light.mjs +2521 -159
  58. package/dist/index.d.mts +264 -47
  59. package/dist/index.d.ts +264 -47
  60. package/dist/index.js +3498 -1850
  61. package/dist/index.mjs +2635 -987
  62. package/dist/instrumentation/index.d.mts +7897 -48
  63. package/dist/instrumentation/index.d.ts +7897 -48
  64. package/dist/instrumentation/index.js +2408 -95
  65. package/dist/instrumentation/index.mjs +2407 -95
  66. package/dist/workerd.d.mts +1 -1
  67. package/dist/workerd.d.ts +1 -1
  68. package/dist/workerd.js +2521 -159
  69. package/dist/workerd.mjs +2521 -159
  70. package/package.json +23 -17
  71. package/util/dist/index.d.mts +3 -1
  72. package/util/dist/index.d.ts +3 -1
  73. package/util/dist/index.js +6 -0
  74. package/util/dist/index.mjs +6 -0
  75. package/dist/auto-instrumentations/chunk-G6ZWXGZB.mjs +0 -116
  76. package/dist/auto-instrumentations/plugin-Df3qKIl2.d.mts +0 -22
  77. package/dist/auto-instrumentations/plugin-Df3qKIl2.d.ts +0 -22
package/dist/browser.js CHANGED
@@ -33,8 +33,10 @@ __export(browser_exports, {
33
33
  Attachment: () => Attachment,
34
34
  AttachmentReference: () => AttachmentReference,
35
35
  BRAINTRUST_CURRENT_SPAN_STORE: () => BRAINTRUST_CURRENT_SPAN_STORE,
36
+ BRAINTRUST_LANGCHAIN_CALLBACK_HANDLER_NAME: () => BRAINTRUST_LANGCHAIN_CALLBACK_HANDLER_NAME,
36
37
  BaseAttachment: () => BaseAttachment,
37
38
  BaseExperiment: () => BaseExperiment,
39
+ BraintrustLangChainCallbackHandler: () => BraintrustLangChainCallbackHandler,
38
40
  BraintrustMiddleware: () => BraintrustMiddleware,
39
41
  BraintrustState: () => BraintrustState,
40
42
  BraintrustStream: () => BraintrustStream,
@@ -45,6 +47,7 @@ __export(browser_exports, {
45
47
  DEFAULT_FETCH_BATCH_SIZE: () => DEFAULT_FETCH_BATCH_SIZE,
46
48
  DEFAULT_MAX_REQUEST_SIZE: () => DEFAULT_MAX_REQUEST_SIZE,
47
49
  Dataset: () => Dataset2,
50
+ DatasetPipeline: () => DatasetPipeline,
48
51
  ERR_PERMALINK: () => ERR_PERMALINK,
49
52
  Eval: () => Eval,
50
53
  EvalResultWithSummary: () => EvalResultWithSummary,
@@ -161,6 +164,8 @@ __export(browser_exports, {
161
164
  wrapCohere: () => wrapCohere,
162
165
  wrapCopilotClient: () => wrapCopilotClient,
163
166
  wrapCursorSDK: () => wrapCursorSDK,
167
+ wrapFlueContext: () => wrapFlueContext,
168
+ wrapFlueSession: () => wrapFlueSession,
164
169
  wrapGenkit: () => wrapGenkit,
165
170
  wrapGoogleADK: () => wrapGoogleADK,
166
171
  wrapGoogleGenAI: () => wrapGoogleGenAI,
@@ -266,6 +271,7 @@ var iso = {
266
271
  getRepoInfo: async (_settings) => void 0,
267
272
  getPastNAncestors: async () => [],
268
273
  getEnv: (_name) => void 0,
274
+ getBraintrustApiKey: async () => void 0,
269
275
  getCallerLocation: () => void 0,
270
276
  newAsyncLocalStorage: () => new DefaultAsyncLocalStorage(),
271
277
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -1098,6 +1104,11 @@ function isPromiseLike(value) {
1098
1104
 
1099
1105
  // util/object_util.ts
1100
1106
  var SET_UNION_FIELDS = /* @__PURE__ */ new Set(["tags"]);
1107
+ var FORBIDDEN_MERGE_KEYS = /* @__PURE__ */ new Set([
1108
+ "__proto__",
1109
+ "constructor",
1110
+ "prototype"
1111
+ ]);
1101
1112
  function mergeDictsWithPaths({
1102
1113
  mergeInto,
1103
1114
  mergeFrom,
@@ -1120,6 +1131,7 @@ function mergeDictsWithPathsHelper({
1120
1131
  mergePaths
1121
1132
  }) {
1122
1133
  Object.entries(mergeFrom).forEach(([k, mergeFromV]) => {
1134
+ if (FORBIDDEN_MERGE_KEYS.has(k)) return;
1123
1135
  const fullPath = path.concat([k]);
1124
1136
  const fullPathSerialized = JSON.stringify(fullPath);
1125
1137
  const mergeIntoV = recordFind(mergeInto, k);
@@ -5191,6 +5203,13 @@ var HTTPConnection = class _HTTPConnection {
5191
5203
  debugLogger.debug(
5192
5204
  `Retrying API request ${object_type} ${JSON.stringify(args)} ${e.status} ${e.text}`
5193
5205
  );
5206
+ const sleepTimeS = HTTP_RETRY_BASE_SLEEP_TIME_S * 2 ** i;
5207
+ debugLogger.info(
5208
+ `Sleeping for ${sleepTimeS}s before retrying API request`
5209
+ );
5210
+ await new Promise(
5211
+ (resolve) => setTimeout(resolve, sleepTimeS * 1e3)
5212
+ );
5194
5213
  continue;
5195
5214
  }
5196
5215
  throw e;
@@ -5592,6 +5611,19 @@ var JSONAttachment = class extends Attachment {
5592
5611
  */
5593
5612
  constructor(data, options) {
5594
5613
  const { filename = "data.json", pretty = false, state } = options ?? {};
5614
+ const deferredJsonAttachment = globalThis.__BT_DATASET_PIPELINE_DEFER_JSON_ATTACHMENT__;
5615
+ if (deferredJsonAttachment) {
5616
+ super({
5617
+ data: new Blob([]),
5618
+ filename,
5619
+ contentType: "application/json",
5620
+ state
5621
+ });
5622
+ return deferredJsonAttachment(data, {
5623
+ filename,
5624
+ pretty
5625
+ });
5626
+ }
5595
5627
  const jsonString = pretty ? JSON.stringify(data, null, 2) : JSON.stringify(data);
5596
5628
  const blob = new Blob([jsonString], { type: "application/json" });
5597
5629
  super({
@@ -5840,20 +5872,7 @@ function startSpanParentArgs(args) {
5840
5872
  `Mismatch between expected span parent object type ${args.parentObjectType} and provided type ${parentComponents.data.object_type}`
5841
5873
  );
5842
5874
  }
5843
- const parentComponentsObjectIdLambda = spanComponentsToObjectIdLambda(
5844
- args.state,
5845
- parentComponents
5846
- );
5847
- const computeParentObjectId = async () => {
5848
- const parentComponentsObjectId = await parentComponentsObjectIdLambda();
5849
- if (await args.parentObjectId.get() !== parentComponentsObjectId) {
5850
- throw new Error(
5851
- `Mismatch between expected span parent object id ${await args.parentObjectId.get()} and provided id ${parentComponentsObjectId}`
5852
- );
5853
- }
5854
- return await args.parentObjectId.get();
5855
- };
5856
- argParentObjectId = new LazyValue(computeParentObjectId);
5875
+ argParentObjectId = args.parentObjectId;
5857
5876
  if (parentComponents.data.row_id) {
5858
5877
  argParentSpanIds = {
5859
5878
  spanId: parentComponents.data.span_id,
@@ -6239,6 +6258,7 @@ var TestBackgroundLogger = class {
6239
6258
  }
6240
6259
  };
6241
6260
  var BACKGROUND_LOGGER_BASE_SLEEP_TIME_S = 1;
6261
+ var HTTP_RETRY_BASE_SLEEP_TIME_S = 1;
6242
6262
  var HTTPBackgroundLogger = class _HTTPBackgroundLogger {
6243
6263
  apiConn;
6244
6264
  queue;
@@ -6869,17 +6889,10 @@ function init(projectOrOptions, optionalOptions) {
6869
6889
  if (repoInfo) {
6870
6890
  return repoInfo;
6871
6891
  }
6872
- let mergedGitMetadataSettings = {
6873
- ...state.gitMetadataSettings || {
6874
- collect: "all"
6875
- }
6876
- };
6877
- if (gitMetadataSettings) {
6878
- mergedGitMetadataSettings = mergeGitMetadataSettings(
6879
- mergedGitMetadataSettings,
6880
- gitMetadataSettings
6881
- );
6882
- }
6892
+ const mergedGitMetadataSettings = state.gitMetadataSettings == null ? gitMetadataSettings ?? { collect: "none" } : mergeGitMetadataSettings(
6893
+ state.gitMetadataSettings,
6894
+ gitMetadataSettings ?? { collect: "all" }
6895
+ );
6883
6896
  return await isomorph_default.getRepoInfo(mergedGitMetadataSettings);
6884
6897
  })();
6885
6898
  if (repoInfoArg) {
@@ -7603,10 +7616,11 @@ async function login(options = {}) {
7603
7616
  async function loginToState(options = {}) {
7604
7617
  const {
7605
7618
  appUrl = isomorph_default.getEnv("BRAINTRUST_APP_URL") || "https://www.braintrust.dev",
7606
- apiKey = isomorph_default.getEnv("BRAINTRUST_API_KEY"),
7619
+ apiKey: apiKeyArg,
7607
7620
  orgName = isomorph_default.getEnv("BRAINTRUST_ORG_NAME"),
7608
7621
  fetch: fetch2 = globalThis.fetch
7609
7622
  } = options || {};
7623
+ const apiKey = apiKeyArg !== void 0 ? apiKeyArg : await isomorph_default.getBraintrustApiKey();
7610
7624
  const appPublicUrl = isomorph_default.getEnv("BRAINTRUST_APP_PUBLIC_URL") || appUrl;
7611
7625
  const state = new BraintrustState(options);
7612
7626
  state.resetLoginInfo();
@@ -8847,9 +8861,15 @@ var SpanImpl = class _SpanImpl {
8847
8861
  const cachedSpan = {
8848
8862
  input: partialRecord.input,
8849
8863
  output: partialRecord.output,
8864
+ expected: partialRecord.expected,
8865
+ error: partialRecord.error,
8866
+ scores: partialRecord.scores,
8867
+ metrics: partialRecord.metrics,
8850
8868
  metadata: partialRecord.metadata,
8869
+ tags: partialRecord.tags,
8851
8870
  span_id: this._spanId,
8852
8871
  span_parents: this._spanParents,
8872
+ is_root: this._spanId === this._rootSpanId,
8853
8873
  span_attributes: partialRecord.span_attributes
8854
8874
  };
8855
8875
  this._state.spanCache.queueWrite(
@@ -9185,6 +9205,7 @@ var Dataset2 = class extends ObjectFetcher {
9185
9205
  metadata,
9186
9206
  tags,
9187
9207
  output,
9208
+ origin,
9188
9209
  isMerge
9189
9210
  }) {
9190
9211
  return new LazyValue(async () => {
@@ -9199,6 +9220,7 @@ var Dataset2 = class extends ObjectFetcher {
9199
9220
  created: !isMerge ? (/* @__PURE__ */ new Date()).toISOString() : void 0,
9200
9221
  //if we're merging/updating an event we will not add this ts
9201
9222
  metadata,
9223
+ origin,
9202
9224
  ...!!isMerge ? {
9203
9225
  [IS_MERGE_FIELD]: true
9204
9226
  } : {}
@@ -9218,6 +9240,7 @@ var Dataset2 = class extends ObjectFetcher {
9218
9240
  * about anything else that's relevant, that you can use to help find and analyze examples later. For example, you could log the
9219
9241
  * `prompt`, example's `id`, or anything else that would be useful to slice/dice later. The values in `metadata` can be any
9220
9242
  * JSON-serializable type, but its keys must be strings.
9243
+ * @param event.origin (Optional) a reference to the source object this dataset record was derived from.
9221
9244
  * @param event.id (Optional) a unique identifier for the event. If you don't provide one, Braintrust will generate one for you.
9222
9245
  * @param event.output: (Deprecated) The output of your application. Use `expected` instead.
9223
9246
  * @returns The `id` of the logged record.
@@ -9228,7 +9251,8 @@ var Dataset2 = class extends ObjectFetcher {
9228
9251
  metadata,
9229
9252
  tags,
9230
9253
  id,
9231
- output
9254
+ output,
9255
+ origin
9232
9256
  }) {
9233
9257
  this.validateEvent({ metadata, expected, output, tags });
9234
9258
  const rowId = id || (0, import_uuid2.v4)();
@@ -9240,6 +9264,7 @@ var Dataset2 = class extends ObjectFetcher {
9240
9264
  metadata,
9241
9265
  tags,
9242
9266
  output,
9267
+ origin,
9243
9268
  isMerge: false
9244
9269
  })
9245
9270
  );
@@ -13575,11 +13600,11 @@ function resolveDenyOutputPaths(event, defaultDenyOutputPaths) {
13575
13600
  if (Array.isArray(event?.denyOutputPaths)) {
13576
13601
  return event.denyOutputPaths;
13577
13602
  }
13578
- const firstArgument = event?.arguments && event.arguments.length > 0 ? event.arguments[0] : void 0;
13579
- if (!firstArgument || typeof firstArgument !== "object") {
13603
+ const firstArgument2 = event?.arguments && event.arguments.length > 0 ? event.arguments[0] : void 0;
13604
+ if (!firstArgument2 || typeof firstArgument2 !== "object") {
13580
13605
  return defaultDenyOutputPaths;
13581
13606
  }
13582
- const runtimeDenyOutputPaths = firstArgument[RUNTIME_DENY_OUTPUT_PATHS];
13607
+ const runtimeDenyOutputPaths = firstArgument2[RUNTIME_DENY_OUTPUT_PATHS];
13583
13608
  if (Array.isArray(runtimeDenyOutputPaths) && runtimeDenyOutputPaths.every((path) => typeof path === "string")) {
13584
13609
  return runtimeDenyOutputPaths;
13585
13610
  }
@@ -17238,6 +17263,467 @@ function cleanMetrics2(metrics) {
17238
17263
  return cleaned;
17239
17264
  }
17240
17265
 
17266
+ // src/instrumentation/plugins/openai-agents-channels.ts
17267
+ var openAIAgentsCoreChannels = defineChannels("@openai/agents-core", {
17268
+ onTraceStart: channel({
17269
+ channelName: "tracing.processor.onTraceStart",
17270
+ kind: "async"
17271
+ }),
17272
+ onTraceEnd: channel({
17273
+ channelName: "tracing.processor.onTraceEnd",
17274
+ kind: "async"
17275
+ }),
17276
+ onSpanStart: channel({
17277
+ channelName: "tracing.processor.onSpanStart",
17278
+ kind: "async"
17279
+ }),
17280
+ onSpanEnd: channel({
17281
+ channelName: "tracing.processor.onSpanEnd",
17282
+ kind: "async"
17283
+ })
17284
+ });
17285
+
17286
+ // src/instrumentation/plugins/openai-agents-trace-processor.ts
17287
+ function isSpanData(spanData, type) {
17288
+ return spanData.type === type;
17289
+ }
17290
+ function spanTypeFromAgents(span) {
17291
+ const spanType = span.spanData.type;
17292
+ if (spanType === "function" || spanType === "guardrail" || spanType === "mcp_tools") {
17293
+ return "tool" /* TOOL */;
17294
+ }
17295
+ if (spanType === "generation" || spanType === "response" || spanType === "transcription" || spanType === "speech") {
17296
+ return "llm" /* LLM */;
17297
+ }
17298
+ return "task" /* TASK */;
17299
+ }
17300
+ function spanNameFromAgents(span) {
17301
+ const spanData = span.spanData;
17302
+ if ("name" in spanData && spanData.name) {
17303
+ return spanData.name;
17304
+ }
17305
+ switch (spanData.type) {
17306
+ case "generation":
17307
+ return "Generation";
17308
+ case "response":
17309
+ return "Response";
17310
+ case "handoff":
17311
+ return "Handoff";
17312
+ case "mcp_tools":
17313
+ return isSpanData(spanData, "mcp_tools") && spanData.server ? `List Tools (${spanData.server})` : "MCP List Tools";
17314
+ case "transcription":
17315
+ return "Transcription";
17316
+ case "speech":
17317
+ return "Speech";
17318
+ case "speech_group":
17319
+ return "Speech Group";
17320
+ default:
17321
+ return "Unknown";
17322
+ }
17323
+ }
17324
+ function getTimeElapsed(end, start) {
17325
+ if (!start || !end) {
17326
+ return void 0;
17327
+ }
17328
+ const startTime = new Date(start).getTime();
17329
+ const endTime = new Date(end).getTime();
17330
+ if (Number.isNaN(startTime) || Number.isNaN(endTime)) {
17331
+ return void 0;
17332
+ }
17333
+ return (endTime - startTime) / 1e3;
17334
+ }
17335
+ function getNumberProperty2(obj, key) {
17336
+ if (!isObject(obj) || !(key in obj)) {
17337
+ return void 0;
17338
+ }
17339
+ const value = obj[key];
17340
+ return typeof value === "number" ? value : void 0;
17341
+ }
17342
+ function parseUsageMetrics(usage) {
17343
+ const metrics = {};
17344
+ if (!isObject(usage)) {
17345
+ return metrics;
17346
+ }
17347
+ const promptTokens = getNumberProperty2(usage, "prompt_tokens") ?? getNumberProperty2(usage, "input_tokens") ?? getNumberProperty2(usage, "promptTokens") ?? getNumberProperty2(usage, "inputTokens");
17348
+ const completionTokens = getNumberProperty2(usage, "completion_tokens") ?? getNumberProperty2(usage, "output_tokens") ?? getNumberProperty2(usage, "completionTokens") ?? getNumberProperty2(usage, "outputTokens");
17349
+ const totalTokens = getNumberProperty2(usage, "total_tokens") ?? getNumberProperty2(usage, "totalTokens");
17350
+ if (promptTokens !== void 0) {
17351
+ metrics.prompt_tokens = promptTokens;
17352
+ }
17353
+ if (completionTokens !== void 0) {
17354
+ metrics.completion_tokens = completionTokens;
17355
+ }
17356
+ if (totalTokens !== void 0) {
17357
+ metrics.tokens = totalTokens;
17358
+ } else if (promptTokens !== void 0 && completionTokens !== void 0) {
17359
+ metrics.tokens = promptTokens + completionTokens;
17360
+ }
17361
+ const inputDetails = usage.input_tokens_details;
17362
+ const cachedTokens = getNumberProperty2(inputDetails, "cached_tokens");
17363
+ const cacheWriteTokens = getNumberProperty2(
17364
+ inputDetails,
17365
+ "cache_write_tokens"
17366
+ );
17367
+ if (cachedTokens !== void 0) {
17368
+ metrics.prompt_cached_tokens = cachedTokens;
17369
+ }
17370
+ if (cacheWriteTokens !== void 0) {
17371
+ metrics.prompt_cache_creation_tokens = cacheWriteTokens;
17372
+ }
17373
+ return metrics;
17374
+ }
17375
+ var OpenAIAgentsTraceProcessor = class _OpenAIAgentsTraceProcessor {
17376
+ static DEFAULT_MAX_TRACES = 1e4;
17377
+ logger;
17378
+ maxTraces;
17379
+ traceSpans = /* @__PURE__ */ new Map();
17380
+ traceOrder = [];
17381
+ _traceSpans = this.traceSpans;
17382
+ constructor(options = {}) {
17383
+ this.logger = options.logger;
17384
+ this.maxTraces = options.maxTraces ?? _OpenAIAgentsTraceProcessor.DEFAULT_MAX_TRACES;
17385
+ }
17386
+ evictOldestTrace() {
17387
+ const oldestTraceId = this.traceOrder.shift();
17388
+ if (oldestTraceId) {
17389
+ this.traceSpans.delete(oldestTraceId);
17390
+ }
17391
+ }
17392
+ onTraceStart(trace) {
17393
+ if (!trace?.traceId) {
17394
+ return Promise.resolve();
17395
+ }
17396
+ if (this.traceOrder.length >= this.maxTraces) {
17397
+ this.evictOldestTrace();
17398
+ }
17399
+ const current = currentSpan();
17400
+ const span = current && current !== NOOP_SPAN ? current.startSpan({
17401
+ name: trace.name,
17402
+ type: "task" /* TASK */
17403
+ }) : this.logger ? this.logger.startSpan({
17404
+ name: trace.name,
17405
+ type: "task" /* TASK */
17406
+ }) : startSpan({
17407
+ name: trace.name,
17408
+ type: "task" /* TASK */
17409
+ });
17410
+ span.log({
17411
+ input: "Agent workflow started",
17412
+ metadata: {
17413
+ group_id: trace.groupId,
17414
+ ...trace.metadata || {}
17415
+ }
17416
+ });
17417
+ this.traceSpans.set(trace.traceId, {
17418
+ rootSpan: span,
17419
+ childSpans: /* @__PURE__ */ new Map(),
17420
+ metadata: {
17421
+ firstInput: null,
17422
+ lastOutput: null
17423
+ }
17424
+ });
17425
+ this.traceOrder.push(trace.traceId);
17426
+ return Promise.resolve();
17427
+ }
17428
+ async onTraceEnd(trace) {
17429
+ const traceData = this.traceSpans.get(trace?.traceId);
17430
+ if (!traceData) {
17431
+ return;
17432
+ }
17433
+ try {
17434
+ traceData.rootSpan.log({
17435
+ input: traceData.metadata.firstInput,
17436
+ output: traceData.metadata.lastOutput
17437
+ });
17438
+ traceData.rootSpan.end();
17439
+ await traceData.rootSpan.flush();
17440
+ } finally {
17441
+ this.traceSpans.delete(trace.traceId);
17442
+ const orderIndex = this.traceOrder.indexOf(trace.traceId);
17443
+ if (orderIndex > -1) {
17444
+ this.traceOrder.splice(orderIndex, 1);
17445
+ }
17446
+ }
17447
+ }
17448
+ onSpanStart(span) {
17449
+ if (!span?.spanId || !span.traceId) {
17450
+ return Promise.resolve();
17451
+ }
17452
+ const traceData = this.traceSpans.get(span.traceId);
17453
+ if (!traceData) {
17454
+ return Promise.resolve();
17455
+ }
17456
+ const parentSpan = span.parentId ? traceData.childSpans.get(span.parentId) : traceData.rootSpan;
17457
+ if (!parentSpan) {
17458
+ return Promise.resolve();
17459
+ }
17460
+ const childSpan = parentSpan.startSpan({
17461
+ name: spanNameFromAgents(span),
17462
+ type: spanTypeFromAgents(span)
17463
+ });
17464
+ traceData.childSpans.set(span.spanId, childSpan);
17465
+ return Promise.resolve();
17466
+ }
17467
+ onSpanEnd(span) {
17468
+ if (!span?.spanId || !span.traceId) {
17469
+ return Promise.resolve();
17470
+ }
17471
+ const traceData = this.traceSpans.get(span.traceId);
17472
+ if (!traceData) {
17473
+ return Promise.resolve();
17474
+ }
17475
+ const braintrustSpan = traceData.childSpans.get(span.spanId);
17476
+ if (!braintrustSpan) {
17477
+ return Promise.resolve();
17478
+ }
17479
+ const logData = this.extractLogData(span);
17480
+ braintrustSpan.log({
17481
+ error: span.error,
17482
+ ...logData
17483
+ });
17484
+ braintrustSpan.end();
17485
+ traceData.childSpans.delete(span.spanId);
17486
+ const input = logData.input;
17487
+ const output = logData.output;
17488
+ if (traceData.metadata.firstInput === null && input != null) {
17489
+ traceData.metadata.firstInput = input;
17490
+ }
17491
+ if (output != null) {
17492
+ traceData.metadata.lastOutput = output;
17493
+ }
17494
+ return Promise.resolve();
17495
+ }
17496
+ async shutdown() {
17497
+ if (this.logger && typeof this.logger.flush === "function") {
17498
+ await this.logger.flush();
17499
+ }
17500
+ }
17501
+ async forceFlush() {
17502
+ if (this.logger && typeof this.logger.flush === "function") {
17503
+ await this.logger.flush();
17504
+ }
17505
+ }
17506
+ extractLogData(span) {
17507
+ const spanData = span.spanData;
17508
+ switch (spanData.type) {
17509
+ case "agent":
17510
+ return this.extractAgentLogData(spanData);
17511
+ case "response":
17512
+ return this.extractResponseLogData(spanData, span);
17513
+ case "function":
17514
+ return this.extractFunctionLogData(spanData);
17515
+ case "handoff":
17516
+ return this.extractHandoffLogData(spanData);
17517
+ case "guardrail":
17518
+ return this.extractGuardrailLogData(spanData);
17519
+ case "generation":
17520
+ return this.extractGenerationLogData(spanData, span);
17521
+ case "custom":
17522
+ return this.extractCustomLogData(spanData);
17523
+ case "mcp_tools":
17524
+ return this.extractMCPListToolsLogData(spanData);
17525
+ case "transcription":
17526
+ return this.extractTranscriptionLogData(spanData);
17527
+ case "speech":
17528
+ return this.extractSpeechLogData(spanData);
17529
+ case "speech_group":
17530
+ return this.extractSpeechGroupLogData(spanData);
17531
+ default:
17532
+ return {};
17533
+ }
17534
+ }
17535
+ extractAgentLogData(spanData) {
17536
+ return {
17537
+ metadata: {
17538
+ tools: spanData.tools,
17539
+ handoffs: spanData.handoffs,
17540
+ output_type: spanData.output_type
17541
+ }
17542
+ };
17543
+ }
17544
+ extractResponseLogData(spanData, span) {
17545
+ const response = spanData._response;
17546
+ const output = isObject(response) ? response.output : void 0;
17547
+ const usage = isObject(response) ? response.usage : void 0;
17548
+ const metrics = {
17549
+ ...this.extractTimingMetrics(span),
17550
+ ...parseUsageMetrics(usage)
17551
+ };
17552
+ return {
17553
+ input: spanData._input,
17554
+ output,
17555
+ metadata: isObject(response) ? this.omitKeys(response, ["output", "usage"]) : {},
17556
+ metrics
17557
+ };
17558
+ }
17559
+ extractFunctionLogData(spanData) {
17560
+ return {
17561
+ input: spanData.input,
17562
+ output: spanData.output
17563
+ };
17564
+ }
17565
+ extractHandoffLogData(spanData) {
17566
+ return {
17567
+ metadata: {
17568
+ from_agent: spanData.from_agent,
17569
+ to_agent: spanData.to_agent
17570
+ }
17571
+ };
17572
+ }
17573
+ extractGuardrailLogData(spanData) {
17574
+ return {
17575
+ metadata: {
17576
+ triggered: spanData.triggered
17577
+ }
17578
+ };
17579
+ }
17580
+ extractGenerationLogData(spanData, span) {
17581
+ return {
17582
+ input: spanData.input,
17583
+ output: spanData.output,
17584
+ metadata: {
17585
+ model: spanData.model,
17586
+ model_config: spanData.model_config
17587
+ },
17588
+ metrics: {
17589
+ ...this.extractTimingMetrics(span),
17590
+ ...parseUsageMetrics(spanData.usage)
17591
+ }
17592
+ };
17593
+ }
17594
+ extractCustomLogData(spanData) {
17595
+ return spanData.data || {};
17596
+ }
17597
+ extractMCPListToolsLogData(spanData) {
17598
+ return {
17599
+ output: spanData.result,
17600
+ metadata: {
17601
+ server: spanData.server
17602
+ }
17603
+ };
17604
+ }
17605
+ extractTranscriptionLogData(spanData) {
17606
+ return {
17607
+ input: spanData.input,
17608
+ output: spanData.output,
17609
+ metadata: {
17610
+ model: spanData.model,
17611
+ model_config: spanData.model_config
17612
+ }
17613
+ };
17614
+ }
17615
+ extractSpeechLogData(spanData) {
17616
+ return {
17617
+ input: spanData.input,
17618
+ output: spanData.output,
17619
+ metadata: {
17620
+ model: spanData.model,
17621
+ model_config: spanData.model_config
17622
+ }
17623
+ };
17624
+ }
17625
+ extractSpeechGroupLogData(spanData) {
17626
+ return {
17627
+ input: spanData.input
17628
+ };
17629
+ }
17630
+ extractTimingMetrics(span) {
17631
+ const timeToFirstToken = getTimeElapsed(
17632
+ span.endedAt ?? void 0,
17633
+ span.startedAt ?? void 0
17634
+ );
17635
+ return timeToFirstToken === void 0 ? {} : { time_to_first_token: timeToFirstToken };
17636
+ }
17637
+ omitKeys(value, keys) {
17638
+ const result = {};
17639
+ for (const [key, fieldValue] of Object.entries(value)) {
17640
+ if (!keys.includes(key)) {
17641
+ result[key] = fieldValue;
17642
+ }
17643
+ }
17644
+ return result;
17645
+ }
17646
+ };
17647
+
17648
+ // src/instrumentation/plugins/openai-agents-plugin.ts
17649
+ function firstArgument(args) {
17650
+ if (Array.isArray(args)) {
17651
+ return args[0];
17652
+ }
17653
+ if (isObject(args) && "length" in args && typeof args.length === "number" && Number.isInteger(args.length) && args.length >= 0) {
17654
+ return Array.from(args)[0];
17655
+ }
17656
+ return void 0;
17657
+ }
17658
+ function isOpenAIAgentsTrace(value) {
17659
+ return isObject(value) && value.type === "trace" && typeof value.traceId === "string";
17660
+ }
17661
+ function isOpenAIAgentsSpan(value) {
17662
+ return isObject(value) && value.type === "trace.span" && typeof value.traceId === "string" && typeof value.spanId === "string";
17663
+ }
17664
+ var OpenAIAgentsPlugin = class extends BasePlugin {
17665
+ processor = new OpenAIAgentsTraceProcessor();
17666
+ onEnable() {
17667
+ this.subscribeToTraceLifecycle();
17668
+ }
17669
+ onDisable() {
17670
+ this.unsubscribers = unsubscribeAll(this.unsubscribers);
17671
+ void this.processor.shutdown();
17672
+ }
17673
+ subscribeToTraceLifecycle() {
17674
+ const traceStartChannel = openAIAgentsCoreChannels.onTraceStart.tracingChannel();
17675
+ const traceStartHandlers = {
17676
+ start: (event) => {
17677
+ const trace = firstArgument(event.arguments);
17678
+ if (isOpenAIAgentsTrace(trace)) {
17679
+ void this.processor.onTraceStart(trace);
17680
+ }
17681
+ }
17682
+ };
17683
+ traceStartChannel.subscribe(traceStartHandlers);
17684
+ this.unsubscribers.push(
17685
+ () => traceStartChannel.unsubscribe(traceStartHandlers)
17686
+ );
17687
+ const traceEndChannel = openAIAgentsCoreChannels.onTraceEnd.tracingChannel();
17688
+ const traceEndHandlers = {
17689
+ start: (event) => {
17690
+ const trace = firstArgument(event.arguments);
17691
+ if (isOpenAIAgentsTrace(trace)) {
17692
+ void this.processor.onTraceEnd(trace);
17693
+ }
17694
+ }
17695
+ };
17696
+ traceEndChannel.subscribe(traceEndHandlers);
17697
+ this.unsubscribers.push(
17698
+ () => traceEndChannel.unsubscribe(traceEndHandlers)
17699
+ );
17700
+ const spanStartChannel = openAIAgentsCoreChannels.onSpanStart.tracingChannel();
17701
+ const spanStartHandlers = {
17702
+ start: (event) => {
17703
+ const span = firstArgument(event.arguments);
17704
+ if (isOpenAIAgentsSpan(span)) {
17705
+ void this.processor.onSpanStart(span);
17706
+ }
17707
+ }
17708
+ };
17709
+ spanStartChannel.subscribe(spanStartHandlers);
17710
+ this.unsubscribers.push(
17711
+ () => spanStartChannel.unsubscribe(spanStartHandlers)
17712
+ );
17713
+ const spanEndChannel = openAIAgentsCoreChannels.onSpanEnd.tracingChannel();
17714
+ const spanEndHandlers = {
17715
+ start: (event) => {
17716
+ const span = firstArgument(event.arguments);
17717
+ if (isOpenAIAgentsSpan(span)) {
17718
+ void this.processor.onSpanEnd(span);
17719
+ }
17720
+ }
17721
+ };
17722
+ spanEndChannel.subscribe(spanEndHandlers);
17723
+ this.unsubscribers.push(() => spanEndChannel.unsubscribe(spanEndHandlers));
17724
+ }
17725
+ };
17726
+
17241
17727
  // src/instrumentation/plugins/google-genai-channels.ts
17242
17728
  var googleGenAIChannels = defineChannels("@google/genai", {
17243
17729
  generateContent: channel({
@@ -23530,58 +24016,1794 @@ var GitHubCopilotPlugin = class extends BasePlugin {
23530
24016
  }
23531
24017
  };
23532
24018
 
23533
- // src/instrumentation/braintrust-plugin.ts
23534
- function getIntegrationConfig(integrations, key) {
23535
- return integrations[key];
24019
+ // src/instrumentation/plugins/flue-channels.ts
24020
+ var flueChannels = defineChannels("@flue/runtime", {
24021
+ createContext: channel({
24022
+ channelName: "createFlueContext",
24023
+ kind: "sync-stream"
24024
+ }),
24025
+ openSession: channel({
24026
+ channelName: "Harness.openSession",
24027
+ kind: "async"
24028
+ }),
24029
+ contextEvent: channel({
24030
+ channelName: "context.event",
24031
+ kind: "sync-stream"
24032
+ }),
24033
+ prompt: channel({
24034
+ channelName: "session.prompt",
24035
+ kind: "async"
24036
+ }),
24037
+ skill: channel({
24038
+ channelName: "session.skill",
24039
+ kind: "async"
24040
+ }),
24041
+ task: channel({
24042
+ channelName: "session.task",
24043
+ kind: "async"
24044
+ }),
24045
+ compact: channel({
24046
+ channelName: "session.compact",
24047
+ kind: "async"
24048
+ })
24049
+ });
24050
+
24051
+ // src/wrappers/flue.ts
24052
+ var WRAPPED_FLUE_CONTEXT = /* @__PURE__ */ Symbol.for("braintrust.flue.wrapped-context");
24053
+ var WRAPPED_FLUE_HARNESS = /* @__PURE__ */ Symbol.for("braintrust.flue.wrapped-harness");
24054
+ var WRAPPED_FLUE_SESSION = /* @__PURE__ */ Symbol.for("braintrust.flue.wrapped-session");
24055
+ var SUBSCRIBED_FLUE_CONTEXT_EVENTS = /* @__PURE__ */ Symbol.for(
24056
+ "braintrust.flue.subscribed-context-events"
24057
+ );
24058
+ function wrapFlueContext(ctx) {
24059
+ if (!isPlausibleFlueContext(ctx)) {
24060
+ console.warn("Unsupported Flue context. Not wrapping.");
24061
+ return ctx;
24062
+ }
24063
+ const context = ctx;
24064
+ subscribeFlueContextEvents(context, { captureTurnSpans: true });
24065
+ return patchFlueContextInPlace(context);
23536
24066
  }
23537
- var BraintrustPlugin = class extends BasePlugin {
23538
- config;
23539
- openaiPlugin = null;
23540
- openAICodexPlugin = null;
23541
- anthropicPlugin = null;
23542
- aiSDKPlugin = null;
23543
- claudeAgentSDKPlugin = null;
23544
- cursorSDKPlugin = null;
23545
- googleGenAIPlugin = null;
23546
- huggingFacePlugin = null;
23547
- openRouterPlugin = null;
23548
- openRouterAgentPlugin = null;
23549
- mistralPlugin = null;
23550
- googleADKPlugin = null;
23551
- coherePlugin = null;
23552
- groqPlugin = null;
23553
- genkitPlugin = null;
23554
- gitHubCopilotPlugin = null;
23555
- constructor(config = {}) {
23556
- super();
23557
- this.config = config;
24067
+ function patchFlueContextInPlace(ctx) {
24068
+ const context = ctx;
24069
+ if (context[WRAPPED_FLUE_CONTEXT]) {
24070
+ return ctx;
23558
24071
  }
23559
- onEnable() {
23560
- const integrations = this.config.integrations || {};
23561
- if (integrations.openai !== false) {
23562
- this.openaiPlugin = new OpenAIPlugin();
23563
- this.openaiPlugin.enable();
23564
- }
23565
- if (integrations.openaiCodexSDK !== false) {
23566
- this.openAICodexPlugin = new OpenAICodexPlugin();
23567
- this.openAICodexPlugin.enable();
23568
- }
23569
- if (integrations.anthropic !== false) {
23570
- this.anthropicPlugin = new AnthropicPlugin();
23571
- this.anthropicPlugin.enable();
23572
- }
23573
- if (integrations.aisdk !== false && integrations.vercel !== false) {
23574
- this.aiSDKPlugin = new AISDKPlugin();
23575
- this.aiSDKPlugin.enable();
23576
- }
23577
- if (integrations.claudeAgentSDK !== false) {
23578
- this.claudeAgentSDKPlugin = new ClaudeAgentSDKPlugin();
24072
+ const originalInit = context.init.bind(context);
24073
+ try {
24074
+ Object.defineProperty(context, WRAPPED_FLUE_CONTEXT, {
24075
+ configurable: false,
24076
+ enumerable: false,
24077
+ value: true
24078
+ });
24079
+ Object.defineProperty(context, "init", {
24080
+ configurable: true,
24081
+ value: async function wrappedFlueInit(options) {
24082
+ const harness = await originalInit(options);
24083
+ return wrapFlueHarness(harness);
24084
+ },
24085
+ writable: true
24086
+ });
24087
+ } catch {
24088
+ }
24089
+ return ctx;
24090
+ }
24091
+ function wrapFlueSession(session) {
24092
+ if (!isPlausibleFlueSession(session)) {
24093
+ console.warn("Unsupported Flue session. Not wrapping.");
24094
+ return session;
24095
+ }
24096
+ return patchFlueSessionInPlace(session);
24097
+ }
24098
+ function subscribeFlueContextEvents(ctx, options = {}) {
24099
+ if (!ctx || typeof ctx !== "object" || typeof ctx.subscribeEvent !== "function") {
24100
+ return void 0;
24101
+ }
24102
+ const context = ctx;
24103
+ const captureTurnSpans = options.captureTurnSpans ?? true;
24104
+ const existingSubscription = context[SUBSCRIBED_FLUE_CONTEXT_EVENTS];
24105
+ if (existingSubscription) {
24106
+ if (existingSubscription.captureTurnSpans || !captureTurnSpans) {
24107
+ return void 0;
24108
+ }
24109
+ try {
24110
+ existingSubscription.unsubscribe();
24111
+ } catch {
24112
+ }
24113
+ }
24114
+ try {
24115
+ const unsubscribe = ctx.subscribeEvent((event) => {
24116
+ flueChannels.contextEvent.traceSync(() => void 0, {
24117
+ arguments: [event],
24118
+ captureTurnSpans,
24119
+ context: ctx
24120
+ });
24121
+ });
24122
+ if (existingSubscription) {
24123
+ existingSubscription.captureTurnSpans = captureTurnSpans;
24124
+ existingSubscription.unsubscribe = unsubscribe;
24125
+ } else {
24126
+ Object.defineProperty(context, SUBSCRIBED_FLUE_CONTEXT_EVENTS, {
24127
+ configurable: false,
24128
+ enumerable: false,
24129
+ value: {
24130
+ captureTurnSpans,
24131
+ unsubscribe
24132
+ }
24133
+ });
24134
+ }
24135
+ return unsubscribe;
24136
+ } catch {
24137
+ return void 0;
24138
+ }
24139
+ }
24140
+ function wrapFlueHarness(harness) {
24141
+ if (!isPlausibleFlueHarness(harness)) {
24142
+ return harness;
24143
+ }
24144
+ const target = harness;
24145
+ if (target[WRAPPED_FLUE_HARNESS]) {
24146
+ return harness;
24147
+ }
24148
+ const originalSession = target.session.bind(target);
24149
+ try {
24150
+ Object.defineProperty(target, WRAPPED_FLUE_HARNESS, {
24151
+ configurable: false,
24152
+ enumerable: false,
24153
+ value: true
24154
+ });
24155
+ Object.defineProperty(target, "session", {
24156
+ configurable: true,
24157
+ value: async function wrappedFlueHarnessSession(name, options) {
24158
+ const session = await originalSession(name, options);
24159
+ return patchFlueSessionInPlace(session);
24160
+ },
24161
+ writable: true
24162
+ });
24163
+ const sessions = target.sessions;
24164
+ if (sessions && typeof sessions === "object") {
24165
+ patchFlueSessionFactory(sessions, "get");
24166
+ patchFlueSessionFactory(sessions, "create");
24167
+ }
24168
+ } catch {
24169
+ }
24170
+ return harness;
24171
+ }
24172
+ function patchFlueSessionInPlace(session) {
24173
+ if (session[WRAPPED_FLUE_SESSION]) {
24174
+ return session;
24175
+ }
24176
+ try {
24177
+ Object.defineProperty(session, WRAPPED_FLUE_SESSION, {
24178
+ configurable: false,
24179
+ enumerable: false,
24180
+ value: true
24181
+ });
24182
+ patchCallHandleMethod(session, "prompt", flueChannels.prompt);
24183
+ patchCallHandleMethod(session, "skill", flueChannels.skill);
24184
+ patchCallHandleMethod(session, "task", flueChannels.task);
24185
+ patchCompact(session);
24186
+ } catch {
24187
+ }
24188
+ return session;
24189
+ }
24190
+ function patchFlueSessionFactory(sessions, method) {
24191
+ const original = sessions[method];
24192
+ if (typeof original !== "function") {
24193
+ return;
24194
+ }
24195
+ const bound = original.bind(sessions);
24196
+ Object.defineProperty(sessions, method, {
24197
+ configurable: true,
24198
+ value: async function wrappedFlueSessionFactory(name, options) {
24199
+ const session = await bound(name, options);
24200
+ return patchFlueSessionInPlace(session);
24201
+ },
24202
+ writable: true
24203
+ });
24204
+ }
24205
+ function patchCallHandleMethod(session, method, channel2) {
24206
+ const original = session[method];
24207
+ if (typeof original !== "function") {
24208
+ return;
24209
+ }
24210
+ const bound = original.bind(session);
24211
+ Object.defineProperty(session, method, {
24212
+ configurable: true,
24213
+ value(input, options) {
24214
+ const args = [input, options];
24215
+ const { originalResult, traced: traced2 } = traceFlueOperation(channel2, {
24216
+ context: {
24217
+ arguments: args,
24218
+ operation: method,
24219
+ session
24220
+ },
24221
+ run: () => bound(input, options)
24222
+ });
24223
+ return preserveCallHandle(originalResult, traced2);
24224
+ },
24225
+ writable: true
24226
+ });
24227
+ }
24228
+ function patchCompact(session) {
24229
+ const original = session.compact;
24230
+ if (typeof original !== "function") {
24231
+ return;
24232
+ }
24233
+ const bound = original.bind(session);
24234
+ Object.defineProperty(session, "compact", {
24235
+ configurable: true,
24236
+ value() {
24237
+ const context = {
24238
+ arguments: [],
24239
+ operation: "compact",
24240
+ session
24241
+ };
24242
+ return flueChannels.compact.tracePromise(() => bound(), context);
24243
+ },
24244
+ writable: true
24245
+ });
24246
+ }
24247
+ function traceFlueOperation(channel2, args) {
24248
+ const tracingChannel2 = channel2.tracingChannel();
24249
+ const context = args.context;
24250
+ let originalResult;
24251
+ let traced2;
24252
+ const run = () => {
24253
+ try {
24254
+ originalResult = args.run();
24255
+ tracingChannel2.end?.publish(context);
24256
+ } catch (error) {
24257
+ context.error = normalizeError3(error);
24258
+ tracingChannel2.error?.publish(context);
24259
+ tracingChannel2.end?.publish(context);
24260
+ throw error;
24261
+ }
24262
+ traced2 = Promise.resolve(originalResult).then(
24263
+ (result) => {
24264
+ context.result = result;
24265
+ tracingChannel2.asyncStart?.publish(context);
24266
+ tracingChannel2.asyncEnd?.publish(context);
24267
+ return result;
24268
+ },
24269
+ (error) => {
24270
+ context.error = normalizeError3(error);
24271
+ tracingChannel2.error?.publish(context);
24272
+ tracingChannel2.asyncStart?.publish(context);
24273
+ tracingChannel2.asyncEnd?.publish(context);
24274
+ throw error;
24275
+ }
24276
+ );
24277
+ };
24278
+ if (tracingChannel2.start?.runStores) {
24279
+ tracingChannel2.start.runStores(context, run);
24280
+ } else {
24281
+ tracingChannel2.start?.publish(context);
24282
+ run();
24283
+ }
24284
+ return { originalResult, traced: traced2 };
24285
+ }
24286
+ function normalizeError3(error) {
24287
+ return error instanceof Error ? error : new Error(String(error));
24288
+ }
24289
+ function preserveCallHandle(originalHandle, traced2) {
24290
+ if (!isFlueCallHandle(originalHandle)) {
24291
+ return traced2;
24292
+ }
24293
+ const handle = originalHandle;
24294
+ const wrapped = {
24295
+ get signal() {
24296
+ return handle.signal;
24297
+ },
24298
+ abort(reason) {
24299
+ return handle.abort(reason);
24300
+ },
24301
+ then(onfulfilled, onrejected) {
24302
+ return traced2.then(onfulfilled, onrejected);
24303
+ }
24304
+ };
24305
+ return wrapped;
24306
+ }
24307
+ function isPlausibleFlueContext(value) {
24308
+ return !!value && typeof value === "object" && typeof value.init === "function";
24309
+ }
24310
+ function isPlausibleFlueHarness(value) {
24311
+ return !!value && typeof value === "object" && typeof value.session === "function";
24312
+ }
24313
+ function isPlausibleFlueSession(value) {
24314
+ return !!value && typeof value === "object" && typeof value.prompt === "function" && typeof value.skill === "function" && typeof value.task === "function" && typeof value.compact === "function";
24315
+ }
24316
+ function isFlueCallHandle(value) {
24317
+ return !!value && typeof value === "object" && typeof value.then === "function" && typeof value.abort === "function" && "signal" in value;
24318
+ }
24319
+
24320
+ // src/instrumentation/plugins/flue-plugin.ts
24321
+ var FluePlugin = class extends BasePlugin {
24322
+ activeOperationsById = /* @__PURE__ */ new Map();
24323
+ activeOperationsByScope = /* @__PURE__ */ new Map();
24324
+ compactionsByScope = /* @__PURE__ */ new Map();
24325
+ pendingOperationsByKey = /* @__PURE__ */ new Map();
24326
+ tasksById = /* @__PURE__ */ new Map();
24327
+ toolsById = /* @__PURE__ */ new Map();
24328
+ turnsByScope = /* @__PURE__ */ new Map();
24329
+ onEnable() {
24330
+ this.subscribeToContextCreation();
24331
+ this.subscribeToSessionCreation();
24332
+ this.subscribeToContextEvents();
24333
+ this.subscribeToSessionOperations();
24334
+ }
24335
+ onDisable() {
24336
+ for (const unsubscribe of this.unsubscribers) {
24337
+ unsubscribe();
24338
+ }
24339
+ this.unsubscribers = [];
24340
+ this.activeOperationsById.clear();
24341
+ this.activeOperationsByScope.clear();
24342
+ this.compactionsByScope.clear();
24343
+ this.pendingOperationsByKey.clear();
24344
+ this.tasksById.clear();
24345
+ this.toolsById.clear();
24346
+ this.turnsByScope.clear();
24347
+ }
24348
+ subscribeToContextCreation() {
24349
+ const channel2 = flueChannels.createContext.tracingChannel();
24350
+ const handlers = {
24351
+ end: (event) => {
24352
+ const ctx = event.result;
24353
+ if (!ctx) {
24354
+ return;
24355
+ }
24356
+ subscribeFlueContextEvents(ctx, { captureTurnSpans: false });
24357
+ patchFlueContextInPlace(ctx);
24358
+ },
24359
+ error: () => {
24360
+ }
24361
+ };
24362
+ channel2.subscribe(handlers);
24363
+ this.unsubscribers.push(() => {
24364
+ channel2.unsubscribe(handlers);
24365
+ });
24366
+ }
24367
+ subscribeToSessionCreation() {
24368
+ const channel2 = flueChannels.openSession.tracingChannel();
24369
+ const handlers = {
24370
+ asyncEnd: (event) => {
24371
+ if (event.result) {
24372
+ patchFlueSessionInPlace(
24373
+ event.result
24374
+ );
24375
+ }
24376
+ if (event.harness) {
24377
+ wrapFlueHarness(event.harness);
24378
+ }
24379
+ },
24380
+ error: () => {
24381
+ }
24382
+ };
24383
+ channel2.subscribe(handlers);
24384
+ this.unsubscribers.push(() => {
24385
+ channel2.unsubscribe(handlers);
24386
+ });
24387
+ }
24388
+ subscribeToSessionOperations() {
24389
+ this.subscribeToSessionOperation(flueChannels.prompt);
24390
+ this.subscribeToSessionOperation(flueChannels.skill);
24391
+ this.subscribeToSessionOperation(flueChannels.task);
24392
+ this.subscribeToCompact();
24393
+ }
24394
+ subscribeToSessionOperation(channel2) {
24395
+ const tracingChannel2 = channel2.tracingChannel();
24396
+ const states = /* @__PURE__ */ new WeakMap();
24397
+ const ensureState2 = (event) => {
24398
+ const existing = states.get(event);
24399
+ if (existing) {
24400
+ return existing;
24401
+ }
24402
+ const state = this.startOperationState({
24403
+ args: event.arguments,
24404
+ moduleVersion: typeof event.moduleVersion === "string" ? event.moduleVersion : void 0,
24405
+ operation: event.operation,
24406
+ session: event.session
24407
+ });
24408
+ states.set(event, state);
24409
+ return state;
24410
+ };
24411
+ const unbindCurrentSpanStore = this.bindCurrentSpanStoreToOperationStart(
24412
+ tracingChannel2,
24413
+ ensureState2
24414
+ );
24415
+ const handlers = {
24416
+ start: (event) => {
24417
+ ensureState2(event);
24418
+ },
24419
+ asyncEnd: (event) => {
24420
+ this.endOperationState(states.get(event), event.result);
24421
+ states.delete(event);
24422
+ },
24423
+ error: (event) => {
24424
+ const state = states.get(event);
24425
+ if (state && event.error) {
24426
+ safeLog3(state.span, { error: errorToString(event.error) });
24427
+ this.finishOperationState(state);
24428
+ }
24429
+ states.delete(event);
24430
+ }
24431
+ };
24432
+ tracingChannel2.subscribe(handlers);
24433
+ this.unsubscribers.push(() => {
24434
+ unbindCurrentSpanStore?.();
24435
+ tracingChannel2.unsubscribe(handlers);
24436
+ });
24437
+ }
24438
+ subscribeToCompact() {
24439
+ const tracingChannel2 = flueChannels.compact.tracingChannel();
24440
+ const states = /* @__PURE__ */ new WeakMap();
24441
+ const ensureState2 = (event) => {
24442
+ const existing = states.get(event);
24443
+ if (existing) {
24444
+ return existing;
24445
+ }
24446
+ const state = this.startOperationState({
24447
+ args: [],
24448
+ moduleVersion: typeof event.moduleVersion === "string" ? event.moduleVersion : void 0,
24449
+ operation: event.operation,
24450
+ session: event.session
24451
+ });
24452
+ states.set(event, state);
24453
+ return state;
24454
+ };
24455
+ const unbindCurrentSpanStore = this.bindCurrentSpanStoreToOperationStart(
24456
+ tracingChannel2,
24457
+ ensureState2
24458
+ );
24459
+ const handlers = {
24460
+ start: (event) => {
24461
+ ensureState2(event);
24462
+ },
24463
+ asyncEnd: (event) => {
24464
+ this.endOperationState(states.get(event), void 0);
24465
+ states.delete(event);
24466
+ },
24467
+ error: (event) => {
24468
+ const state = states.get(event);
24469
+ if (state && event.error) {
24470
+ safeLog3(state.span, { error: errorToString(event.error) });
24471
+ this.finishOperationState(state);
24472
+ }
24473
+ states.delete(event);
24474
+ }
24475
+ };
24476
+ tracingChannel2.subscribe(handlers);
24477
+ this.unsubscribers.push(() => {
24478
+ unbindCurrentSpanStore?.();
24479
+ tracingChannel2.unsubscribe(handlers);
24480
+ });
24481
+ }
24482
+ subscribeToContextEvents() {
24483
+ const channel2 = flueChannels.contextEvent.tracingChannel();
24484
+ const handlers = {
24485
+ start: (event) => {
24486
+ const flueEvent = event.arguments[0];
24487
+ if (!flueEvent) {
24488
+ return;
24489
+ }
24490
+ try {
24491
+ this.handleFlueEvent(flueEvent, {
24492
+ captureTurnSpans: event.captureTurnSpans !== false
24493
+ });
24494
+ } catch (error) {
24495
+ logInstrumentationError3("Flue event", error);
24496
+ }
24497
+ },
24498
+ error: () => {
24499
+ }
24500
+ };
24501
+ channel2.subscribe(handlers);
24502
+ this.unsubscribers.push(() => {
24503
+ channel2.unsubscribe(handlers);
24504
+ });
24505
+ }
24506
+ bindCurrentSpanStoreToOperationStart(tracingChannel2, ensureState2) {
24507
+ const state = _internalGetGlobalState();
24508
+ const startChannel = tracingChannel2.start;
24509
+ const contextManager = state?.contextManager;
24510
+ const currentSpanStore = contextManager ? contextManager[BRAINTRUST_CURRENT_SPAN_STORE] : void 0;
24511
+ if (!currentSpanStore || !startChannel) {
24512
+ return void 0;
24513
+ }
24514
+ startChannel.bindStore(currentSpanStore, (event) => {
24515
+ const operationState = ensureState2(event);
24516
+ return contextManager.wrapSpanForStore(operationState.span);
24517
+ });
24518
+ return () => {
24519
+ startChannel.unbindStore(currentSpanStore);
24520
+ };
24521
+ }
24522
+ startOperationState(args) {
24523
+ const sessionName = getSessionName(args.session);
24524
+ const metadata = {
24525
+ ...extractOperationInputMetadata(args.operation, args.args),
24526
+ ...extractSessionMetadata(args.session),
24527
+ "flue.operation": args.operation,
24528
+ provider: "flue",
24529
+ ...args.moduleVersion ? { "flue.version": args.moduleVersion } : {}
24530
+ };
24531
+ const span = startSpan({
24532
+ name: `flue.session.${args.operation}`,
24533
+ spanAttributes: { type: "task" /* TASK */ }
24534
+ });
24535
+ const state = {
24536
+ metadata,
24537
+ operation: args.operation,
24538
+ sessionName,
24539
+ span,
24540
+ startTime: getCurrentUnixTimestamp()
24541
+ };
24542
+ safeLog3(span, {
24543
+ input: extractOperationInput(args.operation, args.args),
24544
+ metadata
24545
+ });
24546
+ this.pendingOperationQueue(operationKey(sessionName, args.operation)).push(
24547
+ state
24548
+ );
24549
+ addOperationToScope(
24550
+ this.activeOperationsByScope,
24551
+ sessionName ?? "unknown",
24552
+ state
24553
+ );
24554
+ return state;
24555
+ }
24556
+ endOperationState(state, result) {
24557
+ if (!state) {
24558
+ return;
24559
+ }
24560
+ const metadata = {
24561
+ ...state.metadata,
24562
+ ...extractPromptResponseMetadata(result)
24563
+ };
24564
+ const metrics = {
24565
+ ...buildDurationMetrics3(state.startTime),
24566
+ ...metricsFromUsage(result?.usage)
24567
+ };
24568
+ safeLog3(state.span, {
24569
+ metadata,
24570
+ metrics,
24571
+ output: extractOperationOutput(result)
24572
+ });
24573
+ this.finishCompactionsForOperation(state);
24574
+ this.finishOperationState(state);
24575
+ }
24576
+ finishOperationState(state) {
24577
+ removePendingOperation(this.pendingOperationsByKey, state);
24578
+ if (state.operationId) {
24579
+ this.activeOperationsById.delete(state.operationId);
24580
+ }
24581
+ removeScopedOperation(this.activeOperationsByScope, state);
24582
+ state.span.end();
24583
+ }
24584
+ handleFlueEvent(event, options) {
24585
+ switch (event.type) {
24586
+ case "operation_start":
24587
+ this.handleOperationStart(event);
24588
+ return;
24589
+ case "operation":
24590
+ this.handleOperation(event);
24591
+ return;
24592
+ case "text_delta":
24593
+ if (!options.captureTurnSpans) {
24594
+ return;
24595
+ }
24596
+ this.ensureTurnState(event).text.push(
24597
+ typeof event.text === "string" ? event.text : ""
24598
+ );
24599
+ return;
24600
+ case "thinking_start":
24601
+ if (!options.captureTurnSpans) {
24602
+ return;
24603
+ }
24604
+ this.handleThinkingStart(event);
24605
+ return;
24606
+ case "thinking_delta":
24607
+ if (!options.captureTurnSpans) {
24608
+ return;
24609
+ }
24610
+ this.handleThinkingDelta(event);
24611
+ return;
24612
+ case "thinking_end":
24613
+ if (!options.captureTurnSpans) {
24614
+ return;
24615
+ }
24616
+ this.handleThinkingEnd(event);
24617
+ return;
24618
+ case "turn":
24619
+ if (!options.captureTurnSpans) {
24620
+ return;
24621
+ }
24622
+ this.handleTurn(event);
24623
+ return;
24624
+ case "tool_start":
24625
+ this.handleToolStart(event, options);
24626
+ return;
24627
+ case "tool_call":
24628
+ this.handleToolCall(event);
24629
+ return;
24630
+ case "task_start":
24631
+ this.handleTaskStart(event);
24632
+ return;
24633
+ case "task":
24634
+ this.handleTask(event);
24635
+ return;
24636
+ case "compaction_start":
24637
+ this.handleCompactionStart(event);
24638
+ return;
24639
+ case "compaction":
24640
+ this.handleCompaction(event);
24641
+ return;
24642
+ default:
24643
+ return;
24644
+ }
24645
+ }
24646
+ handleOperationStart(event) {
24647
+ if (!isInstrumentedOperation(event.operationKind)) {
24648
+ return;
24649
+ }
24650
+ const state = this.takePendingOperationForEvent(event);
24651
+ if (!state) {
24652
+ return;
24653
+ }
24654
+ state.operationId = event.operationId;
24655
+ this.activeOperationsById.set(event.operationId, state);
24656
+ addScopedOperation(this.activeOperationsByScope, event, state);
24657
+ state.metadata = {
24658
+ ...state.metadata,
24659
+ ...extractEventMetadata(event),
24660
+ "flue.operation_id": event.operationId
24661
+ };
24662
+ safeLog3(state.span, { metadata: state.metadata });
24663
+ }
24664
+ handleOperation(event) {
24665
+ const state = event.operationId ? this.activeOperationsById.get(event.operationId) : void 0;
24666
+ if (!state) {
24667
+ return;
24668
+ }
24669
+ const metadata = {
24670
+ ...state.metadata,
24671
+ ...extractEventMetadata(event),
24672
+ ...typeof event.durationMs === "number" ? { "flue.duration_ms": event.durationMs } : {},
24673
+ ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {}
24674
+ };
24675
+ const metrics = metricsFromUsage(event.usage);
24676
+ safeLog3(state.span, {
24677
+ ...event.error ? { error: errorToString(event.error) } : {},
24678
+ metadata,
24679
+ ...Object.keys(metrics).length ? { metrics } : {}
24680
+ });
24681
+ }
24682
+ ensureTurnState(event) {
24683
+ const scope = scopeKey(event);
24684
+ const existing = this.turnsByScope.get(scope);
24685
+ if (existing) {
24686
+ return existing;
24687
+ }
24688
+ const parent = this.parentSpanForEvent(event);
24689
+ const metadata = {
24690
+ ...extractEventMetadata(event),
24691
+ provider: "flue"
24692
+ };
24693
+ const span = startFlueSpan(parent, {
24694
+ name: "flue.turn",
24695
+ spanAttributes: { type: "llm" /* LLM */ }
24696
+ });
24697
+ const state = {
24698
+ metadata,
24699
+ span,
24700
+ hasThinking: false,
24701
+ startTime: getCurrentUnixTimestamp(),
24702
+ text: [],
24703
+ thinking: [],
24704
+ toolCalls: []
24705
+ };
24706
+ safeLog3(span, { metadata });
24707
+ this.turnsByScope.set(scope, state);
24708
+ return state;
24709
+ }
24710
+ handleTurn(event) {
24711
+ const scope = scopeKey(event);
24712
+ const state = this.ensureTurnState(event);
24713
+ const text = state.text.join("");
24714
+ const reasoning = state.finalThinking ?? state.thinking.join("");
24715
+ const outputReasoning = reasoning || (state.hasThinking ? "[reasoning stream present; content unavailable]" : void 0);
24716
+ const metadata = {
24717
+ ...state.metadata,
24718
+ ...extractEventMetadata(event),
24719
+ ...event.model ? { model: event.model, "flue.model": event.model } : {},
24720
+ ...event.stopReason ? { "flue.stop_reason": event.stopReason } : {},
24721
+ ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {},
24722
+ provider: "flue"
24723
+ };
24724
+ safeLog3(state.span, {
24725
+ ...event.error ? { error: errorToString(event.error) } : {},
24726
+ metadata,
24727
+ metrics: {
24728
+ ...durationMsMetrics(event.durationMs),
24729
+ ...metricsFromUsage(event.usage)
24730
+ },
24731
+ output: toAssistantOutput(
24732
+ text,
24733
+ event.stopReason,
24734
+ outputReasoning,
24735
+ state.toolCalls
24736
+ )
24737
+ });
24738
+ state.span.end();
24739
+ this.turnsByScope.delete(scope);
24740
+ }
24741
+ handleThinkingDelta(event) {
24742
+ const delta = event.delta;
24743
+ if (typeof delta !== "string" || !delta) {
24744
+ return;
24745
+ }
24746
+ const state = this.ensureTurnState(event);
24747
+ state.hasThinking = true;
24748
+ state.metadata["flue.thinking"] = true;
24749
+ state.thinking.push(delta);
24750
+ }
24751
+ handleThinkingStart(event) {
24752
+ const state = this.ensureTurnState(event);
24753
+ state.hasThinking = true;
24754
+ state.metadata["flue.thinking"] = true;
24755
+ }
24756
+ handleThinkingEnd(event) {
24757
+ const state = this.ensureTurnState(event);
24758
+ state.hasThinking = true;
24759
+ state.metadata["flue.thinking"] = true;
24760
+ if (typeof event.content === "string" && event.content) {
24761
+ state.finalThinking = event.content;
24762
+ }
24763
+ }
24764
+ handleToolStart(event, options) {
24765
+ const toolCallId = event.toolCallId;
24766
+ if (!toolCallId) {
24767
+ return;
24768
+ }
24769
+ const parent = this.parentSpanForEvent(event);
24770
+ const scope = scopeKey(event);
24771
+ let turnState = this.turnsByScope.get(scope);
24772
+ if (!turnState && parent && options.captureTurnSpans) {
24773
+ turnState = this.ensureTurnState(event);
24774
+ }
24775
+ const metadata = {
24776
+ ...extractEventMetadata(event),
24777
+ ...event.toolName ? { "flue.tool_name": event.toolName } : {},
24778
+ "flue.tool_call_id": toolCallId,
24779
+ provider: "flue"
24780
+ };
24781
+ const span = startFlueSpan(parent, {
24782
+ name: `tool: ${event.toolName ?? "unknown"}`,
24783
+ spanAttributes: { type: "tool" /* TOOL */ }
24784
+ });
24785
+ if (turnState) {
24786
+ turnState.toolCalls.push({
24787
+ args: event.args,
24788
+ toolCallId,
24789
+ toolName: event.toolName
24790
+ });
24791
+ }
24792
+ safeLog3(span, {
24793
+ input: event.args,
24794
+ metadata
24795
+ });
24796
+ this.toolsById.set(toolKey(event), {
24797
+ metadata,
24798
+ span,
24799
+ startTime: getCurrentUnixTimestamp()
24800
+ });
24801
+ }
24802
+ handleToolCall(event) {
24803
+ const key = toolKey(event);
24804
+ const state = this.toolsById.get(key) ?? this.startSyntheticToolState(event, event.toolName ?? "unknown");
24805
+ const metadata = {
24806
+ ...state.metadata,
24807
+ ...extractEventMetadata(event),
24808
+ ...event.toolName ? { "flue.tool_name": event.toolName } : {},
24809
+ ...event.toolCallId ? { "flue.tool_call_id": event.toolCallId } : {},
24810
+ ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {}
24811
+ };
24812
+ safeLog3(state.span, {
24813
+ ...event.isError ? { error: errorToString(event.result) } : {},
24814
+ metadata,
24815
+ metrics: durationMsMetrics(event.durationMs),
24816
+ output: event.result
24817
+ });
24818
+ state.span.end();
24819
+ this.toolsById.delete(key);
24820
+ }
24821
+ handleTaskStart(event) {
24822
+ const parent = this.parentSpanForEvent(event);
24823
+ const metadata = {
24824
+ ...extractEventMetadata(event),
24825
+ ...event.role ? { "flue.role": event.role } : {},
24826
+ ...event.cwd ? { "flue.cwd": event.cwd } : {},
24827
+ "flue.task_id": event.taskId,
24828
+ provider: "flue"
24829
+ };
24830
+ const span = startFlueSpan(parent, {
24831
+ name: "flue.task",
24832
+ spanAttributes: { type: "task" /* TASK */ }
24833
+ });
24834
+ safeLog3(span, {
24835
+ input: event.prompt,
24836
+ metadata
24837
+ });
24838
+ this.tasksById.set(event.taskId, {
24839
+ metadata,
24840
+ span,
24841
+ startTime: getCurrentUnixTimestamp()
24842
+ });
24843
+ }
24844
+ handleTask(event) {
24845
+ const state = this.tasksById.get(event.taskId);
24846
+ if (!state) {
24847
+ return;
24848
+ }
24849
+ safeLog3(state.span, {
24850
+ ...event.isError ? { error: errorToString(event.result) } : {},
24851
+ metadata: {
24852
+ ...state.metadata,
24853
+ ...extractEventMetadata(event),
24854
+ ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {}
24855
+ },
24856
+ metrics: durationMsMetrics(event.durationMs),
24857
+ output: event.result
24858
+ });
24859
+ state.span.end();
24860
+ this.tasksById.delete(event.taskId);
24861
+ }
24862
+ handleCompactionStart(event) {
24863
+ const operationState = this.operationStateForEvent(event);
24864
+ const parent = operationState?.span ?? this.parentSpanForEvent(event);
24865
+ const metadata = {
24866
+ ...extractEventMetadata(event),
24867
+ ...event.reason ? { "flue.compaction_reason": event.reason } : {},
24868
+ provider: "flue"
24869
+ };
24870
+ const input = {
24871
+ ...typeof event.estimatedTokens === "number" ? { estimatedTokens: event.estimatedTokens } : {},
24872
+ ...event.reason ? { reason: event.reason } : {}
24873
+ };
24874
+ const span = startFlueSpan(parent, {
24875
+ name: "flue.compaction",
24876
+ spanAttributes: { type: "task" /* TASK */ }
24877
+ });
24878
+ safeLog3(span, {
24879
+ input,
24880
+ metadata
24881
+ });
24882
+ this.compactionsByScope.set(scopeKey(event), {
24883
+ input,
24884
+ metadata,
24885
+ operationState,
24886
+ span,
24887
+ startTime: getCurrentUnixTimestamp()
24888
+ });
24889
+ }
24890
+ handleCompaction(event) {
24891
+ const key = scopeKey(event);
24892
+ const state = this.compactionsByScope.get(key) ?? this.findCompactionState(event);
24893
+ if (!state) {
24894
+ return;
24895
+ }
24896
+ safeLog3(state.span, {
24897
+ metadata: {
24898
+ ...state.metadata,
24899
+ ...extractEventMetadata(event),
24900
+ ...typeof event.messagesBefore === "number" ? { "flue.messages_before": event.messagesBefore } : {},
24901
+ ...typeof event.messagesAfter === "number" ? { "flue.messages_after": event.messagesAfter } : {}
24902
+ },
24903
+ metrics: {
24904
+ ...durationMsMetrics(event.durationMs),
24905
+ ...metricsFromUsage(event.usage)
24906
+ },
24907
+ output: {
24908
+ messagesAfter: event.messagesAfter,
24909
+ messagesBefore: event.messagesBefore
24910
+ }
24911
+ });
24912
+ state.span.end();
24913
+ this.deleteCompactionState(state);
24914
+ }
24915
+ findCompactionState(event) {
24916
+ const operationState = this.operationStateForEvent(event);
24917
+ for (const state of this.compactionsByScope.values()) {
24918
+ if (operationState && state.operationState === operationState) {
24919
+ return state;
24920
+ }
24921
+ }
24922
+ return void 0;
24923
+ }
24924
+ finishCompactionsForOperation(operationState) {
24925
+ for (const state of [...this.compactionsByScope.values()]) {
24926
+ if (state.operationState !== operationState) {
24927
+ continue;
24928
+ }
24929
+ safeLog3(state.span, {
24930
+ input: state.input,
24931
+ metadata: state.metadata,
24932
+ metrics: {
24933
+ ...buildDurationMetrics3(state.startTime)
24934
+ },
24935
+ output: { completed: true }
24936
+ });
24937
+ state.span.end();
24938
+ this.deleteCompactionState(state);
24939
+ }
24940
+ }
24941
+ deleteCompactionState(state) {
24942
+ for (const [key, candidate] of this.compactionsByScope) {
24943
+ if (candidate !== state) {
24944
+ continue;
24945
+ }
24946
+ this.compactionsByScope.delete(key);
24947
+ return;
24948
+ }
24949
+ }
24950
+ startSyntheticToolState(event, toolName) {
24951
+ const parent = this.parentSpanForEvent(event);
24952
+ const metadata = {
24953
+ ...extractEventMetadata(event),
24954
+ ...event.toolCallId ? { "flue.tool_call_id": event.toolCallId } : {},
24955
+ "flue.tool_name": toolName,
24956
+ provider: "flue"
24957
+ };
24958
+ const span = startFlueSpan(parent, {
24959
+ name: `tool: ${toolName}`,
24960
+ spanAttributes: { type: "tool" /* TOOL */ }
24961
+ });
24962
+ safeLog3(span, { metadata });
24963
+ return { metadata, span, startTime: getCurrentUnixTimestamp() };
24964
+ }
24965
+ operationStateForEvent(event) {
24966
+ if (event.operationId) {
24967
+ const operation = this.activeOperationsById.get(event.operationId) ?? this.promotePendingOperationForEvent(event);
24968
+ if (operation) {
24969
+ return operation;
24970
+ }
24971
+ }
24972
+ return this.activeOperationForEventScope(event) ?? this.pendingOperationForEventScope(event);
24973
+ }
24974
+ parentSpanForEvent(event) {
24975
+ if (event.operationId) {
24976
+ const operation = this.operationStateForEvent(event);
24977
+ if (operation) {
24978
+ return operation.span;
24979
+ }
24980
+ }
24981
+ if (event.taskId) {
24982
+ return this.tasksById.get(event.taskId)?.span;
24983
+ }
24984
+ return this.operationStateForEvent(event)?.span;
24985
+ }
24986
+ promotePendingOperationForEvent(event) {
24987
+ if (!event.operationId) {
24988
+ return void 0;
24989
+ }
24990
+ const scopePrefixes = operationScopePrefixes(event);
24991
+ for (const [candidateKey, candidateQueue] of this.pendingOperationsByKey) {
24992
+ if (!candidateQueue.length || !operationKeyMatchesScopes(candidateKey, scopePrefixes)) {
24993
+ continue;
24994
+ }
24995
+ const state = candidateQueue.shift();
24996
+ if (!state) {
24997
+ return void 0;
24998
+ }
24999
+ state.operationId = event.operationId;
25000
+ this.activeOperationsById.set(event.operationId, state);
25001
+ addScopedOperation(this.activeOperationsByScope, event, state);
25002
+ state.metadata = {
25003
+ ...state.metadata,
25004
+ ...extractEventMetadata(event),
25005
+ "flue.operation_id": event.operationId
25006
+ };
25007
+ safeLog3(state.span, { metadata: state.metadata });
25008
+ return state;
25009
+ }
25010
+ return void 0;
25011
+ }
25012
+ activeOperationForEventScope(event) {
25013
+ for (const scope of operationScopeNames(event)) {
25014
+ const operations = this.activeOperationsByScope.get(scope);
25015
+ if (operations?.length) {
25016
+ return operations[operations.length - 1];
25017
+ }
25018
+ }
25019
+ return void 0;
25020
+ }
25021
+ pendingOperationForEventScope(event) {
25022
+ const scopePrefixes = operationScopePrefixes(event);
25023
+ for (const [candidateKey, candidateQueue] of this.pendingOperationsByKey) {
25024
+ if (!candidateQueue.length || !operationKeyMatchesScopes(candidateKey, scopePrefixes)) {
25025
+ continue;
25026
+ }
25027
+ return candidateQueue[0];
25028
+ }
25029
+ return void 0;
25030
+ }
25031
+ takePendingOperationForEvent(event) {
25032
+ const key = operationKey(event.session, event.operationKind);
25033
+ const queue2 = this.pendingOperationsByKey.get(key);
25034
+ if (queue2?.length) {
25035
+ return queue2.shift();
25036
+ }
25037
+ for (const [candidateKey, candidateQueue] of this.pendingOperationsByKey) {
25038
+ if (candidateKey.endsWith(`::${event.operationKind}`) && candidateQueue.length) {
25039
+ return candidateQueue.shift();
25040
+ }
25041
+ }
25042
+ return void 0;
25043
+ }
25044
+ pendingOperationQueue(key) {
25045
+ const existing = this.pendingOperationsByKey.get(key);
25046
+ if (existing) {
25047
+ return existing;
25048
+ }
25049
+ const queue2 = [];
25050
+ this.pendingOperationsByKey.set(key, queue2);
25051
+ return queue2;
25052
+ }
25053
+ };
25054
+ function isInstrumentedOperation(operation) {
25055
+ return operation === "prompt" || operation === "skill" || operation === "task" || operation === "compact";
25056
+ }
25057
+ function getSessionName(session) {
25058
+ return typeof session?.name === "string" ? session.name : void 0;
25059
+ }
25060
+ function operationKey(sessionName, operation) {
25061
+ return `${sessionName ?? "unknown"}::${operation}`;
25062
+ }
25063
+ function operationScopePrefixes(event) {
25064
+ const scopes = /* @__PURE__ */ new Set();
25065
+ for (const scope of operationScopeNames(event)) {
25066
+ scopes.add(`${scope}::`);
25067
+ }
25068
+ return scopes;
25069
+ }
25070
+ function operationKeyMatchesScopes(key, scopes) {
25071
+ for (const scope of scopes) {
25072
+ if (key.startsWith(scope)) {
25073
+ return true;
25074
+ }
25075
+ }
25076
+ return false;
25077
+ }
25078
+ function operationScopeNames(event) {
25079
+ const scopes = /* @__PURE__ */ new Set();
25080
+ if (event.session) {
25081
+ scopes.add(event.session);
25082
+ }
25083
+ if (event.parentSession) {
25084
+ scopes.add(event.parentSession);
25085
+ }
25086
+ if (!scopes.size) {
25087
+ scopes.add("unknown");
25088
+ }
25089
+ return scopes;
25090
+ }
25091
+ function addScopedOperation(operationsByScope, event, state) {
25092
+ for (const scope of operationScopeNames(event)) {
25093
+ addOperationToScope(operationsByScope, scope, state);
25094
+ }
25095
+ }
25096
+ function addOperationToScope(operationsByScope, scope, state) {
25097
+ const operations = operationsByScope.get(scope);
25098
+ if (operations) {
25099
+ if (!operations.includes(state)) {
25100
+ operations.push(state);
25101
+ }
25102
+ } else {
25103
+ operationsByScope.set(scope, [state]);
25104
+ }
25105
+ }
25106
+ function removeScopedOperation(operationsByScope, state) {
25107
+ for (const [scope, operations] of operationsByScope) {
25108
+ const index = operations.indexOf(state);
25109
+ if (index === -1) {
25110
+ continue;
25111
+ }
25112
+ operations.splice(index, 1);
25113
+ if (operations.length === 0) {
25114
+ operationsByScope.delete(scope);
25115
+ }
25116
+ }
25117
+ }
25118
+ function removePendingOperation(pendingOperationsByKey, state) {
25119
+ for (const [key, queue2] of pendingOperationsByKey) {
25120
+ const index = queue2.indexOf(state);
25121
+ if (index === -1) {
25122
+ continue;
25123
+ }
25124
+ queue2.splice(index, 1);
25125
+ if (queue2.length === 0) {
25126
+ pendingOperationsByKey.delete(key);
25127
+ }
25128
+ return;
25129
+ }
25130
+ }
25131
+ function extractSessionMetadata(session) {
25132
+ const sessionName = getSessionName(session);
25133
+ return sessionName ? { "flue.session": sessionName } : {};
25134
+ }
25135
+ function extractEventMetadata(event) {
25136
+ return {
25137
+ ...event.runId ? { "flue.run_id": event.runId } : {},
25138
+ ...typeof event.eventIndex === "number" ? { "flue.event_index": event.eventIndex } : {},
25139
+ ...event.session ? { "flue.session": event.session } : {},
25140
+ ...event.parentSession ? { "flue.parent_session": event.parentSession } : {},
25141
+ ...event.harness ? { "flue.harness": event.harness } : {},
25142
+ ...event.taskId ? { "flue.task_id": event.taskId } : {},
25143
+ ...event.operationId ? { "flue.operation_id": event.operationId } : {}
25144
+ };
25145
+ }
25146
+ function extractOperationInput(operation, args) {
25147
+ switch (operation) {
25148
+ case "prompt":
25149
+ case "task":
25150
+ return args[0];
25151
+ case "skill":
25152
+ return {
25153
+ args: getOptionObject(args[1])?.args,
25154
+ name: args[0]
25155
+ };
25156
+ case "compact":
25157
+ return void 0;
25158
+ }
25159
+ }
25160
+ function extractOperationInputMetadata(operation, args) {
25161
+ const options = getOptionObject(args[1]);
25162
+ return {
25163
+ ...operation === "skill" && typeof args[0] === "string" ? { "flue.skill_name": args[0] } : {},
25164
+ ...options?.model ? { model: options.model, "flue.model": options.model } : {},
25165
+ ...options?.role ? { "flue.role": options.role } : {},
25166
+ ...options?.thinkingLevel ? { "flue.thinking_level": options.thinkingLevel } : {},
25167
+ ...typeof options?.cwd === "string" ? { "flue.cwd": options.cwd } : {},
25168
+ ...Array.isArray(options?.tools) ? {
25169
+ "flue.tools_count": options.tools.length,
25170
+ tools: summarizeTools(options.tools)
25171
+ } : {},
25172
+ ...Array.isArray(options?.images) ? { "flue.images_count": options.images.length } : {},
25173
+ ...options?.result || options?.schema ? { "flue.result_schema": true } : {}
25174
+ };
25175
+ }
25176
+ function getOptionObject(value) {
25177
+ return isObject(value) ? value : void 0;
25178
+ }
25179
+ function summarizeTools(tools) {
25180
+ return tools.flatMap((tool) => {
25181
+ if (!isObject(tool)) {
25182
+ return [];
25183
+ }
25184
+ const name = typeof tool.name === "string" ? tool.name : void 0;
25185
+ if (!name) {
25186
+ return [];
25187
+ }
25188
+ return [
25189
+ {
25190
+ function: {
25191
+ description: typeof tool.description === "string" ? tool.description : void 0,
25192
+ name,
25193
+ parameters: tool.parameters
25194
+ },
25195
+ type: "function"
25196
+ }
25197
+ ];
25198
+ });
25199
+ }
25200
+ function extractPromptResponseMetadata(result) {
25201
+ const modelId = result?.model && typeof result.model.id === "string" ? result.model.id : void 0;
25202
+ return modelId ? {
25203
+ model: modelId,
25204
+ "flue.model": modelId
25205
+ } : {};
25206
+ }
25207
+ function extractOperationOutput(result) {
25208
+ if (!result) {
25209
+ return void 0;
25210
+ }
25211
+ if ("data" in result) {
25212
+ return result.data;
25213
+ }
25214
+ if ("text" in result) {
25215
+ return result.text;
25216
+ }
25217
+ return result;
25218
+ }
25219
+ function metricsFromUsage(usage) {
25220
+ return {
25221
+ ...typeof usage?.input === "number" ? { prompt_tokens: usage.input } : {},
25222
+ ...typeof usage?.output === "number" ? { completion_tokens: usage.output } : {},
25223
+ ...typeof usage?.cacheRead === "number" ? { prompt_cached_tokens: usage.cacheRead } : {},
25224
+ ...typeof usage?.cacheWrite === "number" ? { prompt_cache_creation_tokens: usage.cacheWrite } : {},
25225
+ ...typeof usage?.totalTokens === "number" ? { tokens: usage.totalTokens } : {},
25226
+ ...typeof usage?.cost?.total === "number" ? { estimated_cost: usage.cost.total } : {}
25227
+ };
25228
+ }
25229
+ function buildDurationMetrics3(startTime) {
25230
+ return {
25231
+ duration_ms: Math.max(0, (getCurrentUnixTimestamp() - startTime) * 1e3)
25232
+ };
25233
+ }
25234
+ function durationMsMetrics(durationMs) {
25235
+ return typeof durationMs === "number" ? { duration_ms: durationMs } : {};
25236
+ }
25237
+ function scopeKey(event) {
25238
+ if (event.operationId) {
25239
+ return `operation:${event.operationId}`;
25240
+ }
25241
+ if (event.taskId) {
25242
+ return `task:${event.taskId}`;
25243
+ }
25244
+ if (event.session) {
25245
+ return `session:${event.session}`;
25246
+ }
25247
+ return "flue:unknown";
25248
+ }
25249
+ function toolKey(event) {
25250
+ return `${scopeKey(event)}::tool:${event.toolCallId ?? "unknown"}`;
25251
+ }
25252
+ function toAssistantOutput(text, finishReason, reasoning, toolCalls) {
25253
+ return [
25254
+ {
25255
+ finish_reason: finishReason ?? "stop",
25256
+ index: 0,
25257
+ message: {
25258
+ content: text,
25259
+ ...reasoning ? { reasoning } : {},
25260
+ role: "assistant",
25261
+ ...toolCalls?.length ? {
25262
+ tool_calls: toolCalls.map((toolCall) => ({
25263
+ function: {
25264
+ arguments: toolCall.args === void 0 ? "{}" : JSON.stringify(toolCall.args),
25265
+ name: toolCall.toolName ?? "unknown"
25266
+ },
25267
+ ...toolCall.toolCallId ? { id: toolCall.toolCallId } : {},
25268
+ type: "function"
25269
+ }))
25270
+ } : {}
25271
+ }
25272
+ }
25273
+ ];
25274
+ }
25275
+ function startFlueSpan(parent, args) {
25276
+ return parent ? withCurrent(parent, () => startSpan(args)) : startSpan(args);
25277
+ }
25278
+ function safeLog3(span, event) {
25279
+ try {
25280
+ span.log(event);
25281
+ } catch (error) {
25282
+ logInstrumentationError3("Flue span log", error);
25283
+ }
25284
+ }
25285
+ function errorToString(error) {
25286
+ if (error instanceof Error) {
25287
+ return error.message;
25288
+ }
25289
+ if (typeof error === "string") {
25290
+ return error;
25291
+ }
25292
+ try {
25293
+ return JSON.stringify(error);
25294
+ } catch {
25295
+ return String(error);
25296
+ }
25297
+ }
25298
+ function logInstrumentationError3(label, error) {
25299
+ console.error(`Error in ${label} instrumentation:`, error);
25300
+ }
25301
+
25302
+ // src/wrappers/langchain/callback-handler.ts
25303
+ var BRAINTRUST_LANGCHAIN_CALLBACK_HANDLER_NAME = "BraintrustCallbackHandler";
25304
+ var BraintrustLangChainCallbackHandler = class {
25305
+ name = BRAINTRUST_LANGCHAIN_CALLBACK_HANDLER_NAME;
25306
+ spans = /* @__PURE__ */ new Map();
25307
+ skippedRuns = /* @__PURE__ */ new Set();
25308
+ parent;
25309
+ rootRunId;
25310
+ options;
25311
+ startTimes = /* @__PURE__ */ new Map();
25312
+ firstTokenTimes = /* @__PURE__ */ new Map();
25313
+ ttftMs = /* @__PURE__ */ new Map();
25314
+ constructor(options) {
25315
+ this.parent = options?.parent;
25316
+ this.options = {
25317
+ debug: options?.debug ?? false,
25318
+ excludeMetadataProps: options?.excludeMetadataProps ?? /^(l[sc]_|langgraph_|__pregel_|checkpoint_ns)/,
25319
+ logger: options?.logger
25320
+ };
25321
+ }
25322
+ startSpan({
25323
+ runId,
25324
+ parentRunId,
25325
+ ...args
25326
+ }) {
25327
+ if (this.spans.has(runId)) {
25328
+ return;
25329
+ }
25330
+ if (!parentRunId) {
25331
+ this.rootRunId = runId;
25332
+ }
25333
+ const tags = args.event?.tags;
25334
+ const spanAttributes = args.spanAttributes || {};
25335
+ spanAttributes.type = args.type || spanAttributes.type || "task";
25336
+ args.type = spanAttributes.type;
25337
+ const currentParent = (typeof this.parent === "function" ? this.parent() : this.parent) ?? currentSpan();
25338
+ let parentSpan;
25339
+ if (parentRunId && this.spans.has(parentRunId)) {
25340
+ parentSpan = this.spans.get(parentRunId);
25341
+ } else if (!Object.is(currentParent, NOOP_SPAN)) {
25342
+ parentSpan = currentParent;
25343
+ } else if (this.options.logger) {
25344
+ parentSpan = this.options.logger;
25345
+ } else {
25346
+ parentSpan = { startSpan };
25347
+ }
25348
+ args.event = {
25349
+ ...args.event,
25350
+ tags: void 0,
25351
+ metadata: {
25352
+ ...tags ? { tags } : {},
25353
+ ...args.event?.metadata,
25354
+ braintrust: {
25355
+ integration_name: "langchain-js",
25356
+ sdk_language: "javascript"
25357
+ },
25358
+ run_id: runId,
25359
+ parent_run_id: parentRunId,
25360
+ ...this.options.debug ? { runId, parentRunId } : {}
25361
+ }
25362
+ };
25363
+ let span = parentSpan.startSpan(args);
25364
+ if (!Object.is(this.options.logger, NOOP_SPAN) && Object.is(span, NOOP_SPAN)) {
25365
+ span = initLogger().startSpan(args);
25366
+ }
25367
+ this.spans.set(runId, span);
25368
+ }
25369
+ endSpan({
25370
+ runId,
25371
+ parentRunId,
25372
+ tags,
25373
+ metadata,
25374
+ ...args
25375
+ }) {
25376
+ if (!this.spans.has(runId)) {
25377
+ return;
25378
+ }
25379
+ if (this.skippedRuns.has(runId)) {
25380
+ this.skippedRuns.delete(runId);
25381
+ return;
25382
+ }
25383
+ const span = this.spans.get(runId);
25384
+ this.spans.delete(runId);
25385
+ if (runId === this.rootRunId) {
25386
+ this.rootRunId = void 0;
25387
+ }
25388
+ span.log({ ...args, metadata: { tags, ...metadata } });
25389
+ span.end();
25390
+ }
25391
+ async handleLLMStart(llm, prompts, runId, parentRunId, extraParams, tags, metadata, runName) {
25392
+ this.startSpan({
25393
+ runId,
25394
+ parentRunId,
25395
+ name: runName ?? getSerializedName(llm) ?? "LLM",
25396
+ type: "llm",
25397
+ event: {
25398
+ input: prompts,
25399
+ tags,
25400
+ metadata: {
25401
+ serialized: llm,
25402
+ name: runName,
25403
+ metadata,
25404
+ ...extraParams
25405
+ }
25406
+ }
25407
+ });
25408
+ }
25409
+ async handleLLMError(err, runId, parentRunId, tags) {
25410
+ this.endSpan({ runId, parentRunId, error: err, tags });
25411
+ }
25412
+ async handleLLMEnd(output, runId, parentRunId, tags) {
25413
+ const metrics = getMetricsFromResponse(output);
25414
+ const modelName2 = getModelNameFromResponse(output);
25415
+ const ttft = this.ttftMs.get(runId);
25416
+ if (ttft !== void 0) {
25417
+ metrics.time_to_first_token = ttft;
25418
+ }
25419
+ this.startTimes.delete(runId);
25420
+ this.firstTokenTimes.delete(runId);
25421
+ this.ttftMs.delete(runId);
25422
+ this.endSpan({
25423
+ runId,
25424
+ parentRunId,
25425
+ output,
25426
+ metrics,
25427
+ tags,
25428
+ metadata: {
25429
+ model: modelName2
25430
+ }
25431
+ });
25432
+ }
25433
+ async handleChatModelStart(llm, messages, runId, parentRunId, extraParams, tags, metadata, runName) {
25434
+ this.startTimes.set(runId, Date.now());
25435
+ this.firstTokenTimes.delete(runId);
25436
+ this.ttftMs.delete(runId);
25437
+ this.startSpan({
25438
+ runId,
25439
+ parentRunId,
25440
+ name: runName ?? getSerializedName(llm) ?? "Chat Model",
25441
+ type: "llm",
25442
+ event: {
25443
+ input: messages,
25444
+ tags,
25445
+ metadata: {
25446
+ serialized: llm,
25447
+ name: runName,
25448
+ metadata,
25449
+ ...extraParams
25450
+ }
25451
+ }
25452
+ });
25453
+ }
25454
+ async handleChainStart(chain, inputs, runId, parentRunId, tags, metadata, runType, runName) {
25455
+ if (tags?.includes("langsmith:hidden")) {
25456
+ this.skippedRuns.add(runId);
25457
+ return;
25458
+ }
25459
+ this.startSpan({
25460
+ runId,
25461
+ parentRunId,
25462
+ name: runName ?? getSerializedName(chain) ?? "Chain",
25463
+ event: {
25464
+ input: inputs,
25465
+ tags,
25466
+ metadata: {
25467
+ serialized: chain,
25468
+ name: runName,
25469
+ metadata,
25470
+ run_type: runType
25471
+ }
25472
+ }
25473
+ });
25474
+ }
25475
+ async handleChainError(err, runId, parentRunId, tags, kwargs) {
25476
+ this.endSpan({ runId, parentRunId, error: err, tags, metadata: kwargs });
25477
+ }
25478
+ async handleChainEnd(outputs, runId, parentRunId, tags, kwargs) {
25479
+ this.endSpan({
25480
+ runId,
25481
+ parentRunId,
25482
+ tags,
25483
+ output: outputs,
25484
+ metadata: { ...kwargs }
25485
+ });
25486
+ }
25487
+ async handleToolStart(tool, input, runId, parentRunId, tags, metadata, runName) {
25488
+ this.startSpan({
25489
+ runId,
25490
+ parentRunId,
25491
+ name: runName ?? getSerializedName(tool) ?? "Tool",
25492
+ type: "llm",
25493
+ event: {
25494
+ input: safeJsonParse(input),
25495
+ tags,
25496
+ metadata: {
25497
+ metadata,
25498
+ serialized: tool,
25499
+ input_str: input,
25500
+ input: safeJsonParse(input),
25501
+ name: runName
25502
+ }
25503
+ }
25504
+ });
25505
+ }
25506
+ async handleToolError(err, runId, parentRunId, tags) {
25507
+ this.endSpan({ runId, parentRunId, error: err, tags });
25508
+ }
25509
+ async handleToolEnd(output, runId, parentRunId, tags) {
25510
+ this.endSpan({ runId, parentRunId, output, tags });
25511
+ }
25512
+ async handleAgentAction(action, runId, parentRunId, tags) {
25513
+ this.startSpan({
25514
+ runId,
25515
+ parentRunId,
25516
+ type: "llm",
25517
+ name: typeof action.tool === "string" ? action.tool : "Agent",
25518
+ event: {
25519
+ input: action,
25520
+ tags
25521
+ }
25522
+ });
25523
+ }
25524
+ async handleAgentEnd(action, runId, parentRunId, tags) {
25525
+ this.endSpan({ runId, parentRunId, output: action, tags });
25526
+ }
25527
+ async handleRetrieverStart(retriever, query, runId, parentRunId, tags, metadata, name) {
25528
+ this.startSpan({
25529
+ runId,
25530
+ parentRunId,
25531
+ name: name ?? getSerializedName(retriever) ?? "Retriever",
25532
+ type: "function",
25533
+ event: {
25534
+ input: query,
25535
+ tags,
25536
+ metadata: {
25537
+ serialized: retriever,
25538
+ metadata,
25539
+ name
25540
+ }
25541
+ }
25542
+ });
25543
+ }
25544
+ async handleRetrieverEnd(documents, runId, parentRunId, tags) {
25545
+ this.endSpan({ runId, parentRunId, output: documents, tags });
25546
+ }
25547
+ async handleRetrieverError(err, runId, parentRunId, tags) {
25548
+ this.endSpan({ runId, parentRunId, error: err, tags });
25549
+ }
25550
+ async handleLLMNewToken(_token, _idx, runId, _parentRunId, _tags) {
25551
+ if (!this.firstTokenTimes.has(runId)) {
25552
+ const now2 = Date.now();
25553
+ this.firstTokenTimes.set(runId, now2);
25554
+ const start = this.startTimes.get(runId);
25555
+ if (start !== void 0) {
25556
+ this.ttftMs.set(runId, (now2 - start) / 1e3);
25557
+ }
25558
+ }
25559
+ }
25560
+ };
25561
+ function getSerializedName(serialized) {
25562
+ if (typeof serialized.name === "string") {
25563
+ return serialized.name;
25564
+ }
25565
+ const lastIdPart = serialized.id?.at(-1);
25566
+ return typeof lastIdPart === "string" ? lastIdPart : void 0;
25567
+ }
25568
+ function cleanObject(obj) {
25569
+ return Object.fromEntries(
25570
+ Object.entries(obj).filter(([, value]) => {
25571
+ if (typeof value !== "number") {
25572
+ return false;
25573
+ }
25574
+ return Number.isFinite(value);
25575
+ })
25576
+ );
25577
+ }
25578
+ function walkGenerations(response) {
25579
+ const result = [];
25580
+ const generations = response.generations || [];
25581
+ for (const batch of generations) {
25582
+ if (Array.isArray(batch)) {
25583
+ for (const generation of batch) {
25584
+ if (isRecord(generation)) {
25585
+ result.push(generation);
25586
+ }
25587
+ }
25588
+ } else if (isRecord(batch)) {
25589
+ result.push(batch);
25590
+ }
25591
+ }
25592
+ return result;
25593
+ }
25594
+ function getModelNameFromResponse(response) {
25595
+ for (const generation of walkGenerations(response)) {
25596
+ const message = generation.message;
25597
+ if (!isRecord(message)) {
25598
+ continue;
25599
+ }
25600
+ const responseMetadata = message.response_metadata;
25601
+ if (!isRecord(responseMetadata)) {
25602
+ continue;
25603
+ }
25604
+ const modelName3 = responseMetadata.model_name ?? responseMetadata.model;
25605
+ if (typeof modelName3 === "string") {
25606
+ return modelName3;
25607
+ }
25608
+ }
25609
+ const llmOutput = response.llmOutput || {};
25610
+ const modelName2 = llmOutput.model_name ?? llmOutput.model;
25611
+ return typeof modelName2 === "string" ? modelName2 : void 0;
25612
+ }
25613
+ function getMetricsFromResponse(response) {
25614
+ for (const generation of walkGenerations(response)) {
25615
+ const message = generation.message;
25616
+ if (!isRecord(message)) {
25617
+ continue;
25618
+ }
25619
+ const usageMetadata = message.usage_metadata;
25620
+ if (!isRecord(usageMetadata)) {
25621
+ continue;
25622
+ }
25623
+ const inputTokenDetails = usageMetadata.input_token_details;
25624
+ return cleanObject({
25625
+ total_tokens: usageMetadata.total_tokens,
25626
+ prompt_tokens: usageMetadata.input_tokens,
25627
+ completion_tokens: usageMetadata.output_tokens,
25628
+ prompt_cache_creation_tokens: isRecord(inputTokenDetails) ? inputTokenDetails.cache_creation : void 0,
25629
+ prompt_cached_tokens: isRecord(inputTokenDetails) ? inputTokenDetails.cache_read : void 0
25630
+ });
25631
+ }
25632
+ const llmOutput = response.llmOutput || {};
25633
+ const tokenUsage = isRecord(llmOutput.tokenUsage) ? llmOutput.tokenUsage : isRecord(llmOutput.estimatedTokens) ? llmOutput.estimatedTokens : {};
25634
+ return cleanObject({
25635
+ total_tokens: tokenUsage.totalTokens,
25636
+ prompt_tokens: tokenUsage.promptTokens,
25637
+ completion_tokens: tokenUsage.completionTokens
25638
+ });
25639
+ }
25640
+ function safeJsonParse(input) {
25641
+ try {
25642
+ return JSON.parse(input);
25643
+ } catch {
25644
+ return input;
25645
+ }
25646
+ }
25647
+ function isRecord(value) {
25648
+ return typeof value === "object" && value !== null && !Array.isArray(value);
25649
+ }
25650
+
25651
+ // src/instrumentation/plugins/langchain-channels.ts
25652
+ var langChainChannels = defineChannels("@langchain/core", {
25653
+ configure: channel({
25654
+ channelName: "CallbackManager.configure",
25655
+ kind: "sync-stream"
25656
+ }),
25657
+ configureSync: channel({
25658
+ channelName: "CallbackManager._configureSync",
25659
+ kind: "sync-stream"
25660
+ })
25661
+ });
25662
+
25663
+ // src/instrumentation/plugins/langchain-plugin.ts
25664
+ var LangChainPlugin = class extends BasePlugin {
25665
+ injectedManagers = /* @__PURE__ */ new WeakSet();
25666
+ onEnable() {
25667
+ this.subscribeToConfigure(langChainChannels.configure);
25668
+ this.subscribeToConfigure(langChainChannels.configureSync);
25669
+ }
25670
+ onDisable() {
25671
+ for (const unsubscribe of this.unsubscribers) {
25672
+ unsubscribe();
25673
+ }
25674
+ this.unsubscribers = [];
25675
+ this.injectedManagers = /* @__PURE__ */ new WeakSet();
25676
+ }
25677
+ subscribeToConfigure(channel2) {
25678
+ const tracingChannel2 = channel2.tracingChannel();
25679
+ const handlers = {
25680
+ start: (event) => {
25681
+ injectHandlerIntoArguments(event.arguments);
25682
+ },
25683
+ end: (event) => {
25684
+ this.injectHandler(event.result);
25685
+ }
25686
+ };
25687
+ tracingChannel2.subscribe(handlers);
25688
+ this.unsubscribers.push(() => {
25689
+ tracingChannel2.unsubscribe(handlers);
25690
+ });
25691
+ }
25692
+ injectHandler(result) {
25693
+ if (!isCallbackManager(result)) {
25694
+ return;
25695
+ }
25696
+ if (this.injectedManagers.has(result) || hasBraintrustHandler(result)) {
25697
+ return;
25698
+ }
25699
+ try {
25700
+ result.addHandler(new BraintrustLangChainCallbackHandler(), true);
25701
+ this.injectedManagers.add(result);
25702
+ } catch {
25703
+ }
25704
+ }
25705
+ };
25706
+ function isCallbackManager(value) {
25707
+ if (typeof value !== "object" || value === null) {
25708
+ return false;
25709
+ }
25710
+ const maybeManager = value;
25711
+ return typeof maybeManager.addHandler === "function";
25712
+ }
25713
+ function hasBraintrustHandler(manager) {
25714
+ return manager.handlers?.some((handler) => {
25715
+ if (typeof handler !== "object" || handler === null) {
25716
+ return false;
25717
+ }
25718
+ const name = Reflect.get(handler, "name");
25719
+ return name === BRAINTRUST_LANGCHAIN_CALLBACK_HANDLER_NAME;
25720
+ }) ?? false;
25721
+ }
25722
+ function injectHandlerIntoArguments(args) {
25723
+ if (!isWritableArgumentsObject(args)) {
25724
+ return;
25725
+ }
25726
+ const inheritedHandlers = Reflect.get(args, "0");
25727
+ const handler = new BraintrustLangChainCallbackHandler();
25728
+ if (inheritedHandlers === void 0 || inheritedHandlers === null) {
25729
+ Reflect.set(args, "0", [handler]);
25730
+ return;
25731
+ }
25732
+ if (Array.isArray(inheritedHandlers)) {
25733
+ if (!inheritedHandlers.some(isBraintrustHandler)) {
25734
+ inheritedHandlers.push(handler);
25735
+ }
25736
+ }
25737
+ }
25738
+ function isWritableArgumentsObject(args) {
25739
+ return typeof args === "object" && args !== null;
25740
+ }
25741
+ function isBraintrustHandler(handler) {
25742
+ if (typeof handler !== "object" || handler === null) {
25743
+ return false;
25744
+ }
25745
+ return Reflect.get(handler, "name") === BRAINTRUST_LANGCHAIN_CALLBACK_HANDLER_NAME;
25746
+ }
25747
+
25748
+ // src/instrumentation/braintrust-plugin.ts
25749
+ function getIntegrationConfig(integrations, key) {
25750
+ return integrations[key];
25751
+ }
25752
+ var BraintrustPlugin = class extends BasePlugin {
25753
+ config;
25754
+ openaiPlugin = null;
25755
+ openAICodexPlugin = null;
25756
+ anthropicPlugin = null;
25757
+ aiSDKPlugin = null;
25758
+ claudeAgentSDKPlugin = null;
25759
+ cursorSDKPlugin = null;
25760
+ openAIAgentsPlugin = null;
25761
+ googleGenAIPlugin = null;
25762
+ huggingFacePlugin = null;
25763
+ openRouterPlugin = null;
25764
+ openRouterAgentPlugin = null;
25765
+ mistralPlugin = null;
25766
+ googleADKPlugin = null;
25767
+ coherePlugin = null;
25768
+ groqPlugin = null;
25769
+ genkitPlugin = null;
25770
+ gitHubCopilotPlugin = null;
25771
+ fluePlugin = null;
25772
+ langChainPlugin = null;
25773
+ constructor(config = {}) {
25774
+ super();
25775
+ this.config = config;
25776
+ }
25777
+ onEnable() {
25778
+ const integrations = this.config.integrations || {};
25779
+ if (integrations.openai !== false) {
25780
+ this.openaiPlugin = new OpenAIPlugin();
25781
+ this.openaiPlugin.enable();
25782
+ }
25783
+ if (integrations.openaiCodexSDK !== false) {
25784
+ this.openAICodexPlugin = new OpenAICodexPlugin();
25785
+ this.openAICodexPlugin.enable();
25786
+ }
25787
+ if (integrations.anthropic !== false) {
25788
+ this.anthropicPlugin = new AnthropicPlugin();
25789
+ this.anthropicPlugin.enable();
25790
+ }
25791
+ if (integrations.aisdk !== false && integrations.vercel !== false) {
25792
+ this.aiSDKPlugin = new AISDKPlugin();
25793
+ this.aiSDKPlugin.enable();
25794
+ }
25795
+ if (integrations.claudeAgentSDK !== false) {
25796
+ this.claudeAgentSDKPlugin = new ClaudeAgentSDKPlugin();
23579
25797
  this.claudeAgentSDKPlugin.enable();
23580
25798
  }
23581
25799
  if (integrations.cursorSDK !== false && integrations.cursor !== false) {
23582
25800
  this.cursorSDKPlugin = new CursorSDKPlugin();
23583
25801
  this.cursorSDKPlugin.enable();
23584
25802
  }
25803
+ if (integrations.openAIAgents !== false) {
25804
+ this.openAIAgentsPlugin = new OpenAIAgentsPlugin();
25805
+ this.openAIAgentsPlugin.enable();
25806
+ }
23585
25807
  if (integrations.googleGenAI !== false && integrations.google !== false) {
23586
25808
  this.googleGenAIPlugin = new GoogleGenAIPlugin();
23587
25809
  this.googleGenAIPlugin.enable();
@@ -23622,6 +25844,14 @@ var BraintrustPlugin = class extends BasePlugin {
23622
25844
  this.gitHubCopilotPlugin = new GitHubCopilotPlugin();
23623
25845
  this.gitHubCopilotPlugin.enable();
23624
25846
  }
25847
+ if (getIntegrationConfig(integrations, "flue") !== false) {
25848
+ this.fluePlugin = new FluePlugin();
25849
+ this.fluePlugin.enable();
25850
+ }
25851
+ if (integrations.langchain !== false && integrations.langgraph !== false) {
25852
+ this.langChainPlugin = new LangChainPlugin();
25853
+ this.langChainPlugin.enable();
25854
+ }
23625
25855
  }
23626
25856
  onDisable() {
23627
25857
  if (this.openaiPlugin) {
@@ -23648,6 +25878,10 @@ var BraintrustPlugin = class extends BasePlugin {
23648
25878
  this.cursorSDKPlugin.disable();
23649
25879
  this.cursorSDKPlugin = null;
23650
25880
  }
25881
+ if (this.openAIAgentsPlugin) {
25882
+ this.openAIAgentsPlugin.disable();
25883
+ this.openAIAgentsPlugin = null;
25884
+ }
23651
25885
  if (this.googleGenAIPlugin) {
23652
25886
  this.googleGenAIPlugin.disable();
23653
25887
  this.googleGenAIPlugin = null;
@@ -23688,9 +25922,104 @@ var BraintrustPlugin = class extends BasePlugin {
23688
25922
  this.gitHubCopilotPlugin.disable();
23689
25923
  this.gitHubCopilotPlugin = null;
23690
25924
  }
25925
+ if (this.fluePlugin) {
25926
+ this.fluePlugin.disable();
25927
+ this.fluePlugin = null;
25928
+ }
25929
+ if (this.langChainPlugin) {
25930
+ this.langChainPlugin.disable();
25931
+ this.langChainPlugin = null;
25932
+ }
23691
25933
  }
23692
25934
  };
23693
25935
 
25936
+ // src/instrumentation/config.ts
25937
+ var envIntegrationAliases = {
25938
+ openai: "openai",
25939
+ "openai-codex": "openaiCodexSDK",
25940
+ "openai-codex-sdk": "openaiCodexSDK",
25941
+ openaicodexsdk: "openaiCodexSDK",
25942
+ codex: "openaiCodexSDK",
25943
+ "codex-sdk": "openaiCodexSDK",
25944
+ anthropic: "anthropic",
25945
+ aisdk: "aisdk",
25946
+ "ai-sdk": "aisdk",
25947
+ "vercel-ai": "aisdk",
25948
+ vercel: "vercel",
25949
+ claudeagentsdk: "claudeAgentSDK",
25950
+ "claude-agent-sdk": "claudeAgentSDK",
25951
+ cursor: "cursor",
25952
+ "cursor-sdk": "cursorSDK",
25953
+ cursorsdk: "cursorSDK",
25954
+ flue: "flue",
25955
+ "flue-runtime": "flue",
25956
+ "openai-agents": "openAIAgents",
25957
+ openaiagents: "openAIAgents",
25958
+ "openai-agents-core": "openAIAgents",
25959
+ openaiagentscore: "openAIAgents",
25960
+ google: "google",
25961
+ "google-genai": "googleGenAI",
25962
+ googlegenai: "googleGenAI",
25963
+ huggingface: "huggingface",
25964
+ openrouter: "openrouter",
25965
+ openrouteragent: "openrouterAgent",
25966
+ "openrouter-agent": "openrouterAgent",
25967
+ mistral: "mistral",
25968
+ googleadk: "googleADK",
25969
+ "google-adk": "googleADK",
25970
+ cohere: "cohere",
25971
+ groq: "groq",
25972
+ "groq-sdk": "groq",
25973
+ genkit: "genkit",
25974
+ "firebase-genkit": "genkit",
25975
+ githubcopilot: "gitHubCopilot",
25976
+ "github-copilot": "gitHubCopilot",
25977
+ "copilot-sdk": "gitHubCopilot",
25978
+ langchain: "langchain",
25979
+ "langchain-js": "langchain",
25980
+ "@langchain": "langchain",
25981
+ langgraph: "langgraph"
25982
+ };
25983
+ function getDefaultInstrumentationIntegrations() {
25984
+ return {
25985
+ openai: true,
25986
+ openaiCodexSDK: true,
25987
+ anthropic: true,
25988
+ vercel: true,
25989
+ aisdk: true,
25990
+ google: true,
25991
+ googleGenAI: true,
25992
+ googleADK: true,
25993
+ huggingface: true,
25994
+ claudeAgentSDK: true,
25995
+ cursor: true,
25996
+ cursorSDK: true,
25997
+ flue: true,
25998
+ openAIAgents: true,
25999
+ openrouter: true,
26000
+ openrouterAgent: true,
26001
+ mistral: true,
26002
+ cohere: true,
26003
+ groq: true,
26004
+ genkit: true,
26005
+ gitHubCopilot: true,
26006
+ langchain: true,
26007
+ langgraph: true
26008
+ };
26009
+ }
26010
+ function readDisabledInstrumentationEnvConfig(disabledList) {
26011
+ const integrations = {};
26012
+ if (disabledList) {
26013
+ for (const value of disabledList.split(",")) {
26014
+ const sdk = value.trim().toLowerCase();
26015
+ if (sdk.length > 0) {
26016
+ integrations[envIntegrationAliases[sdk] ?? sdk] = false;
26017
+ }
26018
+ }
26019
+ }
26020
+ return { integrations };
26021
+ }
26022
+
23694
26023
  // src/instrumentation/registry.ts
23695
26024
  var REGISTRY_STATE_KEY = /* @__PURE__ */ Symbol.for("braintrust.registry");
23696
26025
  function getSharedState() {
@@ -23769,50 +26098,16 @@ var PluginRegistry = class {
23769
26098
  * Get default configuration (all integrations enabled).
23770
26099
  */
23771
26100
  getDefaultConfig() {
23772
- return {
23773
- openai: true,
23774
- openaiCodexSDK: true,
23775
- anthropic: true,
23776
- vercel: true,
23777
- aisdk: true,
23778
- google: true,
23779
- googleGenAI: true,
23780
- googleADK: true,
23781
- huggingface: true,
23782
- claudeAgentSDK: true,
23783
- cursor: true,
23784
- cursorSDK: true,
23785
- openrouter: true,
23786
- openrouterAgent: true,
23787
- mistral: true,
23788
- cohere: true,
23789
- groq: true,
23790
- genkit: true,
23791
- gitHubCopilot: true
23792
- };
26101
+ return getDefaultInstrumentationIntegrations();
23793
26102
  }
23794
26103
  /**
23795
26104
  * Read configuration from environment variables.
23796
26105
  * Supports: BRAINTRUST_DISABLE_INSTRUMENTATION=openai,anthropic,...
23797
26106
  */
23798
26107
  readEnvConfig() {
23799
- const integrations = {};
23800
- const disabledList = isomorph_default.getEnv("BRAINTRUST_DISABLE_INSTRUMENTATION");
23801
- if (disabledList) {
23802
- const disabled = disabledList.split(",").map((s) => s.trim().toLowerCase()).filter((s) => s.length > 0);
23803
- for (const sdk of disabled) {
23804
- if (sdk === "cursor-sdk") {
23805
- integrations.cursorSDK = false;
23806
- } else if (sdk === "githubcopilot" || sdk === "github-copilot" || sdk === "copilot-sdk") {
23807
- integrations.gitHubCopilot = false;
23808
- } else if (sdk === "openai-codex-sdk") {
23809
- integrations.openaiCodexSDK = false;
23810
- } else {
23811
- integrations[sdk] = false;
23812
- }
23813
- }
23814
- }
23815
- return { integrations };
26108
+ return readDisabledInstrumentationEnvConfig(
26109
+ isomorph_default.getEnv("BRAINTRUST_DISABLE_INSTRUMENTATION")
26110
+ );
23816
26111
  }
23817
26112
  };
23818
26113
  var registry = new PluginRegistry();
@@ -23927,6 +26222,10 @@ function configureBrowser() {
23927
26222
  }
23928
26223
  return process.env[name];
23929
26224
  };
26225
+ isomorph_default.getBraintrustApiKey = async () => {
26226
+ const value = isomorph_default.getEnv("BRAINTRUST_API_KEY");
26227
+ return value?.trim() ? value : void 0;
26228
+ };
23930
26229
  isomorph_default.hash = (data) => {
23931
26230
  let hash = 0;
23932
26231
  for (let i = 0; i < data.length; i++) {
@@ -23948,8 +26247,10 @@ __export(exports_exports, {
23948
26247
  Attachment: () => Attachment,
23949
26248
  AttachmentReference: () => AttachmentReference,
23950
26249
  BRAINTRUST_CURRENT_SPAN_STORE: () => BRAINTRUST_CURRENT_SPAN_STORE,
26250
+ BRAINTRUST_LANGCHAIN_CALLBACK_HANDLER_NAME: () => BRAINTRUST_LANGCHAIN_CALLBACK_HANDLER_NAME,
23951
26251
  BaseAttachment: () => BaseAttachment,
23952
26252
  BaseExperiment: () => BaseExperiment,
26253
+ BraintrustLangChainCallbackHandler: () => BraintrustLangChainCallbackHandler,
23953
26254
  BraintrustMiddleware: () => BraintrustMiddleware,
23954
26255
  BraintrustState: () => BraintrustState,
23955
26256
  BraintrustStream: () => BraintrustStream,
@@ -23960,6 +26261,7 @@ __export(exports_exports, {
23960
26261
  DEFAULT_FETCH_BATCH_SIZE: () => DEFAULT_FETCH_BATCH_SIZE,
23961
26262
  DEFAULT_MAX_REQUEST_SIZE: () => DEFAULT_MAX_REQUEST_SIZE,
23962
26263
  Dataset: () => Dataset2,
26264
+ DatasetPipeline: () => DatasetPipeline,
23963
26265
  ERR_PERMALINK: () => ERR_PERMALINK,
23964
26266
  Eval: () => Eval,
23965
26267
  EvalResultWithSummary: () => EvalResultWithSummary,
@@ -24075,6 +26377,8 @@ __export(exports_exports, {
24075
26377
  wrapCohere: () => wrapCohere,
24076
26378
  wrapCopilotClient: () => wrapCopilotClient,
24077
26379
  wrapCursorSDK: () => wrapCursorSDK,
26380
+ wrapFlueContext: () => wrapFlueContext,
26381
+ wrapFlueSession: () => wrapFlueSession,
24078
26382
  wrapGenkit: () => wrapGenkit,
24079
26383
  wrapGoogleADK: () => wrapGoogleADK,
24080
26384
  wrapGoogleGenAI: () => wrapGoogleGenAI,
@@ -25174,7 +27478,7 @@ function extractModelParameters(params, excludeKeys) {
25174
27478
  }
25175
27479
  return modelParams;
25176
27480
  }
25177
- function getNumberProperty2(obj, key) {
27481
+ function getNumberProperty3(obj, key) {
25178
27482
  if (!obj || typeof obj !== "object" || !(key in obj)) {
25179
27483
  return void 0;
25180
27484
  }
@@ -25183,31 +27487,31 @@ function getNumberProperty2(obj, key) {
25183
27487
  }
25184
27488
  function normalizeUsageMetrics(usage, provider, providerMetadata) {
25185
27489
  const metrics = {};
25186
- const inputTokens = getNumberProperty2(usage, "inputTokens");
27490
+ const inputTokens = getNumberProperty3(usage, "inputTokens");
25187
27491
  if (inputTokens !== void 0) {
25188
27492
  metrics.prompt_tokens = inputTokens;
25189
27493
  }
25190
- const outputTokens = getNumberProperty2(usage, "outputTokens");
27494
+ const outputTokens = getNumberProperty3(usage, "outputTokens");
25191
27495
  if (outputTokens !== void 0) {
25192
27496
  metrics.completion_tokens = outputTokens;
25193
27497
  }
25194
- const totalTokens = getNumberProperty2(usage, "totalTokens");
27498
+ const totalTokens = getNumberProperty3(usage, "totalTokens");
25195
27499
  if (totalTokens !== void 0) {
25196
27500
  metrics.tokens = totalTokens;
25197
27501
  }
25198
- const reasoningTokens = getNumberProperty2(usage, "reasoningTokens");
27502
+ const reasoningTokens = getNumberProperty3(usage, "reasoningTokens");
25199
27503
  if (reasoningTokens !== void 0) {
25200
27504
  metrics.completion_reasoning_tokens = reasoningTokens;
25201
27505
  }
25202
- const cachedInputTokens = getNumberProperty2(usage, "cachedInputTokens");
27506
+ const cachedInputTokens = getNumberProperty3(usage, "cachedInputTokens");
25203
27507
  if (cachedInputTokens !== void 0) {
25204
27508
  metrics.prompt_cached_tokens = cachedInputTokens;
25205
27509
  }
25206
27510
  if (provider === "anthropic") {
25207
27511
  const anthropicMetadata = providerMetadata?.anthropic;
25208
27512
  if (anthropicMetadata) {
25209
- const cacheReadTokens = getNumberProperty2(anthropicMetadata.usage, "cache_read_input_tokens") || 0;
25210
- const cacheCreationTokens = getNumberProperty2(
27513
+ const cacheReadTokens = getNumberProperty3(anthropicMetadata.usage, "cache_read_input_tokens") || 0;
27514
+ const cacheCreationTokens = getNumberProperty3(
25211
27515
  anthropicMetadata.usage,
25212
27516
  "cache_creation_input_tokens"
25213
27517
  ) || 0;
@@ -26182,17 +28486,17 @@ function wrapGenkit(genkit) {
26182
28486
  console.warn("Unsupported Genkit object. Not wrapping.");
26183
28487
  return genkit;
26184
28488
  }
26185
- function isRecord(value) {
28489
+ function isRecord2(value) {
26186
28490
  return typeof value === "object" && value !== null;
26187
28491
  }
26188
28492
  function isPropertyBag(value) {
26189
- return isRecord(value) || typeof value === "function";
28493
+ return isRecord2(value) || typeof value === "function";
26190
28494
  }
26191
28495
  function hasFunction(value, methodName) {
26192
28496
  return isPropertyBag(value) && methodName in value && typeof value[methodName] === "function";
26193
28497
  }
26194
28498
  function isGenkitInstance(value) {
26195
- return isRecord(value) && (hasFunction(value, "generate") || hasFunction(value, "generateStream") || hasFunction(value, "defineFlow") || hasFunction(value, "defineTool"));
28499
+ return isRecord2(value) && (hasFunction(value, "generate") || hasFunction(value, "generateStream") || hasFunction(value, "defineFlow") || hasFunction(value, "defineTool"));
26196
28500
  }
26197
28501
  function isGenkitModule(value) {
26198
28502
  return hasFunction(value, "genkit");
@@ -26246,7 +28550,7 @@ function patchGenkitRegistry(instance) {
26246
28550
  patchGenkitRegistryConstructor(registry2);
26247
28551
  }
26248
28552
  function patchGenkitRegistryLookup(registry2) {
26249
- if (!isRecord(registry2) || hasRegistryPatchedFlag(registry2) || !hasFunction(registry2, "lookupAction")) {
28553
+ if (!isRecord2(registry2) || hasRegistryPatchedFlag(registry2) || !hasFunction(registry2, "lookupAction")) {
26250
28554
  return;
26251
28555
  }
26252
28556
  const originalLookupAction = registry2.lookupAction;
@@ -26272,7 +28576,7 @@ function patchGenkitRegistryLookup(registry2) {
26272
28576
  }
26273
28577
  }
26274
28578
  function patchGenkitRegistryConstructor(registry2) {
26275
- if (!isRecord(registry2)) {
28579
+ if (!isRecord2(registry2)) {
26276
28580
  return;
26277
28581
  }
26278
28582
  const constructor = registry2.constructor;
@@ -26288,7 +28592,7 @@ function patchGenkitRegistryConstructor(registry2) {
26288
28592
  configurable: true,
26289
28593
  value: (...args) => {
26290
28594
  const childRegistry = originalWithParent.apply(constructor, args);
26291
- if (args.some((arg) => isRecord(arg) && hasRegistryPatchedFlag(arg))) {
28595
+ if (args.some((arg) => isRecord2(arg) && hasRegistryPatchedFlag(arg))) {
26292
28596
  patchGenkitRegistryLookup(childRegistry);
26293
28597
  patchGenkitRegistryConstructor(childRegistry);
26294
28598
  }
@@ -26387,7 +28691,7 @@ function hasRegistryConstructorPatchedFlag(value) {
26387
28691
  );
26388
28692
  }
26389
28693
  function isPromiseLike2(value) {
26390
- return isRecord(value) && "then" in value && typeof value.then === "function";
28694
+ return isRecord2(value) && "then" in value && typeof value.then === "function";
26391
28695
  }
26392
28696
 
26393
28697
  // src/wrappers/huggingface.ts
@@ -26750,14 +29054,14 @@ function wrapMistral(mistral) {
26750
29054
  console.warn("Unsupported Mistral library. Not wrapping.");
26751
29055
  return mistral;
26752
29056
  }
26753
- function isRecord2(value) {
29057
+ function isRecord3(value) {
26754
29058
  return typeof value === "object" && value !== null;
26755
29059
  }
26756
29060
  function hasFunction3(value, methodName) {
26757
- return isRecord2(value) && methodName in value && typeof value[methodName] === "function";
29061
+ return isRecord3(value) && methodName in value && typeof value[methodName] === "function";
26758
29062
  }
26759
29063
  function isSupportedMistralClient(value) {
26760
- if (!isRecord2(value)) {
29064
+ if (!isRecord3(value)) {
26761
29065
  return false;
26762
29066
  }
26763
29067
  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);
@@ -26941,14 +29245,14 @@ function wrapCohere(cohere) {
26941
29245
  return cohere;
26942
29246
  }
26943
29247
  var cohereProxyCache = /* @__PURE__ */ new WeakMap();
26944
- function isRecord3(value) {
29248
+ function isRecord4(value) {
26945
29249
  return typeof value === "object" && value !== null;
26946
29250
  }
26947
29251
  function hasFunction4(value, methodName) {
26948
- return isRecord3(value) && methodName in value && typeof value[methodName] === "function";
29252
+ return isRecord4(value) && methodName in value && typeof value[methodName] === "function";
26949
29253
  }
26950
29254
  function isSupportedCohereClient(value) {
26951
- if (!isRecord3(value)) {
29255
+ if (!isRecord4(value)) {
26952
29256
  return false;
26953
29257
  }
26954
29258
  return hasFunction4(value, "chat") || hasFunction4(value, "chatStream") || hasFunction4(value, "embed") || hasFunction4(value, "rerank");
@@ -27008,20 +29312,20 @@ function wrapGroq(groq) {
27008
29312
  console.warn("Unsupported Groq library. Not wrapping.");
27009
29313
  return groq;
27010
29314
  }
27011
- function isRecord4(value) {
29315
+ function isRecord5(value) {
27012
29316
  return typeof value === "object" && value !== null;
27013
29317
  }
27014
29318
  function hasFunction5(value, methodName) {
27015
- return isRecord4(value) && methodName in value && typeof value[methodName] === "function";
29319
+ return isRecord5(value) && methodName in value && typeof value[methodName] === "function";
27016
29320
  }
27017
29321
  function hasChat2(value) {
27018
- return isRecord4(value) && isRecord4(value.completions) && hasFunction5(value.completions, "create");
29322
+ return isRecord5(value) && isRecord5(value.completions) && hasFunction5(value.completions, "create");
27019
29323
  }
27020
29324
  function hasEmbeddings2(value) {
27021
29325
  return hasFunction5(value, "create");
27022
29326
  }
27023
29327
  function isSupportedGroqClient(value) {
27024
- return isRecord4(value) && (value.chat !== void 0 && hasChat2(value.chat) || value.embeddings !== void 0 && hasEmbeddings2(value.embeddings));
29328
+ return isRecord5(value) && (value.chat !== void 0 && hasChat2(value.chat) || value.embeddings !== void 0 && hasEmbeddings2(value.embeddings));
27025
29329
  }
27026
29330
  function groqProxy(groq) {
27027
29331
  const privateMethodWorkaroundCache = /* @__PURE__ */ new WeakMap();
@@ -27216,10 +29520,12 @@ function formatExperimentSummary(summary) {
27216
29520
  // src/wrappers/shared/flush.ts
27217
29521
  async function summarizeAndFlush(experiment, options) {
27218
29522
  const shouldDisplay = options.displaySummary ?? true;
27219
- const summary = await experiment.summarize();
27220
- if (shouldDisplay) {
27221
- console.log(formatExperimentSummary(summary));
29523
+ if (!shouldDisplay) {
29524
+ await experiment.flush();
29525
+ return;
27222
29526
  }
29527
+ const summary = await experiment.summarize();
29528
+ console.log(formatExperimentSummary(summary));
27223
29529
  }
27224
29530
 
27225
29531
  // src/wrappers/vitest/flush-manager.ts
@@ -29083,8 +31389,12 @@ var waterfall$1 = awaitify(waterfall);
29083
31389
 
29084
31390
  // src/trace.ts
29085
31391
  var SpanFetcher = class _SpanFetcher extends ObjectFetcher {
29086
- constructor(objectType, _objectId, rootSpanId, _state, spanTypeFilter) {
29087
- const filterExpr = _SpanFetcher.buildFilter(rootSpanId, spanTypeFilter);
31392
+ constructor(objectType, _objectId, rootSpanId, _state, spanTypeFilter, includeScorers = false) {
31393
+ const filterExpr = _SpanFetcher.buildFilter(
31394
+ rootSpanId,
31395
+ spanTypeFilter,
31396
+ includeScorers
31397
+ );
29088
31398
  super(objectType, void 0, void 0, {
29089
31399
  filter: filterExpr
29090
31400
  });
@@ -29093,16 +31403,17 @@ var SpanFetcher = class _SpanFetcher extends ObjectFetcher {
29093
31403
  this._state = _state;
29094
31404
  this.spanTypeFilter = spanTypeFilter;
29095
31405
  }
29096
- static buildFilter(rootSpanId, spanTypeFilter) {
31406
+ static buildFilter(rootSpanId, spanTypeFilter, includeScorers = false) {
29097
31407
  const children = [
29098
31408
  // Base filter: root_span_id = 'value'
29099
31409
  {
29100
31410
  op: "eq",
29101
31411
  left: { op: "ident", name: ["root_span_id"] },
29102
31412
  right: { op: "literal", value: rootSpanId }
29103
- },
29104
- // Exclude span_attributes.purpose = 'score'
29105
- {
31413
+ }
31414
+ ];
31415
+ if (!includeScorers) {
31416
+ children.push({
29106
31417
  op: "or",
29107
31418
  children: [
29108
31419
  {
@@ -29115,8 +31426,8 @@ var SpanFetcher = class _SpanFetcher extends ObjectFetcher {
29115
31426
  right: { op: "literal", value: "scorer" }
29116
31427
  }
29117
31428
  ]
29118
- }
29119
- ];
31429
+ });
31430
+ }
29120
31431
  if (spanTypeFilter && spanTypeFilter.length > 0) {
29121
31432
  children.push({
29122
31433
  op: "in",
@@ -29142,35 +31453,49 @@ var CachedSpanFetcher = class {
29142
31453
  fetchFn;
29143
31454
  constructor(objectTypeOrFetchFn, objectId, rootSpanId, getState) {
29144
31455
  if (typeof objectTypeOrFetchFn === "function") {
29145
- this.fetchFn = objectTypeOrFetchFn;
31456
+ this.fetchFn = (spanType) => objectTypeOrFetchFn(spanType);
29146
31457
  } else {
29147
31458
  const objectType = objectTypeOrFetchFn;
29148
- this.fetchFn = async (spanType) => {
31459
+ this.fetchFn = async (spanType, includeScorers) => {
29149
31460
  const state = await getState();
29150
31461
  const fetcher = new SpanFetcher(
29151
31462
  objectType,
29152
31463
  objectId,
29153
31464
  rootSpanId,
29154
31465
  state,
29155
- spanType
31466
+ spanType,
31467
+ includeScorers
29156
31468
  );
29157
31469
  const rows = await fetcher.fetchedData();
29158
- return rows.filter((row) => row.span_attributes?.purpose !== "scorer").map((row) => ({
31470
+ return rows.map((row) => ({
29159
31471
  input: row.input,
29160
31472
  output: row.output,
31473
+ expected: row.expected,
31474
+ error: row.error,
31475
+ scores: row.scores,
31476
+ metrics: row.metrics,
29161
31477
  metadata: row.metadata,
29162
31478
  span_id: row.span_id,
29163
31479
  span_parents: row.span_parents,
31480
+ is_root: row.is_root,
29164
31481
  span_attributes: row.span_attributes,
29165
31482
  id: row.id,
29166
31483
  _xact_id: row._xact_id,
29167
31484
  _pagination_key: row._pagination_key,
29168
- root_span_id: row.root_span_id
31485
+ root_span_id: row.root_span_id,
31486
+ created: row.created,
31487
+ tags: row.tags
29169
31488
  }));
29170
31489
  };
29171
31490
  }
29172
31491
  }
29173
- async getSpans({ spanType } = {}) {
31492
+ async getSpans({
31493
+ spanType,
31494
+ includeScorers = false
31495
+ } = {}) {
31496
+ if (includeScorers) {
31497
+ return this.fetchFn(spanType, true);
31498
+ }
29174
31499
  if (this.allFetched) {
29175
31500
  return this.getFromCache(spanType);
29176
31501
  }
@@ -29187,7 +31512,7 @@ var CachedSpanFetcher = class {
29187
31512
  return this.getFromCache(spanType);
29188
31513
  }
29189
31514
  async fetchSpans(spanType) {
29190
- const spans = await this.fetchFn(spanType);
31515
+ const spans = await this.fetchFn(spanType, false);
29191
31516
  for (const span of spans) {
29192
31517
  const type = span.span_attributes?.type ?? "";
29193
31518
  const existing = this.spanCache.get(type) ?? [];
@@ -29265,10 +31590,13 @@ var LocalTrace = class {
29265
31590
  * First checks the local span cache for recently logged spans, then falls
29266
31591
  * back to CachedSpanFetcher which handles BTQL fetching and caching.
29267
31592
  */
29268
- async getSpans({ spanType } = {}) {
31593
+ async getSpans({
31594
+ spanType,
31595
+ includeScorers = false
31596
+ } = {}) {
29269
31597
  const cachedSpans = this.state.spanCache.getByRootSpanId(this.rootSpanId);
29270
31598
  if (cachedSpans && cachedSpans.length > 0) {
29271
- let spans = cachedSpans.filter(
31599
+ let spans = includeScorers ? cachedSpans : cachedSpans.filter(
29272
31600
  (span) => span.span_attributes?.purpose !== "scorer"
29273
31601
  );
29274
31602
  if (spanType && spanType.length > 0) {
@@ -29279,13 +31607,19 @@ var LocalTrace = class {
29279
31607
  return spans.map((span) => ({
29280
31608
  input: span.input,
29281
31609
  output: span.output,
31610
+ expected: span.expected,
31611
+ error: span.error,
31612
+ scores: span.scores,
31613
+ metrics: span.metrics,
29282
31614
  metadata: span.metadata,
29283
31615
  span_id: span.span_id,
29284
31616
  span_parents: span.span_parents,
29285
- span_attributes: span.span_attributes
31617
+ is_root: span.is_root,
31618
+ span_attributes: span.span_attributes,
31619
+ tags: span.tags
29286
31620
  }));
29287
31621
  }
29288
- return this.cachedFetcher.getSpans({ spanType });
31622
+ return this.cachedFetcher.getSpans({ spanType, includeScorers });
29289
31623
  }
29290
31624
  /**
29291
31625
  * Get the thread (preprocessed messages) for this trace.
@@ -30474,6 +32808,34 @@ var defaultReporter = {
30474
32808
  }
30475
32809
  };
30476
32810
 
32811
+ // src/dataset-pipeline.ts
32812
+ function DatasetPipeline(definition) {
32813
+ if (!globalThis.__braintrust_dataset_pipelines) {
32814
+ globalThis.__braintrust_dataset_pipelines = [];
32815
+ }
32816
+ const storedDefinition = {
32817
+ name: definition.name,
32818
+ source: {
32819
+ projectId: definition.source.projectId,
32820
+ projectName: definition.source.projectName,
32821
+ orgName: definition.source.orgName,
32822
+ filter: definition.source.filter,
32823
+ scope: definition.source.scope ?? "span"
32824
+ },
32825
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions, @typescript-eslint/no-explicit-any
32826
+ transform: definition.transform,
32827
+ target: {
32828
+ projectId: definition.target.projectId,
32829
+ projectName: definition.target.projectName,
32830
+ orgName: definition.target.orgName,
32831
+ datasetName: definition.target.datasetName,
32832
+ description: definition.target.description,
32833
+ metadata: definition.target.metadata
32834
+ }
32835
+ };
32836
+ globalThis.__braintrust_dataset_pipelines.push(storedDefinition);
32837
+ }
32838
+
30477
32839
  // src/framework2.ts
30478
32840
  var import_v312 = require("zod/v3");
30479
32841
  var currentFilename = typeof __filename !== "undefined" ? __filename : "unknown";