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
package/dist/cli.js CHANGED
@@ -1232,7 +1232,7 @@ var require_package = __commonJS({
1232
1232
  "package.json"(exports2, module2) {
1233
1233
  module2.exports = {
1234
1234
  name: "braintrust",
1235
- version: "3.11.0",
1235
+ version: "3.12.0",
1236
1236
  description: "SDK for integrating Braintrust",
1237
1237
  repository: {
1238
1238
  type: "git",
@@ -1243,6 +1243,7 @@ var require_package = __commonJS({
1243
1243
  main: "./dist/index.js",
1244
1244
  module: "./dist/index.mjs",
1245
1245
  types: "./dist/index.d.ts",
1246
+ sideEffects: true,
1246
1247
  browser: {
1247
1248
  "./dist/index.js": "./dist/browser.js",
1248
1249
  "./dist/index.d.ts": "./dist/browser.d.ts",
@@ -1282,6 +1283,19 @@ var require_package = __commonJS({
1282
1283
  require: "./dist/browser.js",
1283
1284
  default: "./dist/browser.mjs"
1284
1285
  },
1286
+ "./apply-auto-instrumentation": {
1287
+ types: "./dist/apply-auto-instrumentation.d.ts",
1288
+ "edge-light": "./dist/apply-auto-instrumentation.browser.mjs",
1289
+ workerd: "./dist/apply-auto-instrumentation.browser.mjs",
1290
+ node: {
1291
+ import: "./dist/apply-auto-instrumentation.mjs",
1292
+ require: "./dist/apply-auto-instrumentation.js"
1293
+ },
1294
+ browser: "./dist/apply-auto-instrumentation.browser.mjs",
1295
+ import: "./dist/apply-auto-instrumentation.mjs",
1296
+ require: "./dist/apply-auto-instrumentation.js",
1297
+ default: "./dist/apply-auto-instrumentation.mjs"
1298
+ },
1285
1299
  "./node": {
1286
1300
  types: "./dist/index.d.ts",
1287
1301
  import: "./dist/index.mjs",
@@ -1319,6 +1333,12 @@ var require_package = __commonJS({
1319
1333
  module: "./dist/auto-instrumentations/bundler/webpack.mjs",
1320
1334
  require: "./dist/auto-instrumentations/bundler/webpack.cjs"
1321
1335
  },
1336
+ "./next": {
1337
+ types: "./dist/auto-instrumentations/bundler/next.d.ts",
1338
+ import: "./dist/auto-instrumentations/bundler/next.mjs",
1339
+ module: "./dist/auto-instrumentations/bundler/next.mjs",
1340
+ require: "./dist/auto-instrumentations/bundler/next.cjs"
1341
+ },
1322
1342
  "./webpack-loader": {
1323
1343
  types: "./dist/auto-instrumentations/bundler/webpack-loader.d.ts",
1324
1344
  require: "./dist/auto-instrumentations/bundler/webpack-loader.cjs"
@@ -1350,7 +1370,8 @@ var require_package = __commonJS({
1350
1370
  test: 'vitest run --exclude "src/wrappers/**/*.test.ts" --exclude "src/otel/**/*.test.ts" --exclude "smoke/**/*.test.ts" --exclude "src/zod/**/*.test.ts" --exclude "tests/api-compatibility/**"',
1351
1371
  "test:core": "pnpm prune && pnpm test",
1352
1372
  "test:checks": "pnpm run test:core && pnpm run test:vitest",
1353
- "test:external": "pnpm run test:external:openai && pnpm run test:external:anthropic && pnpm run test:external:google-genai && pnpm run test:external:ai-sdk && pnpm run test:external:claude-agent-sdk",
1373
+ "test:external": "pnpm run test:external:sequential && node scripts/run-parallel.mjs test:external:ai-sdk-v5 test:external:ai-sdk-v6 test:external:claude-agent-sdk",
1374
+ "test:external:sequential": "pnpm run test:external:openai && pnpm run test:external:anthropic && pnpm run test:external:google-genai",
1354
1375
  "test:external:openai": "bash scripts/test-provider.sh test:openai openai",
1355
1376
  "test:external:anthropic": "bash scripts/test-provider.sh test:anthropic @anthropic-ai/sdk",
1356
1377
  "test:external:google-genai": "bash scripts/test-provider.sh test:google-genai @google/genai",
@@ -1411,7 +1432,6 @@ var require_package = __commonJS({
1411
1432
  "cross-env": "^7.0.3",
1412
1433
  "eslint-plugin-node-import": "^1.0.5",
1413
1434
  openai: "6.25.0",
1414
- "openapi-zod-client": "^1.18.3",
1415
1435
  rollup: "^4.60.3",
1416
1436
  tar: "^7.5.2",
1417
1437
  tinybench: "^4.0.1",
@@ -2405,6 +2425,11 @@ function isPromiseLike(value) {
2405
2425
 
2406
2426
  // util/object_util.ts
2407
2427
  var SET_UNION_FIELDS = /* @__PURE__ */ new Set(["tags"]);
2428
+ var FORBIDDEN_MERGE_KEYS = /* @__PURE__ */ new Set([
2429
+ "__proto__",
2430
+ "constructor",
2431
+ "prototype"
2432
+ ]);
2408
2433
  function mergeDictsWithPaths({
2409
2434
  mergeInto,
2410
2435
  mergeFrom,
@@ -2427,6 +2452,7 @@ function mergeDictsWithPathsHelper({
2427
2452
  mergePaths
2428
2453
  }) {
2429
2454
  Object.entries(mergeFrom).forEach(([k, mergeFromV]) => {
2455
+ if (FORBIDDEN_MERGE_KEYS.has(k)) return;
2430
2456
  const fullPath = path8.concat([k]);
2431
2457
  const fullPathSerialized = JSON.stringify(fullPath);
2432
2458
  const mergeIntoV = recordFind(mergeInto, k);
@@ -6490,6 +6516,13 @@ var HTTPConnection = class _HTTPConnection {
6490
6516
  debugLogger.debug(
6491
6517
  `Retrying API request ${object_type} ${JSON.stringify(args)} ${e.status} ${e.text}`
6492
6518
  );
6519
+ const sleepTimeS = HTTP_RETRY_BASE_SLEEP_TIME_S * 2 ** i;
6520
+ debugLogger.info(
6521
+ `Sleeping for ${sleepTimeS}s before retrying API request`
6522
+ );
6523
+ await new Promise(
6524
+ (resolve2) => setTimeout(resolve2, sleepTimeS * 1e3)
6525
+ );
6493
6526
  continue;
6494
6527
  }
6495
6528
  throw e;
@@ -7012,20 +7045,7 @@ function startSpanParentArgs(args) {
7012
7045
  `Mismatch between expected span parent object type ${args.parentObjectType} and provided type ${parentComponents.data.object_type}`
7013
7046
  );
7014
7047
  }
7015
- const parentComponentsObjectIdLambda = spanComponentsToObjectIdLambda(
7016
- args.state,
7017
- parentComponents
7018
- );
7019
- const computeParentObjectId = async () => {
7020
- const parentComponentsObjectId = await parentComponentsObjectIdLambda();
7021
- if (await args.parentObjectId.get() !== parentComponentsObjectId) {
7022
- throw new Error(
7023
- `Mismatch between expected span parent object id ${await args.parentObjectId.get()} and provided id ${parentComponentsObjectId}`
7024
- );
7025
- }
7026
- return await args.parentObjectId.get();
7027
- };
7028
- argParentObjectId = new LazyValue(computeParentObjectId);
7048
+ argParentObjectId = args.parentObjectId;
7029
7049
  if (parentComponents.data.row_id) {
7030
7050
  argParentSpanIds = {
7031
7051
  spanId: parentComponents.data.span_id,
@@ -7354,6 +7374,7 @@ function now() {
7354
7374
  }
7355
7375
  var DEFAULT_FLUSH_BACKPRESSURE_BYTES = 10 * 1024 * 1024;
7356
7376
  var BACKGROUND_LOGGER_BASE_SLEEP_TIME_S = 1;
7377
+ var HTTP_RETRY_BASE_SLEEP_TIME_S = 1;
7357
7378
  var HTTPBackgroundLogger = class _HTTPBackgroundLogger {
7358
7379
  apiConn;
7359
7380
  queue;
@@ -7984,17 +8005,10 @@ function init(projectOrOptions, optionalOptions) {
7984
8005
  if (repoInfo2) {
7985
8006
  return repoInfo2;
7986
8007
  }
7987
- let mergedGitMetadataSettings = {
7988
- ...state.gitMetadataSettings || {
7989
- collect: "all"
7990
- }
7991
- };
7992
- if (gitMetadataSettings) {
7993
- mergedGitMetadataSettings = mergeGitMetadataSettings(
7994
- mergedGitMetadataSettings,
7995
- gitMetadataSettings
7996
- );
7997
- }
8008
+ const mergedGitMetadataSettings = state.gitMetadataSettings == null ? gitMetadataSettings ?? { collect: "none" } : mergeGitMetadataSettings(
8009
+ state.gitMetadataSettings,
8010
+ gitMetadataSettings ?? { collect: "all" }
8011
+ );
7998
8012
  return await isomorph_default.getRepoInfo(mergedGitMetadataSettings);
7999
8013
  })();
8000
8014
  if (repoInfoArg) {
@@ -8376,6 +8390,55 @@ async function computeLoggerMetadata(state, {
8376
8390
  };
8377
8391
  }
8378
8392
  }
8393
+ function initLogger(options = {}) {
8394
+ const {
8395
+ projectName,
8396
+ projectId,
8397
+ asyncFlush: asyncFlushArg,
8398
+ appUrl,
8399
+ apiKey,
8400
+ orgName,
8401
+ forceLogin,
8402
+ debugLogLevel,
8403
+ fetch: fetch2,
8404
+ state: stateArg
8405
+ } = options || {};
8406
+ const asyncFlush = asyncFlushArg === void 0 ? true : asyncFlushArg;
8407
+ const computeMetadataArgs = {
8408
+ project_name: projectName,
8409
+ project_id: projectId
8410
+ };
8411
+ const linkArgs = {
8412
+ org_name: orgName,
8413
+ app_url: appUrl,
8414
+ project_name: projectName,
8415
+ project_id: projectId
8416
+ };
8417
+ const state = stateArg ?? _globalState;
8418
+ state.setDebugLogLevel(debugLogLevel);
8419
+ state.enforceQueueSizeLimit(true);
8420
+ const lazyMetadata = new LazyValue(
8421
+ async () => {
8422
+ await state.login({
8423
+ orgName,
8424
+ apiKey,
8425
+ appUrl,
8426
+ forceLogin,
8427
+ fetch: fetch2
8428
+ });
8429
+ return computeLoggerMetadata(state, computeMetadataArgs);
8430
+ }
8431
+ );
8432
+ const ret = new Logger(state, lazyMetadata, {
8433
+ asyncFlush,
8434
+ computeMetadataArgs,
8435
+ linkArgs
8436
+ });
8437
+ if (options.setCurrent ?? true) {
8438
+ state.currentLogger = ret;
8439
+ }
8440
+ return ret;
8441
+ }
8379
8442
  async function login(options = {}) {
8380
8443
  const { forceLogin = false } = options || {};
8381
8444
  if (!_internalGetGlobalState()) {
@@ -13398,11 +13461,11 @@ function truncateToByteLimit(s, byteLimit = 65536) {
13398
13461
  return new TextDecoder().decode(truncated);
13399
13462
  }
13400
13463
  async function getRepoInfo(settings) {
13401
- if (settings && settings.collect === "none") {
13464
+ if (!settings || settings.collect === "none") {
13402
13465
  return void 0;
13403
13466
  }
13404
13467
  const repo = await repoInfo();
13405
- if (!repo || !settings || settings.collect === "all") {
13468
+ if (!repo || settings.collect === "all") {
13406
13469
  return repo;
13407
13470
  }
13408
13471
  let sanitized = {};
@@ -17099,11 +17162,11 @@ function resolveDenyOutputPaths(event, defaultDenyOutputPaths) {
17099
17162
  if (Array.isArray(event?.denyOutputPaths)) {
17100
17163
  return event.denyOutputPaths;
17101
17164
  }
17102
- const firstArgument = event?.arguments && event.arguments.length > 0 ? event.arguments[0] : void 0;
17103
- if (!firstArgument || typeof firstArgument !== "object") {
17165
+ const firstArgument2 = event?.arguments && event.arguments.length > 0 ? event.arguments[0] : void 0;
17166
+ if (!firstArgument2 || typeof firstArgument2 !== "object") {
17104
17167
  return defaultDenyOutputPaths;
17105
17168
  }
17106
- const runtimeDenyOutputPaths = firstArgument[RUNTIME_DENY_OUTPUT_PATHS];
17169
+ const runtimeDenyOutputPaths = firstArgument2[RUNTIME_DENY_OUTPUT_PATHS];
17107
17170
  if (Array.isArray(runtimeDenyOutputPaths) && runtimeDenyOutputPaths.every((path8) => typeof path8 === "string")) {
17108
17171
  return runtimeDenyOutputPaths;
17109
17172
  }
@@ -20762,6 +20825,467 @@ function cleanMetrics2(metrics) {
20762
20825
  return cleaned;
20763
20826
  }
20764
20827
 
20828
+ // src/instrumentation/plugins/openai-agents-channels.ts
20829
+ var openAIAgentsCoreChannels = defineChannels("@openai/agents-core", {
20830
+ onTraceStart: channel({
20831
+ channelName: "tracing.processor.onTraceStart",
20832
+ kind: "async"
20833
+ }),
20834
+ onTraceEnd: channel({
20835
+ channelName: "tracing.processor.onTraceEnd",
20836
+ kind: "async"
20837
+ }),
20838
+ onSpanStart: channel({
20839
+ channelName: "tracing.processor.onSpanStart",
20840
+ kind: "async"
20841
+ }),
20842
+ onSpanEnd: channel({
20843
+ channelName: "tracing.processor.onSpanEnd",
20844
+ kind: "async"
20845
+ })
20846
+ });
20847
+
20848
+ // src/instrumentation/plugins/openai-agents-trace-processor.ts
20849
+ function isSpanData(spanData, type) {
20850
+ return spanData.type === type;
20851
+ }
20852
+ function spanTypeFromAgents(span) {
20853
+ const spanType = span.spanData.type;
20854
+ if (spanType === "function" || spanType === "guardrail" || spanType === "mcp_tools") {
20855
+ return "tool" /* TOOL */;
20856
+ }
20857
+ if (spanType === "generation" || spanType === "response" || spanType === "transcription" || spanType === "speech") {
20858
+ return "llm" /* LLM */;
20859
+ }
20860
+ return "task" /* TASK */;
20861
+ }
20862
+ function spanNameFromAgents(span) {
20863
+ const spanData = span.spanData;
20864
+ if ("name" in spanData && spanData.name) {
20865
+ return spanData.name;
20866
+ }
20867
+ switch (spanData.type) {
20868
+ case "generation":
20869
+ return "Generation";
20870
+ case "response":
20871
+ return "Response";
20872
+ case "handoff":
20873
+ return "Handoff";
20874
+ case "mcp_tools":
20875
+ return isSpanData(spanData, "mcp_tools") && spanData.server ? `List Tools (${spanData.server})` : "MCP List Tools";
20876
+ case "transcription":
20877
+ return "Transcription";
20878
+ case "speech":
20879
+ return "Speech";
20880
+ case "speech_group":
20881
+ return "Speech Group";
20882
+ default:
20883
+ return "Unknown";
20884
+ }
20885
+ }
20886
+ function getTimeElapsed(end, start) {
20887
+ if (!start || !end) {
20888
+ return void 0;
20889
+ }
20890
+ const startTime = new Date(start).getTime();
20891
+ const endTime = new Date(end).getTime();
20892
+ if (Number.isNaN(startTime) || Number.isNaN(endTime)) {
20893
+ return void 0;
20894
+ }
20895
+ return (endTime - startTime) / 1e3;
20896
+ }
20897
+ function getNumberProperty2(obj, key) {
20898
+ if (!isObject(obj) || !(key in obj)) {
20899
+ return void 0;
20900
+ }
20901
+ const value = obj[key];
20902
+ return typeof value === "number" ? value : void 0;
20903
+ }
20904
+ function parseUsageMetrics(usage) {
20905
+ const metrics = {};
20906
+ if (!isObject(usage)) {
20907
+ return metrics;
20908
+ }
20909
+ const promptTokens = getNumberProperty2(usage, "prompt_tokens") ?? getNumberProperty2(usage, "input_tokens") ?? getNumberProperty2(usage, "promptTokens") ?? getNumberProperty2(usage, "inputTokens");
20910
+ const completionTokens = getNumberProperty2(usage, "completion_tokens") ?? getNumberProperty2(usage, "output_tokens") ?? getNumberProperty2(usage, "completionTokens") ?? getNumberProperty2(usage, "outputTokens");
20911
+ const totalTokens = getNumberProperty2(usage, "total_tokens") ?? getNumberProperty2(usage, "totalTokens");
20912
+ if (promptTokens !== void 0) {
20913
+ metrics.prompt_tokens = promptTokens;
20914
+ }
20915
+ if (completionTokens !== void 0) {
20916
+ metrics.completion_tokens = completionTokens;
20917
+ }
20918
+ if (totalTokens !== void 0) {
20919
+ metrics.tokens = totalTokens;
20920
+ } else if (promptTokens !== void 0 && completionTokens !== void 0) {
20921
+ metrics.tokens = promptTokens + completionTokens;
20922
+ }
20923
+ const inputDetails = usage.input_tokens_details;
20924
+ const cachedTokens = getNumberProperty2(inputDetails, "cached_tokens");
20925
+ const cacheWriteTokens = getNumberProperty2(
20926
+ inputDetails,
20927
+ "cache_write_tokens"
20928
+ );
20929
+ if (cachedTokens !== void 0) {
20930
+ metrics.prompt_cached_tokens = cachedTokens;
20931
+ }
20932
+ if (cacheWriteTokens !== void 0) {
20933
+ metrics.prompt_cache_creation_tokens = cacheWriteTokens;
20934
+ }
20935
+ return metrics;
20936
+ }
20937
+ var OpenAIAgentsTraceProcessor = class _OpenAIAgentsTraceProcessor {
20938
+ static DEFAULT_MAX_TRACES = 1e4;
20939
+ logger;
20940
+ maxTraces;
20941
+ traceSpans = /* @__PURE__ */ new Map();
20942
+ traceOrder = [];
20943
+ _traceSpans = this.traceSpans;
20944
+ constructor(options = {}) {
20945
+ this.logger = options.logger;
20946
+ this.maxTraces = options.maxTraces ?? _OpenAIAgentsTraceProcessor.DEFAULT_MAX_TRACES;
20947
+ }
20948
+ evictOldestTrace() {
20949
+ const oldestTraceId = this.traceOrder.shift();
20950
+ if (oldestTraceId) {
20951
+ this.traceSpans.delete(oldestTraceId);
20952
+ }
20953
+ }
20954
+ onTraceStart(trace) {
20955
+ if (!trace?.traceId) {
20956
+ return Promise.resolve();
20957
+ }
20958
+ if (this.traceOrder.length >= this.maxTraces) {
20959
+ this.evictOldestTrace();
20960
+ }
20961
+ const current = currentSpan();
20962
+ const span = current && current !== NOOP_SPAN ? current.startSpan({
20963
+ name: trace.name,
20964
+ type: "task" /* TASK */
20965
+ }) : this.logger ? this.logger.startSpan({
20966
+ name: trace.name,
20967
+ type: "task" /* TASK */
20968
+ }) : startSpan({
20969
+ name: trace.name,
20970
+ type: "task" /* TASK */
20971
+ });
20972
+ span.log({
20973
+ input: "Agent workflow started",
20974
+ metadata: {
20975
+ group_id: trace.groupId,
20976
+ ...trace.metadata || {}
20977
+ }
20978
+ });
20979
+ this.traceSpans.set(trace.traceId, {
20980
+ rootSpan: span,
20981
+ childSpans: /* @__PURE__ */ new Map(),
20982
+ metadata: {
20983
+ firstInput: null,
20984
+ lastOutput: null
20985
+ }
20986
+ });
20987
+ this.traceOrder.push(trace.traceId);
20988
+ return Promise.resolve();
20989
+ }
20990
+ async onTraceEnd(trace) {
20991
+ const traceData = this.traceSpans.get(trace?.traceId);
20992
+ if (!traceData) {
20993
+ return;
20994
+ }
20995
+ try {
20996
+ traceData.rootSpan.log({
20997
+ input: traceData.metadata.firstInput,
20998
+ output: traceData.metadata.lastOutput
20999
+ });
21000
+ traceData.rootSpan.end();
21001
+ await traceData.rootSpan.flush();
21002
+ } finally {
21003
+ this.traceSpans.delete(trace.traceId);
21004
+ const orderIndex = this.traceOrder.indexOf(trace.traceId);
21005
+ if (orderIndex > -1) {
21006
+ this.traceOrder.splice(orderIndex, 1);
21007
+ }
21008
+ }
21009
+ }
21010
+ onSpanStart(span) {
21011
+ if (!span?.spanId || !span.traceId) {
21012
+ return Promise.resolve();
21013
+ }
21014
+ const traceData = this.traceSpans.get(span.traceId);
21015
+ if (!traceData) {
21016
+ return Promise.resolve();
21017
+ }
21018
+ const parentSpan = span.parentId ? traceData.childSpans.get(span.parentId) : traceData.rootSpan;
21019
+ if (!parentSpan) {
21020
+ return Promise.resolve();
21021
+ }
21022
+ const childSpan = parentSpan.startSpan({
21023
+ name: spanNameFromAgents(span),
21024
+ type: spanTypeFromAgents(span)
21025
+ });
21026
+ traceData.childSpans.set(span.spanId, childSpan);
21027
+ return Promise.resolve();
21028
+ }
21029
+ onSpanEnd(span) {
21030
+ if (!span?.spanId || !span.traceId) {
21031
+ return Promise.resolve();
21032
+ }
21033
+ const traceData = this.traceSpans.get(span.traceId);
21034
+ if (!traceData) {
21035
+ return Promise.resolve();
21036
+ }
21037
+ const braintrustSpan = traceData.childSpans.get(span.spanId);
21038
+ if (!braintrustSpan) {
21039
+ return Promise.resolve();
21040
+ }
21041
+ const logData = this.extractLogData(span);
21042
+ braintrustSpan.log({
21043
+ error: span.error,
21044
+ ...logData
21045
+ });
21046
+ braintrustSpan.end();
21047
+ traceData.childSpans.delete(span.spanId);
21048
+ const input = logData.input;
21049
+ const output = logData.output;
21050
+ if (traceData.metadata.firstInput === null && input != null) {
21051
+ traceData.metadata.firstInput = input;
21052
+ }
21053
+ if (output != null) {
21054
+ traceData.metadata.lastOutput = output;
21055
+ }
21056
+ return Promise.resolve();
21057
+ }
21058
+ async shutdown() {
21059
+ if (this.logger && typeof this.logger.flush === "function") {
21060
+ await this.logger.flush();
21061
+ }
21062
+ }
21063
+ async forceFlush() {
21064
+ if (this.logger && typeof this.logger.flush === "function") {
21065
+ await this.logger.flush();
21066
+ }
21067
+ }
21068
+ extractLogData(span) {
21069
+ const spanData = span.spanData;
21070
+ switch (spanData.type) {
21071
+ case "agent":
21072
+ return this.extractAgentLogData(spanData);
21073
+ case "response":
21074
+ return this.extractResponseLogData(spanData, span);
21075
+ case "function":
21076
+ return this.extractFunctionLogData(spanData);
21077
+ case "handoff":
21078
+ return this.extractHandoffLogData(spanData);
21079
+ case "guardrail":
21080
+ return this.extractGuardrailLogData(spanData);
21081
+ case "generation":
21082
+ return this.extractGenerationLogData(spanData, span);
21083
+ case "custom":
21084
+ return this.extractCustomLogData(spanData);
21085
+ case "mcp_tools":
21086
+ return this.extractMCPListToolsLogData(spanData);
21087
+ case "transcription":
21088
+ return this.extractTranscriptionLogData(spanData);
21089
+ case "speech":
21090
+ return this.extractSpeechLogData(spanData);
21091
+ case "speech_group":
21092
+ return this.extractSpeechGroupLogData(spanData);
21093
+ default:
21094
+ return {};
21095
+ }
21096
+ }
21097
+ extractAgentLogData(spanData) {
21098
+ return {
21099
+ metadata: {
21100
+ tools: spanData.tools,
21101
+ handoffs: spanData.handoffs,
21102
+ output_type: spanData.output_type
21103
+ }
21104
+ };
21105
+ }
21106
+ extractResponseLogData(spanData, span) {
21107
+ const response = spanData._response;
21108
+ const output = isObject(response) ? response.output : void 0;
21109
+ const usage = isObject(response) ? response.usage : void 0;
21110
+ const metrics = {
21111
+ ...this.extractTimingMetrics(span),
21112
+ ...parseUsageMetrics(usage)
21113
+ };
21114
+ return {
21115
+ input: spanData._input,
21116
+ output,
21117
+ metadata: isObject(response) ? this.omitKeys(response, ["output", "usage"]) : {},
21118
+ metrics
21119
+ };
21120
+ }
21121
+ extractFunctionLogData(spanData) {
21122
+ return {
21123
+ input: spanData.input,
21124
+ output: spanData.output
21125
+ };
21126
+ }
21127
+ extractHandoffLogData(spanData) {
21128
+ return {
21129
+ metadata: {
21130
+ from_agent: spanData.from_agent,
21131
+ to_agent: spanData.to_agent
21132
+ }
21133
+ };
21134
+ }
21135
+ extractGuardrailLogData(spanData) {
21136
+ return {
21137
+ metadata: {
21138
+ triggered: spanData.triggered
21139
+ }
21140
+ };
21141
+ }
21142
+ extractGenerationLogData(spanData, span) {
21143
+ return {
21144
+ input: spanData.input,
21145
+ output: spanData.output,
21146
+ metadata: {
21147
+ model: spanData.model,
21148
+ model_config: spanData.model_config
21149
+ },
21150
+ metrics: {
21151
+ ...this.extractTimingMetrics(span),
21152
+ ...parseUsageMetrics(spanData.usage)
21153
+ }
21154
+ };
21155
+ }
21156
+ extractCustomLogData(spanData) {
21157
+ return spanData.data || {};
21158
+ }
21159
+ extractMCPListToolsLogData(spanData) {
21160
+ return {
21161
+ output: spanData.result,
21162
+ metadata: {
21163
+ server: spanData.server
21164
+ }
21165
+ };
21166
+ }
21167
+ extractTranscriptionLogData(spanData) {
21168
+ return {
21169
+ input: spanData.input,
21170
+ output: spanData.output,
21171
+ metadata: {
21172
+ model: spanData.model,
21173
+ model_config: spanData.model_config
21174
+ }
21175
+ };
21176
+ }
21177
+ extractSpeechLogData(spanData) {
21178
+ return {
21179
+ input: spanData.input,
21180
+ output: spanData.output,
21181
+ metadata: {
21182
+ model: spanData.model,
21183
+ model_config: spanData.model_config
21184
+ }
21185
+ };
21186
+ }
21187
+ extractSpeechGroupLogData(spanData) {
21188
+ return {
21189
+ input: spanData.input
21190
+ };
21191
+ }
21192
+ extractTimingMetrics(span) {
21193
+ const timeToFirstToken = getTimeElapsed(
21194
+ span.endedAt ?? void 0,
21195
+ span.startedAt ?? void 0
21196
+ );
21197
+ return timeToFirstToken === void 0 ? {} : { time_to_first_token: timeToFirstToken };
21198
+ }
21199
+ omitKeys(value, keys) {
21200
+ const result = {};
21201
+ for (const [key, fieldValue] of Object.entries(value)) {
21202
+ if (!keys.includes(key)) {
21203
+ result[key] = fieldValue;
21204
+ }
21205
+ }
21206
+ return result;
21207
+ }
21208
+ };
21209
+
21210
+ // src/instrumentation/plugins/openai-agents-plugin.ts
21211
+ function firstArgument(args) {
21212
+ if (Array.isArray(args)) {
21213
+ return args[0];
21214
+ }
21215
+ if (isObject(args) && "length" in args && typeof args.length === "number" && Number.isInteger(args.length) && args.length >= 0) {
21216
+ return Array.from(args)[0];
21217
+ }
21218
+ return void 0;
21219
+ }
21220
+ function isOpenAIAgentsTrace(value) {
21221
+ return isObject(value) && value.type === "trace" && typeof value.traceId === "string";
21222
+ }
21223
+ function isOpenAIAgentsSpan(value) {
21224
+ return isObject(value) && value.type === "trace.span" && typeof value.traceId === "string" && typeof value.spanId === "string";
21225
+ }
21226
+ var OpenAIAgentsPlugin = class extends BasePlugin {
21227
+ processor = new OpenAIAgentsTraceProcessor();
21228
+ onEnable() {
21229
+ this.subscribeToTraceLifecycle();
21230
+ }
21231
+ onDisable() {
21232
+ this.unsubscribers = unsubscribeAll(this.unsubscribers);
21233
+ void this.processor.shutdown();
21234
+ }
21235
+ subscribeToTraceLifecycle() {
21236
+ const traceStartChannel = openAIAgentsCoreChannels.onTraceStart.tracingChannel();
21237
+ const traceStartHandlers = {
21238
+ start: (event) => {
21239
+ const trace = firstArgument(event.arguments);
21240
+ if (isOpenAIAgentsTrace(trace)) {
21241
+ void this.processor.onTraceStart(trace);
21242
+ }
21243
+ }
21244
+ };
21245
+ traceStartChannel.subscribe(traceStartHandlers);
21246
+ this.unsubscribers.push(
21247
+ () => traceStartChannel.unsubscribe(traceStartHandlers)
21248
+ );
21249
+ const traceEndChannel = openAIAgentsCoreChannels.onTraceEnd.tracingChannel();
21250
+ const traceEndHandlers = {
21251
+ start: (event) => {
21252
+ const trace = firstArgument(event.arguments);
21253
+ if (isOpenAIAgentsTrace(trace)) {
21254
+ void this.processor.onTraceEnd(trace);
21255
+ }
21256
+ }
21257
+ };
21258
+ traceEndChannel.subscribe(traceEndHandlers);
21259
+ this.unsubscribers.push(
21260
+ () => traceEndChannel.unsubscribe(traceEndHandlers)
21261
+ );
21262
+ const spanStartChannel = openAIAgentsCoreChannels.onSpanStart.tracingChannel();
21263
+ const spanStartHandlers = {
21264
+ start: (event) => {
21265
+ const span = firstArgument(event.arguments);
21266
+ if (isOpenAIAgentsSpan(span)) {
21267
+ void this.processor.onSpanStart(span);
21268
+ }
21269
+ }
21270
+ };
21271
+ spanStartChannel.subscribe(spanStartHandlers);
21272
+ this.unsubscribers.push(
21273
+ () => spanStartChannel.unsubscribe(spanStartHandlers)
21274
+ );
21275
+ const spanEndChannel = openAIAgentsCoreChannels.onSpanEnd.tracingChannel();
21276
+ const spanEndHandlers = {
21277
+ start: (event) => {
21278
+ const span = firstArgument(event.arguments);
21279
+ if (isOpenAIAgentsSpan(span)) {
21280
+ void this.processor.onSpanEnd(span);
21281
+ }
21282
+ }
21283
+ };
21284
+ spanEndChannel.subscribe(spanEndHandlers);
21285
+ this.unsubscribers.push(() => spanEndChannel.unsubscribe(spanEndHandlers));
21286
+ }
21287
+ };
21288
+
20765
21289
  // src/instrumentation/plugins/google-genai-channels.ts
20766
21290
  var googleGenAIChannels = defineChannels("@google/genai", {
20767
21291
  generateContent: channel({
@@ -27054,33 +27578,1743 @@ var GitHubCopilotPlugin = class extends BasePlugin {
27054
27578
  }
27055
27579
  };
27056
27580
 
27057
- // src/instrumentation/braintrust-plugin.ts
27058
- function getIntegrationConfig(integrations, key) {
27059
- return integrations[key];
27581
+ // src/instrumentation/plugins/flue-channels.ts
27582
+ var flueChannels = defineChannels("@flue/runtime", {
27583
+ createContext: channel({
27584
+ channelName: "createFlueContext",
27585
+ kind: "sync-stream"
27586
+ }),
27587
+ openSession: channel({
27588
+ channelName: "Harness.openSession",
27589
+ kind: "async"
27590
+ }),
27591
+ contextEvent: channel({
27592
+ channelName: "context.event",
27593
+ kind: "sync-stream"
27594
+ }),
27595
+ prompt: channel({
27596
+ channelName: "session.prompt",
27597
+ kind: "async"
27598
+ }),
27599
+ skill: channel({
27600
+ channelName: "session.skill",
27601
+ kind: "async"
27602
+ }),
27603
+ task: channel({
27604
+ channelName: "session.task",
27605
+ kind: "async"
27606
+ }),
27607
+ compact: channel({
27608
+ channelName: "session.compact",
27609
+ kind: "async"
27610
+ })
27611
+ });
27612
+
27613
+ // src/wrappers/flue.ts
27614
+ var WRAPPED_FLUE_CONTEXT = /* @__PURE__ */ Symbol.for("braintrust.flue.wrapped-context");
27615
+ var WRAPPED_FLUE_HARNESS = /* @__PURE__ */ Symbol.for("braintrust.flue.wrapped-harness");
27616
+ var WRAPPED_FLUE_SESSION = /* @__PURE__ */ Symbol.for("braintrust.flue.wrapped-session");
27617
+ var SUBSCRIBED_FLUE_CONTEXT_EVENTS = /* @__PURE__ */ Symbol.for(
27618
+ "braintrust.flue.subscribed-context-events"
27619
+ );
27620
+ function patchFlueContextInPlace(ctx) {
27621
+ const context2 = ctx;
27622
+ if (context2[WRAPPED_FLUE_CONTEXT]) {
27623
+ return ctx;
27624
+ }
27625
+ const originalInit = context2.init.bind(context2);
27626
+ try {
27627
+ Object.defineProperty(context2, WRAPPED_FLUE_CONTEXT, {
27628
+ configurable: false,
27629
+ enumerable: false,
27630
+ value: true
27631
+ });
27632
+ Object.defineProperty(context2, "init", {
27633
+ configurable: true,
27634
+ value: async function wrappedFlueInit(options) {
27635
+ const harness = await originalInit(options);
27636
+ return wrapFlueHarness(harness);
27637
+ },
27638
+ writable: true
27639
+ });
27640
+ } catch {
27641
+ }
27642
+ return ctx;
27060
27643
  }
27061
- var BraintrustPlugin = class extends BasePlugin {
27062
- config;
27063
- openaiPlugin = null;
27064
- openAICodexPlugin = null;
27065
- anthropicPlugin = null;
27066
- aiSDKPlugin = null;
27067
- claudeAgentSDKPlugin = null;
27068
- cursorSDKPlugin = null;
27069
- googleGenAIPlugin = null;
27070
- huggingFacePlugin = null;
27071
- openRouterPlugin = null;
27072
- openRouterAgentPlugin = null;
27073
- mistralPlugin = null;
27074
- googleADKPlugin = null;
27075
- coherePlugin = null;
27076
- groqPlugin = null;
27077
- genkitPlugin = null;
27078
- gitHubCopilotPlugin = null;
27079
- constructor(config3 = {}) {
27080
- super();
27081
- this.config = config3;
27644
+ function subscribeFlueContextEvents(ctx, options = {}) {
27645
+ if (!ctx || typeof ctx !== "object" || typeof ctx.subscribeEvent !== "function") {
27646
+ return void 0;
27082
27647
  }
27083
- onEnable() {
27648
+ const context2 = ctx;
27649
+ const captureTurnSpans = options.captureTurnSpans ?? true;
27650
+ const existingSubscription = context2[SUBSCRIBED_FLUE_CONTEXT_EVENTS];
27651
+ if (existingSubscription) {
27652
+ if (existingSubscription.captureTurnSpans || !captureTurnSpans) {
27653
+ return void 0;
27654
+ }
27655
+ try {
27656
+ existingSubscription.unsubscribe();
27657
+ } catch {
27658
+ }
27659
+ }
27660
+ try {
27661
+ const unsubscribe = ctx.subscribeEvent((event) => {
27662
+ flueChannels.contextEvent.traceSync(() => void 0, {
27663
+ arguments: [event],
27664
+ captureTurnSpans,
27665
+ context: ctx
27666
+ });
27667
+ });
27668
+ if (existingSubscription) {
27669
+ existingSubscription.captureTurnSpans = captureTurnSpans;
27670
+ existingSubscription.unsubscribe = unsubscribe;
27671
+ } else {
27672
+ Object.defineProperty(context2, SUBSCRIBED_FLUE_CONTEXT_EVENTS, {
27673
+ configurable: false,
27674
+ enumerable: false,
27675
+ value: {
27676
+ captureTurnSpans,
27677
+ unsubscribe
27678
+ }
27679
+ });
27680
+ }
27681
+ return unsubscribe;
27682
+ } catch {
27683
+ return void 0;
27684
+ }
27685
+ }
27686
+ function wrapFlueHarness(harness) {
27687
+ if (!isPlausibleFlueHarness(harness)) {
27688
+ return harness;
27689
+ }
27690
+ const target = harness;
27691
+ if (target[WRAPPED_FLUE_HARNESS]) {
27692
+ return harness;
27693
+ }
27694
+ const originalSession = target.session.bind(target);
27695
+ try {
27696
+ Object.defineProperty(target, WRAPPED_FLUE_HARNESS, {
27697
+ configurable: false,
27698
+ enumerable: false,
27699
+ value: true
27700
+ });
27701
+ Object.defineProperty(target, "session", {
27702
+ configurable: true,
27703
+ value: async function wrappedFlueHarnessSession(name, options) {
27704
+ const session = await originalSession(name, options);
27705
+ return patchFlueSessionInPlace(session);
27706
+ },
27707
+ writable: true
27708
+ });
27709
+ const sessions = target.sessions;
27710
+ if (sessions && typeof sessions === "object") {
27711
+ patchFlueSessionFactory(sessions, "get");
27712
+ patchFlueSessionFactory(sessions, "create");
27713
+ }
27714
+ } catch {
27715
+ }
27716
+ return harness;
27717
+ }
27718
+ function patchFlueSessionInPlace(session) {
27719
+ if (session[WRAPPED_FLUE_SESSION]) {
27720
+ return session;
27721
+ }
27722
+ try {
27723
+ Object.defineProperty(session, WRAPPED_FLUE_SESSION, {
27724
+ configurable: false,
27725
+ enumerable: false,
27726
+ value: true
27727
+ });
27728
+ patchCallHandleMethod(session, "prompt", flueChannels.prompt);
27729
+ patchCallHandleMethod(session, "skill", flueChannels.skill);
27730
+ patchCallHandleMethod(session, "task", flueChannels.task);
27731
+ patchCompact(session);
27732
+ } catch {
27733
+ }
27734
+ return session;
27735
+ }
27736
+ function patchFlueSessionFactory(sessions, method) {
27737
+ const original = sessions[method];
27738
+ if (typeof original !== "function") {
27739
+ return;
27740
+ }
27741
+ const bound = original.bind(sessions);
27742
+ Object.defineProperty(sessions, method, {
27743
+ configurable: true,
27744
+ value: async function wrappedFlueSessionFactory(name, options) {
27745
+ const session = await bound(name, options);
27746
+ return patchFlueSessionInPlace(session);
27747
+ },
27748
+ writable: true
27749
+ });
27750
+ }
27751
+ function patchCallHandleMethod(session, method, channel2) {
27752
+ const original = session[method];
27753
+ if (typeof original !== "function") {
27754
+ return;
27755
+ }
27756
+ const bound = original.bind(session);
27757
+ Object.defineProperty(session, method, {
27758
+ configurable: true,
27759
+ value(input, options) {
27760
+ const args = [input, options];
27761
+ const { originalResult, traced: traced2 } = traceFlueOperation(channel2, {
27762
+ context: {
27763
+ arguments: args,
27764
+ operation: method,
27765
+ session
27766
+ },
27767
+ run: () => bound(input, options)
27768
+ });
27769
+ return preserveCallHandle(originalResult, traced2);
27770
+ },
27771
+ writable: true
27772
+ });
27773
+ }
27774
+ function patchCompact(session) {
27775
+ const original = session.compact;
27776
+ if (typeof original !== "function") {
27777
+ return;
27778
+ }
27779
+ const bound = original.bind(session);
27780
+ Object.defineProperty(session, "compact", {
27781
+ configurable: true,
27782
+ value() {
27783
+ const context2 = {
27784
+ arguments: [],
27785
+ operation: "compact",
27786
+ session
27787
+ };
27788
+ return flueChannels.compact.tracePromise(() => bound(), context2);
27789
+ },
27790
+ writable: true
27791
+ });
27792
+ }
27793
+ function traceFlueOperation(channel2, args) {
27794
+ const tracingChannel2 = channel2.tracingChannel();
27795
+ const context2 = args.context;
27796
+ let originalResult;
27797
+ let traced2;
27798
+ const run2 = () => {
27799
+ try {
27800
+ originalResult = args.run();
27801
+ tracingChannel2.end?.publish(context2);
27802
+ } catch (error2) {
27803
+ context2.error = normalizeError3(error2);
27804
+ tracingChannel2.error?.publish(context2);
27805
+ tracingChannel2.end?.publish(context2);
27806
+ throw error2;
27807
+ }
27808
+ traced2 = Promise.resolve(originalResult).then(
27809
+ (result) => {
27810
+ context2.result = result;
27811
+ tracingChannel2.asyncStart?.publish(context2);
27812
+ tracingChannel2.asyncEnd?.publish(context2);
27813
+ return result;
27814
+ },
27815
+ (error2) => {
27816
+ context2.error = normalizeError3(error2);
27817
+ tracingChannel2.error?.publish(context2);
27818
+ tracingChannel2.asyncStart?.publish(context2);
27819
+ tracingChannel2.asyncEnd?.publish(context2);
27820
+ throw error2;
27821
+ }
27822
+ );
27823
+ };
27824
+ if (tracingChannel2.start?.runStores) {
27825
+ tracingChannel2.start.runStores(context2, run2);
27826
+ } else {
27827
+ tracingChannel2.start?.publish(context2);
27828
+ run2();
27829
+ }
27830
+ return { originalResult, traced: traced2 };
27831
+ }
27832
+ function normalizeError3(error2) {
27833
+ return error2 instanceof Error ? error2 : new Error(String(error2));
27834
+ }
27835
+ function preserveCallHandle(originalHandle, traced2) {
27836
+ if (!isFlueCallHandle(originalHandle)) {
27837
+ return traced2;
27838
+ }
27839
+ const handle = originalHandle;
27840
+ const wrapped = {
27841
+ get signal() {
27842
+ return handle.signal;
27843
+ },
27844
+ abort(reason) {
27845
+ return handle.abort(reason);
27846
+ },
27847
+ then(onfulfilled, onrejected) {
27848
+ return traced2.then(onfulfilled, onrejected);
27849
+ }
27850
+ };
27851
+ return wrapped;
27852
+ }
27853
+ function isPlausibleFlueHarness(value) {
27854
+ return !!value && typeof value === "object" && typeof value.session === "function";
27855
+ }
27856
+ function isFlueCallHandle(value) {
27857
+ return !!value && typeof value === "object" && typeof value.then === "function" && typeof value.abort === "function" && "signal" in value;
27858
+ }
27859
+
27860
+ // src/instrumentation/plugins/flue-plugin.ts
27861
+ var FluePlugin = class extends BasePlugin {
27862
+ activeOperationsById = /* @__PURE__ */ new Map();
27863
+ activeOperationsByScope = /* @__PURE__ */ new Map();
27864
+ compactionsByScope = /* @__PURE__ */ new Map();
27865
+ pendingOperationsByKey = /* @__PURE__ */ new Map();
27866
+ tasksById = /* @__PURE__ */ new Map();
27867
+ toolsById = /* @__PURE__ */ new Map();
27868
+ turnsByScope = /* @__PURE__ */ new Map();
27869
+ onEnable() {
27870
+ this.subscribeToContextCreation();
27871
+ this.subscribeToSessionCreation();
27872
+ this.subscribeToContextEvents();
27873
+ this.subscribeToSessionOperations();
27874
+ }
27875
+ onDisable() {
27876
+ for (const unsubscribe of this.unsubscribers) {
27877
+ unsubscribe();
27878
+ }
27879
+ this.unsubscribers = [];
27880
+ this.activeOperationsById.clear();
27881
+ this.activeOperationsByScope.clear();
27882
+ this.compactionsByScope.clear();
27883
+ this.pendingOperationsByKey.clear();
27884
+ this.tasksById.clear();
27885
+ this.toolsById.clear();
27886
+ this.turnsByScope.clear();
27887
+ }
27888
+ subscribeToContextCreation() {
27889
+ const channel2 = flueChannels.createContext.tracingChannel();
27890
+ const handlers = {
27891
+ end: (event) => {
27892
+ const ctx = event.result;
27893
+ if (!ctx) {
27894
+ return;
27895
+ }
27896
+ subscribeFlueContextEvents(ctx, { captureTurnSpans: false });
27897
+ patchFlueContextInPlace(ctx);
27898
+ },
27899
+ error: () => {
27900
+ }
27901
+ };
27902
+ channel2.subscribe(handlers);
27903
+ this.unsubscribers.push(() => {
27904
+ channel2.unsubscribe(handlers);
27905
+ });
27906
+ }
27907
+ subscribeToSessionCreation() {
27908
+ const channel2 = flueChannels.openSession.tracingChannel();
27909
+ const handlers = {
27910
+ asyncEnd: (event) => {
27911
+ if (event.result) {
27912
+ patchFlueSessionInPlace(
27913
+ event.result
27914
+ );
27915
+ }
27916
+ if (event.harness) {
27917
+ wrapFlueHarness(event.harness);
27918
+ }
27919
+ },
27920
+ error: () => {
27921
+ }
27922
+ };
27923
+ channel2.subscribe(handlers);
27924
+ this.unsubscribers.push(() => {
27925
+ channel2.unsubscribe(handlers);
27926
+ });
27927
+ }
27928
+ subscribeToSessionOperations() {
27929
+ this.subscribeToSessionOperation(flueChannels.prompt);
27930
+ this.subscribeToSessionOperation(flueChannels.skill);
27931
+ this.subscribeToSessionOperation(flueChannels.task);
27932
+ this.subscribeToCompact();
27933
+ }
27934
+ subscribeToSessionOperation(channel2) {
27935
+ const tracingChannel2 = channel2.tracingChannel();
27936
+ const states = /* @__PURE__ */ new WeakMap();
27937
+ const ensureState2 = (event) => {
27938
+ const existing = states.get(event);
27939
+ if (existing) {
27940
+ return existing;
27941
+ }
27942
+ const state = this.startOperationState({
27943
+ args: event.arguments,
27944
+ moduleVersion: typeof event.moduleVersion === "string" ? event.moduleVersion : void 0,
27945
+ operation: event.operation,
27946
+ session: event.session
27947
+ });
27948
+ states.set(event, state);
27949
+ return state;
27950
+ };
27951
+ const unbindCurrentSpanStore = this.bindCurrentSpanStoreToOperationStart(
27952
+ tracingChannel2,
27953
+ ensureState2
27954
+ );
27955
+ const handlers = {
27956
+ start: (event) => {
27957
+ ensureState2(event);
27958
+ },
27959
+ asyncEnd: (event) => {
27960
+ this.endOperationState(states.get(event), event.result);
27961
+ states.delete(event);
27962
+ },
27963
+ error: (event) => {
27964
+ const state = states.get(event);
27965
+ if (state && event.error) {
27966
+ safeLog3(state.span, { error: errorToString(event.error) });
27967
+ this.finishOperationState(state);
27968
+ }
27969
+ states.delete(event);
27970
+ }
27971
+ };
27972
+ tracingChannel2.subscribe(handlers);
27973
+ this.unsubscribers.push(() => {
27974
+ unbindCurrentSpanStore?.();
27975
+ tracingChannel2.unsubscribe(handlers);
27976
+ });
27977
+ }
27978
+ subscribeToCompact() {
27979
+ const tracingChannel2 = flueChannels.compact.tracingChannel();
27980
+ const states = /* @__PURE__ */ new WeakMap();
27981
+ const ensureState2 = (event) => {
27982
+ const existing = states.get(event);
27983
+ if (existing) {
27984
+ return existing;
27985
+ }
27986
+ const state = this.startOperationState({
27987
+ args: [],
27988
+ moduleVersion: typeof event.moduleVersion === "string" ? event.moduleVersion : void 0,
27989
+ operation: event.operation,
27990
+ session: event.session
27991
+ });
27992
+ states.set(event, state);
27993
+ return state;
27994
+ };
27995
+ const unbindCurrentSpanStore = this.bindCurrentSpanStoreToOperationStart(
27996
+ tracingChannel2,
27997
+ ensureState2
27998
+ );
27999
+ const handlers = {
28000
+ start: (event) => {
28001
+ ensureState2(event);
28002
+ },
28003
+ asyncEnd: (event) => {
28004
+ this.endOperationState(states.get(event), void 0);
28005
+ states.delete(event);
28006
+ },
28007
+ error: (event) => {
28008
+ const state = states.get(event);
28009
+ if (state && event.error) {
28010
+ safeLog3(state.span, { error: errorToString(event.error) });
28011
+ this.finishOperationState(state);
28012
+ }
28013
+ states.delete(event);
28014
+ }
28015
+ };
28016
+ tracingChannel2.subscribe(handlers);
28017
+ this.unsubscribers.push(() => {
28018
+ unbindCurrentSpanStore?.();
28019
+ tracingChannel2.unsubscribe(handlers);
28020
+ });
28021
+ }
28022
+ subscribeToContextEvents() {
28023
+ const channel2 = flueChannels.contextEvent.tracingChannel();
28024
+ const handlers = {
28025
+ start: (event) => {
28026
+ const flueEvent = event.arguments[0];
28027
+ if (!flueEvent) {
28028
+ return;
28029
+ }
28030
+ try {
28031
+ this.handleFlueEvent(flueEvent, {
28032
+ captureTurnSpans: event.captureTurnSpans !== false
28033
+ });
28034
+ } catch (error2) {
28035
+ logInstrumentationError3("Flue event", error2);
28036
+ }
28037
+ },
28038
+ error: () => {
28039
+ }
28040
+ };
28041
+ channel2.subscribe(handlers);
28042
+ this.unsubscribers.push(() => {
28043
+ channel2.unsubscribe(handlers);
28044
+ });
28045
+ }
28046
+ bindCurrentSpanStoreToOperationStart(tracingChannel2, ensureState2) {
28047
+ const state = _internalGetGlobalState();
28048
+ const startChannel = tracingChannel2.start;
28049
+ const contextManager = state?.contextManager;
28050
+ const currentSpanStore = contextManager ? contextManager[BRAINTRUST_CURRENT_SPAN_STORE] : void 0;
28051
+ if (!currentSpanStore || !startChannel) {
28052
+ return void 0;
28053
+ }
28054
+ startChannel.bindStore(currentSpanStore, (event) => {
28055
+ const operationState = ensureState2(event);
28056
+ return contextManager.wrapSpanForStore(operationState.span);
28057
+ });
28058
+ return () => {
28059
+ startChannel.unbindStore(currentSpanStore);
28060
+ };
28061
+ }
28062
+ startOperationState(args) {
28063
+ const sessionName = getSessionName(args.session);
28064
+ const metadata = {
28065
+ ...extractOperationInputMetadata(args.operation, args.args),
28066
+ ...extractSessionMetadata(args.session),
28067
+ "flue.operation": args.operation,
28068
+ provider: "flue",
28069
+ ...args.moduleVersion ? { "flue.version": args.moduleVersion } : {}
28070
+ };
28071
+ const span = startSpan({
28072
+ name: `flue.session.${args.operation}`,
28073
+ spanAttributes: { type: "task" /* TASK */ }
28074
+ });
28075
+ const state = {
28076
+ metadata,
28077
+ operation: args.operation,
28078
+ sessionName,
28079
+ span,
28080
+ startTime: getCurrentUnixTimestamp()
28081
+ };
28082
+ safeLog3(span, {
28083
+ input: extractOperationInput(args.operation, args.args),
28084
+ metadata
28085
+ });
28086
+ this.pendingOperationQueue(operationKey(sessionName, args.operation)).push(
28087
+ state
28088
+ );
28089
+ addOperationToScope(
28090
+ this.activeOperationsByScope,
28091
+ sessionName ?? "unknown",
28092
+ state
28093
+ );
28094
+ return state;
28095
+ }
28096
+ endOperationState(state, result) {
28097
+ if (!state) {
28098
+ return;
28099
+ }
28100
+ const metadata = {
28101
+ ...state.metadata,
28102
+ ...extractPromptResponseMetadata(result)
28103
+ };
28104
+ const metrics = {
28105
+ ...buildDurationMetrics3(state.startTime),
28106
+ ...metricsFromUsage(result?.usage)
28107
+ };
28108
+ safeLog3(state.span, {
28109
+ metadata,
28110
+ metrics,
28111
+ output: extractOperationOutput(result)
28112
+ });
28113
+ this.finishCompactionsForOperation(state);
28114
+ this.finishOperationState(state);
28115
+ }
28116
+ finishOperationState(state) {
28117
+ removePendingOperation(this.pendingOperationsByKey, state);
28118
+ if (state.operationId) {
28119
+ this.activeOperationsById.delete(state.operationId);
28120
+ }
28121
+ removeScopedOperation(this.activeOperationsByScope, state);
28122
+ state.span.end();
28123
+ }
28124
+ handleFlueEvent(event, options) {
28125
+ switch (event.type) {
28126
+ case "operation_start":
28127
+ this.handleOperationStart(event);
28128
+ return;
28129
+ case "operation":
28130
+ this.handleOperation(event);
28131
+ return;
28132
+ case "text_delta":
28133
+ if (!options.captureTurnSpans) {
28134
+ return;
28135
+ }
28136
+ this.ensureTurnState(event).text.push(
28137
+ typeof event.text === "string" ? event.text : ""
28138
+ );
28139
+ return;
28140
+ case "thinking_start":
28141
+ if (!options.captureTurnSpans) {
28142
+ return;
28143
+ }
28144
+ this.handleThinkingStart(event);
28145
+ return;
28146
+ case "thinking_delta":
28147
+ if (!options.captureTurnSpans) {
28148
+ return;
28149
+ }
28150
+ this.handleThinkingDelta(event);
28151
+ return;
28152
+ case "thinking_end":
28153
+ if (!options.captureTurnSpans) {
28154
+ return;
28155
+ }
28156
+ this.handleThinkingEnd(event);
28157
+ return;
28158
+ case "turn":
28159
+ if (!options.captureTurnSpans) {
28160
+ return;
28161
+ }
28162
+ this.handleTurn(event);
28163
+ return;
28164
+ case "tool_start":
28165
+ this.handleToolStart(event, options);
28166
+ return;
28167
+ case "tool_call":
28168
+ this.handleToolCall(event);
28169
+ return;
28170
+ case "task_start":
28171
+ this.handleTaskStart(event);
28172
+ return;
28173
+ case "task":
28174
+ this.handleTask(event);
28175
+ return;
28176
+ case "compaction_start":
28177
+ this.handleCompactionStart(event);
28178
+ return;
28179
+ case "compaction":
28180
+ this.handleCompaction(event);
28181
+ return;
28182
+ default:
28183
+ return;
28184
+ }
28185
+ }
28186
+ handleOperationStart(event) {
28187
+ if (!isInstrumentedOperation(event.operationKind)) {
28188
+ return;
28189
+ }
28190
+ const state = this.takePendingOperationForEvent(event);
28191
+ if (!state) {
28192
+ return;
28193
+ }
28194
+ state.operationId = event.operationId;
28195
+ this.activeOperationsById.set(event.operationId, state);
28196
+ addScopedOperation(this.activeOperationsByScope, event, state);
28197
+ state.metadata = {
28198
+ ...state.metadata,
28199
+ ...extractEventMetadata(event),
28200
+ "flue.operation_id": event.operationId
28201
+ };
28202
+ safeLog3(state.span, { metadata: state.metadata });
28203
+ }
28204
+ handleOperation(event) {
28205
+ const state = event.operationId ? this.activeOperationsById.get(event.operationId) : void 0;
28206
+ if (!state) {
28207
+ return;
28208
+ }
28209
+ const metadata = {
28210
+ ...state.metadata,
28211
+ ...extractEventMetadata(event),
28212
+ ...typeof event.durationMs === "number" ? { "flue.duration_ms": event.durationMs } : {},
28213
+ ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {}
28214
+ };
28215
+ const metrics = metricsFromUsage(event.usage);
28216
+ safeLog3(state.span, {
28217
+ ...event.error ? { error: errorToString(event.error) } : {},
28218
+ metadata,
28219
+ ...Object.keys(metrics).length ? { metrics } : {}
28220
+ });
28221
+ }
28222
+ ensureTurnState(event) {
28223
+ const scope = scopeKey(event);
28224
+ const existing = this.turnsByScope.get(scope);
28225
+ if (existing) {
28226
+ return existing;
28227
+ }
28228
+ const parent = this.parentSpanForEvent(event);
28229
+ const metadata = {
28230
+ ...extractEventMetadata(event),
28231
+ provider: "flue"
28232
+ };
28233
+ const span = startFlueSpan(parent, {
28234
+ name: "flue.turn",
28235
+ spanAttributes: { type: "llm" /* LLM */ }
28236
+ });
28237
+ const state = {
28238
+ metadata,
28239
+ span,
28240
+ hasThinking: false,
28241
+ startTime: getCurrentUnixTimestamp(),
28242
+ text: [],
28243
+ thinking: [],
28244
+ toolCalls: []
28245
+ };
28246
+ safeLog3(span, { metadata });
28247
+ this.turnsByScope.set(scope, state);
28248
+ return state;
28249
+ }
28250
+ handleTurn(event) {
28251
+ const scope = scopeKey(event);
28252
+ const state = this.ensureTurnState(event);
28253
+ const text = state.text.join("");
28254
+ const reasoning = state.finalThinking ?? state.thinking.join("");
28255
+ const outputReasoning = reasoning || (state.hasThinking ? "[reasoning stream present; content unavailable]" : void 0);
28256
+ const metadata = {
28257
+ ...state.metadata,
28258
+ ...extractEventMetadata(event),
28259
+ ...event.model ? { model: event.model, "flue.model": event.model } : {},
28260
+ ...event.stopReason ? { "flue.stop_reason": event.stopReason } : {},
28261
+ ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {},
28262
+ provider: "flue"
28263
+ };
28264
+ safeLog3(state.span, {
28265
+ ...event.error ? { error: errorToString(event.error) } : {},
28266
+ metadata,
28267
+ metrics: {
28268
+ ...durationMsMetrics(event.durationMs),
28269
+ ...metricsFromUsage(event.usage)
28270
+ },
28271
+ output: toAssistantOutput(
28272
+ text,
28273
+ event.stopReason,
28274
+ outputReasoning,
28275
+ state.toolCalls
28276
+ )
28277
+ });
28278
+ state.span.end();
28279
+ this.turnsByScope.delete(scope);
28280
+ }
28281
+ handleThinkingDelta(event) {
28282
+ const delta = event.delta;
28283
+ if (typeof delta !== "string" || !delta) {
28284
+ return;
28285
+ }
28286
+ const state = this.ensureTurnState(event);
28287
+ state.hasThinking = true;
28288
+ state.metadata["flue.thinking"] = true;
28289
+ state.thinking.push(delta);
28290
+ }
28291
+ handleThinkingStart(event) {
28292
+ const state = this.ensureTurnState(event);
28293
+ state.hasThinking = true;
28294
+ state.metadata["flue.thinking"] = true;
28295
+ }
28296
+ handleThinkingEnd(event) {
28297
+ const state = this.ensureTurnState(event);
28298
+ state.hasThinking = true;
28299
+ state.metadata["flue.thinking"] = true;
28300
+ if (typeof event.content === "string" && event.content) {
28301
+ state.finalThinking = event.content;
28302
+ }
28303
+ }
28304
+ handleToolStart(event, options) {
28305
+ const toolCallId = event.toolCallId;
28306
+ if (!toolCallId) {
28307
+ return;
28308
+ }
28309
+ const parent = this.parentSpanForEvent(event);
28310
+ const scope = scopeKey(event);
28311
+ let turnState = this.turnsByScope.get(scope);
28312
+ if (!turnState && parent && options.captureTurnSpans) {
28313
+ turnState = this.ensureTurnState(event);
28314
+ }
28315
+ const metadata = {
28316
+ ...extractEventMetadata(event),
28317
+ ...event.toolName ? { "flue.tool_name": event.toolName } : {},
28318
+ "flue.tool_call_id": toolCallId,
28319
+ provider: "flue"
28320
+ };
28321
+ const span = startFlueSpan(parent, {
28322
+ name: `tool: ${event.toolName ?? "unknown"}`,
28323
+ spanAttributes: { type: "tool" /* TOOL */ }
28324
+ });
28325
+ if (turnState) {
28326
+ turnState.toolCalls.push({
28327
+ args: event.args,
28328
+ toolCallId,
28329
+ toolName: event.toolName
28330
+ });
28331
+ }
28332
+ safeLog3(span, {
28333
+ input: event.args,
28334
+ metadata
28335
+ });
28336
+ this.toolsById.set(toolKey(event), {
28337
+ metadata,
28338
+ span,
28339
+ startTime: getCurrentUnixTimestamp()
28340
+ });
28341
+ }
28342
+ handleToolCall(event) {
28343
+ const key = toolKey(event);
28344
+ const state = this.toolsById.get(key) ?? this.startSyntheticToolState(event, event.toolName ?? "unknown");
28345
+ const metadata = {
28346
+ ...state.metadata,
28347
+ ...extractEventMetadata(event),
28348
+ ...event.toolName ? { "flue.tool_name": event.toolName } : {},
28349
+ ...event.toolCallId ? { "flue.tool_call_id": event.toolCallId } : {},
28350
+ ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {}
28351
+ };
28352
+ safeLog3(state.span, {
28353
+ ...event.isError ? { error: errorToString(event.result) } : {},
28354
+ metadata,
28355
+ metrics: durationMsMetrics(event.durationMs),
28356
+ output: event.result
28357
+ });
28358
+ state.span.end();
28359
+ this.toolsById.delete(key);
28360
+ }
28361
+ handleTaskStart(event) {
28362
+ const parent = this.parentSpanForEvent(event);
28363
+ const metadata = {
28364
+ ...extractEventMetadata(event),
28365
+ ...event.role ? { "flue.role": event.role } : {},
28366
+ ...event.cwd ? { "flue.cwd": event.cwd } : {},
28367
+ "flue.task_id": event.taskId,
28368
+ provider: "flue"
28369
+ };
28370
+ const span = startFlueSpan(parent, {
28371
+ name: "flue.task",
28372
+ spanAttributes: { type: "task" /* TASK */ }
28373
+ });
28374
+ safeLog3(span, {
28375
+ input: event.prompt,
28376
+ metadata
28377
+ });
28378
+ this.tasksById.set(event.taskId, {
28379
+ metadata,
28380
+ span,
28381
+ startTime: getCurrentUnixTimestamp()
28382
+ });
28383
+ }
28384
+ handleTask(event) {
28385
+ const state = this.tasksById.get(event.taskId);
28386
+ if (!state) {
28387
+ return;
28388
+ }
28389
+ safeLog3(state.span, {
28390
+ ...event.isError ? { error: errorToString(event.result) } : {},
28391
+ metadata: {
28392
+ ...state.metadata,
28393
+ ...extractEventMetadata(event),
28394
+ ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {}
28395
+ },
28396
+ metrics: durationMsMetrics(event.durationMs),
28397
+ output: event.result
28398
+ });
28399
+ state.span.end();
28400
+ this.tasksById.delete(event.taskId);
28401
+ }
28402
+ handleCompactionStart(event) {
28403
+ const operationState = this.operationStateForEvent(event);
28404
+ const parent = operationState?.span ?? this.parentSpanForEvent(event);
28405
+ const metadata = {
28406
+ ...extractEventMetadata(event),
28407
+ ...event.reason ? { "flue.compaction_reason": event.reason } : {},
28408
+ provider: "flue"
28409
+ };
28410
+ const input = {
28411
+ ...typeof event.estimatedTokens === "number" ? { estimatedTokens: event.estimatedTokens } : {},
28412
+ ...event.reason ? { reason: event.reason } : {}
28413
+ };
28414
+ const span = startFlueSpan(parent, {
28415
+ name: "flue.compaction",
28416
+ spanAttributes: { type: "task" /* TASK */ }
28417
+ });
28418
+ safeLog3(span, {
28419
+ input,
28420
+ metadata
28421
+ });
28422
+ this.compactionsByScope.set(scopeKey(event), {
28423
+ input,
28424
+ metadata,
28425
+ operationState,
28426
+ span,
28427
+ startTime: getCurrentUnixTimestamp()
28428
+ });
28429
+ }
28430
+ handleCompaction(event) {
28431
+ const key = scopeKey(event);
28432
+ const state = this.compactionsByScope.get(key) ?? this.findCompactionState(event);
28433
+ if (!state) {
28434
+ return;
28435
+ }
28436
+ safeLog3(state.span, {
28437
+ metadata: {
28438
+ ...state.metadata,
28439
+ ...extractEventMetadata(event),
28440
+ ...typeof event.messagesBefore === "number" ? { "flue.messages_before": event.messagesBefore } : {},
28441
+ ...typeof event.messagesAfter === "number" ? { "flue.messages_after": event.messagesAfter } : {}
28442
+ },
28443
+ metrics: {
28444
+ ...durationMsMetrics(event.durationMs),
28445
+ ...metricsFromUsage(event.usage)
28446
+ },
28447
+ output: {
28448
+ messagesAfter: event.messagesAfter,
28449
+ messagesBefore: event.messagesBefore
28450
+ }
28451
+ });
28452
+ state.span.end();
28453
+ this.deleteCompactionState(state);
28454
+ }
28455
+ findCompactionState(event) {
28456
+ const operationState = this.operationStateForEvent(event);
28457
+ for (const state of this.compactionsByScope.values()) {
28458
+ if (operationState && state.operationState === operationState) {
28459
+ return state;
28460
+ }
28461
+ }
28462
+ return void 0;
28463
+ }
28464
+ finishCompactionsForOperation(operationState) {
28465
+ for (const state of [...this.compactionsByScope.values()]) {
28466
+ if (state.operationState !== operationState) {
28467
+ continue;
28468
+ }
28469
+ safeLog3(state.span, {
28470
+ input: state.input,
28471
+ metadata: state.metadata,
28472
+ metrics: {
28473
+ ...buildDurationMetrics3(state.startTime)
28474
+ },
28475
+ output: { completed: true }
28476
+ });
28477
+ state.span.end();
28478
+ this.deleteCompactionState(state);
28479
+ }
28480
+ }
28481
+ deleteCompactionState(state) {
28482
+ for (const [key, candidate] of this.compactionsByScope) {
28483
+ if (candidate !== state) {
28484
+ continue;
28485
+ }
28486
+ this.compactionsByScope.delete(key);
28487
+ return;
28488
+ }
28489
+ }
28490
+ startSyntheticToolState(event, toolName) {
28491
+ const parent = this.parentSpanForEvent(event);
28492
+ const metadata = {
28493
+ ...extractEventMetadata(event),
28494
+ ...event.toolCallId ? { "flue.tool_call_id": event.toolCallId } : {},
28495
+ "flue.tool_name": toolName,
28496
+ provider: "flue"
28497
+ };
28498
+ const span = startFlueSpan(parent, {
28499
+ name: `tool: ${toolName}`,
28500
+ spanAttributes: { type: "tool" /* TOOL */ }
28501
+ });
28502
+ safeLog3(span, { metadata });
28503
+ return { metadata, span, startTime: getCurrentUnixTimestamp() };
28504
+ }
28505
+ operationStateForEvent(event) {
28506
+ if (event.operationId) {
28507
+ const operation = this.activeOperationsById.get(event.operationId) ?? this.promotePendingOperationForEvent(event);
28508
+ if (operation) {
28509
+ return operation;
28510
+ }
28511
+ }
28512
+ return this.activeOperationForEventScope(event) ?? this.pendingOperationForEventScope(event);
28513
+ }
28514
+ parentSpanForEvent(event) {
28515
+ if (event.operationId) {
28516
+ const operation = this.operationStateForEvent(event);
28517
+ if (operation) {
28518
+ return operation.span;
28519
+ }
28520
+ }
28521
+ if (event.taskId) {
28522
+ return this.tasksById.get(event.taskId)?.span;
28523
+ }
28524
+ return this.operationStateForEvent(event)?.span;
28525
+ }
28526
+ promotePendingOperationForEvent(event) {
28527
+ if (!event.operationId) {
28528
+ return void 0;
28529
+ }
28530
+ const scopePrefixes = operationScopePrefixes(event);
28531
+ for (const [candidateKey, candidateQueue] of this.pendingOperationsByKey) {
28532
+ if (!candidateQueue.length || !operationKeyMatchesScopes(candidateKey, scopePrefixes)) {
28533
+ continue;
28534
+ }
28535
+ const state = candidateQueue.shift();
28536
+ if (!state) {
28537
+ return void 0;
28538
+ }
28539
+ state.operationId = event.operationId;
28540
+ this.activeOperationsById.set(event.operationId, state);
28541
+ addScopedOperation(this.activeOperationsByScope, event, state);
28542
+ state.metadata = {
28543
+ ...state.metadata,
28544
+ ...extractEventMetadata(event),
28545
+ "flue.operation_id": event.operationId
28546
+ };
28547
+ safeLog3(state.span, { metadata: state.metadata });
28548
+ return state;
28549
+ }
28550
+ return void 0;
28551
+ }
28552
+ activeOperationForEventScope(event) {
28553
+ for (const scope of operationScopeNames(event)) {
28554
+ const operations = this.activeOperationsByScope.get(scope);
28555
+ if (operations?.length) {
28556
+ return operations[operations.length - 1];
28557
+ }
28558
+ }
28559
+ return void 0;
28560
+ }
28561
+ pendingOperationForEventScope(event) {
28562
+ const scopePrefixes = operationScopePrefixes(event);
28563
+ for (const [candidateKey, candidateQueue] of this.pendingOperationsByKey) {
28564
+ if (!candidateQueue.length || !operationKeyMatchesScopes(candidateKey, scopePrefixes)) {
28565
+ continue;
28566
+ }
28567
+ return candidateQueue[0];
28568
+ }
28569
+ return void 0;
28570
+ }
28571
+ takePendingOperationForEvent(event) {
28572
+ const key = operationKey(event.session, event.operationKind);
28573
+ const queue2 = this.pendingOperationsByKey.get(key);
28574
+ if (queue2?.length) {
28575
+ return queue2.shift();
28576
+ }
28577
+ for (const [candidateKey, candidateQueue] of this.pendingOperationsByKey) {
28578
+ if (candidateKey.endsWith(`::${event.operationKind}`) && candidateQueue.length) {
28579
+ return candidateQueue.shift();
28580
+ }
28581
+ }
28582
+ return void 0;
28583
+ }
28584
+ pendingOperationQueue(key) {
28585
+ const existing = this.pendingOperationsByKey.get(key);
28586
+ if (existing) {
28587
+ return existing;
28588
+ }
28589
+ const queue2 = [];
28590
+ this.pendingOperationsByKey.set(key, queue2);
28591
+ return queue2;
28592
+ }
28593
+ };
28594
+ function isInstrumentedOperation(operation) {
28595
+ return operation === "prompt" || operation === "skill" || operation === "task" || operation === "compact";
28596
+ }
28597
+ function getSessionName(session) {
28598
+ return typeof session?.name === "string" ? session.name : void 0;
28599
+ }
28600
+ function operationKey(sessionName, operation) {
28601
+ return `${sessionName ?? "unknown"}::${operation}`;
28602
+ }
28603
+ function operationScopePrefixes(event) {
28604
+ const scopes = /* @__PURE__ */ new Set();
28605
+ for (const scope of operationScopeNames(event)) {
28606
+ scopes.add(`${scope}::`);
28607
+ }
28608
+ return scopes;
28609
+ }
28610
+ function operationKeyMatchesScopes(key, scopes) {
28611
+ for (const scope of scopes) {
28612
+ if (key.startsWith(scope)) {
28613
+ return true;
28614
+ }
28615
+ }
28616
+ return false;
28617
+ }
28618
+ function operationScopeNames(event) {
28619
+ const scopes = /* @__PURE__ */ new Set();
28620
+ if (event.session) {
28621
+ scopes.add(event.session);
28622
+ }
28623
+ if (event.parentSession) {
28624
+ scopes.add(event.parentSession);
28625
+ }
28626
+ if (!scopes.size) {
28627
+ scopes.add("unknown");
28628
+ }
28629
+ return scopes;
28630
+ }
28631
+ function addScopedOperation(operationsByScope, event, state) {
28632
+ for (const scope of operationScopeNames(event)) {
28633
+ addOperationToScope(operationsByScope, scope, state);
28634
+ }
28635
+ }
28636
+ function addOperationToScope(operationsByScope, scope, state) {
28637
+ const operations = operationsByScope.get(scope);
28638
+ if (operations) {
28639
+ if (!operations.includes(state)) {
28640
+ operations.push(state);
28641
+ }
28642
+ } else {
28643
+ operationsByScope.set(scope, [state]);
28644
+ }
28645
+ }
28646
+ function removeScopedOperation(operationsByScope, state) {
28647
+ for (const [scope, operations] of operationsByScope) {
28648
+ const index = operations.indexOf(state);
28649
+ if (index === -1) {
28650
+ continue;
28651
+ }
28652
+ operations.splice(index, 1);
28653
+ if (operations.length === 0) {
28654
+ operationsByScope.delete(scope);
28655
+ }
28656
+ }
28657
+ }
28658
+ function removePendingOperation(pendingOperationsByKey, state) {
28659
+ for (const [key, queue2] of pendingOperationsByKey) {
28660
+ const index = queue2.indexOf(state);
28661
+ if (index === -1) {
28662
+ continue;
28663
+ }
28664
+ queue2.splice(index, 1);
28665
+ if (queue2.length === 0) {
28666
+ pendingOperationsByKey.delete(key);
28667
+ }
28668
+ return;
28669
+ }
28670
+ }
28671
+ function extractSessionMetadata(session) {
28672
+ const sessionName = getSessionName(session);
28673
+ return sessionName ? { "flue.session": sessionName } : {};
28674
+ }
28675
+ function extractEventMetadata(event) {
28676
+ return {
28677
+ ...event.runId ? { "flue.run_id": event.runId } : {},
28678
+ ...typeof event.eventIndex === "number" ? { "flue.event_index": event.eventIndex } : {},
28679
+ ...event.session ? { "flue.session": event.session } : {},
28680
+ ...event.parentSession ? { "flue.parent_session": event.parentSession } : {},
28681
+ ...event.harness ? { "flue.harness": event.harness } : {},
28682
+ ...event.taskId ? { "flue.task_id": event.taskId } : {},
28683
+ ...event.operationId ? { "flue.operation_id": event.operationId } : {}
28684
+ };
28685
+ }
28686
+ function extractOperationInput(operation, args) {
28687
+ switch (operation) {
28688
+ case "prompt":
28689
+ case "task":
28690
+ return args[0];
28691
+ case "skill":
28692
+ return {
28693
+ args: getOptionObject(args[1])?.args,
28694
+ name: args[0]
28695
+ };
28696
+ case "compact":
28697
+ return void 0;
28698
+ }
28699
+ }
28700
+ function extractOperationInputMetadata(operation, args) {
28701
+ const options = getOptionObject(args[1]);
28702
+ return {
28703
+ ...operation === "skill" && typeof args[0] === "string" ? { "flue.skill_name": args[0] } : {},
28704
+ ...options?.model ? { model: options.model, "flue.model": options.model } : {},
28705
+ ...options?.role ? { "flue.role": options.role } : {},
28706
+ ...options?.thinkingLevel ? { "flue.thinking_level": options.thinkingLevel } : {},
28707
+ ...typeof options?.cwd === "string" ? { "flue.cwd": options.cwd } : {},
28708
+ ...Array.isArray(options?.tools) ? {
28709
+ "flue.tools_count": options.tools.length,
28710
+ tools: summarizeTools(options.tools)
28711
+ } : {},
28712
+ ...Array.isArray(options?.images) ? { "flue.images_count": options.images.length } : {},
28713
+ ...options?.result || options?.schema ? { "flue.result_schema": true } : {}
28714
+ };
28715
+ }
28716
+ function getOptionObject(value) {
28717
+ return isObject(value) ? value : void 0;
28718
+ }
28719
+ function summarizeTools(tools) {
28720
+ return tools.flatMap((tool) => {
28721
+ if (!isObject(tool)) {
28722
+ return [];
28723
+ }
28724
+ const name = typeof tool.name === "string" ? tool.name : void 0;
28725
+ if (!name) {
28726
+ return [];
28727
+ }
28728
+ return [
28729
+ {
28730
+ function: {
28731
+ description: typeof tool.description === "string" ? tool.description : void 0,
28732
+ name,
28733
+ parameters: tool.parameters
28734
+ },
28735
+ type: "function"
28736
+ }
28737
+ ];
28738
+ });
28739
+ }
28740
+ function extractPromptResponseMetadata(result) {
28741
+ const modelId = result?.model && typeof result.model.id === "string" ? result.model.id : void 0;
28742
+ return modelId ? {
28743
+ model: modelId,
28744
+ "flue.model": modelId
28745
+ } : {};
28746
+ }
28747
+ function extractOperationOutput(result) {
28748
+ if (!result) {
28749
+ return void 0;
28750
+ }
28751
+ if ("data" in result) {
28752
+ return result.data;
28753
+ }
28754
+ if ("text" in result) {
28755
+ return result.text;
28756
+ }
28757
+ return result;
28758
+ }
28759
+ function metricsFromUsage(usage) {
28760
+ return {
28761
+ ...typeof usage?.input === "number" ? { prompt_tokens: usage.input } : {},
28762
+ ...typeof usage?.output === "number" ? { completion_tokens: usage.output } : {},
28763
+ ...typeof usage?.cacheRead === "number" ? { prompt_cached_tokens: usage.cacheRead } : {},
28764
+ ...typeof usage?.cacheWrite === "number" ? { prompt_cache_creation_tokens: usage.cacheWrite } : {},
28765
+ ...typeof usage?.totalTokens === "number" ? { tokens: usage.totalTokens } : {},
28766
+ ...typeof usage?.cost?.total === "number" ? { estimated_cost: usage.cost.total } : {}
28767
+ };
28768
+ }
28769
+ function buildDurationMetrics3(startTime) {
28770
+ return {
28771
+ duration_ms: Math.max(0, (getCurrentUnixTimestamp() - startTime) * 1e3)
28772
+ };
28773
+ }
28774
+ function durationMsMetrics(durationMs) {
28775
+ return typeof durationMs === "number" ? { duration_ms: durationMs } : {};
28776
+ }
28777
+ function scopeKey(event) {
28778
+ if (event.operationId) {
28779
+ return `operation:${event.operationId}`;
28780
+ }
28781
+ if (event.taskId) {
28782
+ return `task:${event.taskId}`;
28783
+ }
28784
+ if (event.session) {
28785
+ return `session:${event.session}`;
28786
+ }
28787
+ return "flue:unknown";
28788
+ }
28789
+ function toolKey(event) {
28790
+ return `${scopeKey(event)}::tool:${event.toolCallId ?? "unknown"}`;
28791
+ }
28792
+ function toAssistantOutput(text, finishReason, reasoning, toolCalls) {
28793
+ return [
28794
+ {
28795
+ finish_reason: finishReason ?? "stop",
28796
+ index: 0,
28797
+ message: {
28798
+ content: text,
28799
+ ...reasoning ? { reasoning } : {},
28800
+ role: "assistant",
28801
+ ...toolCalls?.length ? {
28802
+ tool_calls: toolCalls.map((toolCall) => ({
28803
+ function: {
28804
+ arguments: toolCall.args === void 0 ? "{}" : JSON.stringify(toolCall.args),
28805
+ name: toolCall.toolName ?? "unknown"
28806
+ },
28807
+ ...toolCall.toolCallId ? { id: toolCall.toolCallId } : {},
28808
+ type: "function"
28809
+ }))
28810
+ } : {}
28811
+ }
28812
+ }
28813
+ ];
28814
+ }
28815
+ function startFlueSpan(parent, args) {
28816
+ return parent ? withCurrent(parent, () => startSpan(args)) : startSpan(args);
28817
+ }
28818
+ function safeLog3(span, event) {
28819
+ try {
28820
+ span.log(event);
28821
+ } catch (error2) {
28822
+ logInstrumentationError3("Flue span log", error2);
28823
+ }
28824
+ }
28825
+ function errorToString(error2) {
28826
+ if (error2 instanceof Error) {
28827
+ return error2.message;
28828
+ }
28829
+ if (typeof error2 === "string") {
28830
+ return error2;
28831
+ }
28832
+ try {
28833
+ return JSON.stringify(error2);
28834
+ } catch {
28835
+ return String(error2);
28836
+ }
28837
+ }
28838
+ function logInstrumentationError3(label, error2) {
28839
+ console.error(`Error in ${label} instrumentation:`, error2);
28840
+ }
28841
+
28842
+ // src/wrappers/langchain/callback-handler.ts
28843
+ var BRAINTRUST_LANGCHAIN_CALLBACK_HANDLER_NAME = "BraintrustCallbackHandler";
28844
+ var BraintrustLangChainCallbackHandler = class {
28845
+ name = BRAINTRUST_LANGCHAIN_CALLBACK_HANDLER_NAME;
28846
+ spans = /* @__PURE__ */ new Map();
28847
+ skippedRuns = /* @__PURE__ */ new Set();
28848
+ parent;
28849
+ rootRunId;
28850
+ options;
28851
+ startTimes = /* @__PURE__ */ new Map();
28852
+ firstTokenTimes = /* @__PURE__ */ new Map();
28853
+ ttftMs = /* @__PURE__ */ new Map();
28854
+ constructor(options) {
28855
+ this.parent = options?.parent;
28856
+ this.options = {
28857
+ debug: options?.debug ?? false,
28858
+ excludeMetadataProps: options?.excludeMetadataProps ?? /^(l[sc]_|langgraph_|__pregel_|checkpoint_ns)/,
28859
+ logger: options?.logger
28860
+ };
28861
+ }
28862
+ startSpan({
28863
+ runId,
28864
+ parentRunId,
28865
+ ...args
28866
+ }) {
28867
+ if (this.spans.has(runId)) {
28868
+ return;
28869
+ }
28870
+ if (!parentRunId) {
28871
+ this.rootRunId = runId;
28872
+ }
28873
+ const tags = args.event?.tags;
28874
+ const spanAttributes = args.spanAttributes || {};
28875
+ spanAttributes.type = args.type || spanAttributes.type || "task";
28876
+ args.type = spanAttributes.type;
28877
+ const currentParent = (typeof this.parent === "function" ? this.parent() : this.parent) ?? currentSpan();
28878
+ let parentSpan;
28879
+ if (parentRunId && this.spans.has(parentRunId)) {
28880
+ parentSpan = this.spans.get(parentRunId);
28881
+ } else if (!Object.is(currentParent, NOOP_SPAN)) {
28882
+ parentSpan = currentParent;
28883
+ } else if (this.options.logger) {
28884
+ parentSpan = this.options.logger;
28885
+ } else {
28886
+ parentSpan = { startSpan };
28887
+ }
28888
+ args.event = {
28889
+ ...args.event,
28890
+ tags: void 0,
28891
+ metadata: {
28892
+ ...tags ? { tags } : {},
28893
+ ...args.event?.metadata,
28894
+ braintrust: {
28895
+ integration_name: "langchain-js",
28896
+ sdk_language: "javascript"
28897
+ },
28898
+ run_id: runId,
28899
+ parent_run_id: parentRunId,
28900
+ ...this.options.debug ? { runId, parentRunId } : {}
28901
+ }
28902
+ };
28903
+ let span = parentSpan.startSpan(args);
28904
+ if (!Object.is(this.options.logger, NOOP_SPAN) && Object.is(span, NOOP_SPAN)) {
28905
+ span = initLogger().startSpan(args);
28906
+ }
28907
+ this.spans.set(runId, span);
28908
+ }
28909
+ endSpan({
28910
+ runId,
28911
+ parentRunId,
28912
+ tags,
28913
+ metadata,
28914
+ ...args
28915
+ }) {
28916
+ if (!this.spans.has(runId)) {
28917
+ return;
28918
+ }
28919
+ if (this.skippedRuns.has(runId)) {
28920
+ this.skippedRuns.delete(runId);
28921
+ return;
28922
+ }
28923
+ const span = this.spans.get(runId);
28924
+ this.spans.delete(runId);
28925
+ if (runId === this.rootRunId) {
28926
+ this.rootRunId = void 0;
28927
+ }
28928
+ span.log({ ...args, metadata: { tags, ...metadata } });
28929
+ span.end();
28930
+ }
28931
+ async handleLLMStart(llm, prompts, runId, parentRunId, extraParams, tags, metadata, runName) {
28932
+ this.startSpan({
28933
+ runId,
28934
+ parentRunId,
28935
+ name: runName ?? getSerializedName(llm) ?? "LLM",
28936
+ type: "llm",
28937
+ event: {
28938
+ input: prompts,
28939
+ tags,
28940
+ metadata: {
28941
+ serialized: llm,
28942
+ name: runName,
28943
+ metadata,
28944
+ ...extraParams
28945
+ }
28946
+ }
28947
+ });
28948
+ }
28949
+ async handleLLMError(err, runId, parentRunId, tags) {
28950
+ this.endSpan({ runId, parentRunId, error: err, tags });
28951
+ }
28952
+ async handleLLMEnd(output, runId, parentRunId, tags) {
28953
+ const metrics = getMetricsFromResponse(output);
28954
+ const modelName2 = getModelNameFromResponse(output);
28955
+ const ttft = this.ttftMs.get(runId);
28956
+ if (ttft !== void 0) {
28957
+ metrics.time_to_first_token = ttft;
28958
+ }
28959
+ this.startTimes.delete(runId);
28960
+ this.firstTokenTimes.delete(runId);
28961
+ this.ttftMs.delete(runId);
28962
+ this.endSpan({
28963
+ runId,
28964
+ parentRunId,
28965
+ output,
28966
+ metrics,
28967
+ tags,
28968
+ metadata: {
28969
+ model: modelName2
28970
+ }
28971
+ });
28972
+ }
28973
+ async handleChatModelStart(llm, messages, runId, parentRunId, extraParams, tags, metadata, runName) {
28974
+ this.startTimes.set(runId, Date.now());
28975
+ this.firstTokenTimes.delete(runId);
28976
+ this.ttftMs.delete(runId);
28977
+ this.startSpan({
28978
+ runId,
28979
+ parentRunId,
28980
+ name: runName ?? getSerializedName(llm) ?? "Chat Model",
28981
+ type: "llm",
28982
+ event: {
28983
+ input: messages,
28984
+ tags,
28985
+ metadata: {
28986
+ serialized: llm,
28987
+ name: runName,
28988
+ metadata,
28989
+ ...extraParams
28990
+ }
28991
+ }
28992
+ });
28993
+ }
28994
+ async handleChainStart(chain, inputs, runId, parentRunId, tags, metadata, runType, runName) {
28995
+ if (tags?.includes("langsmith:hidden")) {
28996
+ this.skippedRuns.add(runId);
28997
+ return;
28998
+ }
28999
+ this.startSpan({
29000
+ runId,
29001
+ parentRunId,
29002
+ name: runName ?? getSerializedName(chain) ?? "Chain",
29003
+ event: {
29004
+ input: inputs,
29005
+ tags,
29006
+ metadata: {
29007
+ serialized: chain,
29008
+ name: runName,
29009
+ metadata,
29010
+ run_type: runType
29011
+ }
29012
+ }
29013
+ });
29014
+ }
29015
+ async handleChainError(err, runId, parentRunId, tags, kwargs) {
29016
+ this.endSpan({ runId, parentRunId, error: err, tags, metadata: kwargs });
29017
+ }
29018
+ async handleChainEnd(outputs, runId, parentRunId, tags, kwargs) {
29019
+ this.endSpan({
29020
+ runId,
29021
+ parentRunId,
29022
+ tags,
29023
+ output: outputs,
29024
+ metadata: { ...kwargs }
29025
+ });
29026
+ }
29027
+ async handleToolStart(tool, input, runId, parentRunId, tags, metadata, runName) {
29028
+ this.startSpan({
29029
+ runId,
29030
+ parentRunId,
29031
+ name: runName ?? getSerializedName(tool) ?? "Tool",
29032
+ type: "llm",
29033
+ event: {
29034
+ input: safeJsonParse(input),
29035
+ tags,
29036
+ metadata: {
29037
+ metadata,
29038
+ serialized: tool,
29039
+ input_str: input,
29040
+ input: safeJsonParse(input),
29041
+ name: runName
29042
+ }
29043
+ }
29044
+ });
29045
+ }
29046
+ async handleToolError(err, runId, parentRunId, tags) {
29047
+ this.endSpan({ runId, parentRunId, error: err, tags });
29048
+ }
29049
+ async handleToolEnd(output, runId, parentRunId, tags) {
29050
+ this.endSpan({ runId, parentRunId, output, tags });
29051
+ }
29052
+ async handleAgentAction(action, runId, parentRunId, tags) {
29053
+ this.startSpan({
29054
+ runId,
29055
+ parentRunId,
29056
+ type: "llm",
29057
+ name: typeof action.tool === "string" ? action.tool : "Agent",
29058
+ event: {
29059
+ input: action,
29060
+ tags
29061
+ }
29062
+ });
29063
+ }
29064
+ async handleAgentEnd(action, runId, parentRunId, tags) {
29065
+ this.endSpan({ runId, parentRunId, output: action, tags });
29066
+ }
29067
+ async handleRetrieverStart(retriever, query, runId, parentRunId, tags, metadata, name) {
29068
+ this.startSpan({
29069
+ runId,
29070
+ parentRunId,
29071
+ name: name ?? getSerializedName(retriever) ?? "Retriever",
29072
+ type: "function",
29073
+ event: {
29074
+ input: query,
29075
+ tags,
29076
+ metadata: {
29077
+ serialized: retriever,
29078
+ metadata,
29079
+ name
29080
+ }
29081
+ }
29082
+ });
29083
+ }
29084
+ async handleRetrieverEnd(documents, runId, parentRunId, tags) {
29085
+ this.endSpan({ runId, parentRunId, output: documents, tags });
29086
+ }
29087
+ async handleRetrieverError(err, runId, parentRunId, tags) {
29088
+ this.endSpan({ runId, parentRunId, error: err, tags });
29089
+ }
29090
+ async handleLLMNewToken(_token, _idx, runId, _parentRunId, _tags) {
29091
+ if (!this.firstTokenTimes.has(runId)) {
29092
+ const now2 = Date.now();
29093
+ this.firstTokenTimes.set(runId, now2);
29094
+ const start = this.startTimes.get(runId);
29095
+ if (start !== void 0) {
29096
+ this.ttftMs.set(runId, (now2 - start) / 1e3);
29097
+ }
29098
+ }
29099
+ }
29100
+ };
29101
+ function getSerializedName(serialized) {
29102
+ if (typeof serialized.name === "string") {
29103
+ return serialized.name;
29104
+ }
29105
+ const lastIdPart = serialized.id?.at(-1);
29106
+ return typeof lastIdPart === "string" ? lastIdPart : void 0;
29107
+ }
29108
+ function cleanObject(obj) {
29109
+ return Object.fromEntries(
29110
+ Object.entries(obj).filter(([, value]) => {
29111
+ if (typeof value !== "number") {
29112
+ return false;
29113
+ }
29114
+ return Number.isFinite(value);
29115
+ })
29116
+ );
29117
+ }
29118
+ function walkGenerations(response) {
29119
+ const result = [];
29120
+ const generations = response.generations || [];
29121
+ for (const batch of generations) {
29122
+ if (Array.isArray(batch)) {
29123
+ for (const generation of batch) {
29124
+ if (isRecord(generation)) {
29125
+ result.push(generation);
29126
+ }
29127
+ }
29128
+ } else if (isRecord(batch)) {
29129
+ result.push(batch);
29130
+ }
29131
+ }
29132
+ return result;
29133
+ }
29134
+ function getModelNameFromResponse(response) {
29135
+ for (const generation of walkGenerations(response)) {
29136
+ const message = generation.message;
29137
+ if (!isRecord(message)) {
29138
+ continue;
29139
+ }
29140
+ const responseMetadata = message.response_metadata;
29141
+ if (!isRecord(responseMetadata)) {
29142
+ continue;
29143
+ }
29144
+ const modelName3 = responseMetadata.model_name ?? responseMetadata.model;
29145
+ if (typeof modelName3 === "string") {
29146
+ return modelName3;
29147
+ }
29148
+ }
29149
+ const llmOutput = response.llmOutput || {};
29150
+ const modelName2 = llmOutput.model_name ?? llmOutput.model;
29151
+ return typeof modelName2 === "string" ? modelName2 : void 0;
29152
+ }
29153
+ function getMetricsFromResponse(response) {
29154
+ for (const generation of walkGenerations(response)) {
29155
+ const message = generation.message;
29156
+ if (!isRecord(message)) {
29157
+ continue;
29158
+ }
29159
+ const usageMetadata = message.usage_metadata;
29160
+ if (!isRecord(usageMetadata)) {
29161
+ continue;
29162
+ }
29163
+ const inputTokenDetails = usageMetadata.input_token_details;
29164
+ return cleanObject({
29165
+ total_tokens: usageMetadata.total_tokens,
29166
+ prompt_tokens: usageMetadata.input_tokens,
29167
+ completion_tokens: usageMetadata.output_tokens,
29168
+ prompt_cache_creation_tokens: isRecord(inputTokenDetails) ? inputTokenDetails.cache_creation : void 0,
29169
+ prompt_cached_tokens: isRecord(inputTokenDetails) ? inputTokenDetails.cache_read : void 0
29170
+ });
29171
+ }
29172
+ const llmOutput = response.llmOutput || {};
29173
+ const tokenUsage = isRecord(llmOutput.tokenUsage) ? llmOutput.tokenUsage : isRecord(llmOutput.estimatedTokens) ? llmOutput.estimatedTokens : {};
29174
+ return cleanObject({
29175
+ total_tokens: tokenUsage.totalTokens,
29176
+ prompt_tokens: tokenUsage.promptTokens,
29177
+ completion_tokens: tokenUsage.completionTokens
29178
+ });
29179
+ }
29180
+ function safeJsonParse(input) {
29181
+ try {
29182
+ return JSON.parse(input);
29183
+ } catch {
29184
+ return input;
29185
+ }
29186
+ }
29187
+ function isRecord(value) {
29188
+ return typeof value === "object" && value !== null && !Array.isArray(value);
29189
+ }
29190
+
29191
+ // src/instrumentation/plugins/langchain-channels.ts
29192
+ var langChainChannels = defineChannels("@langchain/core", {
29193
+ configure: channel({
29194
+ channelName: "CallbackManager.configure",
29195
+ kind: "sync-stream"
29196
+ }),
29197
+ configureSync: channel({
29198
+ channelName: "CallbackManager._configureSync",
29199
+ kind: "sync-stream"
29200
+ })
29201
+ });
29202
+
29203
+ // src/instrumentation/plugins/langchain-plugin.ts
29204
+ var LangChainPlugin = class extends BasePlugin {
29205
+ injectedManagers = /* @__PURE__ */ new WeakSet();
29206
+ onEnable() {
29207
+ this.subscribeToConfigure(langChainChannels.configure);
29208
+ this.subscribeToConfigure(langChainChannels.configureSync);
29209
+ }
29210
+ onDisable() {
29211
+ for (const unsubscribe of this.unsubscribers) {
29212
+ unsubscribe();
29213
+ }
29214
+ this.unsubscribers = [];
29215
+ this.injectedManagers = /* @__PURE__ */ new WeakSet();
29216
+ }
29217
+ subscribeToConfigure(channel2) {
29218
+ const tracingChannel2 = channel2.tracingChannel();
29219
+ const handlers = {
29220
+ start: (event) => {
29221
+ injectHandlerIntoArguments(event.arguments);
29222
+ },
29223
+ end: (event) => {
29224
+ this.injectHandler(event.result);
29225
+ }
29226
+ };
29227
+ tracingChannel2.subscribe(handlers);
29228
+ this.unsubscribers.push(() => {
29229
+ tracingChannel2.unsubscribe(handlers);
29230
+ });
29231
+ }
29232
+ injectHandler(result) {
29233
+ if (!isCallbackManager(result)) {
29234
+ return;
29235
+ }
29236
+ if (this.injectedManagers.has(result) || hasBraintrustHandler(result)) {
29237
+ return;
29238
+ }
29239
+ try {
29240
+ result.addHandler(new BraintrustLangChainCallbackHandler(), true);
29241
+ this.injectedManagers.add(result);
29242
+ } catch {
29243
+ }
29244
+ }
29245
+ };
29246
+ function isCallbackManager(value) {
29247
+ if (typeof value !== "object" || value === null) {
29248
+ return false;
29249
+ }
29250
+ const maybeManager = value;
29251
+ return typeof maybeManager.addHandler === "function";
29252
+ }
29253
+ function hasBraintrustHandler(manager) {
29254
+ return manager.handlers?.some((handler) => {
29255
+ if (typeof handler !== "object" || handler === null) {
29256
+ return false;
29257
+ }
29258
+ const name = Reflect.get(handler, "name");
29259
+ return name === BRAINTRUST_LANGCHAIN_CALLBACK_HANDLER_NAME;
29260
+ }) ?? false;
29261
+ }
29262
+ function injectHandlerIntoArguments(args) {
29263
+ if (!isWritableArgumentsObject(args)) {
29264
+ return;
29265
+ }
29266
+ const inheritedHandlers = Reflect.get(args, "0");
29267
+ const handler = new BraintrustLangChainCallbackHandler();
29268
+ if (inheritedHandlers === void 0 || inheritedHandlers === null) {
29269
+ Reflect.set(args, "0", [handler]);
29270
+ return;
29271
+ }
29272
+ if (Array.isArray(inheritedHandlers)) {
29273
+ if (!inheritedHandlers.some(isBraintrustHandler)) {
29274
+ inheritedHandlers.push(handler);
29275
+ }
29276
+ }
29277
+ }
29278
+ function isWritableArgumentsObject(args) {
29279
+ return typeof args === "object" && args !== null;
29280
+ }
29281
+ function isBraintrustHandler(handler) {
29282
+ if (typeof handler !== "object" || handler === null) {
29283
+ return false;
29284
+ }
29285
+ return Reflect.get(handler, "name") === BRAINTRUST_LANGCHAIN_CALLBACK_HANDLER_NAME;
29286
+ }
29287
+
29288
+ // src/instrumentation/braintrust-plugin.ts
29289
+ function getIntegrationConfig(integrations, key) {
29290
+ return integrations[key];
29291
+ }
29292
+ var BraintrustPlugin = class extends BasePlugin {
29293
+ config;
29294
+ openaiPlugin = null;
29295
+ openAICodexPlugin = null;
29296
+ anthropicPlugin = null;
29297
+ aiSDKPlugin = null;
29298
+ claudeAgentSDKPlugin = null;
29299
+ cursorSDKPlugin = null;
29300
+ openAIAgentsPlugin = null;
29301
+ googleGenAIPlugin = null;
29302
+ huggingFacePlugin = null;
29303
+ openRouterPlugin = null;
29304
+ openRouterAgentPlugin = null;
29305
+ mistralPlugin = null;
29306
+ googleADKPlugin = null;
29307
+ coherePlugin = null;
29308
+ groqPlugin = null;
29309
+ genkitPlugin = null;
29310
+ gitHubCopilotPlugin = null;
29311
+ fluePlugin = null;
29312
+ langChainPlugin = null;
29313
+ constructor(config3 = {}) {
29314
+ super();
29315
+ this.config = config3;
29316
+ }
29317
+ onEnable() {
27084
29318
  const integrations = this.config.integrations || {};
27085
29319
  if (integrations.openai !== false) {
27086
29320
  this.openaiPlugin = new OpenAIPlugin();
@@ -27106,6 +29340,10 @@ var BraintrustPlugin = class extends BasePlugin {
27106
29340
  this.cursorSDKPlugin = new CursorSDKPlugin();
27107
29341
  this.cursorSDKPlugin.enable();
27108
29342
  }
29343
+ if (integrations.openAIAgents !== false) {
29344
+ this.openAIAgentsPlugin = new OpenAIAgentsPlugin();
29345
+ this.openAIAgentsPlugin.enable();
29346
+ }
27109
29347
  if (integrations.googleGenAI !== false && integrations.google !== false) {
27110
29348
  this.googleGenAIPlugin = new GoogleGenAIPlugin();
27111
29349
  this.googleGenAIPlugin.enable();
@@ -27146,6 +29384,14 @@ var BraintrustPlugin = class extends BasePlugin {
27146
29384
  this.gitHubCopilotPlugin = new GitHubCopilotPlugin();
27147
29385
  this.gitHubCopilotPlugin.enable();
27148
29386
  }
29387
+ if (getIntegrationConfig(integrations, "flue") !== false) {
29388
+ this.fluePlugin = new FluePlugin();
29389
+ this.fluePlugin.enable();
29390
+ }
29391
+ if (integrations.langchain !== false && integrations.langgraph !== false) {
29392
+ this.langChainPlugin = new LangChainPlugin();
29393
+ this.langChainPlugin.enable();
29394
+ }
27149
29395
  }
27150
29396
  onDisable() {
27151
29397
  if (this.openaiPlugin) {
@@ -27172,6 +29418,10 @@ var BraintrustPlugin = class extends BasePlugin {
27172
29418
  this.cursorSDKPlugin.disable();
27173
29419
  this.cursorSDKPlugin = null;
27174
29420
  }
29421
+ if (this.openAIAgentsPlugin) {
29422
+ this.openAIAgentsPlugin.disable();
29423
+ this.openAIAgentsPlugin = null;
29424
+ }
27175
29425
  if (this.googleGenAIPlugin) {
27176
29426
  this.googleGenAIPlugin.disable();
27177
29427
  this.googleGenAIPlugin = null;
@@ -27212,9 +29462,104 @@ var BraintrustPlugin = class extends BasePlugin {
27212
29462
  this.gitHubCopilotPlugin.disable();
27213
29463
  this.gitHubCopilotPlugin = null;
27214
29464
  }
29465
+ if (this.fluePlugin) {
29466
+ this.fluePlugin.disable();
29467
+ this.fluePlugin = null;
29468
+ }
29469
+ if (this.langChainPlugin) {
29470
+ this.langChainPlugin.disable();
29471
+ this.langChainPlugin = null;
29472
+ }
27215
29473
  }
27216
29474
  };
27217
29475
 
29476
+ // src/instrumentation/config.ts
29477
+ var envIntegrationAliases = {
29478
+ openai: "openai",
29479
+ "openai-codex": "openaiCodexSDK",
29480
+ "openai-codex-sdk": "openaiCodexSDK",
29481
+ openaicodexsdk: "openaiCodexSDK",
29482
+ codex: "openaiCodexSDK",
29483
+ "codex-sdk": "openaiCodexSDK",
29484
+ anthropic: "anthropic",
29485
+ aisdk: "aisdk",
29486
+ "ai-sdk": "aisdk",
29487
+ "vercel-ai": "aisdk",
29488
+ vercel: "vercel",
29489
+ claudeagentsdk: "claudeAgentSDK",
29490
+ "claude-agent-sdk": "claudeAgentSDK",
29491
+ cursor: "cursor",
29492
+ "cursor-sdk": "cursorSDK",
29493
+ cursorsdk: "cursorSDK",
29494
+ flue: "flue",
29495
+ "flue-runtime": "flue",
29496
+ "openai-agents": "openAIAgents",
29497
+ openaiagents: "openAIAgents",
29498
+ "openai-agents-core": "openAIAgents",
29499
+ openaiagentscore: "openAIAgents",
29500
+ google: "google",
29501
+ "google-genai": "googleGenAI",
29502
+ googlegenai: "googleGenAI",
29503
+ huggingface: "huggingface",
29504
+ openrouter: "openrouter",
29505
+ openrouteragent: "openrouterAgent",
29506
+ "openrouter-agent": "openrouterAgent",
29507
+ mistral: "mistral",
29508
+ googleadk: "googleADK",
29509
+ "google-adk": "googleADK",
29510
+ cohere: "cohere",
29511
+ groq: "groq",
29512
+ "groq-sdk": "groq",
29513
+ genkit: "genkit",
29514
+ "firebase-genkit": "genkit",
29515
+ githubcopilot: "gitHubCopilot",
29516
+ "github-copilot": "gitHubCopilot",
29517
+ "copilot-sdk": "gitHubCopilot",
29518
+ langchain: "langchain",
29519
+ "langchain-js": "langchain",
29520
+ "@langchain": "langchain",
29521
+ langgraph: "langgraph"
29522
+ };
29523
+ function getDefaultInstrumentationIntegrations() {
29524
+ return {
29525
+ openai: true,
29526
+ openaiCodexSDK: true,
29527
+ anthropic: true,
29528
+ vercel: true,
29529
+ aisdk: true,
29530
+ google: true,
29531
+ googleGenAI: true,
29532
+ googleADK: true,
29533
+ huggingface: true,
29534
+ claudeAgentSDK: true,
29535
+ cursor: true,
29536
+ cursorSDK: true,
29537
+ flue: true,
29538
+ openAIAgents: true,
29539
+ openrouter: true,
29540
+ openrouterAgent: true,
29541
+ mistral: true,
29542
+ cohere: true,
29543
+ groq: true,
29544
+ genkit: true,
29545
+ gitHubCopilot: true,
29546
+ langchain: true,
29547
+ langgraph: true
29548
+ };
29549
+ }
29550
+ function readDisabledInstrumentationEnvConfig(disabledList) {
29551
+ const integrations = {};
29552
+ if (disabledList) {
29553
+ for (const value of disabledList.split(",")) {
29554
+ const sdk = value.trim().toLowerCase();
29555
+ if (sdk.length > 0) {
29556
+ integrations[envIntegrationAliases[sdk] ?? sdk] = false;
29557
+ }
29558
+ }
29559
+ }
29560
+ return { integrations };
29561
+ }
29562
+
27218
29563
  // src/instrumentation/registry.ts
27219
29564
  var REGISTRY_STATE_KEY = /* @__PURE__ */ Symbol.for("braintrust.registry");
27220
29565
  function getSharedState() {
@@ -27293,50 +29638,16 @@ var PluginRegistry = class {
27293
29638
  * Get default configuration (all integrations enabled).
27294
29639
  */
27295
29640
  getDefaultConfig() {
27296
- return {
27297
- openai: true,
27298
- openaiCodexSDK: true,
27299
- anthropic: true,
27300
- vercel: true,
27301
- aisdk: true,
27302
- google: true,
27303
- googleGenAI: true,
27304
- googleADK: true,
27305
- huggingface: true,
27306
- claudeAgentSDK: true,
27307
- cursor: true,
27308
- cursorSDK: true,
27309
- openrouter: true,
27310
- openrouterAgent: true,
27311
- mistral: true,
27312
- cohere: true,
27313
- groq: true,
27314
- genkit: true,
27315
- gitHubCopilot: true
27316
- };
29641
+ return getDefaultInstrumentationIntegrations();
27317
29642
  }
27318
29643
  /**
27319
29644
  * Read configuration from environment variables.
27320
29645
  * Supports: BRAINTRUST_DISABLE_INSTRUMENTATION=openai,anthropic,...
27321
29646
  */
27322
29647
  readEnvConfig() {
27323
- const integrations = {};
27324
- const disabledList = isomorph_default.getEnv("BRAINTRUST_DISABLE_INSTRUMENTATION");
27325
- if (disabledList) {
27326
- const disabled = disabledList.split(",").map((s) => s.trim().toLowerCase()).filter((s) => s.length > 0);
27327
- for (const sdk of disabled) {
27328
- if (sdk === "cursor-sdk") {
27329
- integrations.cursorSDK = false;
27330
- } else if (sdk === "githubcopilot" || sdk === "github-copilot" || sdk === "copilot-sdk") {
27331
- integrations.gitHubCopilot = false;
27332
- } else if (sdk === "openai-codex-sdk") {
27333
- integrations.openaiCodexSDK = false;
27334
- } else {
27335
- integrations[sdk] = false;
27336
- }
27337
- }
27338
- }
27339
- return { integrations };
29648
+ return readDisabledInstrumentationEnvConfig(
29649
+ isomorph_default.getEnv("BRAINTRUST_DISABLE_INSTRUMENTATION")
29650
+ );
27340
29651
  }
27341
29652
  };
27342
29653
  var registry = new PluginRegistry();