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
@@ -33,8 +33,10 @@ __export(edge_light_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(edge_light_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(edge_light_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,
@@ -263,6 +268,7 @@ var iso = {
263
268
  getRepoInfo: async (_settings) => void 0,
264
269
  getPastNAncestors: async () => [],
265
270
  getEnv: (_name) => void 0,
271
+ getBraintrustApiKey: async () => void 0,
266
272
  getCallerLocation: () => void 0,
267
273
  newAsyncLocalStorage: () => new DefaultAsyncLocalStorage(),
268
274
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -1095,6 +1101,11 @@ function isPromiseLike(value) {
1095
1101
 
1096
1102
  // util/object_util.ts
1097
1103
  var SET_UNION_FIELDS = /* @__PURE__ */ new Set(["tags"]);
1104
+ var FORBIDDEN_MERGE_KEYS = /* @__PURE__ */ new Set([
1105
+ "__proto__",
1106
+ "constructor",
1107
+ "prototype"
1108
+ ]);
1098
1109
  function mergeDictsWithPaths({
1099
1110
  mergeInto,
1100
1111
  mergeFrom,
@@ -1117,6 +1128,7 @@ function mergeDictsWithPathsHelper({
1117
1128
  mergePaths
1118
1129
  }) {
1119
1130
  Object.entries(mergeFrom).forEach(([k, mergeFromV]) => {
1131
+ if (FORBIDDEN_MERGE_KEYS.has(k)) return;
1120
1132
  const fullPath = path.concat([k]);
1121
1133
  const fullPathSerialized = JSON.stringify(fullPath);
1122
1134
  const mergeIntoV = recordFind(mergeInto, k);
@@ -5188,6 +5200,13 @@ var HTTPConnection = class _HTTPConnection {
5188
5200
  debugLogger.debug(
5189
5201
  `Retrying API request ${object_type} ${JSON.stringify(args)} ${e.status} ${e.text}`
5190
5202
  );
5203
+ const sleepTimeS = HTTP_RETRY_BASE_SLEEP_TIME_S * 2 ** i;
5204
+ debugLogger.info(
5205
+ `Sleeping for ${sleepTimeS}s before retrying API request`
5206
+ );
5207
+ await new Promise(
5208
+ (resolve) => setTimeout(resolve, sleepTimeS * 1e3)
5209
+ );
5191
5210
  continue;
5192
5211
  }
5193
5212
  throw e;
@@ -5589,6 +5608,19 @@ var JSONAttachment = class extends Attachment {
5589
5608
  */
5590
5609
  constructor(data, options) {
5591
5610
  const { filename = "data.json", pretty = false, state } = options ?? {};
5611
+ const deferredJsonAttachment = globalThis.__BT_DATASET_PIPELINE_DEFER_JSON_ATTACHMENT__;
5612
+ if (deferredJsonAttachment) {
5613
+ super({
5614
+ data: new Blob([]),
5615
+ filename,
5616
+ contentType: "application/json",
5617
+ state
5618
+ });
5619
+ return deferredJsonAttachment(data, {
5620
+ filename,
5621
+ pretty
5622
+ });
5623
+ }
5592
5624
  const jsonString = pretty ? JSON.stringify(data, null, 2) : JSON.stringify(data);
5593
5625
  const blob = new Blob([jsonString], { type: "application/json" });
5594
5626
  super({
@@ -5837,20 +5869,7 @@ function startSpanParentArgs(args) {
5837
5869
  `Mismatch between expected span parent object type ${args.parentObjectType} and provided type ${parentComponents.data.object_type}`
5838
5870
  );
5839
5871
  }
5840
- const parentComponentsObjectIdLambda = spanComponentsToObjectIdLambda(
5841
- args.state,
5842
- parentComponents
5843
- );
5844
- const computeParentObjectId = async () => {
5845
- const parentComponentsObjectId = await parentComponentsObjectIdLambda();
5846
- if (await args.parentObjectId.get() !== parentComponentsObjectId) {
5847
- throw new Error(
5848
- `Mismatch between expected span parent object id ${await args.parentObjectId.get()} and provided id ${parentComponentsObjectId}`
5849
- );
5850
- }
5851
- return await args.parentObjectId.get();
5852
- };
5853
- argParentObjectId = new LazyValue(computeParentObjectId);
5872
+ argParentObjectId = args.parentObjectId;
5854
5873
  if (parentComponents.data.row_id) {
5855
5874
  argParentSpanIds = {
5856
5875
  spanId: parentComponents.data.span_id,
@@ -6236,6 +6255,7 @@ var TestBackgroundLogger = class {
6236
6255
  }
6237
6256
  };
6238
6257
  var BACKGROUND_LOGGER_BASE_SLEEP_TIME_S = 1;
6258
+ var HTTP_RETRY_BASE_SLEEP_TIME_S = 1;
6239
6259
  var HTTPBackgroundLogger = class _HTTPBackgroundLogger {
6240
6260
  apiConn;
6241
6261
  queue;
@@ -6866,17 +6886,10 @@ function init(projectOrOptions, optionalOptions) {
6866
6886
  if (repoInfo) {
6867
6887
  return repoInfo;
6868
6888
  }
6869
- let mergedGitMetadataSettings = {
6870
- ...state.gitMetadataSettings || {
6871
- collect: "all"
6872
- }
6873
- };
6874
- if (gitMetadataSettings) {
6875
- mergedGitMetadataSettings = mergeGitMetadataSettings(
6876
- mergedGitMetadataSettings,
6877
- gitMetadataSettings
6878
- );
6879
- }
6889
+ const mergedGitMetadataSettings = state.gitMetadataSettings == null ? gitMetadataSettings ?? { collect: "none" } : mergeGitMetadataSettings(
6890
+ state.gitMetadataSettings,
6891
+ gitMetadataSettings ?? { collect: "all" }
6892
+ );
6880
6893
  return await isomorph_default.getRepoInfo(mergedGitMetadataSettings);
6881
6894
  })();
6882
6895
  if (repoInfoArg) {
@@ -7600,10 +7613,11 @@ async function login(options = {}) {
7600
7613
  async function loginToState(options = {}) {
7601
7614
  const {
7602
7615
  appUrl = isomorph_default.getEnv("BRAINTRUST_APP_URL") || "https://www.braintrust.dev",
7603
- apiKey = isomorph_default.getEnv("BRAINTRUST_API_KEY"),
7616
+ apiKey: apiKeyArg,
7604
7617
  orgName = isomorph_default.getEnv("BRAINTRUST_ORG_NAME"),
7605
7618
  fetch: fetch2 = globalThis.fetch
7606
7619
  } = options || {};
7620
+ const apiKey = apiKeyArg !== void 0 ? apiKeyArg : await isomorph_default.getBraintrustApiKey();
7607
7621
  const appPublicUrl = isomorph_default.getEnv("BRAINTRUST_APP_PUBLIC_URL") || appUrl;
7608
7622
  const state = new BraintrustState(options);
7609
7623
  state.resetLoginInfo();
@@ -8844,9 +8858,15 @@ var SpanImpl = class _SpanImpl {
8844
8858
  const cachedSpan = {
8845
8859
  input: partialRecord.input,
8846
8860
  output: partialRecord.output,
8861
+ expected: partialRecord.expected,
8862
+ error: partialRecord.error,
8863
+ scores: partialRecord.scores,
8864
+ metrics: partialRecord.metrics,
8847
8865
  metadata: partialRecord.metadata,
8866
+ tags: partialRecord.tags,
8848
8867
  span_id: this._spanId,
8849
8868
  span_parents: this._spanParents,
8869
+ is_root: this._spanId === this._rootSpanId,
8850
8870
  span_attributes: partialRecord.span_attributes
8851
8871
  };
8852
8872
  this._state.spanCache.queueWrite(
@@ -9182,6 +9202,7 @@ var Dataset2 = class extends ObjectFetcher {
9182
9202
  metadata,
9183
9203
  tags,
9184
9204
  output,
9205
+ origin,
9185
9206
  isMerge
9186
9207
  }) {
9187
9208
  return new LazyValue(async () => {
@@ -9196,6 +9217,7 @@ var Dataset2 = class extends ObjectFetcher {
9196
9217
  created: !isMerge ? (/* @__PURE__ */ new Date()).toISOString() : void 0,
9197
9218
  //if we're merging/updating an event we will not add this ts
9198
9219
  metadata,
9220
+ origin,
9199
9221
  ...!!isMerge ? {
9200
9222
  [IS_MERGE_FIELD]: true
9201
9223
  } : {}
@@ -9215,6 +9237,7 @@ var Dataset2 = class extends ObjectFetcher {
9215
9237
  * about anything else that's relevant, that you can use to help find and analyze examples later. For example, you could log the
9216
9238
  * `prompt`, example's `id`, or anything else that would be useful to slice/dice later. The values in `metadata` can be any
9217
9239
  * JSON-serializable type, but its keys must be strings.
9240
+ * @param event.origin (Optional) a reference to the source object this dataset record was derived from.
9218
9241
  * @param event.id (Optional) a unique identifier for the event. If you don't provide one, Braintrust will generate one for you.
9219
9242
  * @param event.output: (Deprecated) The output of your application. Use `expected` instead.
9220
9243
  * @returns The `id` of the logged record.
@@ -9225,7 +9248,8 @@ var Dataset2 = class extends ObjectFetcher {
9225
9248
  metadata,
9226
9249
  tags,
9227
9250
  id,
9228
- output
9251
+ output,
9252
+ origin
9229
9253
  }) {
9230
9254
  this.validateEvent({ metadata, expected, output, tags });
9231
9255
  const rowId = id || (0, import_uuid2.v4)();
@@ -9237,6 +9261,7 @@ var Dataset2 = class extends ObjectFetcher {
9237
9261
  metadata,
9238
9262
  tags,
9239
9263
  output,
9264
+ origin,
9240
9265
  isMerge: false
9241
9266
  })
9242
9267
  );
@@ -13695,11 +13720,11 @@ function resolveDenyOutputPaths(event, defaultDenyOutputPaths) {
13695
13720
  if (Array.isArray(event?.denyOutputPaths)) {
13696
13721
  return event.denyOutputPaths;
13697
13722
  }
13698
- const firstArgument = event?.arguments && event.arguments.length > 0 ? event.arguments[0] : void 0;
13699
- if (!firstArgument || typeof firstArgument !== "object") {
13723
+ const firstArgument2 = event?.arguments && event.arguments.length > 0 ? event.arguments[0] : void 0;
13724
+ if (!firstArgument2 || typeof firstArgument2 !== "object") {
13700
13725
  return defaultDenyOutputPaths;
13701
13726
  }
13702
- const runtimeDenyOutputPaths = firstArgument[RUNTIME_DENY_OUTPUT_PATHS];
13727
+ const runtimeDenyOutputPaths = firstArgument2[RUNTIME_DENY_OUTPUT_PATHS];
13703
13728
  if (Array.isArray(runtimeDenyOutputPaths) && runtimeDenyOutputPaths.every((path) => typeof path === "string")) {
13704
13729
  return runtimeDenyOutputPaths;
13705
13730
  }
@@ -17358,6 +17383,467 @@ function cleanMetrics2(metrics) {
17358
17383
  return cleaned;
17359
17384
  }
17360
17385
 
17386
+ // src/instrumentation/plugins/openai-agents-channels.ts
17387
+ var openAIAgentsCoreChannels = defineChannels("@openai/agents-core", {
17388
+ onTraceStart: channel({
17389
+ channelName: "tracing.processor.onTraceStart",
17390
+ kind: "async"
17391
+ }),
17392
+ onTraceEnd: channel({
17393
+ channelName: "tracing.processor.onTraceEnd",
17394
+ kind: "async"
17395
+ }),
17396
+ onSpanStart: channel({
17397
+ channelName: "tracing.processor.onSpanStart",
17398
+ kind: "async"
17399
+ }),
17400
+ onSpanEnd: channel({
17401
+ channelName: "tracing.processor.onSpanEnd",
17402
+ kind: "async"
17403
+ })
17404
+ });
17405
+
17406
+ // src/instrumentation/plugins/openai-agents-trace-processor.ts
17407
+ function isSpanData(spanData, type) {
17408
+ return spanData.type === type;
17409
+ }
17410
+ function spanTypeFromAgents(span) {
17411
+ const spanType = span.spanData.type;
17412
+ if (spanType === "function" || spanType === "guardrail" || spanType === "mcp_tools") {
17413
+ return "tool" /* TOOL */;
17414
+ }
17415
+ if (spanType === "generation" || spanType === "response" || spanType === "transcription" || spanType === "speech") {
17416
+ return "llm" /* LLM */;
17417
+ }
17418
+ return "task" /* TASK */;
17419
+ }
17420
+ function spanNameFromAgents(span) {
17421
+ const spanData = span.spanData;
17422
+ if ("name" in spanData && spanData.name) {
17423
+ return spanData.name;
17424
+ }
17425
+ switch (spanData.type) {
17426
+ case "generation":
17427
+ return "Generation";
17428
+ case "response":
17429
+ return "Response";
17430
+ case "handoff":
17431
+ return "Handoff";
17432
+ case "mcp_tools":
17433
+ return isSpanData(spanData, "mcp_tools") && spanData.server ? `List Tools (${spanData.server})` : "MCP List Tools";
17434
+ case "transcription":
17435
+ return "Transcription";
17436
+ case "speech":
17437
+ return "Speech";
17438
+ case "speech_group":
17439
+ return "Speech Group";
17440
+ default:
17441
+ return "Unknown";
17442
+ }
17443
+ }
17444
+ function getTimeElapsed(end, start) {
17445
+ if (!start || !end) {
17446
+ return void 0;
17447
+ }
17448
+ const startTime = new Date(start).getTime();
17449
+ const endTime = new Date(end).getTime();
17450
+ if (Number.isNaN(startTime) || Number.isNaN(endTime)) {
17451
+ return void 0;
17452
+ }
17453
+ return (endTime - startTime) / 1e3;
17454
+ }
17455
+ function getNumberProperty2(obj, key) {
17456
+ if (!isObject(obj) || !(key in obj)) {
17457
+ return void 0;
17458
+ }
17459
+ const value = obj[key];
17460
+ return typeof value === "number" ? value : void 0;
17461
+ }
17462
+ function parseUsageMetrics(usage) {
17463
+ const metrics = {};
17464
+ if (!isObject(usage)) {
17465
+ return metrics;
17466
+ }
17467
+ const promptTokens = getNumberProperty2(usage, "prompt_tokens") ?? getNumberProperty2(usage, "input_tokens") ?? getNumberProperty2(usage, "promptTokens") ?? getNumberProperty2(usage, "inputTokens");
17468
+ const completionTokens = getNumberProperty2(usage, "completion_tokens") ?? getNumberProperty2(usage, "output_tokens") ?? getNumberProperty2(usage, "completionTokens") ?? getNumberProperty2(usage, "outputTokens");
17469
+ const totalTokens = getNumberProperty2(usage, "total_tokens") ?? getNumberProperty2(usage, "totalTokens");
17470
+ if (promptTokens !== void 0) {
17471
+ metrics.prompt_tokens = promptTokens;
17472
+ }
17473
+ if (completionTokens !== void 0) {
17474
+ metrics.completion_tokens = completionTokens;
17475
+ }
17476
+ if (totalTokens !== void 0) {
17477
+ metrics.tokens = totalTokens;
17478
+ } else if (promptTokens !== void 0 && completionTokens !== void 0) {
17479
+ metrics.tokens = promptTokens + completionTokens;
17480
+ }
17481
+ const inputDetails = usage.input_tokens_details;
17482
+ const cachedTokens = getNumberProperty2(inputDetails, "cached_tokens");
17483
+ const cacheWriteTokens = getNumberProperty2(
17484
+ inputDetails,
17485
+ "cache_write_tokens"
17486
+ );
17487
+ if (cachedTokens !== void 0) {
17488
+ metrics.prompt_cached_tokens = cachedTokens;
17489
+ }
17490
+ if (cacheWriteTokens !== void 0) {
17491
+ metrics.prompt_cache_creation_tokens = cacheWriteTokens;
17492
+ }
17493
+ return metrics;
17494
+ }
17495
+ var OpenAIAgentsTraceProcessor = class _OpenAIAgentsTraceProcessor {
17496
+ static DEFAULT_MAX_TRACES = 1e4;
17497
+ logger;
17498
+ maxTraces;
17499
+ traceSpans = /* @__PURE__ */ new Map();
17500
+ traceOrder = [];
17501
+ _traceSpans = this.traceSpans;
17502
+ constructor(options = {}) {
17503
+ this.logger = options.logger;
17504
+ this.maxTraces = options.maxTraces ?? _OpenAIAgentsTraceProcessor.DEFAULT_MAX_TRACES;
17505
+ }
17506
+ evictOldestTrace() {
17507
+ const oldestTraceId = this.traceOrder.shift();
17508
+ if (oldestTraceId) {
17509
+ this.traceSpans.delete(oldestTraceId);
17510
+ }
17511
+ }
17512
+ onTraceStart(trace) {
17513
+ if (!trace?.traceId) {
17514
+ return Promise.resolve();
17515
+ }
17516
+ if (this.traceOrder.length >= this.maxTraces) {
17517
+ this.evictOldestTrace();
17518
+ }
17519
+ const current = currentSpan();
17520
+ const span = current && current !== NOOP_SPAN ? current.startSpan({
17521
+ name: trace.name,
17522
+ type: "task" /* TASK */
17523
+ }) : this.logger ? this.logger.startSpan({
17524
+ name: trace.name,
17525
+ type: "task" /* TASK */
17526
+ }) : startSpan({
17527
+ name: trace.name,
17528
+ type: "task" /* TASK */
17529
+ });
17530
+ span.log({
17531
+ input: "Agent workflow started",
17532
+ metadata: {
17533
+ group_id: trace.groupId,
17534
+ ...trace.metadata || {}
17535
+ }
17536
+ });
17537
+ this.traceSpans.set(trace.traceId, {
17538
+ rootSpan: span,
17539
+ childSpans: /* @__PURE__ */ new Map(),
17540
+ metadata: {
17541
+ firstInput: null,
17542
+ lastOutput: null
17543
+ }
17544
+ });
17545
+ this.traceOrder.push(trace.traceId);
17546
+ return Promise.resolve();
17547
+ }
17548
+ async onTraceEnd(trace) {
17549
+ const traceData = this.traceSpans.get(trace?.traceId);
17550
+ if (!traceData) {
17551
+ return;
17552
+ }
17553
+ try {
17554
+ traceData.rootSpan.log({
17555
+ input: traceData.metadata.firstInput,
17556
+ output: traceData.metadata.lastOutput
17557
+ });
17558
+ traceData.rootSpan.end();
17559
+ await traceData.rootSpan.flush();
17560
+ } finally {
17561
+ this.traceSpans.delete(trace.traceId);
17562
+ const orderIndex = this.traceOrder.indexOf(trace.traceId);
17563
+ if (orderIndex > -1) {
17564
+ this.traceOrder.splice(orderIndex, 1);
17565
+ }
17566
+ }
17567
+ }
17568
+ onSpanStart(span) {
17569
+ if (!span?.spanId || !span.traceId) {
17570
+ return Promise.resolve();
17571
+ }
17572
+ const traceData = this.traceSpans.get(span.traceId);
17573
+ if (!traceData) {
17574
+ return Promise.resolve();
17575
+ }
17576
+ const parentSpan = span.parentId ? traceData.childSpans.get(span.parentId) : traceData.rootSpan;
17577
+ if (!parentSpan) {
17578
+ return Promise.resolve();
17579
+ }
17580
+ const childSpan = parentSpan.startSpan({
17581
+ name: spanNameFromAgents(span),
17582
+ type: spanTypeFromAgents(span)
17583
+ });
17584
+ traceData.childSpans.set(span.spanId, childSpan);
17585
+ return Promise.resolve();
17586
+ }
17587
+ onSpanEnd(span) {
17588
+ if (!span?.spanId || !span.traceId) {
17589
+ return Promise.resolve();
17590
+ }
17591
+ const traceData = this.traceSpans.get(span.traceId);
17592
+ if (!traceData) {
17593
+ return Promise.resolve();
17594
+ }
17595
+ const braintrustSpan = traceData.childSpans.get(span.spanId);
17596
+ if (!braintrustSpan) {
17597
+ return Promise.resolve();
17598
+ }
17599
+ const logData = this.extractLogData(span);
17600
+ braintrustSpan.log({
17601
+ error: span.error,
17602
+ ...logData
17603
+ });
17604
+ braintrustSpan.end();
17605
+ traceData.childSpans.delete(span.spanId);
17606
+ const input = logData.input;
17607
+ const output = logData.output;
17608
+ if (traceData.metadata.firstInput === null && input != null) {
17609
+ traceData.metadata.firstInput = input;
17610
+ }
17611
+ if (output != null) {
17612
+ traceData.metadata.lastOutput = output;
17613
+ }
17614
+ return Promise.resolve();
17615
+ }
17616
+ async shutdown() {
17617
+ if (this.logger && typeof this.logger.flush === "function") {
17618
+ await this.logger.flush();
17619
+ }
17620
+ }
17621
+ async forceFlush() {
17622
+ if (this.logger && typeof this.logger.flush === "function") {
17623
+ await this.logger.flush();
17624
+ }
17625
+ }
17626
+ extractLogData(span) {
17627
+ const spanData = span.spanData;
17628
+ switch (spanData.type) {
17629
+ case "agent":
17630
+ return this.extractAgentLogData(spanData);
17631
+ case "response":
17632
+ return this.extractResponseLogData(spanData, span);
17633
+ case "function":
17634
+ return this.extractFunctionLogData(spanData);
17635
+ case "handoff":
17636
+ return this.extractHandoffLogData(spanData);
17637
+ case "guardrail":
17638
+ return this.extractGuardrailLogData(spanData);
17639
+ case "generation":
17640
+ return this.extractGenerationLogData(spanData, span);
17641
+ case "custom":
17642
+ return this.extractCustomLogData(spanData);
17643
+ case "mcp_tools":
17644
+ return this.extractMCPListToolsLogData(spanData);
17645
+ case "transcription":
17646
+ return this.extractTranscriptionLogData(spanData);
17647
+ case "speech":
17648
+ return this.extractSpeechLogData(spanData);
17649
+ case "speech_group":
17650
+ return this.extractSpeechGroupLogData(spanData);
17651
+ default:
17652
+ return {};
17653
+ }
17654
+ }
17655
+ extractAgentLogData(spanData) {
17656
+ return {
17657
+ metadata: {
17658
+ tools: spanData.tools,
17659
+ handoffs: spanData.handoffs,
17660
+ output_type: spanData.output_type
17661
+ }
17662
+ };
17663
+ }
17664
+ extractResponseLogData(spanData, span) {
17665
+ const response = spanData._response;
17666
+ const output = isObject(response) ? response.output : void 0;
17667
+ const usage = isObject(response) ? response.usage : void 0;
17668
+ const metrics = {
17669
+ ...this.extractTimingMetrics(span),
17670
+ ...parseUsageMetrics(usage)
17671
+ };
17672
+ return {
17673
+ input: spanData._input,
17674
+ output,
17675
+ metadata: isObject(response) ? this.omitKeys(response, ["output", "usage"]) : {},
17676
+ metrics
17677
+ };
17678
+ }
17679
+ extractFunctionLogData(spanData) {
17680
+ return {
17681
+ input: spanData.input,
17682
+ output: spanData.output
17683
+ };
17684
+ }
17685
+ extractHandoffLogData(spanData) {
17686
+ return {
17687
+ metadata: {
17688
+ from_agent: spanData.from_agent,
17689
+ to_agent: spanData.to_agent
17690
+ }
17691
+ };
17692
+ }
17693
+ extractGuardrailLogData(spanData) {
17694
+ return {
17695
+ metadata: {
17696
+ triggered: spanData.triggered
17697
+ }
17698
+ };
17699
+ }
17700
+ extractGenerationLogData(spanData, span) {
17701
+ return {
17702
+ input: spanData.input,
17703
+ output: spanData.output,
17704
+ metadata: {
17705
+ model: spanData.model,
17706
+ model_config: spanData.model_config
17707
+ },
17708
+ metrics: {
17709
+ ...this.extractTimingMetrics(span),
17710
+ ...parseUsageMetrics(spanData.usage)
17711
+ }
17712
+ };
17713
+ }
17714
+ extractCustomLogData(spanData) {
17715
+ return spanData.data || {};
17716
+ }
17717
+ extractMCPListToolsLogData(spanData) {
17718
+ return {
17719
+ output: spanData.result,
17720
+ metadata: {
17721
+ server: spanData.server
17722
+ }
17723
+ };
17724
+ }
17725
+ extractTranscriptionLogData(spanData) {
17726
+ return {
17727
+ input: spanData.input,
17728
+ output: spanData.output,
17729
+ metadata: {
17730
+ model: spanData.model,
17731
+ model_config: spanData.model_config
17732
+ }
17733
+ };
17734
+ }
17735
+ extractSpeechLogData(spanData) {
17736
+ return {
17737
+ input: spanData.input,
17738
+ output: spanData.output,
17739
+ metadata: {
17740
+ model: spanData.model,
17741
+ model_config: spanData.model_config
17742
+ }
17743
+ };
17744
+ }
17745
+ extractSpeechGroupLogData(spanData) {
17746
+ return {
17747
+ input: spanData.input
17748
+ };
17749
+ }
17750
+ extractTimingMetrics(span) {
17751
+ const timeToFirstToken = getTimeElapsed(
17752
+ span.endedAt ?? void 0,
17753
+ span.startedAt ?? void 0
17754
+ );
17755
+ return timeToFirstToken === void 0 ? {} : { time_to_first_token: timeToFirstToken };
17756
+ }
17757
+ omitKeys(value, keys) {
17758
+ const result = {};
17759
+ for (const [key, fieldValue] of Object.entries(value)) {
17760
+ if (!keys.includes(key)) {
17761
+ result[key] = fieldValue;
17762
+ }
17763
+ }
17764
+ return result;
17765
+ }
17766
+ };
17767
+
17768
+ // src/instrumentation/plugins/openai-agents-plugin.ts
17769
+ function firstArgument(args) {
17770
+ if (Array.isArray(args)) {
17771
+ return args[0];
17772
+ }
17773
+ if (isObject(args) && "length" in args && typeof args.length === "number" && Number.isInteger(args.length) && args.length >= 0) {
17774
+ return Array.from(args)[0];
17775
+ }
17776
+ return void 0;
17777
+ }
17778
+ function isOpenAIAgentsTrace(value) {
17779
+ return isObject(value) && value.type === "trace" && typeof value.traceId === "string";
17780
+ }
17781
+ function isOpenAIAgentsSpan(value) {
17782
+ return isObject(value) && value.type === "trace.span" && typeof value.traceId === "string" && typeof value.spanId === "string";
17783
+ }
17784
+ var OpenAIAgentsPlugin = class extends BasePlugin {
17785
+ processor = new OpenAIAgentsTraceProcessor();
17786
+ onEnable() {
17787
+ this.subscribeToTraceLifecycle();
17788
+ }
17789
+ onDisable() {
17790
+ this.unsubscribers = unsubscribeAll(this.unsubscribers);
17791
+ void this.processor.shutdown();
17792
+ }
17793
+ subscribeToTraceLifecycle() {
17794
+ const traceStartChannel = openAIAgentsCoreChannels.onTraceStart.tracingChannel();
17795
+ const traceStartHandlers = {
17796
+ start: (event) => {
17797
+ const trace = firstArgument(event.arguments);
17798
+ if (isOpenAIAgentsTrace(trace)) {
17799
+ void this.processor.onTraceStart(trace);
17800
+ }
17801
+ }
17802
+ };
17803
+ traceStartChannel.subscribe(traceStartHandlers);
17804
+ this.unsubscribers.push(
17805
+ () => traceStartChannel.unsubscribe(traceStartHandlers)
17806
+ );
17807
+ const traceEndChannel = openAIAgentsCoreChannels.onTraceEnd.tracingChannel();
17808
+ const traceEndHandlers = {
17809
+ start: (event) => {
17810
+ const trace = firstArgument(event.arguments);
17811
+ if (isOpenAIAgentsTrace(trace)) {
17812
+ void this.processor.onTraceEnd(trace);
17813
+ }
17814
+ }
17815
+ };
17816
+ traceEndChannel.subscribe(traceEndHandlers);
17817
+ this.unsubscribers.push(
17818
+ () => traceEndChannel.unsubscribe(traceEndHandlers)
17819
+ );
17820
+ const spanStartChannel = openAIAgentsCoreChannels.onSpanStart.tracingChannel();
17821
+ const spanStartHandlers = {
17822
+ start: (event) => {
17823
+ const span = firstArgument(event.arguments);
17824
+ if (isOpenAIAgentsSpan(span)) {
17825
+ void this.processor.onSpanStart(span);
17826
+ }
17827
+ }
17828
+ };
17829
+ spanStartChannel.subscribe(spanStartHandlers);
17830
+ this.unsubscribers.push(
17831
+ () => spanStartChannel.unsubscribe(spanStartHandlers)
17832
+ );
17833
+ const spanEndChannel = openAIAgentsCoreChannels.onSpanEnd.tracingChannel();
17834
+ const spanEndHandlers = {
17835
+ start: (event) => {
17836
+ const span = firstArgument(event.arguments);
17837
+ if (isOpenAIAgentsSpan(span)) {
17838
+ void this.processor.onSpanEnd(span);
17839
+ }
17840
+ }
17841
+ };
17842
+ spanEndChannel.subscribe(spanEndHandlers);
17843
+ this.unsubscribers.push(() => spanEndChannel.unsubscribe(spanEndHandlers));
17844
+ }
17845
+ };
17846
+
17361
17847
  // src/instrumentation/plugins/google-genai-channels.ts
17362
17848
  var googleGenAIChannels = defineChannels("@google/genai", {
17363
17849
  generateContent: channel({
@@ -23650,58 +24136,1794 @@ var GitHubCopilotPlugin = class extends BasePlugin {
23650
24136
  }
23651
24137
  };
23652
24138
 
23653
- // src/instrumentation/braintrust-plugin.ts
23654
- function getIntegrationConfig(integrations, key) {
23655
- return integrations[key];
24139
+ // src/instrumentation/plugins/flue-channels.ts
24140
+ var flueChannels = defineChannels("@flue/runtime", {
24141
+ createContext: channel({
24142
+ channelName: "createFlueContext",
24143
+ kind: "sync-stream"
24144
+ }),
24145
+ openSession: channel({
24146
+ channelName: "Harness.openSession",
24147
+ kind: "async"
24148
+ }),
24149
+ contextEvent: channel({
24150
+ channelName: "context.event",
24151
+ kind: "sync-stream"
24152
+ }),
24153
+ prompt: channel({
24154
+ channelName: "session.prompt",
24155
+ kind: "async"
24156
+ }),
24157
+ skill: channel({
24158
+ channelName: "session.skill",
24159
+ kind: "async"
24160
+ }),
24161
+ task: channel({
24162
+ channelName: "session.task",
24163
+ kind: "async"
24164
+ }),
24165
+ compact: channel({
24166
+ channelName: "session.compact",
24167
+ kind: "async"
24168
+ })
24169
+ });
24170
+
24171
+ // src/wrappers/flue.ts
24172
+ var WRAPPED_FLUE_CONTEXT = /* @__PURE__ */ Symbol.for("braintrust.flue.wrapped-context");
24173
+ var WRAPPED_FLUE_HARNESS = /* @__PURE__ */ Symbol.for("braintrust.flue.wrapped-harness");
24174
+ var WRAPPED_FLUE_SESSION = /* @__PURE__ */ Symbol.for("braintrust.flue.wrapped-session");
24175
+ var SUBSCRIBED_FLUE_CONTEXT_EVENTS = /* @__PURE__ */ Symbol.for(
24176
+ "braintrust.flue.subscribed-context-events"
24177
+ );
24178
+ function wrapFlueContext(ctx) {
24179
+ if (!isPlausibleFlueContext(ctx)) {
24180
+ console.warn("Unsupported Flue context. Not wrapping.");
24181
+ return ctx;
24182
+ }
24183
+ const context = ctx;
24184
+ subscribeFlueContextEvents(context, { captureTurnSpans: true });
24185
+ return patchFlueContextInPlace(context);
23656
24186
  }
23657
- var BraintrustPlugin = class extends BasePlugin {
23658
- config;
23659
- openaiPlugin = null;
23660
- openAICodexPlugin = null;
23661
- anthropicPlugin = null;
23662
- aiSDKPlugin = null;
23663
- claudeAgentSDKPlugin = null;
23664
- cursorSDKPlugin = null;
23665
- googleGenAIPlugin = null;
23666
- huggingFacePlugin = null;
23667
- openRouterPlugin = null;
23668
- openRouterAgentPlugin = null;
23669
- mistralPlugin = null;
23670
- googleADKPlugin = null;
23671
- coherePlugin = null;
23672
- groqPlugin = null;
23673
- genkitPlugin = null;
23674
- gitHubCopilotPlugin = null;
23675
- constructor(config = {}) {
23676
- super();
23677
- this.config = config;
24187
+ function patchFlueContextInPlace(ctx) {
24188
+ const context = ctx;
24189
+ if (context[WRAPPED_FLUE_CONTEXT]) {
24190
+ return ctx;
23678
24191
  }
23679
- onEnable() {
23680
- const integrations = this.config.integrations || {};
23681
- if (integrations.openai !== false) {
23682
- this.openaiPlugin = new OpenAIPlugin();
23683
- this.openaiPlugin.enable();
23684
- }
23685
- if (integrations.openaiCodexSDK !== false) {
23686
- this.openAICodexPlugin = new OpenAICodexPlugin();
23687
- this.openAICodexPlugin.enable();
23688
- }
23689
- if (integrations.anthropic !== false) {
23690
- this.anthropicPlugin = new AnthropicPlugin();
23691
- this.anthropicPlugin.enable();
23692
- }
23693
- if (integrations.aisdk !== false && integrations.vercel !== false) {
23694
- this.aiSDKPlugin = new AISDKPlugin();
23695
- this.aiSDKPlugin.enable();
23696
- }
23697
- if (integrations.claudeAgentSDK !== false) {
23698
- this.claudeAgentSDKPlugin = new ClaudeAgentSDKPlugin();
24192
+ const originalInit = context.init.bind(context);
24193
+ try {
24194
+ Object.defineProperty(context, WRAPPED_FLUE_CONTEXT, {
24195
+ configurable: false,
24196
+ enumerable: false,
24197
+ value: true
24198
+ });
24199
+ Object.defineProperty(context, "init", {
24200
+ configurable: true,
24201
+ value: async function wrappedFlueInit(options) {
24202
+ const harness = await originalInit(options);
24203
+ return wrapFlueHarness(harness);
24204
+ },
24205
+ writable: true
24206
+ });
24207
+ } catch {
24208
+ }
24209
+ return ctx;
24210
+ }
24211
+ function wrapFlueSession(session) {
24212
+ if (!isPlausibleFlueSession(session)) {
24213
+ console.warn("Unsupported Flue session. Not wrapping.");
24214
+ return session;
24215
+ }
24216
+ return patchFlueSessionInPlace(session);
24217
+ }
24218
+ function subscribeFlueContextEvents(ctx, options = {}) {
24219
+ if (!ctx || typeof ctx !== "object" || typeof ctx.subscribeEvent !== "function") {
24220
+ return void 0;
24221
+ }
24222
+ const context = ctx;
24223
+ const captureTurnSpans = options.captureTurnSpans ?? true;
24224
+ const existingSubscription = context[SUBSCRIBED_FLUE_CONTEXT_EVENTS];
24225
+ if (existingSubscription) {
24226
+ if (existingSubscription.captureTurnSpans || !captureTurnSpans) {
24227
+ return void 0;
24228
+ }
24229
+ try {
24230
+ existingSubscription.unsubscribe();
24231
+ } catch {
24232
+ }
24233
+ }
24234
+ try {
24235
+ const unsubscribe = ctx.subscribeEvent((event) => {
24236
+ flueChannels.contextEvent.traceSync(() => void 0, {
24237
+ arguments: [event],
24238
+ captureTurnSpans,
24239
+ context: ctx
24240
+ });
24241
+ });
24242
+ if (existingSubscription) {
24243
+ existingSubscription.captureTurnSpans = captureTurnSpans;
24244
+ existingSubscription.unsubscribe = unsubscribe;
24245
+ } else {
24246
+ Object.defineProperty(context, SUBSCRIBED_FLUE_CONTEXT_EVENTS, {
24247
+ configurable: false,
24248
+ enumerable: false,
24249
+ value: {
24250
+ captureTurnSpans,
24251
+ unsubscribe
24252
+ }
24253
+ });
24254
+ }
24255
+ return unsubscribe;
24256
+ } catch {
24257
+ return void 0;
24258
+ }
24259
+ }
24260
+ function wrapFlueHarness(harness) {
24261
+ if (!isPlausibleFlueHarness(harness)) {
24262
+ return harness;
24263
+ }
24264
+ const target = harness;
24265
+ if (target[WRAPPED_FLUE_HARNESS]) {
24266
+ return harness;
24267
+ }
24268
+ const originalSession = target.session.bind(target);
24269
+ try {
24270
+ Object.defineProperty(target, WRAPPED_FLUE_HARNESS, {
24271
+ configurable: false,
24272
+ enumerable: false,
24273
+ value: true
24274
+ });
24275
+ Object.defineProperty(target, "session", {
24276
+ configurable: true,
24277
+ value: async function wrappedFlueHarnessSession(name, options) {
24278
+ const session = await originalSession(name, options);
24279
+ return patchFlueSessionInPlace(session);
24280
+ },
24281
+ writable: true
24282
+ });
24283
+ const sessions = target.sessions;
24284
+ if (sessions && typeof sessions === "object") {
24285
+ patchFlueSessionFactory(sessions, "get");
24286
+ patchFlueSessionFactory(sessions, "create");
24287
+ }
24288
+ } catch {
24289
+ }
24290
+ return harness;
24291
+ }
24292
+ function patchFlueSessionInPlace(session) {
24293
+ if (session[WRAPPED_FLUE_SESSION]) {
24294
+ return session;
24295
+ }
24296
+ try {
24297
+ Object.defineProperty(session, WRAPPED_FLUE_SESSION, {
24298
+ configurable: false,
24299
+ enumerable: false,
24300
+ value: true
24301
+ });
24302
+ patchCallHandleMethod(session, "prompt", flueChannels.prompt);
24303
+ patchCallHandleMethod(session, "skill", flueChannels.skill);
24304
+ patchCallHandleMethod(session, "task", flueChannels.task);
24305
+ patchCompact(session);
24306
+ } catch {
24307
+ }
24308
+ return session;
24309
+ }
24310
+ function patchFlueSessionFactory(sessions, method) {
24311
+ const original = sessions[method];
24312
+ if (typeof original !== "function") {
24313
+ return;
24314
+ }
24315
+ const bound = original.bind(sessions);
24316
+ Object.defineProperty(sessions, method, {
24317
+ configurable: true,
24318
+ value: async function wrappedFlueSessionFactory(name, options) {
24319
+ const session = await bound(name, options);
24320
+ return patchFlueSessionInPlace(session);
24321
+ },
24322
+ writable: true
24323
+ });
24324
+ }
24325
+ function patchCallHandleMethod(session, method, channel2) {
24326
+ const original = session[method];
24327
+ if (typeof original !== "function") {
24328
+ return;
24329
+ }
24330
+ const bound = original.bind(session);
24331
+ Object.defineProperty(session, method, {
24332
+ configurable: true,
24333
+ value(input, options) {
24334
+ const args = [input, options];
24335
+ const { originalResult, traced: traced2 } = traceFlueOperation(channel2, {
24336
+ context: {
24337
+ arguments: args,
24338
+ operation: method,
24339
+ session
24340
+ },
24341
+ run: () => bound(input, options)
24342
+ });
24343
+ return preserveCallHandle(originalResult, traced2);
24344
+ },
24345
+ writable: true
24346
+ });
24347
+ }
24348
+ function patchCompact(session) {
24349
+ const original = session.compact;
24350
+ if (typeof original !== "function") {
24351
+ return;
24352
+ }
24353
+ const bound = original.bind(session);
24354
+ Object.defineProperty(session, "compact", {
24355
+ configurable: true,
24356
+ value() {
24357
+ const context = {
24358
+ arguments: [],
24359
+ operation: "compact",
24360
+ session
24361
+ };
24362
+ return flueChannels.compact.tracePromise(() => bound(), context);
24363
+ },
24364
+ writable: true
24365
+ });
24366
+ }
24367
+ function traceFlueOperation(channel2, args) {
24368
+ const tracingChannel2 = channel2.tracingChannel();
24369
+ const context = args.context;
24370
+ let originalResult;
24371
+ let traced2;
24372
+ const run = () => {
24373
+ try {
24374
+ originalResult = args.run();
24375
+ tracingChannel2.end?.publish(context);
24376
+ } catch (error) {
24377
+ context.error = normalizeError3(error);
24378
+ tracingChannel2.error?.publish(context);
24379
+ tracingChannel2.end?.publish(context);
24380
+ throw error;
24381
+ }
24382
+ traced2 = Promise.resolve(originalResult).then(
24383
+ (result) => {
24384
+ context.result = result;
24385
+ tracingChannel2.asyncStart?.publish(context);
24386
+ tracingChannel2.asyncEnd?.publish(context);
24387
+ return result;
24388
+ },
24389
+ (error) => {
24390
+ context.error = normalizeError3(error);
24391
+ tracingChannel2.error?.publish(context);
24392
+ tracingChannel2.asyncStart?.publish(context);
24393
+ tracingChannel2.asyncEnd?.publish(context);
24394
+ throw error;
24395
+ }
24396
+ );
24397
+ };
24398
+ if (tracingChannel2.start?.runStores) {
24399
+ tracingChannel2.start.runStores(context, run);
24400
+ } else {
24401
+ tracingChannel2.start?.publish(context);
24402
+ run();
24403
+ }
24404
+ return { originalResult, traced: traced2 };
24405
+ }
24406
+ function normalizeError3(error) {
24407
+ return error instanceof Error ? error : new Error(String(error));
24408
+ }
24409
+ function preserveCallHandle(originalHandle, traced2) {
24410
+ if (!isFlueCallHandle(originalHandle)) {
24411
+ return traced2;
24412
+ }
24413
+ const handle = originalHandle;
24414
+ const wrapped = {
24415
+ get signal() {
24416
+ return handle.signal;
24417
+ },
24418
+ abort(reason) {
24419
+ return handle.abort(reason);
24420
+ },
24421
+ then(onfulfilled, onrejected) {
24422
+ return traced2.then(onfulfilled, onrejected);
24423
+ }
24424
+ };
24425
+ return wrapped;
24426
+ }
24427
+ function isPlausibleFlueContext(value) {
24428
+ return !!value && typeof value === "object" && typeof value.init === "function";
24429
+ }
24430
+ function isPlausibleFlueHarness(value) {
24431
+ return !!value && typeof value === "object" && typeof value.session === "function";
24432
+ }
24433
+ function isPlausibleFlueSession(value) {
24434
+ return !!value && typeof value === "object" && typeof value.prompt === "function" && typeof value.skill === "function" && typeof value.task === "function" && typeof value.compact === "function";
24435
+ }
24436
+ function isFlueCallHandle(value) {
24437
+ return !!value && typeof value === "object" && typeof value.then === "function" && typeof value.abort === "function" && "signal" in value;
24438
+ }
24439
+
24440
+ // src/instrumentation/plugins/flue-plugin.ts
24441
+ var FluePlugin = class extends BasePlugin {
24442
+ activeOperationsById = /* @__PURE__ */ new Map();
24443
+ activeOperationsByScope = /* @__PURE__ */ new Map();
24444
+ compactionsByScope = /* @__PURE__ */ new Map();
24445
+ pendingOperationsByKey = /* @__PURE__ */ new Map();
24446
+ tasksById = /* @__PURE__ */ new Map();
24447
+ toolsById = /* @__PURE__ */ new Map();
24448
+ turnsByScope = /* @__PURE__ */ new Map();
24449
+ onEnable() {
24450
+ this.subscribeToContextCreation();
24451
+ this.subscribeToSessionCreation();
24452
+ this.subscribeToContextEvents();
24453
+ this.subscribeToSessionOperations();
24454
+ }
24455
+ onDisable() {
24456
+ for (const unsubscribe of this.unsubscribers) {
24457
+ unsubscribe();
24458
+ }
24459
+ this.unsubscribers = [];
24460
+ this.activeOperationsById.clear();
24461
+ this.activeOperationsByScope.clear();
24462
+ this.compactionsByScope.clear();
24463
+ this.pendingOperationsByKey.clear();
24464
+ this.tasksById.clear();
24465
+ this.toolsById.clear();
24466
+ this.turnsByScope.clear();
24467
+ }
24468
+ subscribeToContextCreation() {
24469
+ const channel2 = flueChannels.createContext.tracingChannel();
24470
+ const handlers = {
24471
+ end: (event) => {
24472
+ const ctx = event.result;
24473
+ if (!ctx) {
24474
+ return;
24475
+ }
24476
+ subscribeFlueContextEvents(ctx, { captureTurnSpans: false });
24477
+ patchFlueContextInPlace(ctx);
24478
+ },
24479
+ error: () => {
24480
+ }
24481
+ };
24482
+ channel2.subscribe(handlers);
24483
+ this.unsubscribers.push(() => {
24484
+ channel2.unsubscribe(handlers);
24485
+ });
24486
+ }
24487
+ subscribeToSessionCreation() {
24488
+ const channel2 = flueChannels.openSession.tracingChannel();
24489
+ const handlers = {
24490
+ asyncEnd: (event) => {
24491
+ if (event.result) {
24492
+ patchFlueSessionInPlace(
24493
+ event.result
24494
+ );
24495
+ }
24496
+ if (event.harness) {
24497
+ wrapFlueHarness(event.harness);
24498
+ }
24499
+ },
24500
+ error: () => {
24501
+ }
24502
+ };
24503
+ channel2.subscribe(handlers);
24504
+ this.unsubscribers.push(() => {
24505
+ channel2.unsubscribe(handlers);
24506
+ });
24507
+ }
24508
+ subscribeToSessionOperations() {
24509
+ this.subscribeToSessionOperation(flueChannels.prompt);
24510
+ this.subscribeToSessionOperation(flueChannels.skill);
24511
+ this.subscribeToSessionOperation(flueChannels.task);
24512
+ this.subscribeToCompact();
24513
+ }
24514
+ subscribeToSessionOperation(channel2) {
24515
+ const tracingChannel2 = channel2.tracingChannel();
24516
+ const states = /* @__PURE__ */ new WeakMap();
24517
+ const ensureState2 = (event) => {
24518
+ const existing = states.get(event);
24519
+ if (existing) {
24520
+ return existing;
24521
+ }
24522
+ const state = this.startOperationState({
24523
+ args: event.arguments,
24524
+ moduleVersion: typeof event.moduleVersion === "string" ? event.moduleVersion : void 0,
24525
+ operation: event.operation,
24526
+ session: event.session
24527
+ });
24528
+ states.set(event, state);
24529
+ return state;
24530
+ };
24531
+ const unbindCurrentSpanStore = this.bindCurrentSpanStoreToOperationStart(
24532
+ tracingChannel2,
24533
+ ensureState2
24534
+ );
24535
+ const handlers = {
24536
+ start: (event) => {
24537
+ ensureState2(event);
24538
+ },
24539
+ asyncEnd: (event) => {
24540
+ this.endOperationState(states.get(event), event.result);
24541
+ states.delete(event);
24542
+ },
24543
+ error: (event) => {
24544
+ const state = states.get(event);
24545
+ if (state && event.error) {
24546
+ safeLog3(state.span, { error: errorToString(event.error) });
24547
+ this.finishOperationState(state);
24548
+ }
24549
+ states.delete(event);
24550
+ }
24551
+ };
24552
+ tracingChannel2.subscribe(handlers);
24553
+ this.unsubscribers.push(() => {
24554
+ unbindCurrentSpanStore?.();
24555
+ tracingChannel2.unsubscribe(handlers);
24556
+ });
24557
+ }
24558
+ subscribeToCompact() {
24559
+ const tracingChannel2 = flueChannels.compact.tracingChannel();
24560
+ const states = /* @__PURE__ */ new WeakMap();
24561
+ const ensureState2 = (event) => {
24562
+ const existing = states.get(event);
24563
+ if (existing) {
24564
+ return existing;
24565
+ }
24566
+ const state = this.startOperationState({
24567
+ args: [],
24568
+ moduleVersion: typeof event.moduleVersion === "string" ? event.moduleVersion : void 0,
24569
+ operation: event.operation,
24570
+ session: event.session
24571
+ });
24572
+ states.set(event, state);
24573
+ return state;
24574
+ };
24575
+ const unbindCurrentSpanStore = this.bindCurrentSpanStoreToOperationStart(
24576
+ tracingChannel2,
24577
+ ensureState2
24578
+ );
24579
+ const handlers = {
24580
+ start: (event) => {
24581
+ ensureState2(event);
24582
+ },
24583
+ asyncEnd: (event) => {
24584
+ this.endOperationState(states.get(event), void 0);
24585
+ states.delete(event);
24586
+ },
24587
+ error: (event) => {
24588
+ const state = states.get(event);
24589
+ if (state && event.error) {
24590
+ safeLog3(state.span, { error: errorToString(event.error) });
24591
+ this.finishOperationState(state);
24592
+ }
24593
+ states.delete(event);
24594
+ }
24595
+ };
24596
+ tracingChannel2.subscribe(handlers);
24597
+ this.unsubscribers.push(() => {
24598
+ unbindCurrentSpanStore?.();
24599
+ tracingChannel2.unsubscribe(handlers);
24600
+ });
24601
+ }
24602
+ subscribeToContextEvents() {
24603
+ const channel2 = flueChannels.contextEvent.tracingChannel();
24604
+ const handlers = {
24605
+ start: (event) => {
24606
+ const flueEvent = event.arguments[0];
24607
+ if (!flueEvent) {
24608
+ return;
24609
+ }
24610
+ try {
24611
+ this.handleFlueEvent(flueEvent, {
24612
+ captureTurnSpans: event.captureTurnSpans !== false
24613
+ });
24614
+ } catch (error) {
24615
+ logInstrumentationError3("Flue event", error);
24616
+ }
24617
+ },
24618
+ error: () => {
24619
+ }
24620
+ };
24621
+ channel2.subscribe(handlers);
24622
+ this.unsubscribers.push(() => {
24623
+ channel2.unsubscribe(handlers);
24624
+ });
24625
+ }
24626
+ bindCurrentSpanStoreToOperationStart(tracingChannel2, ensureState2) {
24627
+ const state = _internalGetGlobalState();
24628
+ const startChannel = tracingChannel2.start;
24629
+ const contextManager = state?.contextManager;
24630
+ const currentSpanStore = contextManager ? contextManager[BRAINTRUST_CURRENT_SPAN_STORE] : void 0;
24631
+ if (!currentSpanStore || !startChannel) {
24632
+ return void 0;
24633
+ }
24634
+ startChannel.bindStore(currentSpanStore, (event) => {
24635
+ const operationState = ensureState2(event);
24636
+ return contextManager.wrapSpanForStore(operationState.span);
24637
+ });
24638
+ return () => {
24639
+ startChannel.unbindStore(currentSpanStore);
24640
+ };
24641
+ }
24642
+ startOperationState(args) {
24643
+ const sessionName = getSessionName(args.session);
24644
+ const metadata = {
24645
+ ...extractOperationInputMetadata(args.operation, args.args),
24646
+ ...extractSessionMetadata(args.session),
24647
+ "flue.operation": args.operation,
24648
+ provider: "flue",
24649
+ ...args.moduleVersion ? { "flue.version": args.moduleVersion } : {}
24650
+ };
24651
+ const span = startSpan({
24652
+ name: `flue.session.${args.operation}`,
24653
+ spanAttributes: { type: "task" /* TASK */ }
24654
+ });
24655
+ const state = {
24656
+ metadata,
24657
+ operation: args.operation,
24658
+ sessionName,
24659
+ span,
24660
+ startTime: getCurrentUnixTimestamp()
24661
+ };
24662
+ safeLog3(span, {
24663
+ input: extractOperationInput(args.operation, args.args),
24664
+ metadata
24665
+ });
24666
+ this.pendingOperationQueue(operationKey(sessionName, args.operation)).push(
24667
+ state
24668
+ );
24669
+ addOperationToScope(
24670
+ this.activeOperationsByScope,
24671
+ sessionName ?? "unknown",
24672
+ state
24673
+ );
24674
+ return state;
24675
+ }
24676
+ endOperationState(state, result) {
24677
+ if (!state) {
24678
+ return;
24679
+ }
24680
+ const metadata = {
24681
+ ...state.metadata,
24682
+ ...extractPromptResponseMetadata(result)
24683
+ };
24684
+ const metrics = {
24685
+ ...buildDurationMetrics3(state.startTime),
24686
+ ...metricsFromUsage(result?.usage)
24687
+ };
24688
+ safeLog3(state.span, {
24689
+ metadata,
24690
+ metrics,
24691
+ output: extractOperationOutput(result)
24692
+ });
24693
+ this.finishCompactionsForOperation(state);
24694
+ this.finishOperationState(state);
24695
+ }
24696
+ finishOperationState(state) {
24697
+ removePendingOperation(this.pendingOperationsByKey, state);
24698
+ if (state.operationId) {
24699
+ this.activeOperationsById.delete(state.operationId);
24700
+ }
24701
+ removeScopedOperation(this.activeOperationsByScope, state);
24702
+ state.span.end();
24703
+ }
24704
+ handleFlueEvent(event, options) {
24705
+ switch (event.type) {
24706
+ case "operation_start":
24707
+ this.handleOperationStart(event);
24708
+ return;
24709
+ case "operation":
24710
+ this.handleOperation(event);
24711
+ return;
24712
+ case "text_delta":
24713
+ if (!options.captureTurnSpans) {
24714
+ return;
24715
+ }
24716
+ this.ensureTurnState(event).text.push(
24717
+ typeof event.text === "string" ? event.text : ""
24718
+ );
24719
+ return;
24720
+ case "thinking_start":
24721
+ if (!options.captureTurnSpans) {
24722
+ return;
24723
+ }
24724
+ this.handleThinkingStart(event);
24725
+ return;
24726
+ case "thinking_delta":
24727
+ if (!options.captureTurnSpans) {
24728
+ return;
24729
+ }
24730
+ this.handleThinkingDelta(event);
24731
+ return;
24732
+ case "thinking_end":
24733
+ if (!options.captureTurnSpans) {
24734
+ return;
24735
+ }
24736
+ this.handleThinkingEnd(event);
24737
+ return;
24738
+ case "turn":
24739
+ if (!options.captureTurnSpans) {
24740
+ return;
24741
+ }
24742
+ this.handleTurn(event);
24743
+ return;
24744
+ case "tool_start":
24745
+ this.handleToolStart(event, options);
24746
+ return;
24747
+ case "tool_call":
24748
+ this.handleToolCall(event);
24749
+ return;
24750
+ case "task_start":
24751
+ this.handleTaskStart(event);
24752
+ return;
24753
+ case "task":
24754
+ this.handleTask(event);
24755
+ return;
24756
+ case "compaction_start":
24757
+ this.handleCompactionStart(event);
24758
+ return;
24759
+ case "compaction":
24760
+ this.handleCompaction(event);
24761
+ return;
24762
+ default:
24763
+ return;
24764
+ }
24765
+ }
24766
+ handleOperationStart(event) {
24767
+ if (!isInstrumentedOperation(event.operationKind)) {
24768
+ return;
24769
+ }
24770
+ const state = this.takePendingOperationForEvent(event);
24771
+ if (!state) {
24772
+ return;
24773
+ }
24774
+ state.operationId = event.operationId;
24775
+ this.activeOperationsById.set(event.operationId, state);
24776
+ addScopedOperation(this.activeOperationsByScope, event, state);
24777
+ state.metadata = {
24778
+ ...state.metadata,
24779
+ ...extractEventMetadata(event),
24780
+ "flue.operation_id": event.operationId
24781
+ };
24782
+ safeLog3(state.span, { metadata: state.metadata });
24783
+ }
24784
+ handleOperation(event) {
24785
+ const state = event.operationId ? this.activeOperationsById.get(event.operationId) : void 0;
24786
+ if (!state) {
24787
+ return;
24788
+ }
24789
+ const metadata = {
24790
+ ...state.metadata,
24791
+ ...extractEventMetadata(event),
24792
+ ...typeof event.durationMs === "number" ? { "flue.duration_ms": event.durationMs } : {},
24793
+ ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {}
24794
+ };
24795
+ const metrics = metricsFromUsage(event.usage);
24796
+ safeLog3(state.span, {
24797
+ ...event.error ? { error: errorToString(event.error) } : {},
24798
+ metadata,
24799
+ ...Object.keys(metrics).length ? { metrics } : {}
24800
+ });
24801
+ }
24802
+ ensureTurnState(event) {
24803
+ const scope = scopeKey(event);
24804
+ const existing = this.turnsByScope.get(scope);
24805
+ if (existing) {
24806
+ return existing;
24807
+ }
24808
+ const parent = this.parentSpanForEvent(event);
24809
+ const metadata = {
24810
+ ...extractEventMetadata(event),
24811
+ provider: "flue"
24812
+ };
24813
+ const span = startFlueSpan(parent, {
24814
+ name: "flue.turn",
24815
+ spanAttributes: { type: "llm" /* LLM */ }
24816
+ });
24817
+ const state = {
24818
+ metadata,
24819
+ span,
24820
+ hasThinking: false,
24821
+ startTime: getCurrentUnixTimestamp(),
24822
+ text: [],
24823
+ thinking: [],
24824
+ toolCalls: []
24825
+ };
24826
+ safeLog3(span, { metadata });
24827
+ this.turnsByScope.set(scope, state);
24828
+ return state;
24829
+ }
24830
+ handleTurn(event) {
24831
+ const scope = scopeKey(event);
24832
+ const state = this.ensureTurnState(event);
24833
+ const text = state.text.join("");
24834
+ const reasoning = state.finalThinking ?? state.thinking.join("");
24835
+ const outputReasoning = reasoning || (state.hasThinking ? "[reasoning stream present; content unavailable]" : void 0);
24836
+ const metadata = {
24837
+ ...state.metadata,
24838
+ ...extractEventMetadata(event),
24839
+ ...event.model ? { model: event.model, "flue.model": event.model } : {},
24840
+ ...event.stopReason ? { "flue.stop_reason": event.stopReason } : {},
24841
+ ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {},
24842
+ provider: "flue"
24843
+ };
24844
+ safeLog3(state.span, {
24845
+ ...event.error ? { error: errorToString(event.error) } : {},
24846
+ metadata,
24847
+ metrics: {
24848
+ ...durationMsMetrics(event.durationMs),
24849
+ ...metricsFromUsage(event.usage)
24850
+ },
24851
+ output: toAssistantOutput(
24852
+ text,
24853
+ event.stopReason,
24854
+ outputReasoning,
24855
+ state.toolCalls
24856
+ )
24857
+ });
24858
+ state.span.end();
24859
+ this.turnsByScope.delete(scope);
24860
+ }
24861
+ handleThinkingDelta(event) {
24862
+ const delta = event.delta;
24863
+ if (typeof delta !== "string" || !delta) {
24864
+ return;
24865
+ }
24866
+ const state = this.ensureTurnState(event);
24867
+ state.hasThinking = true;
24868
+ state.metadata["flue.thinking"] = true;
24869
+ state.thinking.push(delta);
24870
+ }
24871
+ handleThinkingStart(event) {
24872
+ const state = this.ensureTurnState(event);
24873
+ state.hasThinking = true;
24874
+ state.metadata["flue.thinking"] = true;
24875
+ }
24876
+ handleThinkingEnd(event) {
24877
+ const state = this.ensureTurnState(event);
24878
+ state.hasThinking = true;
24879
+ state.metadata["flue.thinking"] = true;
24880
+ if (typeof event.content === "string" && event.content) {
24881
+ state.finalThinking = event.content;
24882
+ }
24883
+ }
24884
+ handleToolStart(event, options) {
24885
+ const toolCallId = event.toolCallId;
24886
+ if (!toolCallId) {
24887
+ return;
24888
+ }
24889
+ const parent = this.parentSpanForEvent(event);
24890
+ const scope = scopeKey(event);
24891
+ let turnState = this.turnsByScope.get(scope);
24892
+ if (!turnState && parent && options.captureTurnSpans) {
24893
+ turnState = this.ensureTurnState(event);
24894
+ }
24895
+ const metadata = {
24896
+ ...extractEventMetadata(event),
24897
+ ...event.toolName ? { "flue.tool_name": event.toolName } : {},
24898
+ "flue.tool_call_id": toolCallId,
24899
+ provider: "flue"
24900
+ };
24901
+ const span = startFlueSpan(parent, {
24902
+ name: `tool: ${event.toolName ?? "unknown"}`,
24903
+ spanAttributes: { type: "tool" /* TOOL */ }
24904
+ });
24905
+ if (turnState) {
24906
+ turnState.toolCalls.push({
24907
+ args: event.args,
24908
+ toolCallId,
24909
+ toolName: event.toolName
24910
+ });
24911
+ }
24912
+ safeLog3(span, {
24913
+ input: event.args,
24914
+ metadata
24915
+ });
24916
+ this.toolsById.set(toolKey(event), {
24917
+ metadata,
24918
+ span,
24919
+ startTime: getCurrentUnixTimestamp()
24920
+ });
24921
+ }
24922
+ handleToolCall(event) {
24923
+ const key = toolKey(event);
24924
+ const state = this.toolsById.get(key) ?? this.startSyntheticToolState(event, event.toolName ?? "unknown");
24925
+ const metadata = {
24926
+ ...state.metadata,
24927
+ ...extractEventMetadata(event),
24928
+ ...event.toolName ? { "flue.tool_name": event.toolName } : {},
24929
+ ...event.toolCallId ? { "flue.tool_call_id": event.toolCallId } : {},
24930
+ ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {}
24931
+ };
24932
+ safeLog3(state.span, {
24933
+ ...event.isError ? { error: errorToString(event.result) } : {},
24934
+ metadata,
24935
+ metrics: durationMsMetrics(event.durationMs),
24936
+ output: event.result
24937
+ });
24938
+ state.span.end();
24939
+ this.toolsById.delete(key);
24940
+ }
24941
+ handleTaskStart(event) {
24942
+ const parent = this.parentSpanForEvent(event);
24943
+ const metadata = {
24944
+ ...extractEventMetadata(event),
24945
+ ...event.role ? { "flue.role": event.role } : {},
24946
+ ...event.cwd ? { "flue.cwd": event.cwd } : {},
24947
+ "flue.task_id": event.taskId,
24948
+ provider: "flue"
24949
+ };
24950
+ const span = startFlueSpan(parent, {
24951
+ name: "flue.task",
24952
+ spanAttributes: { type: "task" /* TASK */ }
24953
+ });
24954
+ safeLog3(span, {
24955
+ input: event.prompt,
24956
+ metadata
24957
+ });
24958
+ this.tasksById.set(event.taskId, {
24959
+ metadata,
24960
+ span,
24961
+ startTime: getCurrentUnixTimestamp()
24962
+ });
24963
+ }
24964
+ handleTask(event) {
24965
+ const state = this.tasksById.get(event.taskId);
24966
+ if (!state) {
24967
+ return;
24968
+ }
24969
+ safeLog3(state.span, {
24970
+ ...event.isError ? { error: errorToString(event.result) } : {},
24971
+ metadata: {
24972
+ ...state.metadata,
24973
+ ...extractEventMetadata(event),
24974
+ ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {}
24975
+ },
24976
+ metrics: durationMsMetrics(event.durationMs),
24977
+ output: event.result
24978
+ });
24979
+ state.span.end();
24980
+ this.tasksById.delete(event.taskId);
24981
+ }
24982
+ handleCompactionStart(event) {
24983
+ const operationState = this.operationStateForEvent(event);
24984
+ const parent = operationState?.span ?? this.parentSpanForEvent(event);
24985
+ const metadata = {
24986
+ ...extractEventMetadata(event),
24987
+ ...event.reason ? { "flue.compaction_reason": event.reason } : {},
24988
+ provider: "flue"
24989
+ };
24990
+ const input = {
24991
+ ...typeof event.estimatedTokens === "number" ? { estimatedTokens: event.estimatedTokens } : {},
24992
+ ...event.reason ? { reason: event.reason } : {}
24993
+ };
24994
+ const span = startFlueSpan(parent, {
24995
+ name: "flue.compaction",
24996
+ spanAttributes: { type: "task" /* TASK */ }
24997
+ });
24998
+ safeLog3(span, {
24999
+ input,
25000
+ metadata
25001
+ });
25002
+ this.compactionsByScope.set(scopeKey(event), {
25003
+ input,
25004
+ metadata,
25005
+ operationState,
25006
+ span,
25007
+ startTime: getCurrentUnixTimestamp()
25008
+ });
25009
+ }
25010
+ handleCompaction(event) {
25011
+ const key = scopeKey(event);
25012
+ const state = this.compactionsByScope.get(key) ?? this.findCompactionState(event);
25013
+ if (!state) {
25014
+ return;
25015
+ }
25016
+ safeLog3(state.span, {
25017
+ metadata: {
25018
+ ...state.metadata,
25019
+ ...extractEventMetadata(event),
25020
+ ...typeof event.messagesBefore === "number" ? { "flue.messages_before": event.messagesBefore } : {},
25021
+ ...typeof event.messagesAfter === "number" ? { "flue.messages_after": event.messagesAfter } : {}
25022
+ },
25023
+ metrics: {
25024
+ ...durationMsMetrics(event.durationMs),
25025
+ ...metricsFromUsage(event.usage)
25026
+ },
25027
+ output: {
25028
+ messagesAfter: event.messagesAfter,
25029
+ messagesBefore: event.messagesBefore
25030
+ }
25031
+ });
25032
+ state.span.end();
25033
+ this.deleteCompactionState(state);
25034
+ }
25035
+ findCompactionState(event) {
25036
+ const operationState = this.operationStateForEvent(event);
25037
+ for (const state of this.compactionsByScope.values()) {
25038
+ if (operationState && state.operationState === operationState) {
25039
+ return state;
25040
+ }
25041
+ }
25042
+ return void 0;
25043
+ }
25044
+ finishCompactionsForOperation(operationState) {
25045
+ for (const state of [...this.compactionsByScope.values()]) {
25046
+ if (state.operationState !== operationState) {
25047
+ continue;
25048
+ }
25049
+ safeLog3(state.span, {
25050
+ input: state.input,
25051
+ metadata: state.metadata,
25052
+ metrics: {
25053
+ ...buildDurationMetrics3(state.startTime)
25054
+ },
25055
+ output: { completed: true }
25056
+ });
25057
+ state.span.end();
25058
+ this.deleteCompactionState(state);
25059
+ }
25060
+ }
25061
+ deleteCompactionState(state) {
25062
+ for (const [key, candidate] of this.compactionsByScope) {
25063
+ if (candidate !== state) {
25064
+ continue;
25065
+ }
25066
+ this.compactionsByScope.delete(key);
25067
+ return;
25068
+ }
25069
+ }
25070
+ startSyntheticToolState(event, toolName) {
25071
+ const parent = this.parentSpanForEvent(event);
25072
+ const metadata = {
25073
+ ...extractEventMetadata(event),
25074
+ ...event.toolCallId ? { "flue.tool_call_id": event.toolCallId } : {},
25075
+ "flue.tool_name": toolName,
25076
+ provider: "flue"
25077
+ };
25078
+ const span = startFlueSpan(parent, {
25079
+ name: `tool: ${toolName}`,
25080
+ spanAttributes: { type: "tool" /* TOOL */ }
25081
+ });
25082
+ safeLog3(span, { metadata });
25083
+ return { metadata, span, startTime: getCurrentUnixTimestamp() };
25084
+ }
25085
+ operationStateForEvent(event) {
25086
+ if (event.operationId) {
25087
+ const operation = this.activeOperationsById.get(event.operationId) ?? this.promotePendingOperationForEvent(event);
25088
+ if (operation) {
25089
+ return operation;
25090
+ }
25091
+ }
25092
+ return this.activeOperationForEventScope(event) ?? this.pendingOperationForEventScope(event);
25093
+ }
25094
+ parentSpanForEvent(event) {
25095
+ if (event.operationId) {
25096
+ const operation = this.operationStateForEvent(event);
25097
+ if (operation) {
25098
+ return operation.span;
25099
+ }
25100
+ }
25101
+ if (event.taskId) {
25102
+ return this.tasksById.get(event.taskId)?.span;
25103
+ }
25104
+ return this.operationStateForEvent(event)?.span;
25105
+ }
25106
+ promotePendingOperationForEvent(event) {
25107
+ if (!event.operationId) {
25108
+ return void 0;
25109
+ }
25110
+ const scopePrefixes = operationScopePrefixes(event);
25111
+ for (const [candidateKey, candidateQueue] of this.pendingOperationsByKey) {
25112
+ if (!candidateQueue.length || !operationKeyMatchesScopes(candidateKey, scopePrefixes)) {
25113
+ continue;
25114
+ }
25115
+ const state = candidateQueue.shift();
25116
+ if (!state) {
25117
+ return void 0;
25118
+ }
25119
+ state.operationId = event.operationId;
25120
+ this.activeOperationsById.set(event.operationId, state);
25121
+ addScopedOperation(this.activeOperationsByScope, event, state);
25122
+ state.metadata = {
25123
+ ...state.metadata,
25124
+ ...extractEventMetadata(event),
25125
+ "flue.operation_id": event.operationId
25126
+ };
25127
+ safeLog3(state.span, { metadata: state.metadata });
25128
+ return state;
25129
+ }
25130
+ return void 0;
25131
+ }
25132
+ activeOperationForEventScope(event) {
25133
+ for (const scope of operationScopeNames(event)) {
25134
+ const operations = this.activeOperationsByScope.get(scope);
25135
+ if (operations?.length) {
25136
+ return operations[operations.length - 1];
25137
+ }
25138
+ }
25139
+ return void 0;
25140
+ }
25141
+ pendingOperationForEventScope(event) {
25142
+ const scopePrefixes = operationScopePrefixes(event);
25143
+ for (const [candidateKey, candidateQueue] of this.pendingOperationsByKey) {
25144
+ if (!candidateQueue.length || !operationKeyMatchesScopes(candidateKey, scopePrefixes)) {
25145
+ continue;
25146
+ }
25147
+ return candidateQueue[0];
25148
+ }
25149
+ return void 0;
25150
+ }
25151
+ takePendingOperationForEvent(event) {
25152
+ const key = operationKey(event.session, event.operationKind);
25153
+ const queue2 = this.pendingOperationsByKey.get(key);
25154
+ if (queue2?.length) {
25155
+ return queue2.shift();
25156
+ }
25157
+ for (const [candidateKey, candidateQueue] of this.pendingOperationsByKey) {
25158
+ if (candidateKey.endsWith(`::${event.operationKind}`) && candidateQueue.length) {
25159
+ return candidateQueue.shift();
25160
+ }
25161
+ }
25162
+ return void 0;
25163
+ }
25164
+ pendingOperationQueue(key) {
25165
+ const existing = this.pendingOperationsByKey.get(key);
25166
+ if (existing) {
25167
+ return existing;
25168
+ }
25169
+ const queue2 = [];
25170
+ this.pendingOperationsByKey.set(key, queue2);
25171
+ return queue2;
25172
+ }
25173
+ };
25174
+ function isInstrumentedOperation(operation) {
25175
+ return operation === "prompt" || operation === "skill" || operation === "task" || operation === "compact";
25176
+ }
25177
+ function getSessionName(session) {
25178
+ return typeof session?.name === "string" ? session.name : void 0;
25179
+ }
25180
+ function operationKey(sessionName, operation) {
25181
+ return `${sessionName ?? "unknown"}::${operation}`;
25182
+ }
25183
+ function operationScopePrefixes(event) {
25184
+ const scopes = /* @__PURE__ */ new Set();
25185
+ for (const scope of operationScopeNames(event)) {
25186
+ scopes.add(`${scope}::`);
25187
+ }
25188
+ return scopes;
25189
+ }
25190
+ function operationKeyMatchesScopes(key, scopes) {
25191
+ for (const scope of scopes) {
25192
+ if (key.startsWith(scope)) {
25193
+ return true;
25194
+ }
25195
+ }
25196
+ return false;
25197
+ }
25198
+ function operationScopeNames(event) {
25199
+ const scopes = /* @__PURE__ */ new Set();
25200
+ if (event.session) {
25201
+ scopes.add(event.session);
25202
+ }
25203
+ if (event.parentSession) {
25204
+ scopes.add(event.parentSession);
25205
+ }
25206
+ if (!scopes.size) {
25207
+ scopes.add("unknown");
25208
+ }
25209
+ return scopes;
25210
+ }
25211
+ function addScopedOperation(operationsByScope, event, state) {
25212
+ for (const scope of operationScopeNames(event)) {
25213
+ addOperationToScope(operationsByScope, scope, state);
25214
+ }
25215
+ }
25216
+ function addOperationToScope(operationsByScope, scope, state) {
25217
+ const operations = operationsByScope.get(scope);
25218
+ if (operations) {
25219
+ if (!operations.includes(state)) {
25220
+ operations.push(state);
25221
+ }
25222
+ } else {
25223
+ operationsByScope.set(scope, [state]);
25224
+ }
25225
+ }
25226
+ function removeScopedOperation(operationsByScope, state) {
25227
+ for (const [scope, operations] of operationsByScope) {
25228
+ const index = operations.indexOf(state);
25229
+ if (index === -1) {
25230
+ continue;
25231
+ }
25232
+ operations.splice(index, 1);
25233
+ if (operations.length === 0) {
25234
+ operationsByScope.delete(scope);
25235
+ }
25236
+ }
25237
+ }
25238
+ function removePendingOperation(pendingOperationsByKey, state) {
25239
+ for (const [key, queue2] of pendingOperationsByKey) {
25240
+ const index = queue2.indexOf(state);
25241
+ if (index === -1) {
25242
+ continue;
25243
+ }
25244
+ queue2.splice(index, 1);
25245
+ if (queue2.length === 0) {
25246
+ pendingOperationsByKey.delete(key);
25247
+ }
25248
+ return;
25249
+ }
25250
+ }
25251
+ function extractSessionMetadata(session) {
25252
+ const sessionName = getSessionName(session);
25253
+ return sessionName ? { "flue.session": sessionName } : {};
25254
+ }
25255
+ function extractEventMetadata(event) {
25256
+ return {
25257
+ ...event.runId ? { "flue.run_id": event.runId } : {},
25258
+ ...typeof event.eventIndex === "number" ? { "flue.event_index": event.eventIndex } : {},
25259
+ ...event.session ? { "flue.session": event.session } : {},
25260
+ ...event.parentSession ? { "flue.parent_session": event.parentSession } : {},
25261
+ ...event.harness ? { "flue.harness": event.harness } : {},
25262
+ ...event.taskId ? { "flue.task_id": event.taskId } : {},
25263
+ ...event.operationId ? { "flue.operation_id": event.operationId } : {}
25264
+ };
25265
+ }
25266
+ function extractOperationInput(operation, args) {
25267
+ switch (operation) {
25268
+ case "prompt":
25269
+ case "task":
25270
+ return args[0];
25271
+ case "skill":
25272
+ return {
25273
+ args: getOptionObject(args[1])?.args,
25274
+ name: args[0]
25275
+ };
25276
+ case "compact":
25277
+ return void 0;
25278
+ }
25279
+ }
25280
+ function extractOperationInputMetadata(operation, args) {
25281
+ const options = getOptionObject(args[1]);
25282
+ return {
25283
+ ...operation === "skill" && typeof args[0] === "string" ? { "flue.skill_name": args[0] } : {},
25284
+ ...options?.model ? { model: options.model, "flue.model": options.model } : {},
25285
+ ...options?.role ? { "flue.role": options.role } : {},
25286
+ ...options?.thinkingLevel ? { "flue.thinking_level": options.thinkingLevel } : {},
25287
+ ...typeof options?.cwd === "string" ? { "flue.cwd": options.cwd } : {},
25288
+ ...Array.isArray(options?.tools) ? {
25289
+ "flue.tools_count": options.tools.length,
25290
+ tools: summarizeTools(options.tools)
25291
+ } : {},
25292
+ ...Array.isArray(options?.images) ? { "flue.images_count": options.images.length } : {},
25293
+ ...options?.result || options?.schema ? { "flue.result_schema": true } : {}
25294
+ };
25295
+ }
25296
+ function getOptionObject(value) {
25297
+ return isObject(value) ? value : void 0;
25298
+ }
25299
+ function summarizeTools(tools) {
25300
+ return tools.flatMap((tool) => {
25301
+ if (!isObject(tool)) {
25302
+ return [];
25303
+ }
25304
+ const name = typeof tool.name === "string" ? tool.name : void 0;
25305
+ if (!name) {
25306
+ return [];
25307
+ }
25308
+ return [
25309
+ {
25310
+ function: {
25311
+ description: typeof tool.description === "string" ? tool.description : void 0,
25312
+ name,
25313
+ parameters: tool.parameters
25314
+ },
25315
+ type: "function"
25316
+ }
25317
+ ];
25318
+ });
25319
+ }
25320
+ function extractPromptResponseMetadata(result) {
25321
+ const modelId = result?.model && typeof result.model.id === "string" ? result.model.id : void 0;
25322
+ return modelId ? {
25323
+ model: modelId,
25324
+ "flue.model": modelId
25325
+ } : {};
25326
+ }
25327
+ function extractOperationOutput(result) {
25328
+ if (!result) {
25329
+ return void 0;
25330
+ }
25331
+ if ("data" in result) {
25332
+ return result.data;
25333
+ }
25334
+ if ("text" in result) {
25335
+ return result.text;
25336
+ }
25337
+ return result;
25338
+ }
25339
+ function metricsFromUsage(usage) {
25340
+ return {
25341
+ ...typeof usage?.input === "number" ? { prompt_tokens: usage.input } : {},
25342
+ ...typeof usage?.output === "number" ? { completion_tokens: usage.output } : {},
25343
+ ...typeof usage?.cacheRead === "number" ? { prompt_cached_tokens: usage.cacheRead } : {},
25344
+ ...typeof usage?.cacheWrite === "number" ? { prompt_cache_creation_tokens: usage.cacheWrite } : {},
25345
+ ...typeof usage?.totalTokens === "number" ? { tokens: usage.totalTokens } : {},
25346
+ ...typeof usage?.cost?.total === "number" ? { estimated_cost: usage.cost.total } : {}
25347
+ };
25348
+ }
25349
+ function buildDurationMetrics3(startTime) {
25350
+ return {
25351
+ duration_ms: Math.max(0, (getCurrentUnixTimestamp() - startTime) * 1e3)
25352
+ };
25353
+ }
25354
+ function durationMsMetrics(durationMs) {
25355
+ return typeof durationMs === "number" ? { duration_ms: durationMs } : {};
25356
+ }
25357
+ function scopeKey(event) {
25358
+ if (event.operationId) {
25359
+ return `operation:${event.operationId}`;
25360
+ }
25361
+ if (event.taskId) {
25362
+ return `task:${event.taskId}`;
25363
+ }
25364
+ if (event.session) {
25365
+ return `session:${event.session}`;
25366
+ }
25367
+ return "flue:unknown";
25368
+ }
25369
+ function toolKey(event) {
25370
+ return `${scopeKey(event)}::tool:${event.toolCallId ?? "unknown"}`;
25371
+ }
25372
+ function toAssistantOutput(text, finishReason, reasoning, toolCalls) {
25373
+ return [
25374
+ {
25375
+ finish_reason: finishReason ?? "stop",
25376
+ index: 0,
25377
+ message: {
25378
+ content: text,
25379
+ ...reasoning ? { reasoning } : {},
25380
+ role: "assistant",
25381
+ ...toolCalls?.length ? {
25382
+ tool_calls: toolCalls.map((toolCall) => ({
25383
+ function: {
25384
+ arguments: toolCall.args === void 0 ? "{}" : JSON.stringify(toolCall.args),
25385
+ name: toolCall.toolName ?? "unknown"
25386
+ },
25387
+ ...toolCall.toolCallId ? { id: toolCall.toolCallId } : {},
25388
+ type: "function"
25389
+ }))
25390
+ } : {}
25391
+ }
25392
+ }
25393
+ ];
25394
+ }
25395
+ function startFlueSpan(parent, args) {
25396
+ return parent ? withCurrent(parent, () => startSpan(args)) : startSpan(args);
25397
+ }
25398
+ function safeLog3(span, event) {
25399
+ try {
25400
+ span.log(event);
25401
+ } catch (error) {
25402
+ logInstrumentationError3("Flue span log", error);
25403
+ }
25404
+ }
25405
+ function errorToString(error) {
25406
+ if (error instanceof Error) {
25407
+ return error.message;
25408
+ }
25409
+ if (typeof error === "string") {
25410
+ return error;
25411
+ }
25412
+ try {
25413
+ return JSON.stringify(error);
25414
+ } catch {
25415
+ return String(error);
25416
+ }
25417
+ }
25418
+ function logInstrumentationError3(label, error) {
25419
+ console.error(`Error in ${label} instrumentation:`, error);
25420
+ }
25421
+
25422
+ // src/wrappers/langchain/callback-handler.ts
25423
+ var BRAINTRUST_LANGCHAIN_CALLBACK_HANDLER_NAME = "BraintrustCallbackHandler";
25424
+ var BraintrustLangChainCallbackHandler = class {
25425
+ name = BRAINTRUST_LANGCHAIN_CALLBACK_HANDLER_NAME;
25426
+ spans = /* @__PURE__ */ new Map();
25427
+ skippedRuns = /* @__PURE__ */ new Set();
25428
+ parent;
25429
+ rootRunId;
25430
+ options;
25431
+ startTimes = /* @__PURE__ */ new Map();
25432
+ firstTokenTimes = /* @__PURE__ */ new Map();
25433
+ ttftMs = /* @__PURE__ */ new Map();
25434
+ constructor(options) {
25435
+ this.parent = options?.parent;
25436
+ this.options = {
25437
+ debug: options?.debug ?? false,
25438
+ excludeMetadataProps: options?.excludeMetadataProps ?? /^(l[sc]_|langgraph_|__pregel_|checkpoint_ns)/,
25439
+ logger: options?.logger
25440
+ };
25441
+ }
25442
+ startSpan({
25443
+ runId,
25444
+ parentRunId,
25445
+ ...args
25446
+ }) {
25447
+ if (this.spans.has(runId)) {
25448
+ return;
25449
+ }
25450
+ if (!parentRunId) {
25451
+ this.rootRunId = runId;
25452
+ }
25453
+ const tags = args.event?.tags;
25454
+ const spanAttributes = args.spanAttributes || {};
25455
+ spanAttributes.type = args.type || spanAttributes.type || "task";
25456
+ args.type = spanAttributes.type;
25457
+ const currentParent = (typeof this.parent === "function" ? this.parent() : this.parent) ?? currentSpan();
25458
+ let parentSpan;
25459
+ if (parentRunId && this.spans.has(parentRunId)) {
25460
+ parentSpan = this.spans.get(parentRunId);
25461
+ } else if (!Object.is(currentParent, NOOP_SPAN)) {
25462
+ parentSpan = currentParent;
25463
+ } else if (this.options.logger) {
25464
+ parentSpan = this.options.logger;
25465
+ } else {
25466
+ parentSpan = { startSpan };
25467
+ }
25468
+ args.event = {
25469
+ ...args.event,
25470
+ tags: void 0,
25471
+ metadata: {
25472
+ ...tags ? { tags } : {},
25473
+ ...args.event?.metadata,
25474
+ braintrust: {
25475
+ integration_name: "langchain-js",
25476
+ sdk_language: "javascript"
25477
+ },
25478
+ run_id: runId,
25479
+ parent_run_id: parentRunId,
25480
+ ...this.options.debug ? { runId, parentRunId } : {}
25481
+ }
25482
+ };
25483
+ let span = parentSpan.startSpan(args);
25484
+ if (!Object.is(this.options.logger, NOOP_SPAN) && Object.is(span, NOOP_SPAN)) {
25485
+ span = initLogger().startSpan(args);
25486
+ }
25487
+ this.spans.set(runId, span);
25488
+ }
25489
+ endSpan({
25490
+ runId,
25491
+ parentRunId,
25492
+ tags,
25493
+ metadata,
25494
+ ...args
25495
+ }) {
25496
+ if (!this.spans.has(runId)) {
25497
+ return;
25498
+ }
25499
+ if (this.skippedRuns.has(runId)) {
25500
+ this.skippedRuns.delete(runId);
25501
+ return;
25502
+ }
25503
+ const span = this.spans.get(runId);
25504
+ this.spans.delete(runId);
25505
+ if (runId === this.rootRunId) {
25506
+ this.rootRunId = void 0;
25507
+ }
25508
+ span.log({ ...args, metadata: { tags, ...metadata } });
25509
+ span.end();
25510
+ }
25511
+ async handleLLMStart(llm, prompts, runId, parentRunId, extraParams, tags, metadata, runName) {
25512
+ this.startSpan({
25513
+ runId,
25514
+ parentRunId,
25515
+ name: runName ?? getSerializedName(llm) ?? "LLM",
25516
+ type: "llm",
25517
+ event: {
25518
+ input: prompts,
25519
+ tags,
25520
+ metadata: {
25521
+ serialized: llm,
25522
+ name: runName,
25523
+ metadata,
25524
+ ...extraParams
25525
+ }
25526
+ }
25527
+ });
25528
+ }
25529
+ async handleLLMError(err, runId, parentRunId, tags) {
25530
+ this.endSpan({ runId, parentRunId, error: err, tags });
25531
+ }
25532
+ async handleLLMEnd(output, runId, parentRunId, tags) {
25533
+ const metrics = getMetricsFromResponse(output);
25534
+ const modelName2 = getModelNameFromResponse(output);
25535
+ const ttft = this.ttftMs.get(runId);
25536
+ if (ttft !== void 0) {
25537
+ metrics.time_to_first_token = ttft;
25538
+ }
25539
+ this.startTimes.delete(runId);
25540
+ this.firstTokenTimes.delete(runId);
25541
+ this.ttftMs.delete(runId);
25542
+ this.endSpan({
25543
+ runId,
25544
+ parentRunId,
25545
+ output,
25546
+ metrics,
25547
+ tags,
25548
+ metadata: {
25549
+ model: modelName2
25550
+ }
25551
+ });
25552
+ }
25553
+ async handleChatModelStart(llm, messages, runId, parentRunId, extraParams, tags, metadata, runName) {
25554
+ this.startTimes.set(runId, Date.now());
25555
+ this.firstTokenTimes.delete(runId);
25556
+ this.ttftMs.delete(runId);
25557
+ this.startSpan({
25558
+ runId,
25559
+ parentRunId,
25560
+ name: runName ?? getSerializedName(llm) ?? "Chat Model",
25561
+ type: "llm",
25562
+ event: {
25563
+ input: messages,
25564
+ tags,
25565
+ metadata: {
25566
+ serialized: llm,
25567
+ name: runName,
25568
+ metadata,
25569
+ ...extraParams
25570
+ }
25571
+ }
25572
+ });
25573
+ }
25574
+ async handleChainStart(chain, inputs, runId, parentRunId, tags, metadata, runType, runName) {
25575
+ if (tags?.includes("langsmith:hidden")) {
25576
+ this.skippedRuns.add(runId);
25577
+ return;
25578
+ }
25579
+ this.startSpan({
25580
+ runId,
25581
+ parentRunId,
25582
+ name: runName ?? getSerializedName(chain) ?? "Chain",
25583
+ event: {
25584
+ input: inputs,
25585
+ tags,
25586
+ metadata: {
25587
+ serialized: chain,
25588
+ name: runName,
25589
+ metadata,
25590
+ run_type: runType
25591
+ }
25592
+ }
25593
+ });
25594
+ }
25595
+ async handleChainError(err, runId, parentRunId, tags, kwargs) {
25596
+ this.endSpan({ runId, parentRunId, error: err, tags, metadata: kwargs });
25597
+ }
25598
+ async handleChainEnd(outputs, runId, parentRunId, tags, kwargs) {
25599
+ this.endSpan({
25600
+ runId,
25601
+ parentRunId,
25602
+ tags,
25603
+ output: outputs,
25604
+ metadata: { ...kwargs }
25605
+ });
25606
+ }
25607
+ async handleToolStart(tool, input, runId, parentRunId, tags, metadata, runName) {
25608
+ this.startSpan({
25609
+ runId,
25610
+ parentRunId,
25611
+ name: runName ?? getSerializedName(tool) ?? "Tool",
25612
+ type: "llm",
25613
+ event: {
25614
+ input: safeJsonParse(input),
25615
+ tags,
25616
+ metadata: {
25617
+ metadata,
25618
+ serialized: tool,
25619
+ input_str: input,
25620
+ input: safeJsonParse(input),
25621
+ name: runName
25622
+ }
25623
+ }
25624
+ });
25625
+ }
25626
+ async handleToolError(err, runId, parentRunId, tags) {
25627
+ this.endSpan({ runId, parentRunId, error: err, tags });
25628
+ }
25629
+ async handleToolEnd(output, runId, parentRunId, tags) {
25630
+ this.endSpan({ runId, parentRunId, output, tags });
25631
+ }
25632
+ async handleAgentAction(action, runId, parentRunId, tags) {
25633
+ this.startSpan({
25634
+ runId,
25635
+ parentRunId,
25636
+ type: "llm",
25637
+ name: typeof action.tool === "string" ? action.tool : "Agent",
25638
+ event: {
25639
+ input: action,
25640
+ tags
25641
+ }
25642
+ });
25643
+ }
25644
+ async handleAgentEnd(action, runId, parentRunId, tags) {
25645
+ this.endSpan({ runId, parentRunId, output: action, tags });
25646
+ }
25647
+ async handleRetrieverStart(retriever, query, runId, parentRunId, tags, metadata, name) {
25648
+ this.startSpan({
25649
+ runId,
25650
+ parentRunId,
25651
+ name: name ?? getSerializedName(retriever) ?? "Retriever",
25652
+ type: "function",
25653
+ event: {
25654
+ input: query,
25655
+ tags,
25656
+ metadata: {
25657
+ serialized: retriever,
25658
+ metadata,
25659
+ name
25660
+ }
25661
+ }
25662
+ });
25663
+ }
25664
+ async handleRetrieverEnd(documents, runId, parentRunId, tags) {
25665
+ this.endSpan({ runId, parentRunId, output: documents, tags });
25666
+ }
25667
+ async handleRetrieverError(err, runId, parentRunId, tags) {
25668
+ this.endSpan({ runId, parentRunId, error: err, tags });
25669
+ }
25670
+ async handleLLMNewToken(_token, _idx, runId, _parentRunId, _tags) {
25671
+ if (!this.firstTokenTimes.has(runId)) {
25672
+ const now2 = Date.now();
25673
+ this.firstTokenTimes.set(runId, now2);
25674
+ const start = this.startTimes.get(runId);
25675
+ if (start !== void 0) {
25676
+ this.ttftMs.set(runId, (now2 - start) / 1e3);
25677
+ }
25678
+ }
25679
+ }
25680
+ };
25681
+ function getSerializedName(serialized) {
25682
+ if (typeof serialized.name === "string") {
25683
+ return serialized.name;
25684
+ }
25685
+ const lastIdPart = serialized.id?.at(-1);
25686
+ return typeof lastIdPart === "string" ? lastIdPart : void 0;
25687
+ }
25688
+ function cleanObject(obj) {
25689
+ return Object.fromEntries(
25690
+ Object.entries(obj).filter(([, value]) => {
25691
+ if (typeof value !== "number") {
25692
+ return false;
25693
+ }
25694
+ return Number.isFinite(value);
25695
+ })
25696
+ );
25697
+ }
25698
+ function walkGenerations(response) {
25699
+ const result = [];
25700
+ const generations = response.generations || [];
25701
+ for (const batch of generations) {
25702
+ if (Array.isArray(batch)) {
25703
+ for (const generation of batch) {
25704
+ if (isRecord(generation)) {
25705
+ result.push(generation);
25706
+ }
25707
+ }
25708
+ } else if (isRecord(batch)) {
25709
+ result.push(batch);
25710
+ }
25711
+ }
25712
+ return result;
25713
+ }
25714
+ function getModelNameFromResponse(response) {
25715
+ for (const generation of walkGenerations(response)) {
25716
+ const message = generation.message;
25717
+ if (!isRecord(message)) {
25718
+ continue;
25719
+ }
25720
+ const responseMetadata = message.response_metadata;
25721
+ if (!isRecord(responseMetadata)) {
25722
+ continue;
25723
+ }
25724
+ const modelName3 = responseMetadata.model_name ?? responseMetadata.model;
25725
+ if (typeof modelName3 === "string") {
25726
+ return modelName3;
25727
+ }
25728
+ }
25729
+ const llmOutput = response.llmOutput || {};
25730
+ const modelName2 = llmOutput.model_name ?? llmOutput.model;
25731
+ return typeof modelName2 === "string" ? modelName2 : void 0;
25732
+ }
25733
+ function getMetricsFromResponse(response) {
25734
+ for (const generation of walkGenerations(response)) {
25735
+ const message = generation.message;
25736
+ if (!isRecord(message)) {
25737
+ continue;
25738
+ }
25739
+ const usageMetadata = message.usage_metadata;
25740
+ if (!isRecord(usageMetadata)) {
25741
+ continue;
25742
+ }
25743
+ const inputTokenDetails = usageMetadata.input_token_details;
25744
+ return cleanObject({
25745
+ total_tokens: usageMetadata.total_tokens,
25746
+ prompt_tokens: usageMetadata.input_tokens,
25747
+ completion_tokens: usageMetadata.output_tokens,
25748
+ prompt_cache_creation_tokens: isRecord(inputTokenDetails) ? inputTokenDetails.cache_creation : void 0,
25749
+ prompt_cached_tokens: isRecord(inputTokenDetails) ? inputTokenDetails.cache_read : void 0
25750
+ });
25751
+ }
25752
+ const llmOutput = response.llmOutput || {};
25753
+ const tokenUsage = isRecord(llmOutput.tokenUsage) ? llmOutput.tokenUsage : isRecord(llmOutput.estimatedTokens) ? llmOutput.estimatedTokens : {};
25754
+ return cleanObject({
25755
+ total_tokens: tokenUsage.totalTokens,
25756
+ prompt_tokens: tokenUsage.promptTokens,
25757
+ completion_tokens: tokenUsage.completionTokens
25758
+ });
25759
+ }
25760
+ function safeJsonParse(input) {
25761
+ try {
25762
+ return JSON.parse(input);
25763
+ } catch {
25764
+ return input;
25765
+ }
25766
+ }
25767
+ function isRecord(value) {
25768
+ return typeof value === "object" && value !== null && !Array.isArray(value);
25769
+ }
25770
+
25771
+ // src/instrumentation/plugins/langchain-channels.ts
25772
+ var langChainChannels = defineChannels("@langchain/core", {
25773
+ configure: channel({
25774
+ channelName: "CallbackManager.configure",
25775
+ kind: "sync-stream"
25776
+ }),
25777
+ configureSync: channel({
25778
+ channelName: "CallbackManager._configureSync",
25779
+ kind: "sync-stream"
25780
+ })
25781
+ });
25782
+
25783
+ // src/instrumentation/plugins/langchain-plugin.ts
25784
+ var LangChainPlugin = class extends BasePlugin {
25785
+ injectedManagers = /* @__PURE__ */ new WeakSet();
25786
+ onEnable() {
25787
+ this.subscribeToConfigure(langChainChannels.configure);
25788
+ this.subscribeToConfigure(langChainChannels.configureSync);
25789
+ }
25790
+ onDisable() {
25791
+ for (const unsubscribe of this.unsubscribers) {
25792
+ unsubscribe();
25793
+ }
25794
+ this.unsubscribers = [];
25795
+ this.injectedManagers = /* @__PURE__ */ new WeakSet();
25796
+ }
25797
+ subscribeToConfigure(channel2) {
25798
+ const tracingChannel2 = channel2.tracingChannel();
25799
+ const handlers = {
25800
+ start: (event) => {
25801
+ injectHandlerIntoArguments(event.arguments);
25802
+ },
25803
+ end: (event) => {
25804
+ this.injectHandler(event.result);
25805
+ }
25806
+ };
25807
+ tracingChannel2.subscribe(handlers);
25808
+ this.unsubscribers.push(() => {
25809
+ tracingChannel2.unsubscribe(handlers);
25810
+ });
25811
+ }
25812
+ injectHandler(result) {
25813
+ if (!isCallbackManager(result)) {
25814
+ return;
25815
+ }
25816
+ if (this.injectedManagers.has(result) || hasBraintrustHandler(result)) {
25817
+ return;
25818
+ }
25819
+ try {
25820
+ result.addHandler(new BraintrustLangChainCallbackHandler(), true);
25821
+ this.injectedManagers.add(result);
25822
+ } catch {
25823
+ }
25824
+ }
25825
+ };
25826
+ function isCallbackManager(value) {
25827
+ if (typeof value !== "object" || value === null) {
25828
+ return false;
25829
+ }
25830
+ const maybeManager = value;
25831
+ return typeof maybeManager.addHandler === "function";
25832
+ }
25833
+ function hasBraintrustHandler(manager) {
25834
+ return manager.handlers?.some((handler) => {
25835
+ if (typeof handler !== "object" || handler === null) {
25836
+ return false;
25837
+ }
25838
+ const name = Reflect.get(handler, "name");
25839
+ return name === BRAINTRUST_LANGCHAIN_CALLBACK_HANDLER_NAME;
25840
+ }) ?? false;
25841
+ }
25842
+ function injectHandlerIntoArguments(args) {
25843
+ if (!isWritableArgumentsObject(args)) {
25844
+ return;
25845
+ }
25846
+ const inheritedHandlers = Reflect.get(args, "0");
25847
+ const handler = new BraintrustLangChainCallbackHandler();
25848
+ if (inheritedHandlers === void 0 || inheritedHandlers === null) {
25849
+ Reflect.set(args, "0", [handler]);
25850
+ return;
25851
+ }
25852
+ if (Array.isArray(inheritedHandlers)) {
25853
+ if (!inheritedHandlers.some(isBraintrustHandler)) {
25854
+ inheritedHandlers.push(handler);
25855
+ }
25856
+ }
25857
+ }
25858
+ function isWritableArgumentsObject(args) {
25859
+ return typeof args === "object" && args !== null;
25860
+ }
25861
+ function isBraintrustHandler(handler) {
25862
+ if (typeof handler !== "object" || handler === null) {
25863
+ return false;
25864
+ }
25865
+ return Reflect.get(handler, "name") === BRAINTRUST_LANGCHAIN_CALLBACK_HANDLER_NAME;
25866
+ }
25867
+
25868
+ // src/instrumentation/braintrust-plugin.ts
25869
+ function getIntegrationConfig(integrations, key) {
25870
+ return integrations[key];
25871
+ }
25872
+ var BraintrustPlugin = class extends BasePlugin {
25873
+ config;
25874
+ openaiPlugin = null;
25875
+ openAICodexPlugin = null;
25876
+ anthropicPlugin = null;
25877
+ aiSDKPlugin = null;
25878
+ claudeAgentSDKPlugin = null;
25879
+ cursorSDKPlugin = null;
25880
+ openAIAgentsPlugin = null;
25881
+ googleGenAIPlugin = null;
25882
+ huggingFacePlugin = null;
25883
+ openRouterPlugin = null;
25884
+ openRouterAgentPlugin = null;
25885
+ mistralPlugin = null;
25886
+ googleADKPlugin = null;
25887
+ coherePlugin = null;
25888
+ groqPlugin = null;
25889
+ genkitPlugin = null;
25890
+ gitHubCopilotPlugin = null;
25891
+ fluePlugin = null;
25892
+ langChainPlugin = null;
25893
+ constructor(config = {}) {
25894
+ super();
25895
+ this.config = config;
25896
+ }
25897
+ onEnable() {
25898
+ const integrations = this.config.integrations || {};
25899
+ if (integrations.openai !== false) {
25900
+ this.openaiPlugin = new OpenAIPlugin();
25901
+ this.openaiPlugin.enable();
25902
+ }
25903
+ if (integrations.openaiCodexSDK !== false) {
25904
+ this.openAICodexPlugin = new OpenAICodexPlugin();
25905
+ this.openAICodexPlugin.enable();
25906
+ }
25907
+ if (integrations.anthropic !== false) {
25908
+ this.anthropicPlugin = new AnthropicPlugin();
25909
+ this.anthropicPlugin.enable();
25910
+ }
25911
+ if (integrations.aisdk !== false && integrations.vercel !== false) {
25912
+ this.aiSDKPlugin = new AISDKPlugin();
25913
+ this.aiSDKPlugin.enable();
25914
+ }
25915
+ if (integrations.claudeAgentSDK !== false) {
25916
+ this.claudeAgentSDKPlugin = new ClaudeAgentSDKPlugin();
23699
25917
  this.claudeAgentSDKPlugin.enable();
23700
25918
  }
23701
25919
  if (integrations.cursorSDK !== false && integrations.cursor !== false) {
23702
25920
  this.cursorSDKPlugin = new CursorSDKPlugin();
23703
25921
  this.cursorSDKPlugin.enable();
23704
25922
  }
25923
+ if (integrations.openAIAgents !== false) {
25924
+ this.openAIAgentsPlugin = new OpenAIAgentsPlugin();
25925
+ this.openAIAgentsPlugin.enable();
25926
+ }
23705
25927
  if (integrations.googleGenAI !== false && integrations.google !== false) {
23706
25928
  this.googleGenAIPlugin = new GoogleGenAIPlugin();
23707
25929
  this.googleGenAIPlugin.enable();
@@ -23742,6 +25964,14 @@ var BraintrustPlugin = class extends BasePlugin {
23742
25964
  this.gitHubCopilotPlugin = new GitHubCopilotPlugin();
23743
25965
  this.gitHubCopilotPlugin.enable();
23744
25966
  }
25967
+ if (getIntegrationConfig(integrations, "flue") !== false) {
25968
+ this.fluePlugin = new FluePlugin();
25969
+ this.fluePlugin.enable();
25970
+ }
25971
+ if (integrations.langchain !== false && integrations.langgraph !== false) {
25972
+ this.langChainPlugin = new LangChainPlugin();
25973
+ this.langChainPlugin.enable();
25974
+ }
23745
25975
  }
23746
25976
  onDisable() {
23747
25977
  if (this.openaiPlugin) {
@@ -23768,6 +25998,10 @@ var BraintrustPlugin = class extends BasePlugin {
23768
25998
  this.cursorSDKPlugin.disable();
23769
25999
  this.cursorSDKPlugin = null;
23770
26000
  }
26001
+ if (this.openAIAgentsPlugin) {
26002
+ this.openAIAgentsPlugin.disable();
26003
+ this.openAIAgentsPlugin = null;
26004
+ }
23771
26005
  if (this.googleGenAIPlugin) {
23772
26006
  this.googleGenAIPlugin.disable();
23773
26007
  this.googleGenAIPlugin = null;
@@ -23808,9 +26042,104 @@ var BraintrustPlugin = class extends BasePlugin {
23808
26042
  this.gitHubCopilotPlugin.disable();
23809
26043
  this.gitHubCopilotPlugin = null;
23810
26044
  }
26045
+ if (this.fluePlugin) {
26046
+ this.fluePlugin.disable();
26047
+ this.fluePlugin = null;
26048
+ }
26049
+ if (this.langChainPlugin) {
26050
+ this.langChainPlugin.disable();
26051
+ this.langChainPlugin = null;
26052
+ }
23811
26053
  }
23812
26054
  };
23813
26055
 
26056
+ // src/instrumentation/config.ts
26057
+ var envIntegrationAliases = {
26058
+ openai: "openai",
26059
+ "openai-codex": "openaiCodexSDK",
26060
+ "openai-codex-sdk": "openaiCodexSDK",
26061
+ openaicodexsdk: "openaiCodexSDK",
26062
+ codex: "openaiCodexSDK",
26063
+ "codex-sdk": "openaiCodexSDK",
26064
+ anthropic: "anthropic",
26065
+ aisdk: "aisdk",
26066
+ "ai-sdk": "aisdk",
26067
+ "vercel-ai": "aisdk",
26068
+ vercel: "vercel",
26069
+ claudeagentsdk: "claudeAgentSDK",
26070
+ "claude-agent-sdk": "claudeAgentSDK",
26071
+ cursor: "cursor",
26072
+ "cursor-sdk": "cursorSDK",
26073
+ cursorsdk: "cursorSDK",
26074
+ flue: "flue",
26075
+ "flue-runtime": "flue",
26076
+ "openai-agents": "openAIAgents",
26077
+ openaiagents: "openAIAgents",
26078
+ "openai-agents-core": "openAIAgents",
26079
+ openaiagentscore: "openAIAgents",
26080
+ google: "google",
26081
+ "google-genai": "googleGenAI",
26082
+ googlegenai: "googleGenAI",
26083
+ huggingface: "huggingface",
26084
+ openrouter: "openrouter",
26085
+ openrouteragent: "openrouterAgent",
26086
+ "openrouter-agent": "openrouterAgent",
26087
+ mistral: "mistral",
26088
+ googleadk: "googleADK",
26089
+ "google-adk": "googleADK",
26090
+ cohere: "cohere",
26091
+ groq: "groq",
26092
+ "groq-sdk": "groq",
26093
+ genkit: "genkit",
26094
+ "firebase-genkit": "genkit",
26095
+ githubcopilot: "gitHubCopilot",
26096
+ "github-copilot": "gitHubCopilot",
26097
+ "copilot-sdk": "gitHubCopilot",
26098
+ langchain: "langchain",
26099
+ "langchain-js": "langchain",
26100
+ "@langchain": "langchain",
26101
+ langgraph: "langgraph"
26102
+ };
26103
+ function getDefaultInstrumentationIntegrations() {
26104
+ return {
26105
+ openai: true,
26106
+ openaiCodexSDK: true,
26107
+ anthropic: true,
26108
+ vercel: true,
26109
+ aisdk: true,
26110
+ google: true,
26111
+ googleGenAI: true,
26112
+ googleADK: true,
26113
+ huggingface: true,
26114
+ claudeAgentSDK: true,
26115
+ cursor: true,
26116
+ cursorSDK: true,
26117
+ flue: true,
26118
+ openAIAgents: true,
26119
+ openrouter: true,
26120
+ openrouterAgent: true,
26121
+ mistral: true,
26122
+ cohere: true,
26123
+ groq: true,
26124
+ genkit: true,
26125
+ gitHubCopilot: true,
26126
+ langchain: true,
26127
+ langgraph: true
26128
+ };
26129
+ }
26130
+ function readDisabledInstrumentationEnvConfig(disabledList) {
26131
+ const integrations = {};
26132
+ if (disabledList) {
26133
+ for (const value of disabledList.split(",")) {
26134
+ const sdk = value.trim().toLowerCase();
26135
+ if (sdk.length > 0) {
26136
+ integrations[envIntegrationAliases[sdk] ?? sdk] = false;
26137
+ }
26138
+ }
26139
+ }
26140
+ return { integrations };
26141
+ }
26142
+
23814
26143
  // src/instrumentation/registry.ts
23815
26144
  var REGISTRY_STATE_KEY = /* @__PURE__ */ Symbol.for("braintrust.registry");
23816
26145
  function getSharedState() {
@@ -23889,50 +26218,16 @@ var PluginRegistry = class {
23889
26218
  * Get default configuration (all integrations enabled).
23890
26219
  */
23891
26220
  getDefaultConfig() {
23892
- return {
23893
- openai: true,
23894
- openaiCodexSDK: true,
23895
- anthropic: true,
23896
- vercel: true,
23897
- aisdk: true,
23898
- google: true,
23899
- googleGenAI: true,
23900
- googleADK: true,
23901
- huggingface: true,
23902
- claudeAgentSDK: true,
23903
- cursor: true,
23904
- cursorSDK: true,
23905
- openrouter: true,
23906
- openrouterAgent: true,
23907
- mistral: true,
23908
- cohere: true,
23909
- groq: true,
23910
- genkit: true,
23911
- gitHubCopilot: true
23912
- };
26221
+ return getDefaultInstrumentationIntegrations();
23913
26222
  }
23914
26223
  /**
23915
26224
  * Read configuration from environment variables.
23916
26225
  * Supports: BRAINTRUST_DISABLE_INSTRUMENTATION=openai,anthropic,...
23917
26226
  */
23918
26227
  readEnvConfig() {
23919
- const integrations = {};
23920
- const disabledList = isomorph_default.getEnv("BRAINTRUST_DISABLE_INSTRUMENTATION");
23921
- if (disabledList) {
23922
- const disabled = disabledList.split(",").map((s) => s.trim().toLowerCase()).filter((s) => s.length > 0);
23923
- for (const sdk of disabled) {
23924
- if (sdk === "cursor-sdk") {
23925
- integrations.cursorSDK = false;
23926
- } else if (sdk === "githubcopilot" || sdk === "github-copilot" || sdk === "copilot-sdk") {
23927
- integrations.gitHubCopilot = false;
23928
- } else if (sdk === "openai-codex-sdk") {
23929
- integrations.openaiCodexSDK = false;
23930
- } else {
23931
- integrations[sdk] = false;
23932
- }
23933
- }
23934
- }
23935
- return { integrations };
26228
+ return readDisabledInstrumentationEnvConfig(
26229
+ isomorph_default.getEnv("BRAINTRUST_DISABLE_INSTRUMENTATION")
26230
+ );
23936
26231
  }
23937
26232
  };
23938
26233
  var registry = new PluginRegistry();
@@ -23962,6 +26257,10 @@ function configureEdgeLight() {
23962
26257
  }
23963
26258
  return process.env[name];
23964
26259
  };
26260
+ isomorph_default.getBraintrustApiKey = async () => {
26261
+ const value = isomorph_default.getEnv("BRAINTRUST_API_KEY");
26262
+ return value?.trim() ? value : void 0;
26263
+ };
23965
26264
  isomorph_default.hash = (data) => {
23966
26265
  let hash = 0;
23967
26266
  for (let i = 0; i < data.length; i++) {
@@ -23983,8 +26282,10 @@ __export(exports_exports, {
23983
26282
  Attachment: () => Attachment,
23984
26283
  AttachmentReference: () => AttachmentReference,
23985
26284
  BRAINTRUST_CURRENT_SPAN_STORE: () => BRAINTRUST_CURRENT_SPAN_STORE,
26285
+ BRAINTRUST_LANGCHAIN_CALLBACK_HANDLER_NAME: () => BRAINTRUST_LANGCHAIN_CALLBACK_HANDLER_NAME,
23986
26286
  BaseAttachment: () => BaseAttachment,
23987
26287
  BaseExperiment: () => BaseExperiment,
26288
+ BraintrustLangChainCallbackHandler: () => BraintrustLangChainCallbackHandler,
23988
26289
  BraintrustMiddleware: () => BraintrustMiddleware,
23989
26290
  BraintrustState: () => BraintrustState,
23990
26291
  BraintrustStream: () => BraintrustStream,
@@ -23995,6 +26296,7 @@ __export(exports_exports, {
23995
26296
  DEFAULT_FETCH_BATCH_SIZE: () => DEFAULT_FETCH_BATCH_SIZE,
23996
26297
  DEFAULT_MAX_REQUEST_SIZE: () => DEFAULT_MAX_REQUEST_SIZE,
23997
26298
  Dataset: () => Dataset2,
26299
+ DatasetPipeline: () => DatasetPipeline,
23998
26300
  ERR_PERMALINK: () => ERR_PERMALINK,
23999
26301
  Eval: () => Eval,
24000
26302
  EvalResultWithSummary: () => EvalResultWithSummary,
@@ -24110,6 +26412,8 @@ __export(exports_exports, {
24110
26412
  wrapCohere: () => wrapCohere,
24111
26413
  wrapCopilotClient: () => wrapCopilotClient,
24112
26414
  wrapCursorSDK: () => wrapCursorSDK,
26415
+ wrapFlueContext: () => wrapFlueContext,
26416
+ wrapFlueSession: () => wrapFlueSession,
24113
26417
  wrapGenkit: () => wrapGenkit,
24114
26418
  wrapGoogleADK: () => wrapGoogleADK,
24115
26419
  wrapGoogleGenAI: () => wrapGoogleGenAI,
@@ -25209,7 +27513,7 @@ function extractModelParameters(params, excludeKeys) {
25209
27513
  }
25210
27514
  return modelParams;
25211
27515
  }
25212
- function getNumberProperty2(obj, key) {
27516
+ function getNumberProperty3(obj, key) {
25213
27517
  if (!obj || typeof obj !== "object" || !(key in obj)) {
25214
27518
  return void 0;
25215
27519
  }
@@ -25218,31 +27522,31 @@ function getNumberProperty2(obj, key) {
25218
27522
  }
25219
27523
  function normalizeUsageMetrics(usage, provider, providerMetadata) {
25220
27524
  const metrics = {};
25221
- const inputTokens = getNumberProperty2(usage, "inputTokens");
27525
+ const inputTokens = getNumberProperty3(usage, "inputTokens");
25222
27526
  if (inputTokens !== void 0) {
25223
27527
  metrics.prompt_tokens = inputTokens;
25224
27528
  }
25225
- const outputTokens = getNumberProperty2(usage, "outputTokens");
27529
+ const outputTokens = getNumberProperty3(usage, "outputTokens");
25226
27530
  if (outputTokens !== void 0) {
25227
27531
  metrics.completion_tokens = outputTokens;
25228
27532
  }
25229
- const totalTokens = getNumberProperty2(usage, "totalTokens");
27533
+ const totalTokens = getNumberProperty3(usage, "totalTokens");
25230
27534
  if (totalTokens !== void 0) {
25231
27535
  metrics.tokens = totalTokens;
25232
27536
  }
25233
- const reasoningTokens = getNumberProperty2(usage, "reasoningTokens");
27537
+ const reasoningTokens = getNumberProperty3(usage, "reasoningTokens");
25234
27538
  if (reasoningTokens !== void 0) {
25235
27539
  metrics.completion_reasoning_tokens = reasoningTokens;
25236
27540
  }
25237
- const cachedInputTokens = getNumberProperty2(usage, "cachedInputTokens");
27541
+ const cachedInputTokens = getNumberProperty3(usage, "cachedInputTokens");
25238
27542
  if (cachedInputTokens !== void 0) {
25239
27543
  metrics.prompt_cached_tokens = cachedInputTokens;
25240
27544
  }
25241
27545
  if (provider === "anthropic") {
25242
27546
  const anthropicMetadata = providerMetadata?.anthropic;
25243
27547
  if (anthropicMetadata) {
25244
- const cacheReadTokens = getNumberProperty2(anthropicMetadata.usage, "cache_read_input_tokens") || 0;
25245
- const cacheCreationTokens = getNumberProperty2(
27548
+ const cacheReadTokens = getNumberProperty3(anthropicMetadata.usage, "cache_read_input_tokens") || 0;
27549
+ const cacheCreationTokens = getNumberProperty3(
25246
27550
  anthropicMetadata.usage,
25247
27551
  "cache_creation_input_tokens"
25248
27552
  ) || 0;
@@ -26217,17 +28521,17 @@ function wrapGenkit(genkit) {
26217
28521
  console.warn("Unsupported Genkit object. Not wrapping.");
26218
28522
  return genkit;
26219
28523
  }
26220
- function isRecord(value) {
28524
+ function isRecord2(value) {
26221
28525
  return typeof value === "object" && value !== null;
26222
28526
  }
26223
28527
  function isPropertyBag(value) {
26224
- return isRecord(value) || typeof value === "function";
28528
+ return isRecord2(value) || typeof value === "function";
26225
28529
  }
26226
28530
  function hasFunction(value, methodName) {
26227
28531
  return isPropertyBag(value) && methodName in value && typeof value[methodName] === "function";
26228
28532
  }
26229
28533
  function isGenkitInstance(value) {
26230
- return isRecord(value) && (hasFunction(value, "generate") || hasFunction(value, "generateStream") || hasFunction(value, "defineFlow") || hasFunction(value, "defineTool"));
28534
+ return isRecord2(value) && (hasFunction(value, "generate") || hasFunction(value, "generateStream") || hasFunction(value, "defineFlow") || hasFunction(value, "defineTool"));
26231
28535
  }
26232
28536
  function isGenkitModule(value) {
26233
28537
  return hasFunction(value, "genkit");
@@ -26281,7 +28585,7 @@ function patchGenkitRegistry(instance) {
26281
28585
  patchGenkitRegistryConstructor(registry2);
26282
28586
  }
26283
28587
  function patchGenkitRegistryLookup(registry2) {
26284
- if (!isRecord(registry2) || hasRegistryPatchedFlag(registry2) || !hasFunction(registry2, "lookupAction")) {
28588
+ if (!isRecord2(registry2) || hasRegistryPatchedFlag(registry2) || !hasFunction(registry2, "lookupAction")) {
26285
28589
  return;
26286
28590
  }
26287
28591
  const originalLookupAction = registry2.lookupAction;
@@ -26307,7 +28611,7 @@ function patchGenkitRegistryLookup(registry2) {
26307
28611
  }
26308
28612
  }
26309
28613
  function patchGenkitRegistryConstructor(registry2) {
26310
- if (!isRecord(registry2)) {
28614
+ if (!isRecord2(registry2)) {
26311
28615
  return;
26312
28616
  }
26313
28617
  const constructor = registry2.constructor;
@@ -26323,7 +28627,7 @@ function patchGenkitRegistryConstructor(registry2) {
26323
28627
  configurable: true,
26324
28628
  value: (...args) => {
26325
28629
  const childRegistry = originalWithParent.apply(constructor, args);
26326
- if (args.some((arg) => isRecord(arg) && hasRegistryPatchedFlag(arg))) {
28630
+ if (args.some((arg) => isRecord2(arg) && hasRegistryPatchedFlag(arg))) {
26327
28631
  patchGenkitRegistryLookup(childRegistry);
26328
28632
  patchGenkitRegistryConstructor(childRegistry);
26329
28633
  }
@@ -26422,7 +28726,7 @@ function hasRegistryConstructorPatchedFlag(value) {
26422
28726
  );
26423
28727
  }
26424
28728
  function isPromiseLike2(value) {
26425
- return isRecord(value) && "then" in value && typeof value.then === "function";
28729
+ return isRecord2(value) && "then" in value && typeof value.then === "function";
26426
28730
  }
26427
28731
 
26428
28732
  // src/wrappers/huggingface.ts
@@ -26785,14 +29089,14 @@ function wrapMistral(mistral) {
26785
29089
  console.warn("Unsupported Mistral library. Not wrapping.");
26786
29090
  return mistral;
26787
29091
  }
26788
- function isRecord2(value) {
29092
+ function isRecord3(value) {
26789
29093
  return typeof value === "object" && value !== null;
26790
29094
  }
26791
29095
  function hasFunction3(value, methodName) {
26792
- return isRecord2(value) && methodName in value && typeof value[methodName] === "function";
29096
+ return isRecord3(value) && methodName in value && typeof value[methodName] === "function";
26793
29097
  }
26794
29098
  function isSupportedMistralClient(value) {
26795
- if (!isRecord2(value)) {
29099
+ if (!isRecord3(value)) {
26796
29100
  return false;
26797
29101
  }
26798
29102
  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);
@@ -26976,14 +29280,14 @@ function wrapCohere(cohere) {
26976
29280
  return cohere;
26977
29281
  }
26978
29282
  var cohereProxyCache = /* @__PURE__ */ new WeakMap();
26979
- function isRecord3(value) {
29283
+ function isRecord4(value) {
26980
29284
  return typeof value === "object" && value !== null;
26981
29285
  }
26982
29286
  function hasFunction4(value, methodName) {
26983
- return isRecord3(value) && methodName in value && typeof value[methodName] === "function";
29287
+ return isRecord4(value) && methodName in value && typeof value[methodName] === "function";
26984
29288
  }
26985
29289
  function isSupportedCohereClient(value) {
26986
- if (!isRecord3(value)) {
29290
+ if (!isRecord4(value)) {
26987
29291
  return false;
26988
29292
  }
26989
29293
  return hasFunction4(value, "chat") || hasFunction4(value, "chatStream") || hasFunction4(value, "embed") || hasFunction4(value, "rerank");
@@ -27043,20 +29347,20 @@ function wrapGroq(groq) {
27043
29347
  console.warn("Unsupported Groq library. Not wrapping.");
27044
29348
  return groq;
27045
29349
  }
27046
- function isRecord4(value) {
29350
+ function isRecord5(value) {
27047
29351
  return typeof value === "object" && value !== null;
27048
29352
  }
27049
29353
  function hasFunction5(value, methodName) {
27050
- return isRecord4(value) && methodName in value && typeof value[methodName] === "function";
29354
+ return isRecord5(value) && methodName in value && typeof value[methodName] === "function";
27051
29355
  }
27052
29356
  function hasChat2(value) {
27053
- return isRecord4(value) && isRecord4(value.completions) && hasFunction5(value.completions, "create");
29357
+ return isRecord5(value) && isRecord5(value.completions) && hasFunction5(value.completions, "create");
27054
29358
  }
27055
29359
  function hasEmbeddings2(value) {
27056
29360
  return hasFunction5(value, "create");
27057
29361
  }
27058
29362
  function isSupportedGroqClient(value) {
27059
- return isRecord4(value) && (value.chat !== void 0 && hasChat2(value.chat) || value.embeddings !== void 0 && hasEmbeddings2(value.embeddings));
29363
+ return isRecord5(value) && (value.chat !== void 0 && hasChat2(value.chat) || value.embeddings !== void 0 && hasEmbeddings2(value.embeddings));
27060
29364
  }
27061
29365
  function groqProxy(groq) {
27062
29366
  const privateMethodWorkaroundCache = /* @__PURE__ */ new WeakMap();
@@ -27251,10 +29555,12 @@ function formatExperimentSummary(summary) {
27251
29555
  // src/wrappers/shared/flush.ts
27252
29556
  async function summarizeAndFlush(experiment, options) {
27253
29557
  const shouldDisplay = options.displaySummary ?? true;
27254
- const summary = await experiment.summarize();
27255
- if (shouldDisplay) {
27256
- console.log(formatExperimentSummary(summary));
29558
+ if (!shouldDisplay) {
29559
+ await experiment.flush();
29560
+ return;
27257
29561
  }
29562
+ const summary = await experiment.summarize();
29563
+ console.log(formatExperimentSummary(summary));
27258
29564
  }
27259
29565
 
27260
29566
  // src/wrappers/vitest/flush-manager.ts
@@ -29118,8 +31424,12 @@ var waterfall$1 = awaitify(waterfall);
29118
31424
 
29119
31425
  // src/trace.ts
29120
31426
  var SpanFetcher = class _SpanFetcher extends ObjectFetcher {
29121
- constructor(objectType, _objectId, rootSpanId, _state, spanTypeFilter) {
29122
- const filterExpr = _SpanFetcher.buildFilter(rootSpanId, spanTypeFilter);
31427
+ constructor(objectType, _objectId, rootSpanId, _state, spanTypeFilter, includeScorers = false) {
31428
+ const filterExpr = _SpanFetcher.buildFilter(
31429
+ rootSpanId,
31430
+ spanTypeFilter,
31431
+ includeScorers
31432
+ );
29123
31433
  super(objectType, void 0, void 0, {
29124
31434
  filter: filterExpr
29125
31435
  });
@@ -29128,16 +31438,17 @@ var SpanFetcher = class _SpanFetcher extends ObjectFetcher {
29128
31438
  this._state = _state;
29129
31439
  this.spanTypeFilter = spanTypeFilter;
29130
31440
  }
29131
- static buildFilter(rootSpanId, spanTypeFilter) {
31441
+ static buildFilter(rootSpanId, spanTypeFilter, includeScorers = false) {
29132
31442
  const children = [
29133
31443
  // Base filter: root_span_id = 'value'
29134
31444
  {
29135
31445
  op: "eq",
29136
31446
  left: { op: "ident", name: ["root_span_id"] },
29137
31447
  right: { op: "literal", value: rootSpanId }
29138
- },
29139
- // Exclude span_attributes.purpose = 'score'
29140
- {
31448
+ }
31449
+ ];
31450
+ if (!includeScorers) {
31451
+ children.push({
29141
31452
  op: "or",
29142
31453
  children: [
29143
31454
  {
@@ -29150,8 +31461,8 @@ var SpanFetcher = class _SpanFetcher extends ObjectFetcher {
29150
31461
  right: { op: "literal", value: "scorer" }
29151
31462
  }
29152
31463
  ]
29153
- }
29154
- ];
31464
+ });
31465
+ }
29155
31466
  if (spanTypeFilter && spanTypeFilter.length > 0) {
29156
31467
  children.push({
29157
31468
  op: "in",
@@ -29177,35 +31488,49 @@ var CachedSpanFetcher = class {
29177
31488
  fetchFn;
29178
31489
  constructor(objectTypeOrFetchFn, objectId, rootSpanId, getState) {
29179
31490
  if (typeof objectTypeOrFetchFn === "function") {
29180
- this.fetchFn = objectTypeOrFetchFn;
31491
+ this.fetchFn = (spanType) => objectTypeOrFetchFn(spanType);
29181
31492
  } else {
29182
31493
  const objectType = objectTypeOrFetchFn;
29183
- this.fetchFn = async (spanType) => {
31494
+ this.fetchFn = async (spanType, includeScorers) => {
29184
31495
  const state = await getState();
29185
31496
  const fetcher = new SpanFetcher(
29186
31497
  objectType,
29187
31498
  objectId,
29188
31499
  rootSpanId,
29189
31500
  state,
29190
- spanType
31501
+ spanType,
31502
+ includeScorers
29191
31503
  );
29192
31504
  const rows = await fetcher.fetchedData();
29193
- return rows.filter((row) => row.span_attributes?.purpose !== "scorer").map((row) => ({
31505
+ return rows.map((row) => ({
29194
31506
  input: row.input,
29195
31507
  output: row.output,
31508
+ expected: row.expected,
31509
+ error: row.error,
31510
+ scores: row.scores,
31511
+ metrics: row.metrics,
29196
31512
  metadata: row.metadata,
29197
31513
  span_id: row.span_id,
29198
31514
  span_parents: row.span_parents,
31515
+ is_root: row.is_root,
29199
31516
  span_attributes: row.span_attributes,
29200
31517
  id: row.id,
29201
31518
  _xact_id: row._xact_id,
29202
31519
  _pagination_key: row._pagination_key,
29203
- root_span_id: row.root_span_id
31520
+ root_span_id: row.root_span_id,
31521
+ created: row.created,
31522
+ tags: row.tags
29204
31523
  }));
29205
31524
  };
29206
31525
  }
29207
31526
  }
29208
- async getSpans({ spanType } = {}) {
31527
+ async getSpans({
31528
+ spanType,
31529
+ includeScorers = false
31530
+ } = {}) {
31531
+ if (includeScorers) {
31532
+ return this.fetchFn(spanType, true);
31533
+ }
29209
31534
  if (this.allFetched) {
29210
31535
  return this.getFromCache(spanType);
29211
31536
  }
@@ -29222,7 +31547,7 @@ var CachedSpanFetcher = class {
29222
31547
  return this.getFromCache(spanType);
29223
31548
  }
29224
31549
  async fetchSpans(spanType) {
29225
- const spans = await this.fetchFn(spanType);
31550
+ const spans = await this.fetchFn(spanType, false);
29226
31551
  for (const span of spans) {
29227
31552
  const type = span.span_attributes?.type ?? "";
29228
31553
  const existing = this.spanCache.get(type) ?? [];
@@ -29300,10 +31625,13 @@ var LocalTrace = class {
29300
31625
  * First checks the local span cache for recently logged spans, then falls
29301
31626
  * back to CachedSpanFetcher which handles BTQL fetching and caching.
29302
31627
  */
29303
- async getSpans({ spanType } = {}) {
31628
+ async getSpans({
31629
+ spanType,
31630
+ includeScorers = false
31631
+ } = {}) {
29304
31632
  const cachedSpans = this.state.spanCache.getByRootSpanId(this.rootSpanId);
29305
31633
  if (cachedSpans && cachedSpans.length > 0) {
29306
- let spans = cachedSpans.filter(
31634
+ let spans = includeScorers ? cachedSpans : cachedSpans.filter(
29307
31635
  (span) => span.span_attributes?.purpose !== "scorer"
29308
31636
  );
29309
31637
  if (spanType && spanType.length > 0) {
@@ -29314,13 +31642,19 @@ var LocalTrace = class {
29314
31642
  return spans.map((span) => ({
29315
31643
  input: span.input,
29316
31644
  output: span.output,
31645
+ expected: span.expected,
31646
+ error: span.error,
31647
+ scores: span.scores,
31648
+ metrics: span.metrics,
29317
31649
  metadata: span.metadata,
29318
31650
  span_id: span.span_id,
29319
31651
  span_parents: span.span_parents,
29320
- span_attributes: span.span_attributes
31652
+ is_root: span.is_root,
31653
+ span_attributes: span.span_attributes,
31654
+ tags: span.tags
29321
31655
  }));
29322
31656
  }
29323
- return this.cachedFetcher.getSpans({ spanType });
31657
+ return this.cachedFetcher.getSpans({ spanType, includeScorers });
29324
31658
  }
29325
31659
  /**
29326
31660
  * Get the thread (preprocessed messages) for this trace.
@@ -30509,6 +32843,34 @@ var defaultReporter = {
30509
32843
  }
30510
32844
  };
30511
32845
 
32846
+ // src/dataset-pipeline.ts
32847
+ function DatasetPipeline(definition) {
32848
+ if (!globalThis.__braintrust_dataset_pipelines) {
32849
+ globalThis.__braintrust_dataset_pipelines = [];
32850
+ }
32851
+ const storedDefinition = {
32852
+ name: definition.name,
32853
+ source: {
32854
+ projectId: definition.source.projectId,
32855
+ projectName: definition.source.projectName,
32856
+ orgName: definition.source.orgName,
32857
+ filter: definition.source.filter,
32858
+ scope: definition.source.scope ?? "span"
32859
+ },
32860
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions, @typescript-eslint/no-explicit-any
32861
+ transform: definition.transform,
32862
+ target: {
32863
+ projectId: definition.target.projectId,
32864
+ projectName: definition.target.projectName,
32865
+ orgName: definition.target.orgName,
32866
+ datasetName: definition.target.datasetName,
32867
+ description: definition.target.description,
32868
+ metadata: definition.target.metadata
32869
+ }
32870
+ };
32871
+ globalThis.__braintrust_dataset_pipelines.push(storedDefinition);
32872
+ }
32873
+
30512
32874
  // src/framework2.ts
30513
32875
  var import_v312 = require("zod/v3");
30514
32876
  var currentFilename = typeof __filename !== "undefined" ? __filename : "unknown";