braintrust 3.11.0 → 3.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. package/README.md +8 -8
  2. package/dev/dist/index.d.mts +1 -1
  3. package/dev/dist/index.d.ts +1 -1
  4. package/dev/dist/index.js +2607 -316
  5. package/dev/dist/index.mjs +2388 -97
  6. package/dist/apply-auto-instrumentation.browser.d.mts +2 -0
  7. package/dist/apply-auto-instrumentation.browser.d.ts +2 -0
  8. package/dist/apply-auto-instrumentation.browser.js +18 -0
  9. package/dist/apply-auto-instrumentation.browser.mjs +0 -0
  10. package/dist/apply-auto-instrumentation.d.mts +2 -0
  11. package/dist/apply-auto-instrumentation.d.ts +2 -0
  12. package/dist/apply-auto-instrumentation.js +2534 -0
  13. package/dist/apply-auto-instrumentation.mjs +2534 -0
  14. package/dist/auto-instrumentations/bundler/esbuild.cjs +1802 -1283
  15. package/dist/auto-instrumentations/bundler/esbuild.d.mts +9 -5
  16. package/dist/auto-instrumentations/bundler/esbuild.d.ts +9 -5
  17. package/dist/auto-instrumentations/bundler/esbuild.mjs +10 -2
  18. package/dist/auto-instrumentations/bundler/next.cjs +3268 -0
  19. package/dist/auto-instrumentations/bundler/next.d.mts +3 -0
  20. package/dist/auto-instrumentations/bundler/next.d.ts +3 -0
  21. package/dist/auto-instrumentations/bundler/next.mjs +189 -0
  22. package/dist/auto-instrumentations/bundler/rollup.cjs +1802 -1283
  23. package/dist/auto-instrumentations/bundler/rollup.d.mts +9 -5
  24. package/dist/auto-instrumentations/bundler/rollup.d.ts +9 -5
  25. package/dist/auto-instrumentations/bundler/rollup.mjs +10 -2
  26. package/dist/auto-instrumentations/bundler/vite.cjs +1802 -1283
  27. package/dist/auto-instrumentations/bundler/vite.d.mts +9 -5
  28. package/dist/auto-instrumentations/bundler/vite.d.ts +9 -5
  29. package/dist/auto-instrumentations/bundler/vite.mjs +10 -2
  30. package/dist/auto-instrumentations/bundler/webpack-loader.cjs +1860 -1308
  31. package/dist/auto-instrumentations/bundler/webpack-loader.d.ts +3 -3
  32. package/dist/auto-instrumentations/bundler/webpack.cjs +1802 -1283
  33. package/dist/auto-instrumentations/bundler/webpack.d.mts +9 -5
  34. package/dist/auto-instrumentations/bundler/webpack.d.ts +9 -5
  35. package/dist/auto-instrumentations/bundler/webpack.mjs +6 -6
  36. package/dist/auto-instrumentations/{chunk-DIV5TO4S.mjs → chunk-2DPA74KK.mjs} +337 -1
  37. package/dist/auto-instrumentations/chunk-73BZUKVI.mjs +300 -0
  38. package/dist/auto-instrumentations/chunk-AFXRW7I7.mjs +18 -0
  39. package/dist/auto-instrumentations/hook.mjs +1712 -1460
  40. package/dist/auto-instrumentations/index.cjs +93 -0
  41. package/dist/auto-instrumentations/index.d.mts +5 -1
  42. package/dist/auto-instrumentations/index.d.ts +5 -1
  43. package/dist/auto-instrumentations/index.mjs +6 -247
  44. package/dist/auto-instrumentations/loader/esm-hook.mjs +19 -2
  45. package/dist/auto-instrumentations/plugin-D7nDswtC.d.mts +44 -0
  46. package/dist/auto-instrumentations/plugin-D7nDswtC.d.ts +44 -0
  47. package/dist/browser.d.mts +120 -31
  48. package/dist/browser.d.ts +120 -31
  49. package/dist/browser.js +2395 -123
  50. package/dist/browser.mjs +2395 -123
  51. package/dist/chunk-BW4DF4CY.js +816 -0
  52. package/dist/chunk-MSLBGITU.mjs +816 -0
  53. package/dist/cli.js +2407 -96
  54. package/dist/edge-light.d.mts +1 -1
  55. package/dist/edge-light.d.ts +1 -1
  56. package/dist/edge-light.js +2395 -123
  57. package/dist/edge-light.mjs +2395 -123
  58. package/dist/index.d.mts +120 -31
  59. package/dist/index.d.ts +120 -31
  60. package/dist/index.js +3362 -1849
  61. package/dist/index.mjs +2505 -992
  62. package/dist/instrumentation/index.d.mts +7860 -48
  63. package/dist/instrumentation/index.d.ts +7860 -48
  64. package/dist/instrumentation/index.js +2395 -95
  65. package/dist/instrumentation/index.mjs +2394 -95
  66. package/dist/workerd.d.mts +1 -1
  67. package/dist/workerd.d.ts +1 -1
  68. package/dist/workerd.js +2395 -123
  69. package/dist/workerd.mjs +2395 -123
  70. package/package.json +23 -3
  71. package/util/dist/index.js +6 -0
  72. package/util/dist/index.mjs +6 -0
  73. package/dist/auto-instrumentations/chunk-G6ZWXGZB.mjs +0 -116
  74. package/dist/auto-instrumentations/plugin-Df3qKIl2.d.mts +0 -22
  75. package/dist/auto-instrumentations/plugin-Df3qKIl2.d.ts +0 -22
@@ -1126,6 +1126,11 @@ function isPromiseLike(value) {
1126
1126
 
1127
1127
  // util/object_util.ts
1128
1128
  var SET_UNION_FIELDS = /* @__PURE__ */ new Set(["tags"]);
1129
+ var FORBIDDEN_MERGE_KEYS = /* @__PURE__ */ new Set([
1130
+ "__proto__",
1131
+ "constructor",
1132
+ "prototype"
1133
+ ]);
1129
1134
  function mergeDictsWithPaths({
1130
1135
  mergeInto,
1131
1136
  mergeFrom,
@@ -1148,6 +1153,7 @@ function mergeDictsWithPathsHelper({
1148
1153
  mergePaths
1149
1154
  }) {
1150
1155
  Object.entries(mergeFrom).forEach(([k, mergeFromV]) => {
1156
+ if (FORBIDDEN_MERGE_KEYS.has(k)) return;
1151
1157
  const fullPath = path.concat([k]);
1152
1158
  const fullPathSerialized = JSON.stringify(fullPath);
1153
1159
  const mergeIntoV = recordFind(mergeInto, k);
@@ -5019,6 +5025,13 @@ var HTTPConnection = class _HTTPConnection {
5019
5025
  debugLogger.debug(
5020
5026
  `Retrying API request ${object_type} ${JSON.stringify(args)} ${e.status} ${e.text}`
5021
5027
  );
5028
+ const sleepTimeS = HTTP_RETRY_BASE_SLEEP_TIME_S * 2 ** i;
5029
+ debugLogger.info(
5030
+ `Sleeping for ${sleepTimeS}s before retrying API request`
5031
+ );
5032
+ await new Promise(
5033
+ (resolve) => setTimeout(resolve, sleepTimeS * 1e3)
5034
+ );
5022
5035
  continue;
5023
5036
  }
5024
5037
  throw e;
@@ -5541,20 +5554,7 @@ function startSpanParentArgs(args) {
5541
5554
  `Mismatch between expected span parent object type ${args.parentObjectType} and provided type ${parentComponents.data.object_type}`
5542
5555
  );
5543
5556
  }
5544
- const parentComponentsObjectIdLambda = spanComponentsToObjectIdLambda(
5545
- args.state,
5546
- parentComponents
5547
- );
5548
- const computeParentObjectId = async () => {
5549
- const parentComponentsObjectId = await parentComponentsObjectIdLambda();
5550
- if (await args.parentObjectId.get() !== parentComponentsObjectId) {
5551
- throw new Error(
5552
- `Mismatch between expected span parent object id ${await args.parentObjectId.get()} and provided id ${parentComponentsObjectId}`
5553
- );
5554
- }
5555
- return await args.parentObjectId.get();
5556
- };
5557
- argParentObjectId = new LazyValue(computeParentObjectId);
5557
+ argParentObjectId = args.parentObjectId;
5558
5558
  if (parentComponents.data.row_id) {
5559
5559
  argParentSpanIds = {
5560
5560
  spanId: parentComponents.data.span_id,
@@ -5883,6 +5883,7 @@ function now() {
5883
5883
  }
5884
5884
  var DEFAULT_FLUSH_BACKPRESSURE_BYTES = 10 * 1024 * 1024;
5885
5885
  var BACKGROUND_LOGGER_BASE_SLEEP_TIME_S = 1;
5886
+ var HTTP_RETRY_BASE_SLEEP_TIME_S = 1;
5886
5887
  var HTTPBackgroundLogger = class _HTTPBackgroundLogger {
5887
5888
  apiConn;
5888
5889
  queue;
@@ -6455,6 +6456,55 @@ async function computeLoggerMetadata(state, {
6455
6456
  };
6456
6457
  }
6457
6458
  }
6459
+ function initLogger(options = {}) {
6460
+ const {
6461
+ projectName,
6462
+ projectId,
6463
+ asyncFlush: asyncFlushArg,
6464
+ appUrl,
6465
+ apiKey,
6466
+ orgName,
6467
+ forceLogin,
6468
+ debugLogLevel,
6469
+ fetch: fetch2,
6470
+ state: stateArg
6471
+ } = options || {};
6472
+ const asyncFlush = asyncFlushArg === void 0 ? true : asyncFlushArg;
6473
+ const computeMetadataArgs = {
6474
+ project_name: projectName,
6475
+ project_id: projectId
6476
+ };
6477
+ const linkArgs = {
6478
+ org_name: orgName,
6479
+ app_url: appUrl,
6480
+ project_name: projectName,
6481
+ project_id: projectId
6482
+ };
6483
+ const state = stateArg ?? _globalState;
6484
+ state.setDebugLogLevel(debugLogLevel);
6485
+ state.enforceQueueSizeLimit(true);
6486
+ const lazyMetadata = new LazyValue(
6487
+ async () => {
6488
+ await state.login({
6489
+ orgName,
6490
+ apiKey,
6491
+ appUrl,
6492
+ forceLogin,
6493
+ fetch: fetch2
6494
+ });
6495
+ return computeLoggerMetadata(state, computeMetadataArgs);
6496
+ }
6497
+ );
6498
+ const ret = new Logger(state, lazyMetadata, {
6499
+ asyncFlush,
6500
+ computeMetadataArgs,
6501
+ linkArgs
6502
+ });
6503
+ if (options.setCurrent ?? true) {
6504
+ state.currentLogger = ret;
6505
+ }
6506
+ return ret;
6507
+ }
6458
6508
  async function loginToState(options = {}) {
6459
6509
  const {
6460
6510
  appUrl = isomorph_default.getEnv("BRAINTRUST_APP_URL") || "https://www.braintrust.dev",
@@ -11378,11 +11428,11 @@ function resolveDenyOutputPaths(event, defaultDenyOutputPaths) {
11378
11428
  if (Array.isArray(event?.denyOutputPaths)) {
11379
11429
  return event.denyOutputPaths;
11380
11430
  }
11381
- const firstArgument = event?.arguments && event.arguments.length > 0 ? event.arguments[0] : void 0;
11382
- if (!firstArgument || typeof firstArgument !== "object") {
11431
+ const firstArgument2 = event?.arguments && event.arguments.length > 0 ? event.arguments[0] : void 0;
11432
+ if (!firstArgument2 || typeof firstArgument2 !== "object") {
11383
11433
  return defaultDenyOutputPaths;
11384
11434
  }
11385
- const runtimeDenyOutputPaths = firstArgument[RUNTIME_DENY_OUTPUT_PATHS];
11435
+ const runtimeDenyOutputPaths = firstArgument2[RUNTIME_DENY_OUTPUT_PATHS];
11386
11436
  if (Array.isArray(runtimeDenyOutputPaths) && runtimeDenyOutputPaths.every((path) => typeof path === "string")) {
11387
11437
  return runtimeDenyOutputPaths;
11388
11438
  }
@@ -15041,6 +15091,467 @@ function cleanMetrics2(metrics) {
15041
15091
  return cleaned;
15042
15092
  }
15043
15093
 
15094
+ // src/instrumentation/plugins/openai-agents-channels.ts
15095
+ var openAIAgentsCoreChannels = defineChannels("@openai/agents-core", {
15096
+ onTraceStart: channel({
15097
+ channelName: "tracing.processor.onTraceStart",
15098
+ kind: "async"
15099
+ }),
15100
+ onTraceEnd: channel({
15101
+ channelName: "tracing.processor.onTraceEnd",
15102
+ kind: "async"
15103
+ }),
15104
+ onSpanStart: channel({
15105
+ channelName: "tracing.processor.onSpanStart",
15106
+ kind: "async"
15107
+ }),
15108
+ onSpanEnd: channel({
15109
+ channelName: "tracing.processor.onSpanEnd",
15110
+ kind: "async"
15111
+ })
15112
+ });
15113
+
15114
+ // src/instrumentation/plugins/openai-agents-trace-processor.ts
15115
+ function isSpanData(spanData, type) {
15116
+ return spanData.type === type;
15117
+ }
15118
+ function spanTypeFromAgents(span) {
15119
+ const spanType = span.spanData.type;
15120
+ if (spanType === "function" || spanType === "guardrail" || spanType === "mcp_tools") {
15121
+ return "tool" /* TOOL */;
15122
+ }
15123
+ if (spanType === "generation" || spanType === "response" || spanType === "transcription" || spanType === "speech") {
15124
+ return "llm" /* LLM */;
15125
+ }
15126
+ return "task" /* TASK */;
15127
+ }
15128
+ function spanNameFromAgents(span) {
15129
+ const spanData = span.spanData;
15130
+ if ("name" in spanData && spanData.name) {
15131
+ return spanData.name;
15132
+ }
15133
+ switch (spanData.type) {
15134
+ case "generation":
15135
+ return "Generation";
15136
+ case "response":
15137
+ return "Response";
15138
+ case "handoff":
15139
+ return "Handoff";
15140
+ case "mcp_tools":
15141
+ return isSpanData(spanData, "mcp_tools") && spanData.server ? `List Tools (${spanData.server})` : "MCP List Tools";
15142
+ case "transcription":
15143
+ return "Transcription";
15144
+ case "speech":
15145
+ return "Speech";
15146
+ case "speech_group":
15147
+ return "Speech Group";
15148
+ default:
15149
+ return "Unknown";
15150
+ }
15151
+ }
15152
+ function getTimeElapsed(end, start) {
15153
+ if (!start || !end) {
15154
+ return void 0;
15155
+ }
15156
+ const startTime = new Date(start).getTime();
15157
+ const endTime = new Date(end).getTime();
15158
+ if (Number.isNaN(startTime) || Number.isNaN(endTime)) {
15159
+ return void 0;
15160
+ }
15161
+ return (endTime - startTime) / 1e3;
15162
+ }
15163
+ function getNumberProperty2(obj, key) {
15164
+ if (!isObject(obj) || !(key in obj)) {
15165
+ return void 0;
15166
+ }
15167
+ const value = obj[key];
15168
+ return typeof value === "number" ? value : void 0;
15169
+ }
15170
+ function parseUsageMetrics(usage) {
15171
+ const metrics = {};
15172
+ if (!isObject(usage)) {
15173
+ return metrics;
15174
+ }
15175
+ const promptTokens = getNumberProperty2(usage, "prompt_tokens") ?? getNumberProperty2(usage, "input_tokens") ?? getNumberProperty2(usage, "promptTokens") ?? getNumberProperty2(usage, "inputTokens");
15176
+ const completionTokens = getNumberProperty2(usage, "completion_tokens") ?? getNumberProperty2(usage, "output_tokens") ?? getNumberProperty2(usage, "completionTokens") ?? getNumberProperty2(usage, "outputTokens");
15177
+ const totalTokens = getNumberProperty2(usage, "total_tokens") ?? getNumberProperty2(usage, "totalTokens");
15178
+ if (promptTokens !== void 0) {
15179
+ metrics.prompt_tokens = promptTokens;
15180
+ }
15181
+ if (completionTokens !== void 0) {
15182
+ metrics.completion_tokens = completionTokens;
15183
+ }
15184
+ if (totalTokens !== void 0) {
15185
+ metrics.tokens = totalTokens;
15186
+ } else if (promptTokens !== void 0 && completionTokens !== void 0) {
15187
+ metrics.tokens = promptTokens + completionTokens;
15188
+ }
15189
+ const inputDetails = usage.input_tokens_details;
15190
+ const cachedTokens = getNumberProperty2(inputDetails, "cached_tokens");
15191
+ const cacheWriteTokens = getNumberProperty2(
15192
+ inputDetails,
15193
+ "cache_write_tokens"
15194
+ );
15195
+ if (cachedTokens !== void 0) {
15196
+ metrics.prompt_cached_tokens = cachedTokens;
15197
+ }
15198
+ if (cacheWriteTokens !== void 0) {
15199
+ metrics.prompt_cache_creation_tokens = cacheWriteTokens;
15200
+ }
15201
+ return metrics;
15202
+ }
15203
+ var OpenAIAgentsTraceProcessor = class _OpenAIAgentsTraceProcessor {
15204
+ static DEFAULT_MAX_TRACES = 1e4;
15205
+ logger;
15206
+ maxTraces;
15207
+ traceSpans = /* @__PURE__ */ new Map();
15208
+ traceOrder = [];
15209
+ _traceSpans = this.traceSpans;
15210
+ constructor(options = {}) {
15211
+ this.logger = options.logger;
15212
+ this.maxTraces = options.maxTraces ?? _OpenAIAgentsTraceProcessor.DEFAULT_MAX_TRACES;
15213
+ }
15214
+ evictOldestTrace() {
15215
+ const oldestTraceId = this.traceOrder.shift();
15216
+ if (oldestTraceId) {
15217
+ this.traceSpans.delete(oldestTraceId);
15218
+ }
15219
+ }
15220
+ onTraceStart(trace) {
15221
+ if (!trace?.traceId) {
15222
+ return Promise.resolve();
15223
+ }
15224
+ if (this.traceOrder.length >= this.maxTraces) {
15225
+ this.evictOldestTrace();
15226
+ }
15227
+ const current = currentSpan();
15228
+ const span = current && current !== NOOP_SPAN ? current.startSpan({
15229
+ name: trace.name,
15230
+ type: "task" /* TASK */
15231
+ }) : this.logger ? this.logger.startSpan({
15232
+ name: trace.name,
15233
+ type: "task" /* TASK */
15234
+ }) : startSpan({
15235
+ name: trace.name,
15236
+ type: "task" /* TASK */
15237
+ });
15238
+ span.log({
15239
+ input: "Agent workflow started",
15240
+ metadata: {
15241
+ group_id: trace.groupId,
15242
+ ...trace.metadata || {}
15243
+ }
15244
+ });
15245
+ this.traceSpans.set(trace.traceId, {
15246
+ rootSpan: span,
15247
+ childSpans: /* @__PURE__ */ new Map(),
15248
+ metadata: {
15249
+ firstInput: null,
15250
+ lastOutput: null
15251
+ }
15252
+ });
15253
+ this.traceOrder.push(trace.traceId);
15254
+ return Promise.resolve();
15255
+ }
15256
+ async onTraceEnd(trace) {
15257
+ const traceData = this.traceSpans.get(trace?.traceId);
15258
+ if (!traceData) {
15259
+ return;
15260
+ }
15261
+ try {
15262
+ traceData.rootSpan.log({
15263
+ input: traceData.metadata.firstInput,
15264
+ output: traceData.metadata.lastOutput
15265
+ });
15266
+ traceData.rootSpan.end();
15267
+ await traceData.rootSpan.flush();
15268
+ } finally {
15269
+ this.traceSpans.delete(trace.traceId);
15270
+ const orderIndex = this.traceOrder.indexOf(trace.traceId);
15271
+ if (orderIndex > -1) {
15272
+ this.traceOrder.splice(orderIndex, 1);
15273
+ }
15274
+ }
15275
+ }
15276
+ onSpanStart(span) {
15277
+ if (!span?.spanId || !span.traceId) {
15278
+ return Promise.resolve();
15279
+ }
15280
+ const traceData = this.traceSpans.get(span.traceId);
15281
+ if (!traceData) {
15282
+ return Promise.resolve();
15283
+ }
15284
+ const parentSpan = span.parentId ? traceData.childSpans.get(span.parentId) : traceData.rootSpan;
15285
+ if (!parentSpan) {
15286
+ return Promise.resolve();
15287
+ }
15288
+ const childSpan = parentSpan.startSpan({
15289
+ name: spanNameFromAgents(span),
15290
+ type: spanTypeFromAgents(span)
15291
+ });
15292
+ traceData.childSpans.set(span.spanId, childSpan);
15293
+ return Promise.resolve();
15294
+ }
15295
+ onSpanEnd(span) {
15296
+ if (!span?.spanId || !span.traceId) {
15297
+ return Promise.resolve();
15298
+ }
15299
+ const traceData = this.traceSpans.get(span.traceId);
15300
+ if (!traceData) {
15301
+ return Promise.resolve();
15302
+ }
15303
+ const braintrustSpan = traceData.childSpans.get(span.spanId);
15304
+ if (!braintrustSpan) {
15305
+ return Promise.resolve();
15306
+ }
15307
+ const logData = this.extractLogData(span);
15308
+ braintrustSpan.log({
15309
+ error: span.error,
15310
+ ...logData
15311
+ });
15312
+ braintrustSpan.end();
15313
+ traceData.childSpans.delete(span.spanId);
15314
+ const input = logData.input;
15315
+ const output = logData.output;
15316
+ if (traceData.metadata.firstInput === null && input != null) {
15317
+ traceData.metadata.firstInput = input;
15318
+ }
15319
+ if (output != null) {
15320
+ traceData.metadata.lastOutput = output;
15321
+ }
15322
+ return Promise.resolve();
15323
+ }
15324
+ async shutdown() {
15325
+ if (this.logger && typeof this.logger.flush === "function") {
15326
+ await this.logger.flush();
15327
+ }
15328
+ }
15329
+ async forceFlush() {
15330
+ if (this.logger && typeof this.logger.flush === "function") {
15331
+ await this.logger.flush();
15332
+ }
15333
+ }
15334
+ extractLogData(span) {
15335
+ const spanData = span.spanData;
15336
+ switch (spanData.type) {
15337
+ case "agent":
15338
+ return this.extractAgentLogData(spanData);
15339
+ case "response":
15340
+ return this.extractResponseLogData(spanData, span);
15341
+ case "function":
15342
+ return this.extractFunctionLogData(spanData);
15343
+ case "handoff":
15344
+ return this.extractHandoffLogData(spanData);
15345
+ case "guardrail":
15346
+ return this.extractGuardrailLogData(spanData);
15347
+ case "generation":
15348
+ return this.extractGenerationLogData(spanData, span);
15349
+ case "custom":
15350
+ return this.extractCustomLogData(spanData);
15351
+ case "mcp_tools":
15352
+ return this.extractMCPListToolsLogData(spanData);
15353
+ case "transcription":
15354
+ return this.extractTranscriptionLogData(spanData);
15355
+ case "speech":
15356
+ return this.extractSpeechLogData(spanData);
15357
+ case "speech_group":
15358
+ return this.extractSpeechGroupLogData(spanData);
15359
+ default:
15360
+ return {};
15361
+ }
15362
+ }
15363
+ extractAgentLogData(spanData) {
15364
+ return {
15365
+ metadata: {
15366
+ tools: spanData.tools,
15367
+ handoffs: spanData.handoffs,
15368
+ output_type: spanData.output_type
15369
+ }
15370
+ };
15371
+ }
15372
+ extractResponseLogData(spanData, span) {
15373
+ const response = spanData._response;
15374
+ const output = isObject(response) ? response.output : void 0;
15375
+ const usage = isObject(response) ? response.usage : void 0;
15376
+ const metrics = {
15377
+ ...this.extractTimingMetrics(span),
15378
+ ...parseUsageMetrics(usage)
15379
+ };
15380
+ return {
15381
+ input: spanData._input,
15382
+ output,
15383
+ metadata: isObject(response) ? this.omitKeys(response, ["output", "usage"]) : {},
15384
+ metrics
15385
+ };
15386
+ }
15387
+ extractFunctionLogData(spanData) {
15388
+ return {
15389
+ input: spanData.input,
15390
+ output: spanData.output
15391
+ };
15392
+ }
15393
+ extractHandoffLogData(spanData) {
15394
+ return {
15395
+ metadata: {
15396
+ from_agent: spanData.from_agent,
15397
+ to_agent: spanData.to_agent
15398
+ }
15399
+ };
15400
+ }
15401
+ extractGuardrailLogData(spanData) {
15402
+ return {
15403
+ metadata: {
15404
+ triggered: spanData.triggered
15405
+ }
15406
+ };
15407
+ }
15408
+ extractGenerationLogData(spanData, span) {
15409
+ return {
15410
+ input: spanData.input,
15411
+ output: spanData.output,
15412
+ metadata: {
15413
+ model: spanData.model,
15414
+ model_config: spanData.model_config
15415
+ },
15416
+ metrics: {
15417
+ ...this.extractTimingMetrics(span),
15418
+ ...parseUsageMetrics(spanData.usage)
15419
+ }
15420
+ };
15421
+ }
15422
+ extractCustomLogData(spanData) {
15423
+ return spanData.data || {};
15424
+ }
15425
+ extractMCPListToolsLogData(spanData) {
15426
+ return {
15427
+ output: spanData.result,
15428
+ metadata: {
15429
+ server: spanData.server
15430
+ }
15431
+ };
15432
+ }
15433
+ extractTranscriptionLogData(spanData) {
15434
+ return {
15435
+ input: spanData.input,
15436
+ output: spanData.output,
15437
+ metadata: {
15438
+ model: spanData.model,
15439
+ model_config: spanData.model_config
15440
+ }
15441
+ };
15442
+ }
15443
+ extractSpeechLogData(spanData) {
15444
+ return {
15445
+ input: spanData.input,
15446
+ output: spanData.output,
15447
+ metadata: {
15448
+ model: spanData.model,
15449
+ model_config: spanData.model_config
15450
+ }
15451
+ };
15452
+ }
15453
+ extractSpeechGroupLogData(spanData) {
15454
+ return {
15455
+ input: spanData.input
15456
+ };
15457
+ }
15458
+ extractTimingMetrics(span) {
15459
+ const timeToFirstToken = getTimeElapsed(
15460
+ span.endedAt ?? void 0,
15461
+ span.startedAt ?? void 0
15462
+ );
15463
+ return timeToFirstToken === void 0 ? {} : { time_to_first_token: timeToFirstToken };
15464
+ }
15465
+ omitKeys(value, keys) {
15466
+ const result = {};
15467
+ for (const [key, fieldValue] of Object.entries(value)) {
15468
+ if (!keys.includes(key)) {
15469
+ result[key] = fieldValue;
15470
+ }
15471
+ }
15472
+ return result;
15473
+ }
15474
+ };
15475
+
15476
+ // src/instrumentation/plugins/openai-agents-plugin.ts
15477
+ function firstArgument(args) {
15478
+ if (Array.isArray(args)) {
15479
+ return args[0];
15480
+ }
15481
+ if (isObject(args) && "length" in args && typeof args.length === "number" && Number.isInteger(args.length) && args.length >= 0) {
15482
+ return Array.from(args)[0];
15483
+ }
15484
+ return void 0;
15485
+ }
15486
+ function isOpenAIAgentsTrace(value) {
15487
+ return isObject(value) && value.type === "trace" && typeof value.traceId === "string";
15488
+ }
15489
+ function isOpenAIAgentsSpan(value) {
15490
+ return isObject(value) && value.type === "trace.span" && typeof value.traceId === "string" && typeof value.spanId === "string";
15491
+ }
15492
+ var OpenAIAgentsPlugin = class extends BasePlugin {
15493
+ processor = new OpenAIAgentsTraceProcessor();
15494
+ onEnable() {
15495
+ this.subscribeToTraceLifecycle();
15496
+ }
15497
+ onDisable() {
15498
+ this.unsubscribers = unsubscribeAll(this.unsubscribers);
15499
+ void this.processor.shutdown();
15500
+ }
15501
+ subscribeToTraceLifecycle() {
15502
+ const traceStartChannel = openAIAgentsCoreChannels.onTraceStart.tracingChannel();
15503
+ const traceStartHandlers = {
15504
+ start: (event) => {
15505
+ const trace = firstArgument(event.arguments);
15506
+ if (isOpenAIAgentsTrace(trace)) {
15507
+ void this.processor.onTraceStart(trace);
15508
+ }
15509
+ }
15510
+ };
15511
+ traceStartChannel.subscribe(traceStartHandlers);
15512
+ this.unsubscribers.push(
15513
+ () => traceStartChannel.unsubscribe(traceStartHandlers)
15514
+ );
15515
+ const traceEndChannel = openAIAgentsCoreChannels.onTraceEnd.tracingChannel();
15516
+ const traceEndHandlers = {
15517
+ start: (event) => {
15518
+ const trace = firstArgument(event.arguments);
15519
+ if (isOpenAIAgentsTrace(trace)) {
15520
+ void this.processor.onTraceEnd(trace);
15521
+ }
15522
+ }
15523
+ };
15524
+ traceEndChannel.subscribe(traceEndHandlers);
15525
+ this.unsubscribers.push(
15526
+ () => traceEndChannel.unsubscribe(traceEndHandlers)
15527
+ );
15528
+ const spanStartChannel = openAIAgentsCoreChannels.onSpanStart.tracingChannel();
15529
+ const spanStartHandlers = {
15530
+ start: (event) => {
15531
+ const span = firstArgument(event.arguments);
15532
+ if (isOpenAIAgentsSpan(span)) {
15533
+ void this.processor.onSpanStart(span);
15534
+ }
15535
+ }
15536
+ };
15537
+ spanStartChannel.subscribe(spanStartHandlers);
15538
+ this.unsubscribers.push(
15539
+ () => spanStartChannel.unsubscribe(spanStartHandlers)
15540
+ );
15541
+ const spanEndChannel = openAIAgentsCoreChannels.onSpanEnd.tracingChannel();
15542
+ const spanEndHandlers = {
15543
+ start: (event) => {
15544
+ const span = firstArgument(event.arguments);
15545
+ if (isOpenAIAgentsSpan(span)) {
15546
+ void this.processor.onSpanEnd(span);
15547
+ }
15548
+ }
15549
+ };
15550
+ spanEndChannel.subscribe(spanEndHandlers);
15551
+ this.unsubscribers.push(() => spanEndChannel.unsubscribe(spanEndHandlers));
15552
+ }
15553
+ };
15554
+
15044
15555
  // src/instrumentation/plugins/google-genai-channels.ts
15045
15556
  var googleGenAIChannels = defineChannels("@google/genai", {
15046
15557
  generateContent: channel({
@@ -21333,51 +21844,1761 @@ var GitHubCopilotPlugin = class extends BasePlugin {
21333
21844
  }
21334
21845
  };
21335
21846
 
21336
- // src/instrumentation/braintrust-plugin.ts
21337
- function getIntegrationConfig(integrations, key) {
21338
- return integrations[key];
21847
+ // src/instrumentation/plugins/flue-channels.ts
21848
+ var flueChannels = defineChannels("@flue/runtime", {
21849
+ createContext: channel({
21850
+ channelName: "createFlueContext",
21851
+ kind: "sync-stream"
21852
+ }),
21853
+ openSession: channel({
21854
+ channelName: "Harness.openSession",
21855
+ kind: "async"
21856
+ }),
21857
+ contextEvent: channel({
21858
+ channelName: "context.event",
21859
+ kind: "sync-stream"
21860
+ }),
21861
+ prompt: channel({
21862
+ channelName: "session.prompt",
21863
+ kind: "async"
21864
+ }),
21865
+ skill: channel({
21866
+ channelName: "session.skill",
21867
+ kind: "async"
21868
+ }),
21869
+ task: channel({
21870
+ channelName: "session.task",
21871
+ kind: "async"
21872
+ }),
21873
+ compact: channel({
21874
+ channelName: "session.compact",
21875
+ kind: "async"
21876
+ })
21877
+ });
21878
+
21879
+ // src/wrappers/flue.ts
21880
+ var WRAPPED_FLUE_CONTEXT = /* @__PURE__ */ Symbol.for("braintrust.flue.wrapped-context");
21881
+ var WRAPPED_FLUE_HARNESS = /* @__PURE__ */ Symbol.for("braintrust.flue.wrapped-harness");
21882
+ var WRAPPED_FLUE_SESSION = /* @__PURE__ */ Symbol.for("braintrust.flue.wrapped-session");
21883
+ var SUBSCRIBED_FLUE_CONTEXT_EVENTS = /* @__PURE__ */ Symbol.for(
21884
+ "braintrust.flue.subscribed-context-events"
21885
+ );
21886
+ function patchFlueContextInPlace(ctx) {
21887
+ const context = ctx;
21888
+ if (context[WRAPPED_FLUE_CONTEXT]) {
21889
+ return ctx;
21890
+ }
21891
+ const originalInit = context.init.bind(context);
21892
+ try {
21893
+ Object.defineProperty(context, WRAPPED_FLUE_CONTEXT, {
21894
+ configurable: false,
21895
+ enumerable: false,
21896
+ value: true
21897
+ });
21898
+ Object.defineProperty(context, "init", {
21899
+ configurable: true,
21900
+ value: async function wrappedFlueInit(options) {
21901
+ const harness = await originalInit(options);
21902
+ return wrapFlueHarness(harness);
21903
+ },
21904
+ writable: true
21905
+ });
21906
+ } catch {
21907
+ }
21908
+ return ctx;
21339
21909
  }
21340
- var BraintrustPlugin = class extends BasePlugin {
21341
- config;
21342
- openaiPlugin = null;
21343
- openAICodexPlugin = null;
21344
- anthropicPlugin = null;
21345
- aiSDKPlugin = null;
21346
- claudeAgentSDKPlugin = null;
21347
- cursorSDKPlugin = null;
21348
- googleGenAIPlugin = null;
21349
- huggingFacePlugin = null;
21350
- openRouterPlugin = null;
21351
- openRouterAgentPlugin = null;
21352
- mistralPlugin = null;
21353
- googleADKPlugin = null;
21354
- coherePlugin = null;
21355
- groqPlugin = null;
21356
- genkitPlugin = null;
21357
- gitHubCopilotPlugin = null;
21358
- constructor(config = {}) {
21359
- super();
21360
- this.config = config;
21910
+ function subscribeFlueContextEvents(ctx, options = {}) {
21911
+ if (!ctx || typeof ctx !== "object" || typeof ctx.subscribeEvent !== "function") {
21912
+ return void 0;
21361
21913
  }
21362
- onEnable() {
21363
- const integrations = this.config.integrations || {};
21364
- if (integrations.openai !== false) {
21365
- this.openaiPlugin = new OpenAIPlugin();
21366
- this.openaiPlugin.enable();
21367
- }
21368
- if (integrations.openaiCodexSDK !== false) {
21369
- this.openAICodexPlugin = new OpenAICodexPlugin();
21370
- this.openAICodexPlugin.enable();
21914
+ const context = ctx;
21915
+ const captureTurnSpans = options.captureTurnSpans ?? true;
21916
+ const existingSubscription = context[SUBSCRIBED_FLUE_CONTEXT_EVENTS];
21917
+ if (existingSubscription) {
21918
+ if (existingSubscription.captureTurnSpans || !captureTurnSpans) {
21919
+ return void 0;
21371
21920
  }
21372
- if (integrations.anthropic !== false) {
21373
- this.anthropicPlugin = new AnthropicPlugin();
21374
- this.anthropicPlugin.enable();
21921
+ try {
21922
+ existingSubscription.unsubscribe();
21923
+ } catch {
21375
21924
  }
21376
- if (integrations.aisdk !== false && integrations.vercel !== false) {
21377
- this.aiSDKPlugin = new AISDKPlugin();
21378
- this.aiSDKPlugin.enable();
21925
+ }
21926
+ try {
21927
+ const unsubscribe = ctx.subscribeEvent((event) => {
21928
+ flueChannels.contextEvent.traceSync(() => void 0, {
21929
+ arguments: [event],
21930
+ captureTurnSpans,
21931
+ context: ctx
21932
+ });
21933
+ });
21934
+ if (existingSubscription) {
21935
+ existingSubscription.captureTurnSpans = captureTurnSpans;
21936
+ existingSubscription.unsubscribe = unsubscribe;
21937
+ } else {
21938
+ Object.defineProperty(context, SUBSCRIBED_FLUE_CONTEXT_EVENTS, {
21939
+ configurable: false,
21940
+ enumerable: false,
21941
+ value: {
21942
+ captureTurnSpans,
21943
+ unsubscribe
21944
+ }
21945
+ });
21379
21946
  }
21380
- if (integrations.claudeAgentSDK !== false) {
21947
+ return unsubscribe;
21948
+ } catch {
21949
+ return void 0;
21950
+ }
21951
+ }
21952
+ function wrapFlueHarness(harness) {
21953
+ if (!isPlausibleFlueHarness(harness)) {
21954
+ return harness;
21955
+ }
21956
+ const target = harness;
21957
+ if (target[WRAPPED_FLUE_HARNESS]) {
21958
+ return harness;
21959
+ }
21960
+ const originalSession = target.session.bind(target);
21961
+ try {
21962
+ Object.defineProperty(target, WRAPPED_FLUE_HARNESS, {
21963
+ configurable: false,
21964
+ enumerable: false,
21965
+ value: true
21966
+ });
21967
+ Object.defineProperty(target, "session", {
21968
+ configurable: true,
21969
+ value: async function wrappedFlueHarnessSession(name, options) {
21970
+ const session = await originalSession(name, options);
21971
+ return patchFlueSessionInPlace(session);
21972
+ },
21973
+ writable: true
21974
+ });
21975
+ const sessions = target.sessions;
21976
+ if (sessions && typeof sessions === "object") {
21977
+ patchFlueSessionFactory(sessions, "get");
21978
+ patchFlueSessionFactory(sessions, "create");
21979
+ }
21980
+ } catch {
21981
+ }
21982
+ return harness;
21983
+ }
21984
+ function patchFlueSessionInPlace(session) {
21985
+ if (session[WRAPPED_FLUE_SESSION]) {
21986
+ return session;
21987
+ }
21988
+ try {
21989
+ Object.defineProperty(session, WRAPPED_FLUE_SESSION, {
21990
+ configurable: false,
21991
+ enumerable: false,
21992
+ value: true
21993
+ });
21994
+ patchCallHandleMethod(session, "prompt", flueChannels.prompt);
21995
+ patchCallHandleMethod(session, "skill", flueChannels.skill);
21996
+ patchCallHandleMethod(session, "task", flueChannels.task);
21997
+ patchCompact(session);
21998
+ } catch {
21999
+ }
22000
+ return session;
22001
+ }
22002
+ function patchFlueSessionFactory(sessions, method) {
22003
+ const original = sessions[method];
22004
+ if (typeof original !== "function") {
22005
+ return;
22006
+ }
22007
+ const bound = original.bind(sessions);
22008
+ Object.defineProperty(sessions, method, {
22009
+ configurable: true,
22010
+ value: async function wrappedFlueSessionFactory(name, options) {
22011
+ const session = await bound(name, options);
22012
+ return patchFlueSessionInPlace(session);
22013
+ },
22014
+ writable: true
22015
+ });
22016
+ }
22017
+ function patchCallHandleMethod(session, method, channel2) {
22018
+ const original = session[method];
22019
+ if (typeof original !== "function") {
22020
+ return;
22021
+ }
22022
+ const bound = original.bind(session);
22023
+ Object.defineProperty(session, method, {
22024
+ configurable: true,
22025
+ value(input, options) {
22026
+ const args = [input, options];
22027
+ const { originalResult, traced } = traceFlueOperation(channel2, {
22028
+ context: {
22029
+ arguments: args,
22030
+ operation: method,
22031
+ session
22032
+ },
22033
+ run: () => bound(input, options)
22034
+ });
22035
+ return preserveCallHandle(originalResult, traced);
22036
+ },
22037
+ writable: true
22038
+ });
22039
+ }
22040
+ function patchCompact(session) {
22041
+ const original = session.compact;
22042
+ if (typeof original !== "function") {
22043
+ return;
22044
+ }
22045
+ const bound = original.bind(session);
22046
+ Object.defineProperty(session, "compact", {
22047
+ configurable: true,
22048
+ value() {
22049
+ const context = {
22050
+ arguments: [],
22051
+ operation: "compact",
22052
+ session
22053
+ };
22054
+ return flueChannels.compact.tracePromise(() => bound(), context);
22055
+ },
22056
+ writable: true
22057
+ });
22058
+ }
22059
+ function traceFlueOperation(channel2, args) {
22060
+ const tracingChannel = channel2.tracingChannel();
22061
+ const context = args.context;
22062
+ let originalResult;
22063
+ let traced;
22064
+ const run = () => {
22065
+ try {
22066
+ originalResult = args.run();
22067
+ tracingChannel.end?.publish(context);
22068
+ } catch (error) {
22069
+ context.error = normalizeError3(error);
22070
+ tracingChannel.error?.publish(context);
22071
+ tracingChannel.end?.publish(context);
22072
+ throw error;
22073
+ }
22074
+ traced = Promise.resolve(originalResult).then(
22075
+ (result) => {
22076
+ context.result = result;
22077
+ tracingChannel.asyncStart?.publish(context);
22078
+ tracingChannel.asyncEnd?.publish(context);
22079
+ return result;
22080
+ },
22081
+ (error) => {
22082
+ context.error = normalizeError3(error);
22083
+ tracingChannel.error?.publish(context);
22084
+ tracingChannel.asyncStart?.publish(context);
22085
+ tracingChannel.asyncEnd?.publish(context);
22086
+ throw error;
22087
+ }
22088
+ );
22089
+ };
22090
+ if (tracingChannel.start?.runStores) {
22091
+ tracingChannel.start.runStores(context, run);
22092
+ } else {
22093
+ tracingChannel.start?.publish(context);
22094
+ run();
22095
+ }
22096
+ return { originalResult, traced };
22097
+ }
22098
+ function normalizeError3(error) {
22099
+ return error instanceof Error ? error : new Error(String(error));
22100
+ }
22101
+ function preserveCallHandle(originalHandle, traced) {
22102
+ if (!isFlueCallHandle(originalHandle)) {
22103
+ return traced;
22104
+ }
22105
+ const handle = originalHandle;
22106
+ const wrapped = {
22107
+ get signal() {
22108
+ return handle.signal;
22109
+ },
22110
+ abort(reason) {
22111
+ return handle.abort(reason);
22112
+ },
22113
+ then(onfulfilled, onrejected) {
22114
+ return traced.then(onfulfilled, onrejected);
22115
+ }
22116
+ };
22117
+ return wrapped;
22118
+ }
22119
+ function isPlausibleFlueHarness(value) {
22120
+ return !!value && typeof value === "object" && typeof value.session === "function";
22121
+ }
22122
+ function isFlueCallHandle(value) {
22123
+ return !!value && typeof value === "object" && typeof value.then === "function" && typeof value.abort === "function" && "signal" in value;
22124
+ }
22125
+
22126
+ // src/instrumentation/plugins/flue-plugin.ts
22127
+ var FluePlugin = class extends BasePlugin {
22128
+ activeOperationsById = /* @__PURE__ */ new Map();
22129
+ activeOperationsByScope = /* @__PURE__ */ new Map();
22130
+ compactionsByScope = /* @__PURE__ */ new Map();
22131
+ pendingOperationsByKey = /* @__PURE__ */ new Map();
22132
+ tasksById = /* @__PURE__ */ new Map();
22133
+ toolsById = /* @__PURE__ */ new Map();
22134
+ turnsByScope = /* @__PURE__ */ new Map();
22135
+ onEnable() {
22136
+ this.subscribeToContextCreation();
22137
+ this.subscribeToSessionCreation();
22138
+ this.subscribeToContextEvents();
22139
+ this.subscribeToSessionOperations();
22140
+ }
22141
+ onDisable() {
22142
+ for (const unsubscribe of this.unsubscribers) {
22143
+ unsubscribe();
22144
+ }
22145
+ this.unsubscribers = [];
22146
+ this.activeOperationsById.clear();
22147
+ this.activeOperationsByScope.clear();
22148
+ this.compactionsByScope.clear();
22149
+ this.pendingOperationsByKey.clear();
22150
+ this.tasksById.clear();
22151
+ this.toolsById.clear();
22152
+ this.turnsByScope.clear();
22153
+ }
22154
+ subscribeToContextCreation() {
22155
+ const channel2 = flueChannels.createContext.tracingChannel();
22156
+ const handlers = {
22157
+ end: (event) => {
22158
+ const ctx = event.result;
22159
+ if (!ctx) {
22160
+ return;
22161
+ }
22162
+ subscribeFlueContextEvents(ctx, { captureTurnSpans: false });
22163
+ patchFlueContextInPlace(ctx);
22164
+ },
22165
+ error: () => {
22166
+ }
22167
+ };
22168
+ channel2.subscribe(handlers);
22169
+ this.unsubscribers.push(() => {
22170
+ channel2.unsubscribe(handlers);
22171
+ });
22172
+ }
22173
+ subscribeToSessionCreation() {
22174
+ const channel2 = flueChannels.openSession.tracingChannel();
22175
+ const handlers = {
22176
+ asyncEnd: (event) => {
22177
+ if (event.result) {
22178
+ patchFlueSessionInPlace(
22179
+ event.result
22180
+ );
22181
+ }
22182
+ if (event.harness) {
22183
+ wrapFlueHarness(event.harness);
22184
+ }
22185
+ },
22186
+ error: () => {
22187
+ }
22188
+ };
22189
+ channel2.subscribe(handlers);
22190
+ this.unsubscribers.push(() => {
22191
+ channel2.unsubscribe(handlers);
22192
+ });
22193
+ }
22194
+ subscribeToSessionOperations() {
22195
+ this.subscribeToSessionOperation(flueChannels.prompt);
22196
+ this.subscribeToSessionOperation(flueChannels.skill);
22197
+ this.subscribeToSessionOperation(flueChannels.task);
22198
+ this.subscribeToCompact();
22199
+ }
22200
+ subscribeToSessionOperation(channel2) {
22201
+ const tracingChannel = channel2.tracingChannel();
22202
+ const states = /* @__PURE__ */ new WeakMap();
22203
+ const ensureState2 = (event) => {
22204
+ const existing = states.get(event);
22205
+ if (existing) {
22206
+ return existing;
22207
+ }
22208
+ const state = this.startOperationState({
22209
+ args: event.arguments,
22210
+ moduleVersion: typeof event.moduleVersion === "string" ? event.moduleVersion : void 0,
22211
+ operation: event.operation,
22212
+ session: event.session
22213
+ });
22214
+ states.set(event, state);
22215
+ return state;
22216
+ };
22217
+ const unbindCurrentSpanStore = this.bindCurrentSpanStoreToOperationStart(
22218
+ tracingChannel,
22219
+ ensureState2
22220
+ );
22221
+ const handlers = {
22222
+ start: (event) => {
22223
+ ensureState2(event);
22224
+ },
22225
+ asyncEnd: (event) => {
22226
+ this.endOperationState(states.get(event), event.result);
22227
+ states.delete(event);
22228
+ },
22229
+ error: (event) => {
22230
+ const state = states.get(event);
22231
+ if (state && event.error) {
22232
+ safeLog3(state.span, { error: errorToString(event.error) });
22233
+ this.finishOperationState(state);
22234
+ }
22235
+ states.delete(event);
22236
+ }
22237
+ };
22238
+ tracingChannel.subscribe(handlers);
22239
+ this.unsubscribers.push(() => {
22240
+ unbindCurrentSpanStore?.();
22241
+ tracingChannel.unsubscribe(handlers);
22242
+ });
22243
+ }
22244
+ subscribeToCompact() {
22245
+ const tracingChannel = flueChannels.compact.tracingChannel();
22246
+ const states = /* @__PURE__ */ new WeakMap();
22247
+ const ensureState2 = (event) => {
22248
+ const existing = states.get(event);
22249
+ if (existing) {
22250
+ return existing;
22251
+ }
22252
+ const state = this.startOperationState({
22253
+ args: [],
22254
+ moduleVersion: typeof event.moduleVersion === "string" ? event.moduleVersion : void 0,
22255
+ operation: event.operation,
22256
+ session: event.session
22257
+ });
22258
+ states.set(event, state);
22259
+ return state;
22260
+ };
22261
+ const unbindCurrentSpanStore = this.bindCurrentSpanStoreToOperationStart(
22262
+ tracingChannel,
22263
+ ensureState2
22264
+ );
22265
+ const handlers = {
22266
+ start: (event) => {
22267
+ ensureState2(event);
22268
+ },
22269
+ asyncEnd: (event) => {
22270
+ this.endOperationState(states.get(event), void 0);
22271
+ states.delete(event);
22272
+ },
22273
+ error: (event) => {
22274
+ const state = states.get(event);
22275
+ if (state && event.error) {
22276
+ safeLog3(state.span, { error: errorToString(event.error) });
22277
+ this.finishOperationState(state);
22278
+ }
22279
+ states.delete(event);
22280
+ }
22281
+ };
22282
+ tracingChannel.subscribe(handlers);
22283
+ this.unsubscribers.push(() => {
22284
+ unbindCurrentSpanStore?.();
22285
+ tracingChannel.unsubscribe(handlers);
22286
+ });
22287
+ }
22288
+ subscribeToContextEvents() {
22289
+ const channel2 = flueChannels.contextEvent.tracingChannel();
22290
+ const handlers = {
22291
+ start: (event) => {
22292
+ const flueEvent = event.arguments[0];
22293
+ if (!flueEvent) {
22294
+ return;
22295
+ }
22296
+ try {
22297
+ this.handleFlueEvent(flueEvent, {
22298
+ captureTurnSpans: event.captureTurnSpans !== false
22299
+ });
22300
+ } catch (error) {
22301
+ logInstrumentationError3("Flue event", error);
22302
+ }
22303
+ },
22304
+ error: () => {
22305
+ }
22306
+ };
22307
+ channel2.subscribe(handlers);
22308
+ this.unsubscribers.push(() => {
22309
+ channel2.unsubscribe(handlers);
22310
+ });
22311
+ }
22312
+ bindCurrentSpanStoreToOperationStart(tracingChannel, ensureState2) {
22313
+ const state = _internalGetGlobalState();
22314
+ const startChannel = tracingChannel.start;
22315
+ const contextManager = state?.contextManager;
22316
+ const currentSpanStore = contextManager ? contextManager[BRAINTRUST_CURRENT_SPAN_STORE] : void 0;
22317
+ if (!currentSpanStore || !startChannel) {
22318
+ return void 0;
22319
+ }
22320
+ startChannel.bindStore(currentSpanStore, (event) => {
22321
+ const operationState = ensureState2(event);
22322
+ return contextManager.wrapSpanForStore(operationState.span);
22323
+ });
22324
+ return () => {
22325
+ startChannel.unbindStore(currentSpanStore);
22326
+ };
22327
+ }
22328
+ startOperationState(args) {
22329
+ const sessionName = getSessionName(args.session);
22330
+ const metadata = {
22331
+ ...extractOperationInputMetadata(args.operation, args.args),
22332
+ ...extractSessionMetadata(args.session),
22333
+ "flue.operation": args.operation,
22334
+ provider: "flue",
22335
+ ...args.moduleVersion ? { "flue.version": args.moduleVersion } : {}
22336
+ };
22337
+ const span = startSpan({
22338
+ name: `flue.session.${args.operation}`,
22339
+ spanAttributes: { type: "task" /* TASK */ }
22340
+ });
22341
+ const state = {
22342
+ metadata,
22343
+ operation: args.operation,
22344
+ sessionName,
22345
+ span,
22346
+ startTime: getCurrentUnixTimestamp()
22347
+ };
22348
+ safeLog3(span, {
22349
+ input: extractOperationInput(args.operation, args.args),
22350
+ metadata
22351
+ });
22352
+ this.pendingOperationQueue(operationKey(sessionName, args.operation)).push(
22353
+ state
22354
+ );
22355
+ addOperationToScope(
22356
+ this.activeOperationsByScope,
22357
+ sessionName ?? "unknown",
22358
+ state
22359
+ );
22360
+ return state;
22361
+ }
22362
+ endOperationState(state, result) {
22363
+ if (!state) {
22364
+ return;
22365
+ }
22366
+ const metadata = {
22367
+ ...state.metadata,
22368
+ ...extractPromptResponseMetadata(result)
22369
+ };
22370
+ const metrics = {
22371
+ ...buildDurationMetrics3(state.startTime),
22372
+ ...metricsFromUsage(result?.usage)
22373
+ };
22374
+ safeLog3(state.span, {
22375
+ metadata,
22376
+ metrics,
22377
+ output: extractOperationOutput(result)
22378
+ });
22379
+ this.finishCompactionsForOperation(state);
22380
+ this.finishOperationState(state);
22381
+ }
22382
+ finishOperationState(state) {
22383
+ removePendingOperation(this.pendingOperationsByKey, state);
22384
+ if (state.operationId) {
22385
+ this.activeOperationsById.delete(state.operationId);
22386
+ }
22387
+ removeScopedOperation(this.activeOperationsByScope, state);
22388
+ state.span.end();
22389
+ }
22390
+ handleFlueEvent(event, options) {
22391
+ switch (event.type) {
22392
+ case "operation_start":
22393
+ this.handleOperationStart(event);
22394
+ return;
22395
+ case "operation":
22396
+ this.handleOperation(event);
22397
+ return;
22398
+ case "text_delta":
22399
+ if (!options.captureTurnSpans) {
22400
+ return;
22401
+ }
22402
+ this.ensureTurnState(event).text.push(
22403
+ typeof event.text === "string" ? event.text : ""
22404
+ );
22405
+ return;
22406
+ case "thinking_start":
22407
+ if (!options.captureTurnSpans) {
22408
+ return;
22409
+ }
22410
+ this.handleThinkingStart(event);
22411
+ return;
22412
+ case "thinking_delta":
22413
+ if (!options.captureTurnSpans) {
22414
+ return;
22415
+ }
22416
+ this.handleThinkingDelta(event);
22417
+ return;
22418
+ case "thinking_end":
22419
+ if (!options.captureTurnSpans) {
22420
+ return;
22421
+ }
22422
+ this.handleThinkingEnd(event);
22423
+ return;
22424
+ case "turn":
22425
+ if (!options.captureTurnSpans) {
22426
+ return;
22427
+ }
22428
+ this.handleTurn(event);
22429
+ return;
22430
+ case "tool_start":
22431
+ this.handleToolStart(event, options);
22432
+ return;
22433
+ case "tool_call":
22434
+ this.handleToolCall(event);
22435
+ return;
22436
+ case "task_start":
22437
+ this.handleTaskStart(event);
22438
+ return;
22439
+ case "task":
22440
+ this.handleTask(event);
22441
+ return;
22442
+ case "compaction_start":
22443
+ this.handleCompactionStart(event);
22444
+ return;
22445
+ case "compaction":
22446
+ this.handleCompaction(event);
22447
+ return;
22448
+ default:
22449
+ return;
22450
+ }
22451
+ }
22452
+ handleOperationStart(event) {
22453
+ if (!isInstrumentedOperation(event.operationKind)) {
22454
+ return;
22455
+ }
22456
+ const state = this.takePendingOperationForEvent(event);
22457
+ if (!state) {
22458
+ return;
22459
+ }
22460
+ state.operationId = event.operationId;
22461
+ this.activeOperationsById.set(event.operationId, state);
22462
+ addScopedOperation(this.activeOperationsByScope, event, state);
22463
+ state.metadata = {
22464
+ ...state.metadata,
22465
+ ...extractEventMetadata(event),
22466
+ "flue.operation_id": event.operationId
22467
+ };
22468
+ safeLog3(state.span, { metadata: state.metadata });
22469
+ }
22470
+ handleOperation(event) {
22471
+ const state = event.operationId ? this.activeOperationsById.get(event.operationId) : void 0;
22472
+ if (!state) {
22473
+ return;
22474
+ }
22475
+ const metadata = {
22476
+ ...state.metadata,
22477
+ ...extractEventMetadata(event),
22478
+ ...typeof event.durationMs === "number" ? { "flue.duration_ms": event.durationMs } : {},
22479
+ ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {}
22480
+ };
22481
+ const metrics = metricsFromUsage(event.usage);
22482
+ safeLog3(state.span, {
22483
+ ...event.error ? { error: errorToString(event.error) } : {},
22484
+ metadata,
22485
+ ...Object.keys(metrics).length ? { metrics } : {}
22486
+ });
22487
+ }
22488
+ ensureTurnState(event) {
22489
+ const scope = scopeKey(event);
22490
+ const existing = this.turnsByScope.get(scope);
22491
+ if (existing) {
22492
+ return existing;
22493
+ }
22494
+ const parent = this.parentSpanForEvent(event);
22495
+ const metadata = {
22496
+ ...extractEventMetadata(event),
22497
+ provider: "flue"
22498
+ };
22499
+ const span = startFlueSpan(parent, {
22500
+ name: "flue.turn",
22501
+ spanAttributes: { type: "llm" /* LLM */ }
22502
+ });
22503
+ const state = {
22504
+ metadata,
22505
+ span,
22506
+ hasThinking: false,
22507
+ startTime: getCurrentUnixTimestamp(),
22508
+ text: [],
22509
+ thinking: [],
22510
+ toolCalls: []
22511
+ };
22512
+ safeLog3(span, { metadata });
22513
+ this.turnsByScope.set(scope, state);
22514
+ return state;
22515
+ }
22516
+ handleTurn(event) {
22517
+ const scope = scopeKey(event);
22518
+ const state = this.ensureTurnState(event);
22519
+ const text = state.text.join("");
22520
+ const reasoning = state.finalThinking ?? state.thinking.join("");
22521
+ const outputReasoning = reasoning || (state.hasThinking ? "[reasoning stream present; content unavailable]" : void 0);
22522
+ const metadata = {
22523
+ ...state.metadata,
22524
+ ...extractEventMetadata(event),
22525
+ ...event.model ? { model: event.model, "flue.model": event.model } : {},
22526
+ ...event.stopReason ? { "flue.stop_reason": event.stopReason } : {},
22527
+ ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {},
22528
+ provider: "flue"
22529
+ };
22530
+ safeLog3(state.span, {
22531
+ ...event.error ? { error: errorToString(event.error) } : {},
22532
+ metadata,
22533
+ metrics: {
22534
+ ...durationMsMetrics(event.durationMs),
22535
+ ...metricsFromUsage(event.usage)
22536
+ },
22537
+ output: toAssistantOutput(
22538
+ text,
22539
+ event.stopReason,
22540
+ outputReasoning,
22541
+ state.toolCalls
22542
+ )
22543
+ });
22544
+ state.span.end();
22545
+ this.turnsByScope.delete(scope);
22546
+ }
22547
+ handleThinkingDelta(event) {
22548
+ const delta = event.delta;
22549
+ if (typeof delta !== "string" || !delta) {
22550
+ return;
22551
+ }
22552
+ const state = this.ensureTurnState(event);
22553
+ state.hasThinking = true;
22554
+ state.metadata["flue.thinking"] = true;
22555
+ state.thinking.push(delta);
22556
+ }
22557
+ handleThinkingStart(event) {
22558
+ const state = this.ensureTurnState(event);
22559
+ state.hasThinking = true;
22560
+ state.metadata["flue.thinking"] = true;
22561
+ }
22562
+ handleThinkingEnd(event) {
22563
+ const state = this.ensureTurnState(event);
22564
+ state.hasThinking = true;
22565
+ state.metadata["flue.thinking"] = true;
22566
+ if (typeof event.content === "string" && event.content) {
22567
+ state.finalThinking = event.content;
22568
+ }
22569
+ }
22570
+ handleToolStart(event, options) {
22571
+ const toolCallId = event.toolCallId;
22572
+ if (!toolCallId) {
22573
+ return;
22574
+ }
22575
+ const parent = this.parentSpanForEvent(event);
22576
+ const scope = scopeKey(event);
22577
+ let turnState = this.turnsByScope.get(scope);
22578
+ if (!turnState && parent && options.captureTurnSpans) {
22579
+ turnState = this.ensureTurnState(event);
22580
+ }
22581
+ const metadata = {
22582
+ ...extractEventMetadata(event),
22583
+ ...event.toolName ? { "flue.tool_name": event.toolName } : {},
22584
+ "flue.tool_call_id": toolCallId,
22585
+ provider: "flue"
22586
+ };
22587
+ const span = startFlueSpan(parent, {
22588
+ name: `tool: ${event.toolName ?? "unknown"}`,
22589
+ spanAttributes: { type: "tool" /* TOOL */ }
22590
+ });
22591
+ if (turnState) {
22592
+ turnState.toolCalls.push({
22593
+ args: event.args,
22594
+ toolCallId,
22595
+ toolName: event.toolName
22596
+ });
22597
+ }
22598
+ safeLog3(span, {
22599
+ input: event.args,
22600
+ metadata
22601
+ });
22602
+ this.toolsById.set(toolKey(event), {
22603
+ metadata,
22604
+ span,
22605
+ startTime: getCurrentUnixTimestamp()
22606
+ });
22607
+ }
22608
+ handleToolCall(event) {
22609
+ const key = toolKey(event);
22610
+ const state = this.toolsById.get(key) ?? this.startSyntheticToolState(event, event.toolName ?? "unknown");
22611
+ const metadata = {
22612
+ ...state.metadata,
22613
+ ...extractEventMetadata(event),
22614
+ ...event.toolName ? { "flue.tool_name": event.toolName } : {},
22615
+ ...event.toolCallId ? { "flue.tool_call_id": event.toolCallId } : {},
22616
+ ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {}
22617
+ };
22618
+ safeLog3(state.span, {
22619
+ ...event.isError ? { error: errorToString(event.result) } : {},
22620
+ metadata,
22621
+ metrics: durationMsMetrics(event.durationMs),
22622
+ output: event.result
22623
+ });
22624
+ state.span.end();
22625
+ this.toolsById.delete(key);
22626
+ }
22627
+ handleTaskStart(event) {
22628
+ const parent = this.parentSpanForEvent(event);
22629
+ const metadata = {
22630
+ ...extractEventMetadata(event),
22631
+ ...event.role ? { "flue.role": event.role } : {},
22632
+ ...event.cwd ? { "flue.cwd": event.cwd } : {},
22633
+ "flue.task_id": event.taskId,
22634
+ provider: "flue"
22635
+ };
22636
+ const span = startFlueSpan(parent, {
22637
+ name: "flue.task",
22638
+ spanAttributes: { type: "task" /* TASK */ }
22639
+ });
22640
+ safeLog3(span, {
22641
+ input: event.prompt,
22642
+ metadata
22643
+ });
22644
+ this.tasksById.set(event.taskId, {
22645
+ metadata,
22646
+ span,
22647
+ startTime: getCurrentUnixTimestamp()
22648
+ });
22649
+ }
22650
+ handleTask(event) {
22651
+ const state = this.tasksById.get(event.taskId);
22652
+ if (!state) {
22653
+ return;
22654
+ }
22655
+ safeLog3(state.span, {
22656
+ ...event.isError ? { error: errorToString(event.result) } : {},
22657
+ metadata: {
22658
+ ...state.metadata,
22659
+ ...extractEventMetadata(event),
22660
+ ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {}
22661
+ },
22662
+ metrics: durationMsMetrics(event.durationMs),
22663
+ output: event.result
22664
+ });
22665
+ state.span.end();
22666
+ this.tasksById.delete(event.taskId);
22667
+ }
22668
+ handleCompactionStart(event) {
22669
+ const operationState = this.operationStateForEvent(event);
22670
+ const parent = operationState?.span ?? this.parentSpanForEvent(event);
22671
+ const metadata = {
22672
+ ...extractEventMetadata(event),
22673
+ ...event.reason ? { "flue.compaction_reason": event.reason } : {},
22674
+ provider: "flue"
22675
+ };
22676
+ const input = {
22677
+ ...typeof event.estimatedTokens === "number" ? { estimatedTokens: event.estimatedTokens } : {},
22678
+ ...event.reason ? { reason: event.reason } : {}
22679
+ };
22680
+ const span = startFlueSpan(parent, {
22681
+ name: "flue.compaction",
22682
+ spanAttributes: { type: "task" /* TASK */ }
22683
+ });
22684
+ safeLog3(span, {
22685
+ input,
22686
+ metadata
22687
+ });
22688
+ this.compactionsByScope.set(scopeKey(event), {
22689
+ input,
22690
+ metadata,
22691
+ operationState,
22692
+ span,
22693
+ startTime: getCurrentUnixTimestamp()
22694
+ });
22695
+ }
22696
+ handleCompaction(event) {
22697
+ const key = scopeKey(event);
22698
+ const state = this.compactionsByScope.get(key) ?? this.findCompactionState(event);
22699
+ if (!state) {
22700
+ return;
22701
+ }
22702
+ safeLog3(state.span, {
22703
+ metadata: {
22704
+ ...state.metadata,
22705
+ ...extractEventMetadata(event),
22706
+ ...typeof event.messagesBefore === "number" ? { "flue.messages_before": event.messagesBefore } : {},
22707
+ ...typeof event.messagesAfter === "number" ? { "flue.messages_after": event.messagesAfter } : {}
22708
+ },
22709
+ metrics: {
22710
+ ...durationMsMetrics(event.durationMs),
22711
+ ...metricsFromUsage(event.usage)
22712
+ },
22713
+ output: {
22714
+ messagesAfter: event.messagesAfter,
22715
+ messagesBefore: event.messagesBefore
22716
+ }
22717
+ });
22718
+ state.span.end();
22719
+ this.deleteCompactionState(state);
22720
+ }
22721
+ findCompactionState(event) {
22722
+ const operationState = this.operationStateForEvent(event);
22723
+ for (const state of this.compactionsByScope.values()) {
22724
+ if (operationState && state.operationState === operationState) {
22725
+ return state;
22726
+ }
22727
+ }
22728
+ return void 0;
22729
+ }
22730
+ finishCompactionsForOperation(operationState) {
22731
+ for (const state of [...this.compactionsByScope.values()]) {
22732
+ if (state.operationState !== operationState) {
22733
+ continue;
22734
+ }
22735
+ safeLog3(state.span, {
22736
+ input: state.input,
22737
+ metadata: state.metadata,
22738
+ metrics: {
22739
+ ...buildDurationMetrics3(state.startTime)
22740
+ },
22741
+ output: { completed: true }
22742
+ });
22743
+ state.span.end();
22744
+ this.deleteCompactionState(state);
22745
+ }
22746
+ }
22747
+ deleteCompactionState(state) {
22748
+ for (const [key, candidate] of this.compactionsByScope) {
22749
+ if (candidate !== state) {
22750
+ continue;
22751
+ }
22752
+ this.compactionsByScope.delete(key);
22753
+ return;
22754
+ }
22755
+ }
22756
+ startSyntheticToolState(event, toolName) {
22757
+ const parent = this.parentSpanForEvent(event);
22758
+ const metadata = {
22759
+ ...extractEventMetadata(event),
22760
+ ...event.toolCallId ? { "flue.tool_call_id": event.toolCallId } : {},
22761
+ "flue.tool_name": toolName,
22762
+ provider: "flue"
22763
+ };
22764
+ const span = startFlueSpan(parent, {
22765
+ name: `tool: ${toolName}`,
22766
+ spanAttributes: { type: "tool" /* TOOL */ }
22767
+ });
22768
+ safeLog3(span, { metadata });
22769
+ return { metadata, span, startTime: getCurrentUnixTimestamp() };
22770
+ }
22771
+ operationStateForEvent(event) {
22772
+ if (event.operationId) {
22773
+ const operation = this.activeOperationsById.get(event.operationId) ?? this.promotePendingOperationForEvent(event);
22774
+ if (operation) {
22775
+ return operation;
22776
+ }
22777
+ }
22778
+ return this.activeOperationForEventScope(event) ?? this.pendingOperationForEventScope(event);
22779
+ }
22780
+ parentSpanForEvent(event) {
22781
+ if (event.operationId) {
22782
+ const operation = this.operationStateForEvent(event);
22783
+ if (operation) {
22784
+ return operation.span;
22785
+ }
22786
+ }
22787
+ if (event.taskId) {
22788
+ return this.tasksById.get(event.taskId)?.span;
22789
+ }
22790
+ return this.operationStateForEvent(event)?.span;
22791
+ }
22792
+ promotePendingOperationForEvent(event) {
22793
+ if (!event.operationId) {
22794
+ return void 0;
22795
+ }
22796
+ const scopePrefixes = operationScopePrefixes(event);
22797
+ for (const [candidateKey, candidateQueue] of this.pendingOperationsByKey) {
22798
+ if (!candidateQueue.length || !operationKeyMatchesScopes(candidateKey, scopePrefixes)) {
22799
+ continue;
22800
+ }
22801
+ const state = candidateQueue.shift();
22802
+ if (!state) {
22803
+ return void 0;
22804
+ }
22805
+ state.operationId = event.operationId;
22806
+ this.activeOperationsById.set(event.operationId, state);
22807
+ addScopedOperation(this.activeOperationsByScope, event, state);
22808
+ state.metadata = {
22809
+ ...state.metadata,
22810
+ ...extractEventMetadata(event),
22811
+ "flue.operation_id": event.operationId
22812
+ };
22813
+ safeLog3(state.span, { metadata: state.metadata });
22814
+ return state;
22815
+ }
22816
+ return void 0;
22817
+ }
22818
+ activeOperationForEventScope(event) {
22819
+ for (const scope of operationScopeNames(event)) {
22820
+ const operations = this.activeOperationsByScope.get(scope);
22821
+ if (operations?.length) {
22822
+ return operations[operations.length - 1];
22823
+ }
22824
+ }
22825
+ return void 0;
22826
+ }
22827
+ pendingOperationForEventScope(event) {
22828
+ const scopePrefixes = operationScopePrefixes(event);
22829
+ for (const [candidateKey, candidateQueue] of this.pendingOperationsByKey) {
22830
+ if (!candidateQueue.length || !operationKeyMatchesScopes(candidateKey, scopePrefixes)) {
22831
+ continue;
22832
+ }
22833
+ return candidateQueue[0];
22834
+ }
22835
+ return void 0;
22836
+ }
22837
+ takePendingOperationForEvent(event) {
22838
+ const key = operationKey(event.session, event.operationKind);
22839
+ const queue = this.pendingOperationsByKey.get(key);
22840
+ if (queue?.length) {
22841
+ return queue.shift();
22842
+ }
22843
+ for (const [candidateKey, candidateQueue] of this.pendingOperationsByKey) {
22844
+ if (candidateKey.endsWith(`::${event.operationKind}`) && candidateQueue.length) {
22845
+ return candidateQueue.shift();
22846
+ }
22847
+ }
22848
+ return void 0;
22849
+ }
22850
+ pendingOperationQueue(key) {
22851
+ const existing = this.pendingOperationsByKey.get(key);
22852
+ if (existing) {
22853
+ return existing;
22854
+ }
22855
+ const queue = [];
22856
+ this.pendingOperationsByKey.set(key, queue);
22857
+ return queue;
22858
+ }
22859
+ };
22860
+ function isInstrumentedOperation(operation) {
22861
+ return operation === "prompt" || operation === "skill" || operation === "task" || operation === "compact";
22862
+ }
22863
+ function getSessionName(session) {
22864
+ return typeof session?.name === "string" ? session.name : void 0;
22865
+ }
22866
+ function operationKey(sessionName, operation) {
22867
+ return `${sessionName ?? "unknown"}::${operation}`;
22868
+ }
22869
+ function operationScopePrefixes(event) {
22870
+ const scopes = /* @__PURE__ */ new Set();
22871
+ for (const scope of operationScopeNames(event)) {
22872
+ scopes.add(`${scope}::`);
22873
+ }
22874
+ return scopes;
22875
+ }
22876
+ function operationKeyMatchesScopes(key, scopes) {
22877
+ for (const scope of scopes) {
22878
+ if (key.startsWith(scope)) {
22879
+ return true;
22880
+ }
22881
+ }
22882
+ return false;
22883
+ }
22884
+ function operationScopeNames(event) {
22885
+ const scopes = /* @__PURE__ */ new Set();
22886
+ if (event.session) {
22887
+ scopes.add(event.session);
22888
+ }
22889
+ if (event.parentSession) {
22890
+ scopes.add(event.parentSession);
22891
+ }
22892
+ if (!scopes.size) {
22893
+ scopes.add("unknown");
22894
+ }
22895
+ return scopes;
22896
+ }
22897
+ function addScopedOperation(operationsByScope, event, state) {
22898
+ for (const scope of operationScopeNames(event)) {
22899
+ addOperationToScope(operationsByScope, scope, state);
22900
+ }
22901
+ }
22902
+ function addOperationToScope(operationsByScope, scope, state) {
22903
+ const operations = operationsByScope.get(scope);
22904
+ if (operations) {
22905
+ if (!operations.includes(state)) {
22906
+ operations.push(state);
22907
+ }
22908
+ } else {
22909
+ operationsByScope.set(scope, [state]);
22910
+ }
22911
+ }
22912
+ function removeScopedOperation(operationsByScope, state) {
22913
+ for (const [scope, operations] of operationsByScope) {
22914
+ const index = operations.indexOf(state);
22915
+ if (index === -1) {
22916
+ continue;
22917
+ }
22918
+ operations.splice(index, 1);
22919
+ if (operations.length === 0) {
22920
+ operationsByScope.delete(scope);
22921
+ }
22922
+ }
22923
+ }
22924
+ function removePendingOperation(pendingOperationsByKey, state) {
22925
+ for (const [key, queue] of pendingOperationsByKey) {
22926
+ const index = queue.indexOf(state);
22927
+ if (index === -1) {
22928
+ continue;
22929
+ }
22930
+ queue.splice(index, 1);
22931
+ if (queue.length === 0) {
22932
+ pendingOperationsByKey.delete(key);
22933
+ }
22934
+ return;
22935
+ }
22936
+ }
22937
+ function extractSessionMetadata(session) {
22938
+ const sessionName = getSessionName(session);
22939
+ return sessionName ? { "flue.session": sessionName } : {};
22940
+ }
22941
+ function extractEventMetadata(event) {
22942
+ return {
22943
+ ...event.runId ? { "flue.run_id": event.runId } : {},
22944
+ ...typeof event.eventIndex === "number" ? { "flue.event_index": event.eventIndex } : {},
22945
+ ...event.session ? { "flue.session": event.session } : {},
22946
+ ...event.parentSession ? { "flue.parent_session": event.parentSession } : {},
22947
+ ...event.harness ? { "flue.harness": event.harness } : {},
22948
+ ...event.taskId ? { "flue.task_id": event.taskId } : {},
22949
+ ...event.operationId ? { "flue.operation_id": event.operationId } : {}
22950
+ };
22951
+ }
22952
+ function extractOperationInput(operation, args) {
22953
+ switch (operation) {
22954
+ case "prompt":
22955
+ case "task":
22956
+ return args[0];
22957
+ case "skill":
22958
+ return {
22959
+ args: getOptionObject(args[1])?.args,
22960
+ name: args[0]
22961
+ };
22962
+ case "compact":
22963
+ return void 0;
22964
+ }
22965
+ }
22966
+ function extractOperationInputMetadata(operation, args) {
22967
+ const options = getOptionObject(args[1]);
22968
+ return {
22969
+ ...operation === "skill" && typeof args[0] === "string" ? { "flue.skill_name": args[0] } : {},
22970
+ ...options?.model ? { model: options.model, "flue.model": options.model } : {},
22971
+ ...options?.role ? { "flue.role": options.role } : {},
22972
+ ...options?.thinkingLevel ? { "flue.thinking_level": options.thinkingLevel } : {},
22973
+ ...typeof options?.cwd === "string" ? { "flue.cwd": options.cwd } : {},
22974
+ ...Array.isArray(options?.tools) ? {
22975
+ "flue.tools_count": options.tools.length,
22976
+ tools: summarizeTools(options.tools)
22977
+ } : {},
22978
+ ...Array.isArray(options?.images) ? { "flue.images_count": options.images.length } : {},
22979
+ ...options?.result || options?.schema ? { "flue.result_schema": true } : {}
22980
+ };
22981
+ }
22982
+ function getOptionObject(value) {
22983
+ return isObject(value) ? value : void 0;
22984
+ }
22985
+ function summarizeTools(tools) {
22986
+ return tools.flatMap((tool) => {
22987
+ if (!isObject(tool)) {
22988
+ return [];
22989
+ }
22990
+ const name = typeof tool.name === "string" ? tool.name : void 0;
22991
+ if (!name) {
22992
+ return [];
22993
+ }
22994
+ return [
22995
+ {
22996
+ function: {
22997
+ description: typeof tool.description === "string" ? tool.description : void 0,
22998
+ name,
22999
+ parameters: tool.parameters
23000
+ },
23001
+ type: "function"
23002
+ }
23003
+ ];
23004
+ });
23005
+ }
23006
+ function extractPromptResponseMetadata(result) {
23007
+ const modelId = result?.model && typeof result.model.id === "string" ? result.model.id : void 0;
23008
+ return modelId ? {
23009
+ model: modelId,
23010
+ "flue.model": modelId
23011
+ } : {};
23012
+ }
23013
+ function extractOperationOutput(result) {
23014
+ if (!result) {
23015
+ return void 0;
23016
+ }
23017
+ if ("data" in result) {
23018
+ return result.data;
23019
+ }
23020
+ if ("text" in result) {
23021
+ return result.text;
23022
+ }
23023
+ return result;
23024
+ }
23025
+ function metricsFromUsage(usage) {
23026
+ return {
23027
+ ...typeof usage?.input === "number" ? { prompt_tokens: usage.input } : {},
23028
+ ...typeof usage?.output === "number" ? { completion_tokens: usage.output } : {},
23029
+ ...typeof usage?.cacheRead === "number" ? { prompt_cached_tokens: usage.cacheRead } : {},
23030
+ ...typeof usage?.cacheWrite === "number" ? { prompt_cache_creation_tokens: usage.cacheWrite } : {},
23031
+ ...typeof usage?.totalTokens === "number" ? { tokens: usage.totalTokens } : {},
23032
+ ...typeof usage?.cost?.total === "number" ? { estimated_cost: usage.cost.total } : {}
23033
+ };
23034
+ }
23035
+ function buildDurationMetrics3(startTime) {
23036
+ return {
23037
+ duration_ms: Math.max(0, (getCurrentUnixTimestamp() - startTime) * 1e3)
23038
+ };
23039
+ }
23040
+ function durationMsMetrics(durationMs) {
23041
+ return typeof durationMs === "number" ? { duration_ms: durationMs } : {};
23042
+ }
23043
+ function scopeKey(event) {
23044
+ if (event.operationId) {
23045
+ return `operation:${event.operationId}`;
23046
+ }
23047
+ if (event.taskId) {
23048
+ return `task:${event.taskId}`;
23049
+ }
23050
+ if (event.session) {
23051
+ return `session:${event.session}`;
23052
+ }
23053
+ return "flue:unknown";
23054
+ }
23055
+ function toolKey(event) {
23056
+ return `${scopeKey(event)}::tool:${event.toolCallId ?? "unknown"}`;
23057
+ }
23058
+ function toAssistantOutput(text, finishReason, reasoning, toolCalls) {
23059
+ return [
23060
+ {
23061
+ finish_reason: finishReason ?? "stop",
23062
+ index: 0,
23063
+ message: {
23064
+ content: text,
23065
+ ...reasoning ? { reasoning } : {},
23066
+ role: "assistant",
23067
+ ...toolCalls?.length ? {
23068
+ tool_calls: toolCalls.map((toolCall) => ({
23069
+ function: {
23070
+ arguments: toolCall.args === void 0 ? "{}" : JSON.stringify(toolCall.args),
23071
+ name: toolCall.toolName ?? "unknown"
23072
+ },
23073
+ ...toolCall.toolCallId ? { id: toolCall.toolCallId } : {},
23074
+ type: "function"
23075
+ }))
23076
+ } : {}
23077
+ }
23078
+ }
23079
+ ];
23080
+ }
23081
+ function startFlueSpan(parent, args) {
23082
+ return parent ? withCurrent(parent, () => startSpan(args)) : startSpan(args);
23083
+ }
23084
+ function safeLog3(span, event) {
23085
+ try {
23086
+ span.log(event);
23087
+ } catch (error) {
23088
+ logInstrumentationError3("Flue span log", error);
23089
+ }
23090
+ }
23091
+ function errorToString(error) {
23092
+ if (error instanceof Error) {
23093
+ return error.message;
23094
+ }
23095
+ if (typeof error === "string") {
23096
+ return error;
23097
+ }
23098
+ try {
23099
+ return JSON.stringify(error);
23100
+ } catch {
23101
+ return String(error);
23102
+ }
23103
+ }
23104
+ function logInstrumentationError3(label, error) {
23105
+ console.error(`Error in ${label} instrumentation:`, error);
23106
+ }
23107
+
23108
+ // src/wrappers/langchain/callback-handler.ts
23109
+ var BRAINTRUST_LANGCHAIN_CALLBACK_HANDLER_NAME = "BraintrustCallbackHandler";
23110
+ var BraintrustLangChainCallbackHandler = class {
23111
+ name = BRAINTRUST_LANGCHAIN_CALLBACK_HANDLER_NAME;
23112
+ spans = /* @__PURE__ */ new Map();
23113
+ skippedRuns = /* @__PURE__ */ new Set();
23114
+ parent;
23115
+ rootRunId;
23116
+ options;
23117
+ startTimes = /* @__PURE__ */ new Map();
23118
+ firstTokenTimes = /* @__PURE__ */ new Map();
23119
+ ttftMs = /* @__PURE__ */ new Map();
23120
+ constructor(options) {
23121
+ this.parent = options?.parent;
23122
+ this.options = {
23123
+ debug: options?.debug ?? false,
23124
+ excludeMetadataProps: options?.excludeMetadataProps ?? /^(l[sc]_|langgraph_|__pregel_|checkpoint_ns)/,
23125
+ logger: options?.logger
23126
+ };
23127
+ }
23128
+ startSpan({
23129
+ runId,
23130
+ parentRunId,
23131
+ ...args
23132
+ }) {
23133
+ if (this.spans.has(runId)) {
23134
+ return;
23135
+ }
23136
+ if (!parentRunId) {
23137
+ this.rootRunId = runId;
23138
+ }
23139
+ const tags = args.event?.tags;
23140
+ const spanAttributes = args.spanAttributes || {};
23141
+ spanAttributes.type = args.type || spanAttributes.type || "task";
23142
+ args.type = spanAttributes.type;
23143
+ const currentParent = (typeof this.parent === "function" ? this.parent() : this.parent) ?? currentSpan();
23144
+ let parentSpan;
23145
+ if (parentRunId && this.spans.has(parentRunId)) {
23146
+ parentSpan = this.spans.get(parentRunId);
23147
+ } else if (!Object.is(currentParent, NOOP_SPAN)) {
23148
+ parentSpan = currentParent;
23149
+ } else if (this.options.logger) {
23150
+ parentSpan = this.options.logger;
23151
+ } else {
23152
+ parentSpan = { startSpan };
23153
+ }
23154
+ args.event = {
23155
+ ...args.event,
23156
+ tags: void 0,
23157
+ metadata: {
23158
+ ...tags ? { tags } : {},
23159
+ ...args.event?.metadata,
23160
+ braintrust: {
23161
+ integration_name: "langchain-js",
23162
+ sdk_language: "javascript"
23163
+ },
23164
+ run_id: runId,
23165
+ parent_run_id: parentRunId,
23166
+ ...this.options.debug ? { runId, parentRunId } : {}
23167
+ }
23168
+ };
23169
+ let span = parentSpan.startSpan(args);
23170
+ if (!Object.is(this.options.logger, NOOP_SPAN) && Object.is(span, NOOP_SPAN)) {
23171
+ span = initLogger().startSpan(args);
23172
+ }
23173
+ this.spans.set(runId, span);
23174
+ }
23175
+ endSpan({
23176
+ runId,
23177
+ parentRunId,
23178
+ tags,
23179
+ metadata,
23180
+ ...args
23181
+ }) {
23182
+ if (!this.spans.has(runId)) {
23183
+ return;
23184
+ }
23185
+ if (this.skippedRuns.has(runId)) {
23186
+ this.skippedRuns.delete(runId);
23187
+ return;
23188
+ }
23189
+ const span = this.spans.get(runId);
23190
+ this.spans.delete(runId);
23191
+ if (runId === this.rootRunId) {
23192
+ this.rootRunId = void 0;
23193
+ }
23194
+ span.log({ ...args, metadata: { tags, ...metadata } });
23195
+ span.end();
23196
+ }
23197
+ async handleLLMStart(llm, prompts, runId, parentRunId, extraParams, tags, metadata, runName) {
23198
+ this.startSpan({
23199
+ runId,
23200
+ parentRunId,
23201
+ name: runName ?? getSerializedName(llm) ?? "LLM",
23202
+ type: "llm",
23203
+ event: {
23204
+ input: prompts,
23205
+ tags,
23206
+ metadata: {
23207
+ serialized: llm,
23208
+ name: runName,
23209
+ metadata,
23210
+ ...extraParams
23211
+ }
23212
+ }
23213
+ });
23214
+ }
23215
+ async handleLLMError(err, runId, parentRunId, tags) {
23216
+ this.endSpan({ runId, parentRunId, error: err, tags });
23217
+ }
23218
+ async handleLLMEnd(output, runId, parentRunId, tags) {
23219
+ const metrics = getMetricsFromResponse(output);
23220
+ const modelName2 = getModelNameFromResponse(output);
23221
+ const ttft = this.ttftMs.get(runId);
23222
+ if (ttft !== void 0) {
23223
+ metrics.time_to_first_token = ttft;
23224
+ }
23225
+ this.startTimes.delete(runId);
23226
+ this.firstTokenTimes.delete(runId);
23227
+ this.ttftMs.delete(runId);
23228
+ this.endSpan({
23229
+ runId,
23230
+ parentRunId,
23231
+ output,
23232
+ metrics,
23233
+ tags,
23234
+ metadata: {
23235
+ model: modelName2
23236
+ }
23237
+ });
23238
+ }
23239
+ async handleChatModelStart(llm, messages, runId, parentRunId, extraParams, tags, metadata, runName) {
23240
+ this.startTimes.set(runId, Date.now());
23241
+ this.firstTokenTimes.delete(runId);
23242
+ this.ttftMs.delete(runId);
23243
+ this.startSpan({
23244
+ runId,
23245
+ parentRunId,
23246
+ name: runName ?? getSerializedName(llm) ?? "Chat Model",
23247
+ type: "llm",
23248
+ event: {
23249
+ input: messages,
23250
+ tags,
23251
+ metadata: {
23252
+ serialized: llm,
23253
+ name: runName,
23254
+ metadata,
23255
+ ...extraParams
23256
+ }
23257
+ }
23258
+ });
23259
+ }
23260
+ async handleChainStart(chain, inputs, runId, parentRunId, tags, metadata, runType, runName) {
23261
+ if (tags?.includes("langsmith:hidden")) {
23262
+ this.skippedRuns.add(runId);
23263
+ return;
23264
+ }
23265
+ this.startSpan({
23266
+ runId,
23267
+ parentRunId,
23268
+ name: runName ?? getSerializedName(chain) ?? "Chain",
23269
+ event: {
23270
+ input: inputs,
23271
+ tags,
23272
+ metadata: {
23273
+ serialized: chain,
23274
+ name: runName,
23275
+ metadata,
23276
+ run_type: runType
23277
+ }
23278
+ }
23279
+ });
23280
+ }
23281
+ async handleChainError(err, runId, parentRunId, tags, kwargs) {
23282
+ this.endSpan({ runId, parentRunId, error: err, tags, metadata: kwargs });
23283
+ }
23284
+ async handleChainEnd(outputs, runId, parentRunId, tags, kwargs) {
23285
+ this.endSpan({
23286
+ runId,
23287
+ parentRunId,
23288
+ tags,
23289
+ output: outputs,
23290
+ metadata: { ...kwargs }
23291
+ });
23292
+ }
23293
+ async handleToolStart(tool, input, runId, parentRunId, tags, metadata, runName) {
23294
+ this.startSpan({
23295
+ runId,
23296
+ parentRunId,
23297
+ name: runName ?? getSerializedName(tool) ?? "Tool",
23298
+ type: "llm",
23299
+ event: {
23300
+ input: safeJsonParse(input),
23301
+ tags,
23302
+ metadata: {
23303
+ metadata,
23304
+ serialized: tool,
23305
+ input_str: input,
23306
+ input: safeJsonParse(input),
23307
+ name: runName
23308
+ }
23309
+ }
23310
+ });
23311
+ }
23312
+ async handleToolError(err, runId, parentRunId, tags) {
23313
+ this.endSpan({ runId, parentRunId, error: err, tags });
23314
+ }
23315
+ async handleToolEnd(output, runId, parentRunId, tags) {
23316
+ this.endSpan({ runId, parentRunId, output, tags });
23317
+ }
23318
+ async handleAgentAction(action, runId, parentRunId, tags) {
23319
+ this.startSpan({
23320
+ runId,
23321
+ parentRunId,
23322
+ type: "llm",
23323
+ name: typeof action.tool === "string" ? action.tool : "Agent",
23324
+ event: {
23325
+ input: action,
23326
+ tags
23327
+ }
23328
+ });
23329
+ }
23330
+ async handleAgentEnd(action, runId, parentRunId, tags) {
23331
+ this.endSpan({ runId, parentRunId, output: action, tags });
23332
+ }
23333
+ async handleRetrieverStart(retriever, query, runId, parentRunId, tags, metadata, name) {
23334
+ this.startSpan({
23335
+ runId,
23336
+ parentRunId,
23337
+ name: name ?? getSerializedName(retriever) ?? "Retriever",
23338
+ type: "function",
23339
+ event: {
23340
+ input: query,
23341
+ tags,
23342
+ metadata: {
23343
+ serialized: retriever,
23344
+ metadata,
23345
+ name
23346
+ }
23347
+ }
23348
+ });
23349
+ }
23350
+ async handleRetrieverEnd(documents, runId, parentRunId, tags) {
23351
+ this.endSpan({ runId, parentRunId, output: documents, tags });
23352
+ }
23353
+ async handleRetrieverError(err, runId, parentRunId, tags) {
23354
+ this.endSpan({ runId, parentRunId, error: err, tags });
23355
+ }
23356
+ async handleLLMNewToken(_token, _idx, runId, _parentRunId, _tags) {
23357
+ if (!this.firstTokenTimes.has(runId)) {
23358
+ const now2 = Date.now();
23359
+ this.firstTokenTimes.set(runId, now2);
23360
+ const start = this.startTimes.get(runId);
23361
+ if (start !== void 0) {
23362
+ this.ttftMs.set(runId, (now2 - start) / 1e3);
23363
+ }
23364
+ }
23365
+ }
23366
+ };
23367
+ function getSerializedName(serialized) {
23368
+ if (typeof serialized.name === "string") {
23369
+ return serialized.name;
23370
+ }
23371
+ const lastIdPart = serialized.id?.at(-1);
23372
+ return typeof lastIdPart === "string" ? lastIdPart : void 0;
23373
+ }
23374
+ function cleanObject(obj) {
23375
+ return Object.fromEntries(
23376
+ Object.entries(obj).filter(([, value]) => {
23377
+ if (typeof value !== "number") {
23378
+ return false;
23379
+ }
23380
+ return Number.isFinite(value);
23381
+ })
23382
+ );
23383
+ }
23384
+ function walkGenerations(response) {
23385
+ const result = [];
23386
+ const generations = response.generations || [];
23387
+ for (const batch of generations) {
23388
+ if (Array.isArray(batch)) {
23389
+ for (const generation of batch) {
23390
+ if (isRecord(generation)) {
23391
+ result.push(generation);
23392
+ }
23393
+ }
23394
+ } else if (isRecord(batch)) {
23395
+ result.push(batch);
23396
+ }
23397
+ }
23398
+ return result;
23399
+ }
23400
+ function getModelNameFromResponse(response) {
23401
+ for (const generation of walkGenerations(response)) {
23402
+ const message = generation.message;
23403
+ if (!isRecord(message)) {
23404
+ continue;
23405
+ }
23406
+ const responseMetadata = message.response_metadata;
23407
+ if (!isRecord(responseMetadata)) {
23408
+ continue;
23409
+ }
23410
+ const modelName3 = responseMetadata.model_name ?? responseMetadata.model;
23411
+ if (typeof modelName3 === "string") {
23412
+ return modelName3;
23413
+ }
23414
+ }
23415
+ const llmOutput = response.llmOutput || {};
23416
+ const modelName2 = llmOutput.model_name ?? llmOutput.model;
23417
+ return typeof modelName2 === "string" ? modelName2 : void 0;
23418
+ }
23419
+ function getMetricsFromResponse(response) {
23420
+ for (const generation of walkGenerations(response)) {
23421
+ const message = generation.message;
23422
+ if (!isRecord(message)) {
23423
+ continue;
23424
+ }
23425
+ const usageMetadata = message.usage_metadata;
23426
+ if (!isRecord(usageMetadata)) {
23427
+ continue;
23428
+ }
23429
+ const inputTokenDetails = usageMetadata.input_token_details;
23430
+ return cleanObject({
23431
+ total_tokens: usageMetadata.total_tokens,
23432
+ prompt_tokens: usageMetadata.input_tokens,
23433
+ completion_tokens: usageMetadata.output_tokens,
23434
+ prompt_cache_creation_tokens: isRecord(inputTokenDetails) ? inputTokenDetails.cache_creation : void 0,
23435
+ prompt_cached_tokens: isRecord(inputTokenDetails) ? inputTokenDetails.cache_read : void 0
23436
+ });
23437
+ }
23438
+ const llmOutput = response.llmOutput || {};
23439
+ const tokenUsage = isRecord(llmOutput.tokenUsage) ? llmOutput.tokenUsage : isRecord(llmOutput.estimatedTokens) ? llmOutput.estimatedTokens : {};
23440
+ return cleanObject({
23441
+ total_tokens: tokenUsage.totalTokens,
23442
+ prompt_tokens: tokenUsage.promptTokens,
23443
+ completion_tokens: tokenUsage.completionTokens
23444
+ });
23445
+ }
23446
+ function safeJsonParse(input) {
23447
+ try {
23448
+ return JSON.parse(input);
23449
+ } catch {
23450
+ return input;
23451
+ }
23452
+ }
23453
+ function isRecord(value) {
23454
+ return typeof value === "object" && value !== null && !Array.isArray(value);
23455
+ }
23456
+
23457
+ // src/instrumentation/plugins/langchain-channels.ts
23458
+ var langChainChannels = defineChannels("@langchain/core", {
23459
+ configure: channel({
23460
+ channelName: "CallbackManager.configure",
23461
+ kind: "sync-stream"
23462
+ }),
23463
+ configureSync: channel({
23464
+ channelName: "CallbackManager._configureSync",
23465
+ kind: "sync-stream"
23466
+ })
23467
+ });
23468
+
23469
+ // src/instrumentation/plugins/langchain-plugin.ts
23470
+ var LangChainPlugin = class extends BasePlugin {
23471
+ injectedManagers = /* @__PURE__ */ new WeakSet();
23472
+ onEnable() {
23473
+ this.subscribeToConfigure(langChainChannels.configure);
23474
+ this.subscribeToConfigure(langChainChannels.configureSync);
23475
+ }
23476
+ onDisable() {
23477
+ for (const unsubscribe of this.unsubscribers) {
23478
+ unsubscribe();
23479
+ }
23480
+ this.unsubscribers = [];
23481
+ this.injectedManagers = /* @__PURE__ */ new WeakSet();
23482
+ }
23483
+ subscribeToConfigure(channel2) {
23484
+ const tracingChannel = channel2.tracingChannel();
23485
+ const handlers = {
23486
+ start: (event) => {
23487
+ injectHandlerIntoArguments(event.arguments);
23488
+ },
23489
+ end: (event) => {
23490
+ this.injectHandler(event.result);
23491
+ }
23492
+ };
23493
+ tracingChannel.subscribe(handlers);
23494
+ this.unsubscribers.push(() => {
23495
+ tracingChannel.unsubscribe(handlers);
23496
+ });
23497
+ }
23498
+ injectHandler(result) {
23499
+ if (!isCallbackManager(result)) {
23500
+ return;
23501
+ }
23502
+ if (this.injectedManagers.has(result) || hasBraintrustHandler(result)) {
23503
+ return;
23504
+ }
23505
+ try {
23506
+ result.addHandler(new BraintrustLangChainCallbackHandler(), true);
23507
+ this.injectedManagers.add(result);
23508
+ } catch {
23509
+ }
23510
+ }
23511
+ };
23512
+ function isCallbackManager(value) {
23513
+ if (typeof value !== "object" || value === null) {
23514
+ return false;
23515
+ }
23516
+ const maybeManager = value;
23517
+ return typeof maybeManager.addHandler === "function";
23518
+ }
23519
+ function hasBraintrustHandler(manager) {
23520
+ return manager.handlers?.some((handler) => {
23521
+ if (typeof handler !== "object" || handler === null) {
23522
+ return false;
23523
+ }
23524
+ const name = Reflect.get(handler, "name");
23525
+ return name === BRAINTRUST_LANGCHAIN_CALLBACK_HANDLER_NAME;
23526
+ }) ?? false;
23527
+ }
23528
+ function injectHandlerIntoArguments(args) {
23529
+ if (!isWritableArgumentsObject(args)) {
23530
+ return;
23531
+ }
23532
+ const inheritedHandlers = Reflect.get(args, "0");
23533
+ const handler = new BraintrustLangChainCallbackHandler();
23534
+ if (inheritedHandlers === void 0 || inheritedHandlers === null) {
23535
+ Reflect.set(args, "0", [handler]);
23536
+ return;
23537
+ }
23538
+ if (Array.isArray(inheritedHandlers)) {
23539
+ if (!inheritedHandlers.some(isBraintrustHandler)) {
23540
+ inheritedHandlers.push(handler);
23541
+ }
23542
+ }
23543
+ }
23544
+ function isWritableArgumentsObject(args) {
23545
+ return typeof args === "object" && args !== null;
23546
+ }
23547
+ function isBraintrustHandler(handler) {
23548
+ if (typeof handler !== "object" || handler === null) {
23549
+ return false;
23550
+ }
23551
+ return Reflect.get(handler, "name") === BRAINTRUST_LANGCHAIN_CALLBACK_HANDLER_NAME;
23552
+ }
23553
+
23554
+ // src/instrumentation/braintrust-plugin.ts
23555
+ function getIntegrationConfig(integrations, key) {
23556
+ return integrations[key];
23557
+ }
23558
+ var BraintrustPlugin = class extends BasePlugin {
23559
+ config;
23560
+ openaiPlugin = null;
23561
+ openAICodexPlugin = null;
23562
+ anthropicPlugin = null;
23563
+ aiSDKPlugin = null;
23564
+ claudeAgentSDKPlugin = null;
23565
+ cursorSDKPlugin = null;
23566
+ openAIAgentsPlugin = null;
23567
+ googleGenAIPlugin = null;
23568
+ huggingFacePlugin = null;
23569
+ openRouterPlugin = null;
23570
+ openRouterAgentPlugin = null;
23571
+ mistralPlugin = null;
23572
+ googleADKPlugin = null;
23573
+ coherePlugin = null;
23574
+ groqPlugin = null;
23575
+ genkitPlugin = null;
23576
+ gitHubCopilotPlugin = null;
23577
+ fluePlugin = null;
23578
+ langChainPlugin = null;
23579
+ constructor(config = {}) {
23580
+ super();
23581
+ this.config = config;
23582
+ }
23583
+ onEnable() {
23584
+ const integrations = this.config.integrations || {};
23585
+ if (integrations.openai !== false) {
23586
+ this.openaiPlugin = new OpenAIPlugin();
23587
+ this.openaiPlugin.enable();
23588
+ }
23589
+ if (integrations.openaiCodexSDK !== false) {
23590
+ this.openAICodexPlugin = new OpenAICodexPlugin();
23591
+ this.openAICodexPlugin.enable();
23592
+ }
23593
+ if (integrations.anthropic !== false) {
23594
+ this.anthropicPlugin = new AnthropicPlugin();
23595
+ this.anthropicPlugin.enable();
23596
+ }
23597
+ if (integrations.aisdk !== false && integrations.vercel !== false) {
23598
+ this.aiSDKPlugin = new AISDKPlugin();
23599
+ this.aiSDKPlugin.enable();
23600
+ }
23601
+ if (integrations.claudeAgentSDK !== false) {
21381
23602
  this.claudeAgentSDKPlugin = new ClaudeAgentSDKPlugin();
21382
23603
  this.claudeAgentSDKPlugin.enable();
21383
23604
  }
@@ -21385,6 +23606,10 @@ var BraintrustPlugin = class extends BasePlugin {
21385
23606
  this.cursorSDKPlugin = new CursorSDKPlugin();
21386
23607
  this.cursorSDKPlugin.enable();
21387
23608
  }
23609
+ if (integrations.openAIAgents !== false) {
23610
+ this.openAIAgentsPlugin = new OpenAIAgentsPlugin();
23611
+ this.openAIAgentsPlugin.enable();
23612
+ }
21388
23613
  if (integrations.googleGenAI !== false && integrations.google !== false) {
21389
23614
  this.googleGenAIPlugin = new GoogleGenAIPlugin();
21390
23615
  this.googleGenAIPlugin.enable();
@@ -21425,6 +23650,14 @@ var BraintrustPlugin = class extends BasePlugin {
21425
23650
  this.gitHubCopilotPlugin = new GitHubCopilotPlugin();
21426
23651
  this.gitHubCopilotPlugin.enable();
21427
23652
  }
23653
+ if (getIntegrationConfig(integrations, "flue") !== false) {
23654
+ this.fluePlugin = new FluePlugin();
23655
+ this.fluePlugin.enable();
23656
+ }
23657
+ if (integrations.langchain !== false && integrations.langgraph !== false) {
23658
+ this.langChainPlugin = new LangChainPlugin();
23659
+ this.langChainPlugin.enable();
23660
+ }
21428
23661
  }
21429
23662
  onDisable() {
21430
23663
  if (this.openaiPlugin) {
@@ -21451,6 +23684,10 @@ var BraintrustPlugin = class extends BasePlugin {
21451
23684
  this.cursorSDKPlugin.disable();
21452
23685
  this.cursorSDKPlugin = null;
21453
23686
  }
23687
+ if (this.openAIAgentsPlugin) {
23688
+ this.openAIAgentsPlugin.disable();
23689
+ this.openAIAgentsPlugin = null;
23690
+ }
21454
23691
  if (this.googleGenAIPlugin) {
21455
23692
  this.googleGenAIPlugin.disable();
21456
23693
  this.googleGenAIPlugin = null;
@@ -21491,9 +23728,104 @@ var BraintrustPlugin = class extends BasePlugin {
21491
23728
  this.gitHubCopilotPlugin.disable();
21492
23729
  this.gitHubCopilotPlugin = null;
21493
23730
  }
23731
+ if (this.fluePlugin) {
23732
+ this.fluePlugin.disable();
23733
+ this.fluePlugin = null;
23734
+ }
23735
+ if (this.langChainPlugin) {
23736
+ this.langChainPlugin.disable();
23737
+ this.langChainPlugin = null;
23738
+ }
21494
23739
  }
21495
23740
  };
21496
23741
 
23742
+ // src/instrumentation/config.ts
23743
+ var envIntegrationAliases = {
23744
+ openai: "openai",
23745
+ "openai-codex": "openaiCodexSDK",
23746
+ "openai-codex-sdk": "openaiCodexSDK",
23747
+ openaicodexsdk: "openaiCodexSDK",
23748
+ codex: "openaiCodexSDK",
23749
+ "codex-sdk": "openaiCodexSDK",
23750
+ anthropic: "anthropic",
23751
+ aisdk: "aisdk",
23752
+ "ai-sdk": "aisdk",
23753
+ "vercel-ai": "aisdk",
23754
+ vercel: "vercel",
23755
+ claudeagentsdk: "claudeAgentSDK",
23756
+ "claude-agent-sdk": "claudeAgentSDK",
23757
+ cursor: "cursor",
23758
+ "cursor-sdk": "cursorSDK",
23759
+ cursorsdk: "cursorSDK",
23760
+ flue: "flue",
23761
+ "flue-runtime": "flue",
23762
+ "openai-agents": "openAIAgents",
23763
+ openaiagents: "openAIAgents",
23764
+ "openai-agents-core": "openAIAgents",
23765
+ openaiagentscore: "openAIAgents",
23766
+ google: "google",
23767
+ "google-genai": "googleGenAI",
23768
+ googlegenai: "googleGenAI",
23769
+ huggingface: "huggingface",
23770
+ openrouter: "openrouter",
23771
+ openrouteragent: "openrouterAgent",
23772
+ "openrouter-agent": "openrouterAgent",
23773
+ mistral: "mistral",
23774
+ googleadk: "googleADK",
23775
+ "google-adk": "googleADK",
23776
+ cohere: "cohere",
23777
+ groq: "groq",
23778
+ "groq-sdk": "groq",
23779
+ genkit: "genkit",
23780
+ "firebase-genkit": "genkit",
23781
+ githubcopilot: "gitHubCopilot",
23782
+ "github-copilot": "gitHubCopilot",
23783
+ "copilot-sdk": "gitHubCopilot",
23784
+ langchain: "langchain",
23785
+ "langchain-js": "langchain",
23786
+ "@langchain": "langchain",
23787
+ langgraph: "langgraph"
23788
+ };
23789
+ function getDefaultInstrumentationIntegrations() {
23790
+ return {
23791
+ openai: true,
23792
+ openaiCodexSDK: true,
23793
+ anthropic: true,
23794
+ vercel: true,
23795
+ aisdk: true,
23796
+ google: true,
23797
+ googleGenAI: true,
23798
+ googleADK: true,
23799
+ huggingface: true,
23800
+ claudeAgentSDK: true,
23801
+ cursor: true,
23802
+ cursorSDK: true,
23803
+ flue: true,
23804
+ openAIAgents: true,
23805
+ openrouter: true,
23806
+ openrouterAgent: true,
23807
+ mistral: true,
23808
+ cohere: true,
23809
+ groq: true,
23810
+ genkit: true,
23811
+ gitHubCopilot: true,
23812
+ langchain: true,
23813
+ langgraph: true
23814
+ };
23815
+ }
23816
+ function readDisabledInstrumentationEnvConfig(disabledList) {
23817
+ const integrations = {};
23818
+ if (disabledList) {
23819
+ for (const value of disabledList.split(",")) {
23820
+ const sdk = value.trim().toLowerCase();
23821
+ if (sdk.length > 0) {
23822
+ integrations[envIntegrationAliases[sdk] ?? sdk] = false;
23823
+ }
23824
+ }
23825
+ }
23826
+ return { integrations };
23827
+ }
23828
+
21497
23829
  // src/instrumentation/registry.ts
21498
23830
  var REGISTRY_STATE_KEY = /* @__PURE__ */ Symbol.for("braintrust.registry");
21499
23831
  function getSharedState() {
@@ -21572,50 +23904,16 @@ var PluginRegistry = class {
21572
23904
  * Get default configuration (all integrations enabled).
21573
23905
  */
21574
23906
  getDefaultConfig() {
21575
- return {
21576
- openai: true,
21577
- openaiCodexSDK: true,
21578
- anthropic: true,
21579
- vercel: true,
21580
- aisdk: true,
21581
- google: true,
21582
- googleGenAI: true,
21583
- googleADK: true,
21584
- huggingface: true,
21585
- claudeAgentSDK: true,
21586
- cursor: true,
21587
- cursorSDK: true,
21588
- openrouter: true,
21589
- openrouterAgent: true,
21590
- mistral: true,
21591
- cohere: true,
21592
- groq: true,
21593
- genkit: true,
21594
- gitHubCopilot: true
21595
- };
23907
+ return getDefaultInstrumentationIntegrations();
21596
23908
  }
21597
23909
  /**
21598
23910
  * Read configuration from environment variables.
21599
23911
  * Supports: BRAINTRUST_DISABLE_INSTRUMENTATION=openai,anthropic,...
21600
23912
  */
21601
23913
  readEnvConfig() {
21602
- const integrations = {};
21603
- const disabledList = isomorph_default.getEnv("BRAINTRUST_DISABLE_INSTRUMENTATION");
21604
- if (disabledList) {
21605
- const disabled = disabledList.split(",").map((s) => s.trim().toLowerCase()).filter((s) => s.length > 0);
21606
- for (const sdk of disabled) {
21607
- if (sdk === "cursor-sdk") {
21608
- integrations.cursorSDK = false;
21609
- } else if (sdk === "githubcopilot" || sdk === "github-copilot" || sdk === "copilot-sdk") {
21610
- integrations.gitHubCopilot = false;
21611
- } else if (sdk === "openai-codex-sdk") {
21612
- integrations.openaiCodexSDK = false;
21613
- } else {
21614
- integrations[sdk] = false;
21615
- }
21616
- }
21617
- }
21618
- return { integrations };
23914
+ return readDisabledInstrumentationEnvConfig(
23915
+ isomorph_default.getEnv("BRAINTRUST_DISABLE_INSTRUMENTATION")
23916
+ );
21619
23917
  }
21620
23918
  };
21621
23919
  var registry = new PluginRegistry();
@@ -21625,6 +23923,7 @@ function configureInstrumentation(config) {
21625
23923
  export {
21626
23924
  BasePlugin,
21627
23925
  BraintrustPlugin,
23926
+ OpenAIAgentsTraceProcessor,
21628
23927
  configureInstrumentation,
21629
23928
  createChannelName,
21630
23929
  isValidChannelName,