braintrust 3.11.0 → 3.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/README.md +8 -8
  2. package/dev/dist/index.d.mts +26 -7
  3. package/dev/dist/index.d.ts +26 -7
  4. package/dev/dist/index.js +2717 -335
  5. package/dev/dist/index.mjs +2499 -117
  6. package/dist/apply-auto-instrumentation.browser.d.mts +2 -0
  7. package/dist/apply-auto-instrumentation.browser.d.ts +2 -0
  8. package/dist/apply-auto-instrumentation.browser.js +18 -0
  9. package/dist/apply-auto-instrumentation.browser.mjs +0 -0
  10. package/dist/apply-auto-instrumentation.d.mts +2 -0
  11. package/dist/apply-auto-instrumentation.d.ts +2 -0
  12. package/dist/apply-auto-instrumentation.js +2534 -0
  13. package/dist/apply-auto-instrumentation.mjs +2534 -0
  14. package/dist/auto-instrumentations/bundler/esbuild.cjs +1803 -1283
  15. package/dist/auto-instrumentations/bundler/esbuild.d.mts +9 -5
  16. package/dist/auto-instrumentations/bundler/esbuild.d.ts +9 -5
  17. package/dist/auto-instrumentations/bundler/esbuild.mjs +10 -2
  18. package/dist/auto-instrumentations/bundler/next.cjs +3269 -0
  19. package/dist/auto-instrumentations/bundler/next.d.mts +3 -0
  20. package/dist/auto-instrumentations/bundler/next.d.ts +3 -0
  21. package/dist/auto-instrumentations/bundler/next.mjs +189 -0
  22. package/dist/auto-instrumentations/bundler/rollup.cjs +1803 -1283
  23. package/dist/auto-instrumentations/bundler/rollup.d.mts +9 -5
  24. package/dist/auto-instrumentations/bundler/rollup.d.ts +9 -5
  25. package/dist/auto-instrumentations/bundler/rollup.mjs +10 -2
  26. package/dist/auto-instrumentations/bundler/vite.cjs +1803 -1283
  27. package/dist/auto-instrumentations/bundler/vite.d.mts +9 -5
  28. package/dist/auto-instrumentations/bundler/vite.d.ts +9 -5
  29. package/dist/auto-instrumentations/bundler/vite.mjs +10 -2
  30. package/dist/auto-instrumentations/bundler/webpack-loader.cjs +1861 -1308
  31. package/dist/auto-instrumentations/bundler/webpack-loader.d.ts +3 -3
  32. package/dist/auto-instrumentations/bundler/webpack.cjs +1803 -1283
  33. package/dist/auto-instrumentations/bundler/webpack.d.mts +9 -5
  34. package/dist/auto-instrumentations/bundler/webpack.d.ts +9 -5
  35. package/dist/auto-instrumentations/bundler/webpack.mjs +6 -6
  36. package/dist/auto-instrumentations/{chunk-DIV5TO4S.mjs → chunk-E5DUYJWK.mjs} +338 -1
  37. package/dist/auto-instrumentations/chunk-GJOO4ESL.mjs +300 -0
  38. package/dist/auto-instrumentations/chunk-WFEUJACP.mjs +18 -0
  39. package/dist/auto-instrumentations/hook.mjs +1713 -1460
  40. package/dist/auto-instrumentations/index.cjs +94 -0
  41. package/dist/auto-instrumentations/index.d.mts +5 -1
  42. package/dist/auto-instrumentations/index.d.ts +5 -1
  43. package/dist/auto-instrumentations/index.mjs +6 -247
  44. package/dist/auto-instrumentations/loader/esm-hook.mjs +19 -2
  45. package/dist/auto-instrumentations/plugin-D7nDswtC.d.mts +44 -0
  46. package/dist/auto-instrumentations/plugin-D7nDswtC.d.ts +44 -0
  47. package/dist/browser.d.mts +264 -47
  48. package/dist/browser.d.ts +264 -47
  49. package/dist/browser.js +2521 -159
  50. package/dist/browser.mjs +2521 -159
  51. package/dist/chunk-26JGOELH.js +817 -0
  52. package/dist/chunk-75IQCUB2.mjs +817 -0
  53. package/dist/cli.js +2510 -122
  54. package/dist/edge-light.d.mts +1 -1
  55. package/dist/edge-light.d.ts +1 -1
  56. package/dist/edge-light.js +2521 -159
  57. package/dist/edge-light.mjs +2521 -159
  58. package/dist/index.d.mts +264 -47
  59. package/dist/index.d.ts +264 -47
  60. package/dist/index.js +3498 -1850
  61. package/dist/index.mjs +2635 -987
  62. package/dist/instrumentation/index.d.mts +7897 -48
  63. package/dist/instrumentation/index.d.ts +7897 -48
  64. package/dist/instrumentation/index.js +2408 -95
  65. package/dist/instrumentation/index.mjs +2407 -95
  66. package/dist/workerd.d.mts +1 -1
  67. package/dist/workerd.d.ts +1 -1
  68. package/dist/workerd.js +2521 -159
  69. package/dist/workerd.mjs +2521 -159
  70. package/package.json +23 -17
  71. package/util/dist/index.d.mts +3 -1
  72. package/util/dist/index.d.ts +3 -1
  73. package/util/dist/index.js +6 -0
  74. package/util/dist/index.mjs +6 -0
  75. package/dist/auto-instrumentations/chunk-G6ZWXGZB.mjs +0 -116
  76. package/dist/auto-instrumentations/plugin-Df3qKIl2.d.mts +0 -22
  77. package/dist/auto-instrumentations/plugin-Df3qKIl2.d.ts +0 -22
package/dist/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.13.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,28 +1370,16 @@ 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",
1354
- "test:external:openai": "bash scripts/test-provider.sh test:openai openai",
1355
- "test:external:anthropic": "bash scripts/test-provider.sh test:anthropic @anthropic-ai/sdk",
1356
- "test:external:google-genai": "bash scripts/test-provider.sh test:google-genai @google/genai",
1357
- "test:external:ai-sdk": "pnpm run test:external:ai-sdk-v5 && pnpm run test:external:ai-sdk-v6",
1358
- "test:external:ai-sdk-v5": "cd src/wrappers/ai-sdk/tests/v5 && pnpm install --ignore-workspace && pnpm test",
1359
- "test:external:ai-sdk-v6": "cd src/wrappers/ai-sdk/tests/v6 && pnpm install --ignore-workspace && pnpm test",
1360
- "test:external:claude-agent-sdk": "cd src/wrappers/claude-agent-sdk && pnpm install && pnpm test",
1361
- "test:all": "pnpm run test:checks && pnpm run test:external",
1373
+ "test:all": "pnpm run test:checks",
1362
1374
  "test:api-compat": "vitest run tests/api-compatibility/api-compatibility.test.ts",
1363
- "test:anthropic": "vitest run src/wrappers/anthropic.test.ts",
1364
- "test:openai": "vitest run src/wrappers/oai.test.ts",
1365
1375
  "test:otel": "vitest run --dir src/otel",
1366
1376
  "test:otel-no-deps": "vitest run src/otel/otel-no-deps.test.ts --reporter=verbose",
1367
- "test:google-genai": "vitest run src/wrappers/google-genai.test.ts",
1368
1377
  "test:ai-sdk-v1": "vitest run src/wrappers/ai-sdk-v1.test.ts",
1369
1378
  "test:ai-sdk-v2": "vitest run src/wrappers/ai-sdk-v2.test.ts src/wrappers/ai-sdk-v1.test.ts",
1370
1379
  "test:ai-sdk-v3": "vitest run src/wrappers/ai-sdk-v3.test.ts",
1371
1380
  "test:zod-v3": "vitest run src/zod/zod-v3-serialization.test.ts",
1372
1381
  "test:zod-v4": "vitest run src/zod/zod-v4-serialization.test.ts",
1373
1382
  "test:mastra": "vitest run src/wrappers/mastra.test.ts",
1374
- "test:claude-agent-sdk": "pnpm --filter @braintrust/claude-agent-sdk-tests test",
1375
1383
  "test:vitest": "pnpm --filter @braintrust/vitest-wrapper-tests test",
1376
1384
  "test:output": "tsx scripts/test-output.ts --with-comparison --with-metrics --with-progress",
1377
1385
  bench: "tsx src/queue.bench.ts",
@@ -1402,7 +1410,6 @@ var require_package = __commonJS({
1402
1410
  "@types/node": "^20.10.5",
1403
1411
  "@types/pluralize": "^0.0.30",
1404
1412
  "@types/tar": "^6.1.13",
1405
- "@types/uuid": "^9.0.7",
1406
1413
  "@typescript-eslint/eslint-plugin": "^8.49.0",
1407
1414
  "@typescript-eslint/parser": "^8.49.0",
1408
1415
  ai: "^6.0.0",
@@ -1411,7 +1418,6 @@ var require_package = __commonJS({
1411
1418
  "cross-env": "^7.0.3",
1412
1419
  "eslint-plugin-node-import": "^1.0.5",
1413
1420
  openai: "6.25.0",
1414
- "openapi-zod-client": "^1.18.3",
1415
1421
  rollup: "^4.60.3",
1416
1422
  tar: "^7.5.2",
1417
1423
  tinybench: "^4.0.1",
@@ -1450,7 +1456,7 @@ var require_package = __commonJS({
1450
1456
  "source-map": "^0.7.4",
1451
1457
  "termi-link": "^1.0.1",
1452
1458
  unplugin: "^2.3.5",
1453
- uuid: "^9.0.1",
1459
+ uuid: "^11.1.1",
1454
1460
  "zod-to-json-schema": "^3.25.0"
1455
1461
  },
1456
1462
  peerDependencies: {
@@ -1474,7 +1480,7 @@ __export(cli_exports, {
1474
1480
  });
1475
1481
  module.exports = __toCommonJS(cli_exports);
1476
1482
  var esbuild = __toESM(require("esbuild"));
1477
- var dotenv2 = __toESM(require("dotenv"));
1483
+ var dotenv3 = __toESM(require("dotenv"));
1478
1484
  var import_node_fs2 = __toESM(require("node:fs"));
1479
1485
  var import_node_os = __toESM(require("node:os"));
1480
1486
  var import_node_path5 = __toESM(require("node:path"));
@@ -1573,6 +1579,7 @@ var iso = {
1573
1579
  getRepoInfo: async (_settings) => void 0,
1574
1580
  getPastNAncestors: async () => [],
1575
1581
  getEnv: (_name) => void 0,
1582
+ getBraintrustApiKey: async () => void 0,
1576
1583
  getCallerLocation: () => void 0,
1577
1584
  newAsyncLocalStorage: () => new DefaultAsyncLocalStorage(),
1578
1585
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -2405,6 +2412,11 @@ function isPromiseLike(value) {
2405
2412
 
2406
2413
  // util/object_util.ts
2407
2414
  var SET_UNION_FIELDS = /* @__PURE__ */ new Set(["tags"]);
2415
+ var FORBIDDEN_MERGE_KEYS = /* @__PURE__ */ new Set([
2416
+ "__proto__",
2417
+ "constructor",
2418
+ "prototype"
2419
+ ]);
2408
2420
  function mergeDictsWithPaths({
2409
2421
  mergeInto,
2410
2422
  mergeFrom,
@@ -2427,6 +2439,7 @@ function mergeDictsWithPathsHelper({
2427
2439
  mergePaths
2428
2440
  }) {
2429
2441
  Object.entries(mergeFrom).forEach(([k, mergeFromV]) => {
2442
+ if (FORBIDDEN_MERGE_KEYS.has(k)) return;
2430
2443
  const fullPath = path8.concat([k]);
2431
2444
  const fullPathSerialized = JSON.stringify(fullPath);
2432
2445
  const mergeIntoV = recordFind(mergeInto, k);
@@ -6490,6 +6503,13 @@ var HTTPConnection = class _HTTPConnection {
6490
6503
  debugLogger.debug(
6491
6504
  `Retrying API request ${object_type} ${JSON.stringify(args)} ${e.status} ${e.text}`
6492
6505
  );
6506
+ const sleepTimeS = HTTP_RETRY_BASE_SLEEP_TIME_S * 2 ** i;
6507
+ debugLogger.info(
6508
+ `Sleeping for ${sleepTimeS}s before retrying API request`
6509
+ );
6510
+ await new Promise(
6511
+ (resolve2) => setTimeout(resolve2, sleepTimeS * 1e3)
6512
+ );
6493
6513
  continue;
6494
6514
  }
6495
6515
  throw e;
@@ -7012,20 +7032,7 @@ function startSpanParentArgs(args) {
7012
7032
  `Mismatch between expected span parent object type ${args.parentObjectType} and provided type ${parentComponents.data.object_type}`
7013
7033
  );
7014
7034
  }
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);
7035
+ argParentObjectId = args.parentObjectId;
7029
7036
  if (parentComponents.data.row_id) {
7030
7037
  argParentSpanIds = {
7031
7038
  spanId: parentComponents.data.span_id,
@@ -7354,6 +7361,7 @@ function now() {
7354
7361
  }
7355
7362
  var DEFAULT_FLUSH_BACKPRESSURE_BYTES = 10 * 1024 * 1024;
7356
7363
  var BACKGROUND_LOGGER_BASE_SLEEP_TIME_S = 1;
7364
+ var HTTP_RETRY_BASE_SLEEP_TIME_S = 1;
7357
7365
  var HTTPBackgroundLogger = class _HTTPBackgroundLogger {
7358
7366
  apiConn;
7359
7367
  queue;
@@ -7984,17 +7992,10 @@ function init(projectOrOptions, optionalOptions) {
7984
7992
  if (repoInfo2) {
7985
7993
  return repoInfo2;
7986
7994
  }
7987
- let mergedGitMetadataSettings = {
7988
- ...state.gitMetadataSettings || {
7989
- collect: "all"
7990
- }
7991
- };
7992
- if (gitMetadataSettings) {
7993
- mergedGitMetadataSettings = mergeGitMetadataSettings(
7994
- mergedGitMetadataSettings,
7995
- gitMetadataSettings
7996
- );
7997
- }
7995
+ const mergedGitMetadataSettings = state.gitMetadataSettings == null ? gitMetadataSettings ?? { collect: "none" } : mergeGitMetadataSettings(
7996
+ state.gitMetadataSettings,
7997
+ gitMetadataSettings ?? { collect: "all" }
7998
+ );
7998
7999
  return await isomorph_default.getRepoInfo(mergedGitMetadataSettings);
7999
8000
  })();
8000
8001
  if (repoInfoArg) {
@@ -8376,6 +8377,55 @@ async function computeLoggerMetadata(state, {
8376
8377
  };
8377
8378
  }
8378
8379
  }
8380
+ function initLogger(options = {}) {
8381
+ const {
8382
+ projectName,
8383
+ projectId,
8384
+ asyncFlush: asyncFlushArg,
8385
+ appUrl,
8386
+ apiKey,
8387
+ orgName,
8388
+ forceLogin,
8389
+ debugLogLevel,
8390
+ fetch: fetch2,
8391
+ state: stateArg
8392
+ } = options || {};
8393
+ const asyncFlush = asyncFlushArg === void 0 ? true : asyncFlushArg;
8394
+ const computeMetadataArgs = {
8395
+ project_name: projectName,
8396
+ project_id: projectId
8397
+ };
8398
+ const linkArgs = {
8399
+ org_name: orgName,
8400
+ app_url: appUrl,
8401
+ project_name: projectName,
8402
+ project_id: projectId
8403
+ };
8404
+ const state = stateArg ?? _globalState;
8405
+ state.setDebugLogLevel(debugLogLevel);
8406
+ state.enforceQueueSizeLimit(true);
8407
+ const lazyMetadata = new LazyValue(
8408
+ async () => {
8409
+ await state.login({
8410
+ orgName,
8411
+ apiKey,
8412
+ appUrl,
8413
+ forceLogin,
8414
+ fetch: fetch2
8415
+ });
8416
+ return computeLoggerMetadata(state, computeMetadataArgs);
8417
+ }
8418
+ );
8419
+ const ret = new Logger(state, lazyMetadata, {
8420
+ asyncFlush,
8421
+ computeMetadataArgs,
8422
+ linkArgs
8423
+ });
8424
+ if (options.setCurrent ?? true) {
8425
+ state.currentLogger = ret;
8426
+ }
8427
+ return ret;
8428
+ }
8379
8429
  async function login(options = {}) {
8380
8430
  const { forceLogin = false } = options || {};
8381
8431
  if (!_internalGetGlobalState()) {
@@ -8407,10 +8457,11 @@ async function login(options = {}) {
8407
8457
  async function loginToState(options = {}) {
8408
8458
  const {
8409
8459
  appUrl = isomorph_default.getEnv("BRAINTRUST_APP_URL") || "https://www.braintrust.dev",
8410
- apiKey = isomorph_default.getEnv("BRAINTRUST_API_KEY"),
8460
+ apiKey: apiKeyArg,
8411
8461
  orgName = isomorph_default.getEnv("BRAINTRUST_ORG_NAME"),
8412
8462
  fetch: fetch2 = globalThis.fetch
8413
8463
  } = options || {};
8464
+ const apiKey = apiKeyArg !== void 0 ? apiKeyArg : await isomorph_default.getBraintrustApiKey();
8414
8465
  const appPublicUrl = isomorph_default.getEnv("BRAINTRUST_APP_PUBLIC_URL") || appUrl;
8415
8466
  const state = new BraintrustState(options);
8416
8467
  state.resetLoginInfo();
@@ -9429,9 +9480,15 @@ var SpanImpl = class _SpanImpl {
9429
9480
  const cachedSpan = {
9430
9481
  input: partialRecord.input,
9431
9482
  output: partialRecord.output,
9483
+ expected: partialRecord.expected,
9484
+ error: partialRecord.error,
9485
+ scores: partialRecord.scores,
9486
+ metrics: partialRecord.metrics,
9432
9487
  metadata: partialRecord.metadata,
9488
+ tags: partialRecord.tags,
9433
9489
  span_id: this._spanId,
9434
9490
  span_parents: this._spanParents,
9491
+ is_root: this._spanId === this._rootSpanId,
9435
9492
  span_attributes: partialRecord.span_attributes
9436
9493
  };
9437
9494
  this._state.spanCache.queueWrite(
@@ -9767,6 +9824,7 @@ var Dataset2 = class extends ObjectFetcher {
9767
9824
  metadata,
9768
9825
  tags,
9769
9826
  output,
9827
+ origin,
9770
9828
  isMerge
9771
9829
  }) {
9772
9830
  return new LazyValue(async () => {
@@ -9781,6 +9839,7 @@ var Dataset2 = class extends ObjectFetcher {
9781
9839
  created: !isMerge ? (/* @__PURE__ */ new Date()).toISOString() : void 0,
9782
9840
  //if we're merging/updating an event we will not add this ts
9783
9841
  metadata,
9842
+ origin,
9784
9843
  ...!!isMerge ? {
9785
9844
  [IS_MERGE_FIELD]: true
9786
9845
  } : {}
@@ -9800,6 +9859,7 @@ var Dataset2 = class extends ObjectFetcher {
9800
9859
  * about anything else that's relevant, that you can use to help find and analyze examples later. For example, you could log the
9801
9860
  * `prompt`, example's `id`, or anything else that would be useful to slice/dice later. The values in `metadata` can be any
9802
9861
  * JSON-serializable type, but its keys must be strings.
9862
+ * @param event.origin (Optional) a reference to the source object this dataset record was derived from.
9803
9863
  * @param event.id (Optional) a unique identifier for the event. If you don't provide one, Braintrust will generate one for you.
9804
9864
  * @param event.output: (Deprecated) The output of your application. Use `expected` instead.
9805
9865
  * @returns The `id` of the logged record.
@@ -9810,7 +9870,8 @@ var Dataset2 = class extends ObjectFetcher {
9810
9870
  metadata,
9811
9871
  tags,
9812
9872
  id,
9813
- output
9873
+ output,
9874
+ origin
9814
9875
  }) {
9815
9876
  this.validateEvent({ metadata, expected, output, tags });
9816
9877
  const rowId = id || (0, import_uuid2.v4)();
@@ -9822,6 +9883,7 @@ var Dataset2 = class extends ObjectFetcher {
9822
9883
  metadata,
9823
9884
  tags,
9824
9885
  output,
9886
+ origin,
9825
9887
  isMerge: false
9826
9888
  })
9827
9889
  );
@@ -11643,8 +11705,12 @@ async function invoke(args) {
11643
11705
 
11644
11706
  // src/trace.ts
11645
11707
  var SpanFetcher = class _SpanFetcher extends ObjectFetcher {
11646
- constructor(objectType, _objectId, rootSpanId, _state, spanTypeFilter) {
11647
- const filterExpr = _SpanFetcher.buildFilter(rootSpanId, spanTypeFilter);
11708
+ constructor(objectType, _objectId, rootSpanId, _state, spanTypeFilter, includeScorers = false) {
11709
+ const filterExpr = _SpanFetcher.buildFilter(
11710
+ rootSpanId,
11711
+ spanTypeFilter,
11712
+ includeScorers
11713
+ );
11648
11714
  super(objectType, void 0, void 0, {
11649
11715
  filter: filterExpr
11650
11716
  });
@@ -11653,16 +11719,17 @@ var SpanFetcher = class _SpanFetcher extends ObjectFetcher {
11653
11719
  this._state = _state;
11654
11720
  this.spanTypeFilter = spanTypeFilter;
11655
11721
  }
11656
- static buildFilter(rootSpanId, spanTypeFilter) {
11722
+ static buildFilter(rootSpanId, spanTypeFilter, includeScorers = false) {
11657
11723
  const children = [
11658
11724
  // Base filter: root_span_id = 'value'
11659
11725
  {
11660
11726
  op: "eq",
11661
11727
  left: { op: "ident", name: ["root_span_id"] },
11662
11728
  right: { op: "literal", value: rootSpanId }
11663
- },
11664
- // Exclude span_attributes.purpose = 'score'
11665
- {
11729
+ }
11730
+ ];
11731
+ if (!includeScorers) {
11732
+ children.push({
11666
11733
  op: "or",
11667
11734
  children: [
11668
11735
  {
@@ -11675,8 +11742,8 @@ var SpanFetcher = class _SpanFetcher extends ObjectFetcher {
11675
11742
  right: { op: "literal", value: "scorer" }
11676
11743
  }
11677
11744
  ]
11678
- }
11679
- ];
11745
+ });
11746
+ }
11680
11747
  if (spanTypeFilter && spanTypeFilter.length > 0) {
11681
11748
  children.push({
11682
11749
  op: "in",
@@ -11702,35 +11769,49 @@ var CachedSpanFetcher = class {
11702
11769
  fetchFn;
11703
11770
  constructor(objectTypeOrFetchFn, objectId, rootSpanId, getState) {
11704
11771
  if (typeof objectTypeOrFetchFn === "function") {
11705
- this.fetchFn = objectTypeOrFetchFn;
11772
+ this.fetchFn = (spanType) => objectTypeOrFetchFn(spanType);
11706
11773
  } else {
11707
11774
  const objectType = objectTypeOrFetchFn;
11708
- this.fetchFn = async (spanType) => {
11775
+ this.fetchFn = async (spanType, includeScorers) => {
11709
11776
  const state = await getState();
11710
11777
  const fetcher = new SpanFetcher(
11711
11778
  objectType,
11712
11779
  objectId,
11713
11780
  rootSpanId,
11714
11781
  state,
11715
- spanType
11782
+ spanType,
11783
+ includeScorers
11716
11784
  );
11717
11785
  const rows = await fetcher.fetchedData();
11718
- return rows.filter((row) => row.span_attributes?.purpose !== "scorer").map((row) => ({
11786
+ return rows.map((row) => ({
11719
11787
  input: row.input,
11720
11788
  output: row.output,
11789
+ expected: row.expected,
11790
+ error: row.error,
11791
+ scores: row.scores,
11792
+ metrics: row.metrics,
11721
11793
  metadata: row.metadata,
11722
11794
  span_id: row.span_id,
11723
11795
  span_parents: row.span_parents,
11796
+ is_root: row.is_root,
11724
11797
  span_attributes: row.span_attributes,
11725
11798
  id: row.id,
11726
11799
  _xact_id: row._xact_id,
11727
11800
  _pagination_key: row._pagination_key,
11728
- root_span_id: row.root_span_id
11801
+ root_span_id: row.root_span_id,
11802
+ created: row.created,
11803
+ tags: row.tags
11729
11804
  }));
11730
11805
  };
11731
11806
  }
11732
11807
  }
11733
- async getSpans({ spanType } = {}) {
11808
+ async getSpans({
11809
+ spanType,
11810
+ includeScorers = false
11811
+ } = {}) {
11812
+ if (includeScorers) {
11813
+ return this.fetchFn(spanType, true);
11814
+ }
11734
11815
  if (this.allFetched) {
11735
11816
  return this.getFromCache(spanType);
11736
11817
  }
@@ -11747,7 +11828,7 @@ var CachedSpanFetcher = class {
11747
11828
  return this.getFromCache(spanType);
11748
11829
  }
11749
11830
  async fetchSpans(spanType) {
11750
- const spans = await this.fetchFn(spanType);
11831
+ const spans = await this.fetchFn(spanType, false);
11751
11832
  for (const span of spans) {
11752
11833
  const type = span.span_attributes?.type ?? "";
11753
11834
  const existing = this.spanCache.get(type) ?? [];
@@ -11825,10 +11906,13 @@ var LocalTrace = class {
11825
11906
  * First checks the local span cache for recently logged spans, then falls
11826
11907
  * back to CachedSpanFetcher which handles BTQL fetching and caching.
11827
11908
  */
11828
- async getSpans({ spanType } = {}) {
11909
+ async getSpans({
11910
+ spanType,
11911
+ includeScorers = false
11912
+ } = {}) {
11829
11913
  const cachedSpans = this.state.spanCache.getByRootSpanId(this.rootSpanId);
11830
11914
  if (cachedSpans && cachedSpans.length > 0) {
11831
- let spans = cachedSpans.filter(
11915
+ let spans = includeScorers ? cachedSpans : cachedSpans.filter(
11832
11916
  (span) => span.span_attributes?.purpose !== "scorer"
11833
11917
  );
11834
11918
  if (spanType && spanType.length > 0) {
@@ -11839,13 +11923,19 @@ var LocalTrace = class {
11839
11923
  return spans.map((span) => ({
11840
11924
  input: span.input,
11841
11925
  output: span.output,
11926
+ expected: span.expected,
11927
+ error: span.error,
11928
+ scores: span.scores,
11929
+ metrics: span.metrics,
11842
11930
  metadata: span.metadata,
11843
11931
  span_id: span.span_id,
11844
11932
  span_parents: span.span_parents,
11845
- span_attributes: span.span_attributes
11933
+ is_root: span.is_root,
11934
+ span_attributes: span.span_attributes,
11935
+ tags: span.tags
11846
11936
  }));
11847
11937
  }
11848
- return this.cachedFetcher.getSpans({ spanType });
11938
+ return this.cachedFetcher.getSpans({ spanType, includeScorers });
11849
11939
  }
11850
11940
  /**
11851
11941
  * Get the thread (preprocessed messages) for this trace.
@@ -13290,6 +13380,7 @@ var fsSync = __toESM(require("node:fs"));
13290
13380
  var crypto = __toESM(require("node:crypto"));
13291
13381
  var import_node_util3 = require("node:util");
13292
13382
  var zlib = __toESM(require("node:zlib"));
13383
+ var dotenv = __toESM(require("dotenv"));
13293
13384
 
13294
13385
  // src/gitutil.ts
13295
13386
  var import_simple_git = require("simple-git");
@@ -13398,11 +13489,11 @@ function truncateToByteLimit(s, byteLimit = 65536) {
13398
13489
  return new TextDecoder().decode(truncated);
13399
13490
  }
13400
13491
  async function getRepoInfo(settings) {
13401
- if (settings && settings.collect === "none") {
13492
+ if (!settings || settings.collect === "none") {
13402
13493
  return void 0;
13403
13494
  }
13404
13495
  const repo = await repoInfo();
13405
- if (!repo || !settings || settings.collect === "all") {
13496
+ if (!repo || settings.collect === "all") {
13406
13497
  return repo;
13407
13498
  }
13408
13499
  let sanitized = {};
@@ -17099,11 +17190,11 @@ function resolveDenyOutputPaths(event, defaultDenyOutputPaths) {
17099
17190
  if (Array.isArray(event?.denyOutputPaths)) {
17100
17191
  return event.denyOutputPaths;
17101
17192
  }
17102
- const firstArgument = event?.arguments && event.arguments.length > 0 ? event.arguments[0] : void 0;
17103
- if (!firstArgument || typeof firstArgument !== "object") {
17193
+ const firstArgument2 = event?.arguments && event.arguments.length > 0 ? event.arguments[0] : void 0;
17194
+ if (!firstArgument2 || typeof firstArgument2 !== "object") {
17104
17195
  return defaultDenyOutputPaths;
17105
17196
  }
17106
- const runtimeDenyOutputPaths = firstArgument[RUNTIME_DENY_OUTPUT_PATHS];
17197
+ const runtimeDenyOutputPaths = firstArgument2[RUNTIME_DENY_OUTPUT_PATHS];
17107
17198
  if (Array.isArray(runtimeDenyOutputPaths) && runtimeDenyOutputPaths.every((path8) => typeof path8 === "string")) {
17108
17199
  return runtimeDenyOutputPaths;
17109
17200
  }
@@ -20762,6 +20853,467 @@ function cleanMetrics2(metrics) {
20762
20853
  return cleaned;
20763
20854
  }
20764
20855
 
20856
+ // src/instrumentation/plugins/openai-agents-channels.ts
20857
+ var openAIAgentsCoreChannels = defineChannels("@openai/agents-core", {
20858
+ onTraceStart: channel({
20859
+ channelName: "tracing.processor.onTraceStart",
20860
+ kind: "async"
20861
+ }),
20862
+ onTraceEnd: channel({
20863
+ channelName: "tracing.processor.onTraceEnd",
20864
+ kind: "async"
20865
+ }),
20866
+ onSpanStart: channel({
20867
+ channelName: "tracing.processor.onSpanStart",
20868
+ kind: "async"
20869
+ }),
20870
+ onSpanEnd: channel({
20871
+ channelName: "tracing.processor.onSpanEnd",
20872
+ kind: "async"
20873
+ })
20874
+ });
20875
+
20876
+ // src/instrumentation/plugins/openai-agents-trace-processor.ts
20877
+ function isSpanData(spanData, type) {
20878
+ return spanData.type === type;
20879
+ }
20880
+ function spanTypeFromAgents(span) {
20881
+ const spanType = span.spanData.type;
20882
+ if (spanType === "function" || spanType === "guardrail" || spanType === "mcp_tools") {
20883
+ return "tool" /* TOOL */;
20884
+ }
20885
+ if (spanType === "generation" || spanType === "response" || spanType === "transcription" || spanType === "speech") {
20886
+ return "llm" /* LLM */;
20887
+ }
20888
+ return "task" /* TASK */;
20889
+ }
20890
+ function spanNameFromAgents(span) {
20891
+ const spanData = span.spanData;
20892
+ if ("name" in spanData && spanData.name) {
20893
+ return spanData.name;
20894
+ }
20895
+ switch (spanData.type) {
20896
+ case "generation":
20897
+ return "Generation";
20898
+ case "response":
20899
+ return "Response";
20900
+ case "handoff":
20901
+ return "Handoff";
20902
+ case "mcp_tools":
20903
+ return isSpanData(spanData, "mcp_tools") && spanData.server ? `List Tools (${spanData.server})` : "MCP List Tools";
20904
+ case "transcription":
20905
+ return "Transcription";
20906
+ case "speech":
20907
+ return "Speech";
20908
+ case "speech_group":
20909
+ return "Speech Group";
20910
+ default:
20911
+ return "Unknown";
20912
+ }
20913
+ }
20914
+ function getTimeElapsed(end, start) {
20915
+ if (!start || !end) {
20916
+ return void 0;
20917
+ }
20918
+ const startTime = new Date(start).getTime();
20919
+ const endTime = new Date(end).getTime();
20920
+ if (Number.isNaN(startTime) || Number.isNaN(endTime)) {
20921
+ return void 0;
20922
+ }
20923
+ return (endTime - startTime) / 1e3;
20924
+ }
20925
+ function getNumberProperty2(obj, key) {
20926
+ if (!isObject(obj) || !(key in obj)) {
20927
+ return void 0;
20928
+ }
20929
+ const value = obj[key];
20930
+ return typeof value === "number" ? value : void 0;
20931
+ }
20932
+ function parseUsageMetrics(usage) {
20933
+ const metrics = {};
20934
+ if (!isObject(usage)) {
20935
+ return metrics;
20936
+ }
20937
+ const promptTokens = getNumberProperty2(usage, "prompt_tokens") ?? getNumberProperty2(usage, "input_tokens") ?? getNumberProperty2(usage, "promptTokens") ?? getNumberProperty2(usage, "inputTokens");
20938
+ const completionTokens = getNumberProperty2(usage, "completion_tokens") ?? getNumberProperty2(usage, "output_tokens") ?? getNumberProperty2(usage, "completionTokens") ?? getNumberProperty2(usage, "outputTokens");
20939
+ const totalTokens = getNumberProperty2(usage, "total_tokens") ?? getNumberProperty2(usage, "totalTokens");
20940
+ if (promptTokens !== void 0) {
20941
+ metrics.prompt_tokens = promptTokens;
20942
+ }
20943
+ if (completionTokens !== void 0) {
20944
+ metrics.completion_tokens = completionTokens;
20945
+ }
20946
+ if (totalTokens !== void 0) {
20947
+ metrics.tokens = totalTokens;
20948
+ } else if (promptTokens !== void 0 && completionTokens !== void 0) {
20949
+ metrics.tokens = promptTokens + completionTokens;
20950
+ }
20951
+ const inputDetails = usage.input_tokens_details;
20952
+ const cachedTokens = getNumberProperty2(inputDetails, "cached_tokens");
20953
+ const cacheWriteTokens = getNumberProperty2(
20954
+ inputDetails,
20955
+ "cache_write_tokens"
20956
+ );
20957
+ if (cachedTokens !== void 0) {
20958
+ metrics.prompt_cached_tokens = cachedTokens;
20959
+ }
20960
+ if (cacheWriteTokens !== void 0) {
20961
+ metrics.prompt_cache_creation_tokens = cacheWriteTokens;
20962
+ }
20963
+ return metrics;
20964
+ }
20965
+ var OpenAIAgentsTraceProcessor = class _OpenAIAgentsTraceProcessor {
20966
+ static DEFAULT_MAX_TRACES = 1e4;
20967
+ logger;
20968
+ maxTraces;
20969
+ traceSpans = /* @__PURE__ */ new Map();
20970
+ traceOrder = [];
20971
+ _traceSpans = this.traceSpans;
20972
+ constructor(options = {}) {
20973
+ this.logger = options.logger;
20974
+ this.maxTraces = options.maxTraces ?? _OpenAIAgentsTraceProcessor.DEFAULT_MAX_TRACES;
20975
+ }
20976
+ evictOldestTrace() {
20977
+ const oldestTraceId = this.traceOrder.shift();
20978
+ if (oldestTraceId) {
20979
+ this.traceSpans.delete(oldestTraceId);
20980
+ }
20981
+ }
20982
+ onTraceStart(trace) {
20983
+ if (!trace?.traceId) {
20984
+ return Promise.resolve();
20985
+ }
20986
+ if (this.traceOrder.length >= this.maxTraces) {
20987
+ this.evictOldestTrace();
20988
+ }
20989
+ const current = currentSpan();
20990
+ const span = current && current !== NOOP_SPAN ? current.startSpan({
20991
+ name: trace.name,
20992
+ type: "task" /* TASK */
20993
+ }) : this.logger ? this.logger.startSpan({
20994
+ name: trace.name,
20995
+ type: "task" /* TASK */
20996
+ }) : startSpan({
20997
+ name: trace.name,
20998
+ type: "task" /* TASK */
20999
+ });
21000
+ span.log({
21001
+ input: "Agent workflow started",
21002
+ metadata: {
21003
+ group_id: trace.groupId,
21004
+ ...trace.metadata || {}
21005
+ }
21006
+ });
21007
+ this.traceSpans.set(trace.traceId, {
21008
+ rootSpan: span,
21009
+ childSpans: /* @__PURE__ */ new Map(),
21010
+ metadata: {
21011
+ firstInput: null,
21012
+ lastOutput: null
21013
+ }
21014
+ });
21015
+ this.traceOrder.push(trace.traceId);
21016
+ return Promise.resolve();
21017
+ }
21018
+ async onTraceEnd(trace) {
21019
+ const traceData = this.traceSpans.get(trace?.traceId);
21020
+ if (!traceData) {
21021
+ return;
21022
+ }
21023
+ try {
21024
+ traceData.rootSpan.log({
21025
+ input: traceData.metadata.firstInput,
21026
+ output: traceData.metadata.lastOutput
21027
+ });
21028
+ traceData.rootSpan.end();
21029
+ await traceData.rootSpan.flush();
21030
+ } finally {
21031
+ this.traceSpans.delete(trace.traceId);
21032
+ const orderIndex = this.traceOrder.indexOf(trace.traceId);
21033
+ if (orderIndex > -1) {
21034
+ this.traceOrder.splice(orderIndex, 1);
21035
+ }
21036
+ }
21037
+ }
21038
+ onSpanStart(span) {
21039
+ if (!span?.spanId || !span.traceId) {
21040
+ return Promise.resolve();
21041
+ }
21042
+ const traceData = this.traceSpans.get(span.traceId);
21043
+ if (!traceData) {
21044
+ return Promise.resolve();
21045
+ }
21046
+ const parentSpan = span.parentId ? traceData.childSpans.get(span.parentId) : traceData.rootSpan;
21047
+ if (!parentSpan) {
21048
+ return Promise.resolve();
21049
+ }
21050
+ const childSpan = parentSpan.startSpan({
21051
+ name: spanNameFromAgents(span),
21052
+ type: spanTypeFromAgents(span)
21053
+ });
21054
+ traceData.childSpans.set(span.spanId, childSpan);
21055
+ return Promise.resolve();
21056
+ }
21057
+ onSpanEnd(span) {
21058
+ if (!span?.spanId || !span.traceId) {
21059
+ return Promise.resolve();
21060
+ }
21061
+ const traceData = this.traceSpans.get(span.traceId);
21062
+ if (!traceData) {
21063
+ return Promise.resolve();
21064
+ }
21065
+ const braintrustSpan = traceData.childSpans.get(span.spanId);
21066
+ if (!braintrustSpan) {
21067
+ return Promise.resolve();
21068
+ }
21069
+ const logData = this.extractLogData(span);
21070
+ braintrustSpan.log({
21071
+ error: span.error,
21072
+ ...logData
21073
+ });
21074
+ braintrustSpan.end();
21075
+ traceData.childSpans.delete(span.spanId);
21076
+ const input = logData.input;
21077
+ const output = logData.output;
21078
+ if (traceData.metadata.firstInput === null && input != null) {
21079
+ traceData.metadata.firstInput = input;
21080
+ }
21081
+ if (output != null) {
21082
+ traceData.metadata.lastOutput = output;
21083
+ }
21084
+ return Promise.resolve();
21085
+ }
21086
+ async shutdown() {
21087
+ if (this.logger && typeof this.logger.flush === "function") {
21088
+ await this.logger.flush();
21089
+ }
21090
+ }
21091
+ async forceFlush() {
21092
+ if (this.logger && typeof this.logger.flush === "function") {
21093
+ await this.logger.flush();
21094
+ }
21095
+ }
21096
+ extractLogData(span) {
21097
+ const spanData = span.spanData;
21098
+ switch (spanData.type) {
21099
+ case "agent":
21100
+ return this.extractAgentLogData(spanData);
21101
+ case "response":
21102
+ return this.extractResponseLogData(spanData, span);
21103
+ case "function":
21104
+ return this.extractFunctionLogData(spanData);
21105
+ case "handoff":
21106
+ return this.extractHandoffLogData(spanData);
21107
+ case "guardrail":
21108
+ return this.extractGuardrailLogData(spanData);
21109
+ case "generation":
21110
+ return this.extractGenerationLogData(spanData, span);
21111
+ case "custom":
21112
+ return this.extractCustomLogData(spanData);
21113
+ case "mcp_tools":
21114
+ return this.extractMCPListToolsLogData(spanData);
21115
+ case "transcription":
21116
+ return this.extractTranscriptionLogData(spanData);
21117
+ case "speech":
21118
+ return this.extractSpeechLogData(spanData);
21119
+ case "speech_group":
21120
+ return this.extractSpeechGroupLogData(spanData);
21121
+ default:
21122
+ return {};
21123
+ }
21124
+ }
21125
+ extractAgentLogData(spanData) {
21126
+ return {
21127
+ metadata: {
21128
+ tools: spanData.tools,
21129
+ handoffs: spanData.handoffs,
21130
+ output_type: spanData.output_type
21131
+ }
21132
+ };
21133
+ }
21134
+ extractResponseLogData(spanData, span) {
21135
+ const response = spanData._response;
21136
+ const output = isObject(response) ? response.output : void 0;
21137
+ const usage = isObject(response) ? response.usage : void 0;
21138
+ const metrics = {
21139
+ ...this.extractTimingMetrics(span),
21140
+ ...parseUsageMetrics(usage)
21141
+ };
21142
+ return {
21143
+ input: spanData._input,
21144
+ output,
21145
+ metadata: isObject(response) ? this.omitKeys(response, ["output", "usage"]) : {},
21146
+ metrics
21147
+ };
21148
+ }
21149
+ extractFunctionLogData(spanData) {
21150
+ return {
21151
+ input: spanData.input,
21152
+ output: spanData.output
21153
+ };
21154
+ }
21155
+ extractHandoffLogData(spanData) {
21156
+ return {
21157
+ metadata: {
21158
+ from_agent: spanData.from_agent,
21159
+ to_agent: spanData.to_agent
21160
+ }
21161
+ };
21162
+ }
21163
+ extractGuardrailLogData(spanData) {
21164
+ return {
21165
+ metadata: {
21166
+ triggered: spanData.triggered
21167
+ }
21168
+ };
21169
+ }
21170
+ extractGenerationLogData(spanData, span) {
21171
+ return {
21172
+ input: spanData.input,
21173
+ output: spanData.output,
21174
+ metadata: {
21175
+ model: spanData.model,
21176
+ model_config: spanData.model_config
21177
+ },
21178
+ metrics: {
21179
+ ...this.extractTimingMetrics(span),
21180
+ ...parseUsageMetrics(spanData.usage)
21181
+ }
21182
+ };
21183
+ }
21184
+ extractCustomLogData(spanData) {
21185
+ return spanData.data || {};
21186
+ }
21187
+ extractMCPListToolsLogData(spanData) {
21188
+ return {
21189
+ output: spanData.result,
21190
+ metadata: {
21191
+ server: spanData.server
21192
+ }
21193
+ };
21194
+ }
21195
+ extractTranscriptionLogData(spanData) {
21196
+ return {
21197
+ input: spanData.input,
21198
+ output: spanData.output,
21199
+ metadata: {
21200
+ model: spanData.model,
21201
+ model_config: spanData.model_config
21202
+ }
21203
+ };
21204
+ }
21205
+ extractSpeechLogData(spanData) {
21206
+ return {
21207
+ input: spanData.input,
21208
+ output: spanData.output,
21209
+ metadata: {
21210
+ model: spanData.model,
21211
+ model_config: spanData.model_config
21212
+ }
21213
+ };
21214
+ }
21215
+ extractSpeechGroupLogData(spanData) {
21216
+ return {
21217
+ input: spanData.input
21218
+ };
21219
+ }
21220
+ extractTimingMetrics(span) {
21221
+ const timeToFirstToken = getTimeElapsed(
21222
+ span.endedAt ?? void 0,
21223
+ span.startedAt ?? void 0
21224
+ );
21225
+ return timeToFirstToken === void 0 ? {} : { time_to_first_token: timeToFirstToken };
21226
+ }
21227
+ omitKeys(value, keys) {
21228
+ const result = {};
21229
+ for (const [key, fieldValue] of Object.entries(value)) {
21230
+ if (!keys.includes(key)) {
21231
+ result[key] = fieldValue;
21232
+ }
21233
+ }
21234
+ return result;
21235
+ }
21236
+ };
21237
+
21238
+ // src/instrumentation/plugins/openai-agents-plugin.ts
21239
+ function firstArgument(args) {
21240
+ if (Array.isArray(args)) {
21241
+ return args[0];
21242
+ }
21243
+ if (isObject(args) && "length" in args && typeof args.length === "number" && Number.isInteger(args.length) && args.length >= 0) {
21244
+ return Array.from(args)[0];
21245
+ }
21246
+ return void 0;
21247
+ }
21248
+ function isOpenAIAgentsTrace(value) {
21249
+ return isObject(value) && value.type === "trace" && typeof value.traceId === "string";
21250
+ }
21251
+ function isOpenAIAgentsSpan(value) {
21252
+ return isObject(value) && value.type === "trace.span" && typeof value.traceId === "string" && typeof value.spanId === "string";
21253
+ }
21254
+ var OpenAIAgentsPlugin = class extends BasePlugin {
21255
+ processor = new OpenAIAgentsTraceProcessor();
21256
+ onEnable() {
21257
+ this.subscribeToTraceLifecycle();
21258
+ }
21259
+ onDisable() {
21260
+ this.unsubscribers = unsubscribeAll(this.unsubscribers);
21261
+ void this.processor.shutdown();
21262
+ }
21263
+ subscribeToTraceLifecycle() {
21264
+ const traceStartChannel = openAIAgentsCoreChannels.onTraceStart.tracingChannel();
21265
+ const traceStartHandlers = {
21266
+ start: (event) => {
21267
+ const trace = firstArgument(event.arguments);
21268
+ if (isOpenAIAgentsTrace(trace)) {
21269
+ void this.processor.onTraceStart(trace);
21270
+ }
21271
+ }
21272
+ };
21273
+ traceStartChannel.subscribe(traceStartHandlers);
21274
+ this.unsubscribers.push(
21275
+ () => traceStartChannel.unsubscribe(traceStartHandlers)
21276
+ );
21277
+ const traceEndChannel = openAIAgentsCoreChannels.onTraceEnd.tracingChannel();
21278
+ const traceEndHandlers = {
21279
+ start: (event) => {
21280
+ const trace = firstArgument(event.arguments);
21281
+ if (isOpenAIAgentsTrace(trace)) {
21282
+ void this.processor.onTraceEnd(trace);
21283
+ }
21284
+ }
21285
+ };
21286
+ traceEndChannel.subscribe(traceEndHandlers);
21287
+ this.unsubscribers.push(
21288
+ () => traceEndChannel.unsubscribe(traceEndHandlers)
21289
+ );
21290
+ const spanStartChannel = openAIAgentsCoreChannels.onSpanStart.tracingChannel();
21291
+ const spanStartHandlers = {
21292
+ start: (event) => {
21293
+ const span = firstArgument(event.arguments);
21294
+ if (isOpenAIAgentsSpan(span)) {
21295
+ void this.processor.onSpanStart(span);
21296
+ }
21297
+ }
21298
+ };
21299
+ spanStartChannel.subscribe(spanStartHandlers);
21300
+ this.unsubscribers.push(
21301
+ () => spanStartChannel.unsubscribe(spanStartHandlers)
21302
+ );
21303
+ const spanEndChannel = openAIAgentsCoreChannels.onSpanEnd.tracingChannel();
21304
+ const spanEndHandlers = {
21305
+ start: (event) => {
21306
+ const span = firstArgument(event.arguments);
21307
+ if (isOpenAIAgentsSpan(span)) {
21308
+ void this.processor.onSpanEnd(span);
21309
+ }
21310
+ }
21311
+ };
21312
+ spanEndChannel.subscribe(spanEndHandlers);
21313
+ this.unsubscribers.push(() => spanEndChannel.unsubscribe(spanEndHandlers));
21314
+ }
21315
+ };
21316
+
20765
21317
  // src/instrumentation/plugins/google-genai-channels.ts
20766
21318
  var googleGenAIChannels = defineChannels("@google/genai", {
20767
21319
  generateContent: channel({
@@ -27054,18 +27606,1726 @@ var GitHubCopilotPlugin = class extends BasePlugin {
27054
27606
  }
27055
27607
  };
27056
27608
 
27057
- // src/instrumentation/braintrust-plugin.ts
27058
- function getIntegrationConfig(integrations, key) {
27059
- return integrations[key];
27609
+ // src/instrumentation/plugins/flue-channels.ts
27610
+ var flueChannels = defineChannels("@flue/runtime", {
27611
+ createContext: channel({
27612
+ channelName: "createFlueContext",
27613
+ kind: "sync-stream"
27614
+ }),
27615
+ openSession: channel({
27616
+ channelName: "Harness.openSession",
27617
+ kind: "async"
27618
+ }),
27619
+ contextEvent: channel({
27620
+ channelName: "context.event",
27621
+ kind: "sync-stream"
27622
+ }),
27623
+ prompt: channel({
27624
+ channelName: "session.prompt",
27625
+ kind: "async"
27626
+ }),
27627
+ skill: channel({
27628
+ channelName: "session.skill",
27629
+ kind: "async"
27630
+ }),
27631
+ task: channel({
27632
+ channelName: "session.task",
27633
+ kind: "async"
27634
+ }),
27635
+ compact: channel({
27636
+ channelName: "session.compact",
27637
+ kind: "async"
27638
+ })
27639
+ });
27640
+
27641
+ // src/wrappers/flue.ts
27642
+ var WRAPPED_FLUE_CONTEXT = /* @__PURE__ */ Symbol.for("braintrust.flue.wrapped-context");
27643
+ var WRAPPED_FLUE_HARNESS = /* @__PURE__ */ Symbol.for("braintrust.flue.wrapped-harness");
27644
+ var WRAPPED_FLUE_SESSION = /* @__PURE__ */ Symbol.for("braintrust.flue.wrapped-session");
27645
+ var SUBSCRIBED_FLUE_CONTEXT_EVENTS = /* @__PURE__ */ Symbol.for(
27646
+ "braintrust.flue.subscribed-context-events"
27647
+ );
27648
+ function patchFlueContextInPlace(ctx) {
27649
+ const context2 = ctx;
27650
+ if (context2[WRAPPED_FLUE_CONTEXT]) {
27651
+ return ctx;
27652
+ }
27653
+ const originalInit = context2.init.bind(context2);
27654
+ try {
27655
+ Object.defineProperty(context2, WRAPPED_FLUE_CONTEXT, {
27656
+ configurable: false,
27657
+ enumerable: false,
27658
+ value: true
27659
+ });
27660
+ Object.defineProperty(context2, "init", {
27661
+ configurable: true,
27662
+ value: async function wrappedFlueInit(options) {
27663
+ const harness = await originalInit(options);
27664
+ return wrapFlueHarness(harness);
27665
+ },
27666
+ writable: true
27667
+ });
27668
+ } catch {
27669
+ }
27670
+ return ctx;
27060
27671
  }
27061
- var BraintrustPlugin = class extends BasePlugin {
27062
- config;
27063
- openaiPlugin = null;
27064
- openAICodexPlugin = null;
27065
- anthropicPlugin = null;
27066
- aiSDKPlugin = null;
27067
- claudeAgentSDKPlugin = null;
27672
+ function subscribeFlueContextEvents(ctx, options = {}) {
27673
+ if (!ctx || typeof ctx !== "object" || typeof ctx.subscribeEvent !== "function") {
27674
+ return void 0;
27675
+ }
27676
+ const context2 = ctx;
27677
+ const captureTurnSpans = options.captureTurnSpans ?? true;
27678
+ const existingSubscription = context2[SUBSCRIBED_FLUE_CONTEXT_EVENTS];
27679
+ if (existingSubscription) {
27680
+ if (existingSubscription.captureTurnSpans || !captureTurnSpans) {
27681
+ return void 0;
27682
+ }
27683
+ try {
27684
+ existingSubscription.unsubscribe();
27685
+ } catch {
27686
+ }
27687
+ }
27688
+ try {
27689
+ const unsubscribe = ctx.subscribeEvent((event) => {
27690
+ flueChannels.contextEvent.traceSync(() => void 0, {
27691
+ arguments: [event],
27692
+ captureTurnSpans,
27693
+ context: ctx
27694
+ });
27695
+ });
27696
+ if (existingSubscription) {
27697
+ existingSubscription.captureTurnSpans = captureTurnSpans;
27698
+ existingSubscription.unsubscribe = unsubscribe;
27699
+ } else {
27700
+ Object.defineProperty(context2, SUBSCRIBED_FLUE_CONTEXT_EVENTS, {
27701
+ configurable: false,
27702
+ enumerable: false,
27703
+ value: {
27704
+ captureTurnSpans,
27705
+ unsubscribe
27706
+ }
27707
+ });
27708
+ }
27709
+ return unsubscribe;
27710
+ } catch {
27711
+ return void 0;
27712
+ }
27713
+ }
27714
+ function wrapFlueHarness(harness) {
27715
+ if (!isPlausibleFlueHarness(harness)) {
27716
+ return harness;
27717
+ }
27718
+ const target = harness;
27719
+ if (target[WRAPPED_FLUE_HARNESS]) {
27720
+ return harness;
27721
+ }
27722
+ const originalSession = target.session.bind(target);
27723
+ try {
27724
+ Object.defineProperty(target, WRAPPED_FLUE_HARNESS, {
27725
+ configurable: false,
27726
+ enumerable: false,
27727
+ value: true
27728
+ });
27729
+ Object.defineProperty(target, "session", {
27730
+ configurable: true,
27731
+ value: async function wrappedFlueHarnessSession(name, options) {
27732
+ const session = await originalSession(name, options);
27733
+ return patchFlueSessionInPlace(session);
27734
+ },
27735
+ writable: true
27736
+ });
27737
+ const sessions = target.sessions;
27738
+ if (sessions && typeof sessions === "object") {
27739
+ patchFlueSessionFactory(sessions, "get");
27740
+ patchFlueSessionFactory(sessions, "create");
27741
+ }
27742
+ } catch {
27743
+ }
27744
+ return harness;
27745
+ }
27746
+ function patchFlueSessionInPlace(session) {
27747
+ if (session[WRAPPED_FLUE_SESSION]) {
27748
+ return session;
27749
+ }
27750
+ try {
27751
+ Object.defineProperty(session, WRAPPED_FLUE_SESSION, {
27752
+ configurable: false,
27753
+ enumerable: false,
27754
+ value: true
27755
+ });
27756
+ patchCallHandleMethod(session, "prompt", flueChannels.prompt);
27757
+ patchCallHandleMethod(session, "skill", flueChannels.skill);
27758
+ patchCallHandleMethod(session, "task", flueChannels.task);
27759
+ patchCompact(session);
27760
+ } catch {
27761
+ }
27762
+ return session;
27763
+ }
27764
+ function patchFlueSessionFactory(sessions, method) {
27765
+ const original = sessions[method];
27766
+ if (typeof original !== "function") {
27767
+ return;
27768
+ }
27769
+ const bound = original.bind(sessions);
27770
+ Object.defineProperty(sessions, method, {
27771
+ configurable: true,
27772
+ value: async function wrappedFlueSessionFactory(name, options) {
27773
+ const session = await bound(name, options);
27774
+ return patchFlueSessionInPlace(session);
27775
+ },
27776
+ writable: true
27777
+ });
27778
+ }
27779
+ function patchCallHandleMethod(session, method, channel2) {
27780
+ const original = session[method];
27781
+ if (typeof original !== "function") {
27782
+ return;
27783
+ }
27784
+ const bound = original.bind(session);
27785
+ Object.defineProperty(session, method, {
27786
+ configurable: true,
27787
+ value(input, options) {
27788
+ const args = [input, options];
27789
+ const { originalResult, traced: traced2 } = traceFlueOperation(channel2, {
27790
+ context: {
27791
+ arguments: args,
27792
+ operation: method,
27793
+ session
27794
+ },
27795
+ run: () => bound(input, options)
27796
+ });
27797
+ return preserveCallHandle(originalResult, traced2);
27798
+ },
27799
+ writable: true
27800
+ });
27801
+ }
27802
+ function patchCompact(session) {
27803
+ const original = session.compact;
27804
+ if (typeof original !== "function") {
27805
+ return;
27806
+ }
27807
+ const bound = original.bind(session);
27808
+ Object.defineProperty(session, "compact", {
27809
+ configurable: true,
27810
+ value() {
27811
+ const context2 = {
27812
+ arguments: [],
27813
+ operation: "compact",
27814
+ session
27815
+ };
27816
+ return flueChannels.compact.tracePromise(() => bound(), context2);
27817
+ },
27818
+ writable: true
27819
+ });
27820
+ }
27821
+ function traceFlueOperation(channel2, args) {
27822
+ const tracingChannel2 = channel2.tracingChannel();
27823
+ const context2 = args.context;
27824
+ let originalResult;
27825
+ let traced2;
27826
+ const run2 = () => {
27827
+ try {
27828
+ originalResult = args.run();
27829
+ tracingChannel2.end?.publish(context2);
27830
+ } catch (error2) {
27831
+ context2.error = normalizeError3(error2);
27832
+ tracingChannel2.error?.publish(context2);
27833
+ tracingChannel2.end?.publish(context2);
27834
+ throw error2;
27835
+ }
27836
+ traced2 = Promise.resolve(originalResult).then(
27837
+ (result) => {
27838
+ context2.result = result;
27839
+ tracingChannel2.asyncStart?.publish(context2);
27840
+ tracingChannel2.asyncEnd?.publish(context2);
27841
+ return result;
27842
+ },
27843
+ (error2) => {
27844
+ context2.error = normalizeError3(error2);
27845
+ tracingChannel2.error?.publish(context2);
27846
+ tracingChannel2.asyncStart?.publish(context2);
27847
+ tracingChannel2.asyncEnd?.publish(context2);
27848
+ throw error2;
27849
+ }
27850
+ );
27851
+ };
27852
+ if (tracingChannel2.start?.runStores) {
27853
+ tracingChannel2.start.runStores(context2, run2);
27854
+ } else {
27855
+ tracingChannel2.start?.publish(context2);
27856
+ run2();
27857
+ }
27858
+ return { originalResult, traced: traced2 };
27859
+ }
27860
+ function normalizeError3(error2) {
27861
+ return error2 instanceof Error ? error2 : new Error(String(error2));
27862
+ }
27863
+ function preserveCallHandle(originalHandle, traced2) {
27864
+ if (!isFlueCallHandle(originalHandle)) {
27865
+ return traced2;
27866
+ }
27867
+ const handle = originalHandle;
27868
+ const wrapped = {
27869
+ get signal() {
27870
+ return handle.signal;
27871
+ },
27872
+ abort(reason) {
27873
+ return handle.abort(reason);
27874
+ },
27875
+ then(onfulfilled, onrejected) {
27876
+ return traced2.then(onfulfilled, onrejected);
27877
+ }
27878
+ };
27879
+ return wrapped;
27880
+ }
27881
+ function isPlausibleFlueHarness(value) {
27882
+ return !!value && typeof value === "object" && typeof value.session === "function";
27883
+ }
27884
+ function isFlueCallHandle(value) {
27885
+ return !!value && typeof value === "object" && typeof value.then === "function" && typeof value.abort === "function" && "signal" in value;
27886
+ }
27887
+
27888
+ // src/instrumentation/plugins/flue-plugin.ts
27889
+ var FluePlugin = class extends BasePlugin {
27890
+ activeOperationsById = /* @__PURE__ */ new Map();
27891
+ activeOperationsByScope = /* @__PURE__ */ new Map();
27892
+ compactionsByScope = /* @__PURE__ */ new Map();
27893
+ pendingOperationsByKey = /* @__PURE__ */ new Map();
27894
+ tasksById = /* @__PURE__ */ new Map();
27895
+ toolsById = /* @__PURE__ */ new Map();
27896
+ turnsByScope = /* @__PURE__ */ new Map();
27897
+ onEnable() {
27898
+ this.subscribeToContextCreation();
27899
+ this.subscribeToSessionCreation();
27900
+ this.subscribeToContextEvents();
27901
+ this.subscribeToSessionOperations();
27902
+ }
27903
+ onDisable() {
27904
+ for (const unsubscribe of this.unsubscribers) {
27905
+ unsubscribe();
27906
+ }
27907
+ this.unsubscribers = [];
27908
+ this.activeOperationsById.clear();
27909
+ this.activeOperationsByScope.clear();
27910
+ this.compactionsByScope.clear();
27911
+ this.pendingOperationsByKey.clear();
27912
+ this.tasksById.clear();
27913
+ this.toolsById.clear();
27914
+ this.turnsByScope.clear();
27915
+ }
27916
+ subscribeToContextCreation() {
27917
+ const channel2 = flueChannels.createContext.tracingChannel();
27918
+ const handlers = {
27919
+ end: (event) => {
27920
+ const ctx = event.result;
27921
+ if (!ctx) {
27922
+ return;
27923
+ }
27924
+ subscribeFlueContextEvents(ctx, { captureTurnSpans: false });
27925
+ patchFlueContextInPlace(ctx);
27926
+ },
27927
+ error: () => {
27928
+ }
27929
+ };
27930
+ channel2.subscribe(handlers);
27931
+ this.unsubscribers.push(() => {
27932
+ channel2.unsubscribe(handlers);
27933
+ });
27934
+ }
27935
+ subscribeToSessionCreation() {
27936
+ const channel2 = flueChannels.openSession.tracingChannel();
27937
+ const handlers = {
27938
+ asyncEnd: (event) => {
27939
+ if (event.result) {
27940
+ patchFlueSessionInPlace(
27941
+ event.result
27942
+ );
27943
+ }
27944
+ if (event.harness) {
27945
+ wrapFlueHarness(event.harness);
27946
+ }
27947
+ },
27948
+ error: () => {
27949
+ }
27950
+ };
27951
+ channel2.subscribe(handlers);
27952
+ this.unsubscribers.push(() => {
27953
+ channel2.unsubscribe(handlers);
27954
+ });
27955
+ }
27956
+ subscribeToSessionOperations() {
27957
+ this.subscribeToSessionOperation(flueChannels.prompt);
27958
+ this.subscribeToSessionOperation(flueChannels.skill);
27959
+ this.subscribeToSessionOperation(flueChannels.task);
27960
+ this.subscribeToCompact();
27961
+ }
27962
+ subscribeToSessionOperation(channel2) {
27963
+ const tracingChannel2 = channel2.tracingChannel();
27964
+ const states = /* @__PURE__ */ new WeakMap();
27965
+ const ensureState2 = (event) => {
27966
+ const existing = states.get(event);
27967
+ if (existing) {
27968
+ return existing;
27969
+ }
27970
+ const state = this.startOperationState({
27971
+ args: event.arguments,
27972
+ moduleVersion: typeof event.moduleVersion === "string" ? event.moduleVersion : void 0,
27973
+ operation: event.operation,
27974
+ session: event.session
27975
+ });
27976
+ states.set(event, state);
27977
+ return state;
27978
+ };
27979
+ const unbindCurrentSpanStore = this.bindCurrentSpanStoreToOperationStart(
27980
+ tracingChannel2,
27981
+ ensureState2
27982
+ );
27983
+ const handlers = {
27984
+ start: (event) => {
27985
+ ensureState2(event);
27986
+ },
27987
+ asyncEnd: (event) => {
27988
+ this.endOperationState(states.get(event), event.result);
27989
+ states.delete(event);
27990
+ },
27991
+ error: (event) => {
27992
+ const state = states.get(event);
27993
+ if (state && event.error) {
27994
+ safeLog3(state.span, { error: errorToString(event.error) });
27995
+ this.finishOperationState(state);
27996
+ }
27997
+ states.delete(event);
27998
+ }
27999
+ };
28000
+ tracingChannel2.subscribe(handlers);
28001
+ this.unsubscribers.push(() => {
28002
+ unbindCurrentSpanStore?.();
28003
+ tracingChannel2.unsubscribe(handlers);
28004
+ });
28005
+ }
28006
+ subscribeToCompact() {
28007
+ const tracingChannel2 = flueChannels.compact.tracingChannel();
28008
+ const states = /* @__PURE__ */ new WeakMap();
28009
+ const ensureState2 = (event) => {
28010
+ const existing = states.get(event);
28011
+ if (existing) {
28012
+ return existing;
28013
+ }
28014
+ const state = this.startOperationState({
28015
+ args: [],
28016
+ moduleVersion: typeof event.moduleVersion === "string" ? event.moduleVersion : void 0,
28017
+ operation: event.operation,
28018
+ session: event.session
28019
+ });
28020
+ states.set(event, state);
28021
+ return state;
28022
+ };
28023
+ const unbindCurrentSpanStore = this.bindCurrentSpanStoreToOperationStart(
28024
+ tracingChannel2,
28025
+ ensureState2
28026
+ );
28027
+ const handlers = {
28028
+ start: (event) => {
28029
+ ensureState2(event);
28030
+ },
28031
+ asyncEnd: (event) => {
28032
+ this.endOperationState(states.get(event), void 0);
28033
+ states.delete(event);
28034
+ },
28035
+ error: (event) => {
28036
+ const state = states.get(event);
28037
+ if (state && event.error) {
28038
+ safeLog3(state.span, { error: errorToString(event.error) });
28039
+ this.finishOperationState(state);
28040
+ }
28041
+ states.delete(event);
28042
+ }
28043
+ };
28044
+ tracingChannel2.subscribe(handlers);
28045
+ this.unsubscribers.push(() => {
28046
+ unbindCurrentSpanStore?.();
28047
+ tracingChannel2.unsubscribe(handlers);
28048
+ });
28049
+ }
28050
+ subscribeToContextEvents() {
28051
+ const channel2 = flueChannels.contextEvent.tracingChannel();
28052
+ const handlers = {
28053
+ start: (event) => {
28054
+ const flueEvent = event.arguments[0];
28055
+ if (!flueEvent) {
28056
+ return;
28057
+ }
28058
+ try {
28059
+ this.handleFlueEvent(flueEvent, {
28060
+ captureTurnSpans: event.captureTurnSpans !== false
28061
+ });
28062
+ } catch (error2) {
28063
+ logInstrumentationError3("Flue event", error2);
28064
+ }
28065
+ },
28066
+ error: () => {
28067
+ }
28068
+ };
28069
+ channel2.subscribe(handlers);
28070
+ this.unsubscribers.push(() => {
28071
+ channel2.unsubscribe(handlers);
28072
+ });
28073
+ }
28074
+ bindCurrentSpanStoreToOperationStart(tracingChannel2, ensureState2) {
28075
+ const state = _internalGetGlobalState();
28076
+ const startChannel = tracingChannel2.start;
28077
+ const contextManager = state?.contextManager;
28078
+ const currentSpanStore = contextManager ? contextManager[BRAINTRUST_CURRENT_SPAN_STORE] : void 0;
28079
+ if (!currentSpanStore || !startChannel) {
28080
+ return void 0;
28081
+ }
28082
+ startChannel.bindStore(currentSpanStore, (event) => {
28083
+ const operationState = ensureState2(event);
28084
+ return contextManager.wrapSpanForStore(operationState.span);
28085
+ });
28086
+ return () => {
28087
+ startChannel.unbindStore(currentSpanStore);
28088
+ };
28089
+ }
28090
+ startOperationState(args) {
28091
+ const sessionName = getSessionName(args.session);
28092
+ const metadata = {
28093
+ ...extractOperationInputMetadata(args.operation, args.args),
28094
+ ...extractSessionMetadata(args.session),
28095
+ "flue.operation": args.operation,
28096
+ provider: "flue",
28097
+ ...args.moduleVersion ? { "flue.version": args.moduleVersion } : {}
28098
+ };
28099
+ const span = startSpan({
28100
+ name: `flue.session.${args.operation}`,
28101
+ spanAttributes: { type: "task" /* TASK */ }
28102
+ });
28103
+ const state = {
28104
+ metadata,
28105
+ operation: args.operation,
28106
+ sessionName,
28107
+ span,
28108
+ startTime: getCurrentUnixTimestamp()
28109
+ };
28110
+ safeLog3(span, {
28111
+ input: extractOperationInput(args.operation, args.args),
28112
+ metadata
28113
+ });
28114
+ this.pendingOperationQueue(operationKey(sessionName, args.operation)).push(
28115
+ state
28116
+ );
28117
+ addOperationToScope(
28118
+ this.activeOperationsByScope,
28119
+ sessionName ?? "unknown",
28120
+ state
28121
+ );
28122
+ return state;
28123
+ }
28124
+ endOperationState(state, result) {
28125
+ if (!state) {
28126
+ return;
28127
+ }
28128
+ const metadata = {
28129
+ ...state.metadata,
28130
+ ...extractPromptResponseMetadata(result)
28131
+ };
28132
+ const metrics = {
28133
+ ...buildDurationMetrics3(state.startTime),
28134
+ ...metricsFromUsage(result?.usage)
28135
+ };
28136
+ safeLog3(state.span, {
28137
+ metadata,
28138
+ metrics,
28139
+ output: extractOperationOutput(result)
28140
+ });
28141
+ this.finishCompactionsForOperation(state);
28142
+ this.finishOperationState(state);
28143
+ }
28144
+ finishOperationState(state) {
28145
+ removePendingOperation(this.pendingOperationsByKey, state);
28146
+ if (state.operationId) {
28147
+ this.activeOperationsById.delete(state.operationId);
28148
+ }
28149
+ removeScopedOperation(this.activeOperationsByScope, state);
28150
+ state.span.end();
28151
+ }
28152
+ handleFlueEvent(event, options) {
28153
+ switch (event.type) {
28154
+ case "operation_start":
28155
+ this.handleOperationStart(event);
28156
+ return;
28157
+ case "operation":
28158
+ this.handleOperation(event);
28159
+ return;
28160
+ case "text_delta":
28161
+ if (!options.captureTurnSpans) {
28162
+ return;
28163
+ }
28164
+ this.ensureTurnState(event).text.push(
28165
+ typeof event.text === "string" ? event.text : ""
28166
+ );
28167
+ return;
28168
+ case "thinking_start":
28169
+ if (!options.captureTurnSpans) {
28170
+ return;
28171
+ }
28172
+ this.handleThinkingStart(event);
28173
+ return;
28174
+ case "thinking_delta":
28175
+ if (!options.captureTurnSpans) {
28176
+ return;
28177
+ }
28178
+ this.handleThinkingDelta(event);
28179
+ return;
28180
+ case "thinking_end":
28181
+ if (!options.captureTurnSpans) {
28182
+ return;
28183
+ }
28184
+ this.handleThinkingEnd(event);
28185
+ return;
28186
+ case "turn":
28187
+ if (!options.captureTurnSpans) {
28188
+ return;
28189
+ }
28190
+ this.handleTurn(event);
28191
+ return;
28192
+ case "tool_start":
28193
+ this.handleToolStart(event, options);
28194
+ return;
28195
+ case "tool_call":
28196
+ this.handleToolCall(event);
28197
+ return;
28198
+ case "task_start":
28199
+ this.handleTaskStart(event);
28200
+ return;
28201
+ case "task":
28202
+ this.handleTask(event);
28203
+ return;
28204
+ case "compaction_start":
28205
+ this.handleCompactionStart(event);
28206
+ return;
28207
+ case "compaction":
28208
+ this.handleCompaction(event);
28209
+ return;
28210
+ default:
28211
+ return;
28212
+ }
28213
+ }
28214
+ handleOperationStart(event) {
28215
+ if (!isInstrumentedOperation(event.operationKind)) {
28216
+ return;
28217
+ }
28218
+ const state = this.takePendingOperationForEvent(event);
28219
+ if (!state) {
28220
+ return;
28221
+ }
28222
+ state.operationId = event.operationId;
28223
+ this.activeOperationsById.set(event.operationId, state);
28224
+ addScopedOperation(this.activeOperationsByScope, event, state);
28225
+ state.metadata = {
28226
+ ...state.metadata,
28227
+ ...extractEventMetadata(event),
28228
+ "flue.operation_id": event.operationId
28229
+ };
28230
+ safeLog3(state.span, { metadata: state.metadata });
28231
+ }
28232
+ handleOperation(event) {
28233
+ const state = event.operationId ? this.activeOperationsById.get(event.operationId) : void 0;
28234
+ if (!state) {
28235
+ return;
28236
+ }
28237
+ const metadata = {
28238
+ ...state.metadata,
28239
+ ...extractEventMetadata(event),
28240
+ ...typeof event.durationMs === "number" ? { "flue.duration_ms": event.durationMs } : {},
28241
+ ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {}
28242
+ };
28243
+ const metrics = metricsFromUsage(event.usage);
28244
+ safeLog3(state.span, {
28245
+ ...event.error ? { error: errorToString(event.error) } : {},
28246
+ metadata,
28247
+ ...Object.keys(metrics).length ? { metrics } : {}
28248
+ });
28249
+ }
28250
+ ensureTurnState(event) {
28251
+ const scope = scopeKey(event);
28252
+ const existing = this.turnsByScope.get(scope);
28253
+ if (existing) {
28254
+ return existing;
28255
+ }
28256
+ const parent = this.parentSpanForEvent(event);
28257
+ const metadata = {
28258
+ ...extractEventMetadata(event),
28259
+ provider: "flue"
28260
+ };
28261
+ const span = startFlueSpan(parent, {
28262
+ name: "flue.turn",
28263
+ spanAttributes: { type: "llm" /* LLM */ }
28264
+ });
28265
+ const state = {
28266
+ metadata,
28267
+ span,
28268
+ hasThinking: false,
28269
+ startTime: getCurrentUnixTimestamp(),
28270
+ text: [],
28271
+ thinking: [],
28272
+ toolCalls: []
28273
+ };
28274
+ safeLog3(span, { metadata });
28275
+ this.turnsByScope.set(scope, state);
28276
+ return state;
28277
+ }
28278
+ handleTurn(event) {
28279
+ const scope = scopeKey(event);
28280
+ const state = this.ensureTurnState(event);
28281
+ const text = state.text.join("");
28282
+ const reasoning = state.finalThinking ?? state.thinking.join("");
28283
+ const outputReasoning = reasoning || (state.hasThinking ? "[reasoning stream present; content unavailable]" : void 0);
28284
+ const metadata = {
28285
+ ...state.metadata,
28286
+ ...extractEventMetadata(event),
28287
+ ...event.model ? { model: event.model, "flue.model": event.model } : {},
28288
+ ...event.stopReason ? { "flue.stop_reason": event.stopReason } : {},
28289
+ ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {},
28290
+ provider: "flue"
28291
+ };
28292
+ safeLog3(state.span, {
28293
+ ...event.error ? { error: errorToString(event.error) } : {},
28294
+ metadata,
28295
+ metrics: {
28296
+ ...durationMsMetrics(event.durationMs),
28297
+ ...metricsFromUsage(event.usage)
28298
+ },
28299
+ output: toAssistantOutput(
28300
+ text,
28301
+ event.stopReason,
28302
+ outputReasoning,
28303
+ state.toolCalls
28304
+ )
28305
+ });
28306
+ state.span.end();
28307
+ this.turnsByScope.delete(scope);
28308
+ }
28309
+ handleThinkingDelta(event) {
28310
+ const delta = event.delta;
28311
+ if (typeof delta !== "string" || !delta) {
28312
+ return;
28313
+ }
28314
+ const state = this.ensureTurnState(event);
28315
+ state.hasThinking = true;
28316
+ state.metadata["flue.thinking"] = true;
28317
+ state.thinking.push(delta);
28318
+ }
28319
+ handleThinkingStart(event) {
28320
+ const state = this.ensureTurnState(event);
28321
+ state.hasThinking = true;
28322
+ state.metadata["flue.thinking"] = true;
28323
+ }
28324
+ handleThinkingEnd(event) {
28325
+ const state = this.ensureTurnState(event);
28326
+ state.hasThinking = true;
28327
+ state.metadata["flue.thinking"] = true;
28328
+ if (typeof event.content === "string" && event.content) {
28329
+ state.finalThinking = event.content;
28330
+ }
28331
+ }
28332
+ handleToolStart(event, options) {
28333
+ const toolCallId = event.toolCallId;
28334
+ if (!toolCallId) {
28335
+ return;
28336
+ }
28337
+ const parent = this.parentSpanForEvent(event);
28338
+ const scope = scopeKey(event);
28339
+ let turnState = this.turnsByScope.get(scope);
28340
+ if (!turnState && parent && options.captureTurnSpans) {
28341
+ turnState = this.ensureTurnState(event);
28342
+ }
28343
+ const metadata = {
28344
+ ...extractEventMetadata(event),
28345
+ ...event.toolName ? { "flue.tool_name": event.toolName } : {},
28346
+ "flue.tool_call_id": toolCallId,
28347
+ provider: "flue"
28348
+ };
28349
+ const span = startFlueSpan(parent, {
28350
+ name: `tool: ${event.toolName ?? "unknown"}`,
28351
+ spanAttributes: { type: "tool" /* TOOL */ }
28352
+ });
28353
+ if (turnState) {
28354
+ turnState.toolCalls.push({
28355
+ args: event.args,
28356
+ toolCallId,
28357
+ toolName: event.toolName
28358
+ });
28359
+ }
28360
+ safeLog3(span, {
28361
+ input: event.args,
28362
+ metadata
28363
+ });
28364
+ this.toolsById.set(toolKey(event), {
28365
+ metadata,
28366
+ span,
28367
+ startTime: getCurrentUnixTimestamp()
28368
+ });
28369
+ }
28370
+ handleToolCall(event) {
28371
+ const key = toolKey(event);
28372
+ const state = this.toolsById.get(key) ?? this.startSyntheticToolState(event, event.toolName ?? "unknown");
28373
+ const metadata = {
28374
+ ...state.metadata,
28375
+ ...extractEventMetadata(event),
28376
+ ...event.toolName ? { "flue.tool_name": event.toolName } : {},
28377
+ ...event.toolCallId ? { "flue.tool_call_id": event.toolCallId } : {},
28378
+ ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {}
28379
+ };
28380
+ safeLog3(state.span, {
28381
+ ...event.isError ? { error: errorToString(event.result) } : {},
28382
+ metadata,
28383
+ metrics: durationMsMetrics(event.durationMs),
28384
+ output: event.result
28385
+ });
28386
+ state.span.end();
28387
+ this.toolsById.delete(key);
28388
+ }
28389
+ handleTaskStart(event) {
28390
+ const parent = this.parentSpanForEvent(event);
28391
+ const metadata = {
28392
+ ...extractEventMetadata(event),
28393
+ ...event.role ? { "flue.role": event.role } : {},
28394
+ ...event.cwd ? { "flue.cwd": event.cwd } : {},
28395
+ "flue.task_id": event.taskId,
28396
+ provider: "flue"
28397
+ };
28398
+ const span = startFlueSpan(parent, {
28399
+ name: "flue.task",
28400
+ spanAttributes: { type: "task" /* TASK */ }
28401
+ });
28402
+ safeLog3(span, {
28403
+ input: event.prompt,
28404
+ metadata
28405
+ });
28406
+ this.tasksById.set(event.taskId, {
28407
+ metadata,
28408
+ span,
28409
+ startTime: getCurrentUnixTimestamp()
28410
+ });
28411
+ }
28412
+ handleTask(event) {
28413
+ const state = this.tasksById.get(event.taskId);
28414
+ if (!state) {
28415
+ return;
28416
+ }
28417
+ safeLog3(state.span, {
28418
+ ...event.isError ? { error: errorToString(event.result) } : {},
28419
+ metadata: {
28420
+ ...state.metadata,
28421
+ ...extractEventMetadata(event),
28422
+ ...event.isError !== void 0 ? { "flue.is_error": event.isError } : {}
28423
+ },
28424
+ metrics: durationMsMetrics(event.durationMs),
28425
+ output: event.result
28426
+ });
28427
+ state.span.end();
28428
+ this.tasksById.delete(event.taskId);
28429
+ }
28430
+ handleCompactionStart(event) {
28431
+ const operationState = this.operationStateForEvent(event);
28432
+ const parent = operationState?.span ?? this.parentSpanForEvent(event);
28433
+ const metadata = {
28434
+ ...extractEventMetadata(event),
28435
+ ...event.reason ? { "flue.compaction_reason": event.reason } : {},
28436
+ provider: "flue"
28437
+ };
28438
+ const input = {
28439
+ ...typeof event.estimatedTokens === "number" ? { estimatedTokens: event.estimatedTokens } : {},
28440
+ ...event.reason ? { reason: event.reason } : {}
28441
+ };
28442
+ const span = startFlueSpan(parent, {
28443
+ name: "flue.compaction",
28444
+ spanAttributes: { type: "task" /* TASK */ }
28445
+ });
28446
+ safeLog3(span, {
28447
+ input,
28448
+ metadata
28449
+ });
28450
+ this.compactionsByScope.set(scopeKey(event), {
28451
+ input,
28452
+ metadata,
28453
+ operationState,
28454
+ span,
28455
+ startTime: getCurrentUnixTimestamp()
28456
+ });
28457
+ }
28458
+ handleCompaction(event) {
28459
+ const key = scopeKey(event);
28460
+ const state = this.compactionsByScope.get(key) ?? this.findCompactionState(event);
28461
+ if (!state) {
28462
+ return;
28463
+ }
28464
+ safeLog3(state.span, {
28465
+ metadata: {
28466
+ ...state.metadata,
28467
+ ...extractEventMetadata(event),
28468
+ ...typeof event.messagesBefore === "number" ? { "flue.messages_before": event.messagesBefore } : {},
28469
+ ...typeof event.messagesAfter === "number" ? { "flue.messages_after": event.messagesAfter } : {}
28470
+ },
28471
+ metrics: {
28472
+ ...durationMsMetrics(event.durationMs),
28473
+ ...metricsFromUsage(event.usage)
28474
+ },
28475
+ output: {
28476
+ messagesAfter: event.messagesAfter,
28477
+ messagesBefore: event.messagesBefore
28478
+ }
28479
+ });
28480
+ state.span.end();
28481
+ this.deleteCompactionState(state);
28482
+ }
28483
+ findCompactionState(event) {
28484
+ const operationState = this.operationStateForEvent(event);
28485
+ for (const state of this.compactionsByScope.values()) {
28486
+ if (operationState && state.operationState === operationState) {
28487
+ return state;
28488
+ }
28489
+ }
28490
+ return void 0;
28491
+ }
28492
+ finishCompactionsForOperation(operationState) {
28493
+ for (const state of [...this.compactionsByScope.values()]) {
28494
+ if (state.operationState !== operationState) {
28495
+ continue;
28496
+ }
28497
+ safeLog3(state.span, {
28498
+ input: state.input,
28499
+ metadata: state.metadata,
28500
+ metrics: {
28501
+ ...buildDurationMetrics3(state.startTime)
28502
+ },
28503
+ output: { completed: true }
28504
+ });
28505
+ state.span.end();
28506
+ this.deleteCompactionState(state);
28507
+ }
28508
+ }
28509
+ deleteCompactionState(state) {
28510
+ for (const [key, candidate] of this.compactionsByScope) {
28511
+ if (candidate !== state) {
28512
+ continue;
28513
+ }
28514
+ this.compactionsByScope.delete(key);
28515
+ return;
28516
+ }
28517
+ }
28518
+ startSyntheticToolState(event, toolName) {
28519
+ const parent = this.parentSpanForEvent(event);
28520
+ const metadata = {
28521
+ ...extractEventMetadata(event),
28522
+ ...event.toolCallId ? { "flue.tool_call_id": event.toolCallId } : {},
28523
+ "flue.tool_name": toolName,
28524
+ provider: "flue"
28525
+ };
28526
+ const span = startFlueSpan(parent, {
28527
+ name: `tool: ${toolName}`,
28528
+ spanAttributes: { type: "tool" /* TOOL */ }
28529
+ });
28530
+ safeLog3(span, { metadata });
28531
+ return { metadata, span, startTime: getCurrentUnixTimestamp() };
28532
+ }
28533
+ operationStateForEvent(event) {
28534
+ if (event.operationId) {
28535
+ const operation = this.activeOperationsById.get(event.operationId) ?? this.promotePendingOperationForEvent(event);
28536
+ if (operation) {
28537
+ return operation;
28538
+ }
28539
+ }
28540
+ return this.activeOperationForEventScope(event) ?? this.pendingOperationForEventScope(event);
28541
+ }
28542
+ parentSpanForEvent(event) {
28543
+ if (event.operationId) {
28544
+ const operation = this.operationStateForEvent(event);
28545
+ if (operation) {
28546
+ return operation.span;
28547
+ }
28548
+ }
28549
+ if (event.taskId) {
28550
+ return this.tasksById.get(event.taskId)?.span;
28551
+ }
28552
+ return this.operationStateForEvent(event)?.span;
28553
+ }
28554
+ promotePendingOperationForEvent(event) {
28555
+ if (!event.operationId) {
28556
+ return void 0;
28557
+ }
28558
+ const scopePrefixes = operationScopePrefixes(event);
28559
+ for (const [candidateKey, candidateQueue] of this.pendingOperationsByKey) {
28560
+ if (!candidateQueue.length || !operationKeyMatchesScopes(candidateKey, scopePrefixes)) {
28561
+ continue;
28562
+ }
28563
+ const state = candidateQueue.shift();
28564
+ if (!state) {
28565
+ return void 0;
28566
+ }
28567
+ state.operationId = event.operationId;
28568
+ this.activeOperationsById.set(event.operationId, state);
28569
+ addScopedOperation(this.activeOperationsByScope, event, state);
28570
+ state.metadata = {
28571
+ ...state.metadata,
28572
+ ...extractEventMetadata(event),
28573
+ "flue.operation_id": event.operationId
28574
+ };
28575
+ safeLog3(state.span, { metadata: state.metadata });
28576
+ return state;
28577
+ }
28578
+ return void 0;
28579
+ }
28580
+ activeOperationForEventScope(event) {
28581
+ for (const scope of operationScopeNames(event)) {
28582
+ const operations = this.activeOperationsByScope.get(scope);
28583
+ if (operations?.length) {
28584
+ return operations[operations.length - 1];
28585
+ }
28586
+ }
28587
+ return void 0;
28588
+ }
28589
+ pendingOperationForEventScope(event) {
28590
+ const scopePrefixes = operationScopePrefixes(event);
28591
+ for (const [candidateKey, candidateQueue] of this.pendingOperationsByKey) {
28592
+ if (!candidateQueue.length || !operationKeyMatchesScopes(candidateKey, scopePrefixes)) {
28593
+ continue;
28594
+ }
28595
+ return candidateQueue[0];
28596
+ }
28597
+ return void 0;
28598
+ }
28599
+ takePendingOperationForEvent(event) {
28600
+ const key = operationKey(event.session, event.operationKind);
28601
+ const queue2 = this.pendingOperationsByKey.get(key);
28602
+ if (queue2?.length) {
28603
+ return queue2.shift();
28604
+ }
28605
+ for (const [candidateKey, candidateQueue] of this.pendingOperationsByKey) {
28606
+ if (candidateKey.endsWith(`::${event.operationKind}`) && candidateQueue.length) {
28607
+ return candidateQueue.shift();
28608
+ }
28609
+ }
28610
+ return void 0;
28611
+ }
28612
+ pendingOperationQueue(key) {
28613
+ const existing = this.pendingOperationsByKey.get(key);
28614
+ if (existing) {
28615
+ return existing;
28616
+ }
28617
+ const queue2 = [];
28618
+ this.pendingOperationsByKey.set(key, queue2);
28619
+ return queue2;
28620
+ }
28621
+ };
28622
+ function isInstrumentedOperation(operation) {
28623
+ return operation === "prompt" || operation === "skill" || operation === "task" || operation === "compact";
28624
+ }
28625
+ function getSessionName(session) {
28626
+ return typeof session?.name === "string" ? session.name : void 0;
28627
+ }
28628
+ function operationKey(sessionName, operation) {
28629
+ return `${sessionName ?? "unknown"}::${operation}`;
28630
+ }
28631
+ function operationScopePrefixes(event) {
28632
+ const scopes = /* @__PURE__ */ new Set();
28633
+ for (const scope of operationScopeNames(event)) {
28634
+ scopes.add(`${scope}::`);
28635
+ }
28636
+ return scopes;
28637
+ }
28638
+ function operationKeyMatchesScopes(key, scopes) {
28639
+ for (const scope of scopes) {
28640
+ if (key.startsWith(scope)) {
28641
+ return true;
28642
+ }
28643
+ }
28644
+ return false;
28645
+ }
28646
+ function operationScopeNames(event) {
28647
+ const scopes = /* @__PURE__ */ new Set();
28648
+ if (event.session) {
28649
+ scopes.add(event.session);
28650
+ }
28651
+ if (event.parentSession) {
28652
+ scopes.add(event.parentSession);
28653
+ }
28654
+ if (!scopes.size) {
28655
+ scopes.add("unknown");
28656
+ }
28657
+ return scopes;
28658
+ }
28659
+ function addScopedOperation(operationsByScope, event, state) {
28660
+ for (const scope of operationScopeNames(event)) {
28661
+ addOperationToScope(operationsByScope, scope, state);
28662
+ }
28663
+ }
28664
+ function addOperationToScope(operationsByScope, scope, state) {
28665
+ const operations = operationsByScope.get(scope);
28666
+ if (operations) {
28667
+ if (!operations.includes(state)) {
28668
+ operations.push(state);
28669
+ }
28670
+ } else {
28671
+ operationsByScope.set(scope, [state]);
28672
+ }
28673
+ }
28674
+ function removeScopedOperation(operationsByScope, state) {
28675
+ for (const [scope, operations] of operationsByScope) {
28676
+ const index = operations.indexOf(state);
28677
+ if (index === -1) {
28678
+ continue;
28679
+ }
28680
+ operations.splice(index, 1);
28681
+ if (operations.length === 0) {
28682
+ operationsByScope.delete(scope);
28683
+ }
28684
+ }
28685
+ }
28686
+ function removePendingOperation(pendingOperationsByKey, state) {
28687
+ for (const [key, queue2] of pendingOperationsByKey) {
28688
+ const index = queue2.indexOf(state);
28689
+ if (index === -1) {
28690
+ continue;
28691
+ }
28692
+ queue2.splice(index, 1);
28693
+ if (queue2.length === 0) {
28694
+ pendingOperationsByKey.delete(key);
28695
+ }
28696
+ return;
28697
+ }
28698
+ }
28699
+ function extractSessionMetadata(session) {
28700
+ const sessionName = getSessionName(session);
28701
+ return sessionName ? { "flue.session": sessionName } : {};
28702
+ }
28703
+ function extractEventMetadata(event) {
28704
+ return {
28705
+ ...event.runId ? { "flue.run_id": event.runId } : {},
28706
+ ...typeof event.eventIndex === "number" ? { "flue.event_index": event.eventIndex } : {},
28707
+ ...event.session ? { "flue.session": event.session } : {},
28708
+ ...event.parentSession ? { "flue.parent_session": event.parentSession } : {},
28709
+ ...event.harness ? { "flue.harness": event.harness } : {},
28710
+ ...event.taskId ? { "flue.task_id": event.taskId } : {},
28711
+ ...event.operationId ? { "flue.operation_id": event.operationId } : {}
28712
+ };
28713
+ }
28714
+ function extractOperationInput(operation, args) {
28715
+ switch (operation) {
28716
+ case "prompt":
28717
+ case "task":
28718
+ return args[0];
28719
+ case "skill":
28720
+ return {
28721
+ args: getOptionObject(args[1])?.args,
28722
+ name: args[0]
28723
+ };
28724
+ case "compact":
28725
+ return void 0;
28726
+ }
28727
+ }
28728
+ function extractOperationInputMetadata(operation, args) {
28729
+ const options = getOptionObject(args[1]);
28730
+ return {
28731
+ ...operation === "skill" && typeof args[0] === "string" ? { "flue.skill_name": args[0] } : {},
28732
+ ...options?.model ? { model: options.model, "flue.model": options.model } : {},
28733
+ ...options?.role ? { "flue.role": options.role } : {},
28734
+ ...options?.thinkingLevel ? { "flue.thinking_level": options.thinkingLevel } : {},
28735
+ ...typeof options?.cwd === "string" ? { "flue.cwd": options.cwd } : {},
28736
+ ...Array.isArray(options?.tools) ? {
28737
+ "flue.tools_count": options.tools.length,
28738
+ tools: summarizeTools(options.tools)
28739
+ } : {},
28740
+ ...Array.isArray(options?.images) ? { "flue.images_count": options.images.length } : {},
28741
+ ...options?.result || options?.schema ? { "flue.result_schema": true } : {}
28742
+ };
28743
+ }
28744
+ function getOptionObject(value) {
28745
+ return isObject(value) ? value : void 0;
28746
+ }
28747
+ function summarizeTools(tools) {
28748
+ return tools.flatMap((tool) => {
28749
+ if (!isObject(tool)) {
28750
+ return [];
28751
+ }
28752
+ const name = typeof tool.name === "string" ? tool.name : void 0;
28753
+ if (!name) {
28754
+ return [];
28755
+ }
28756
+ return [
28757
+ {
28758
+ function: {
28759
+ description: typeof tool.description === "string" ? tool.description : void 0,
28760
+ name,
28761
+ parameters: tool.parameters
28762
+ },
28763
+ type: "function"
28764
+ }
28765
+ ];
28766
+ });
28767
+ }
28768
+ function extractPromptResponseMetadata(result) {
28769
+ const modelId = result?.model && typeof result.model.id === "string" ? result.model.id : void 0;
28770
+ return modelId ? {
28771
+ model: modelId,
28772
+ "flue.model": modelId
28773
+ } : {};
28774
+ }
28775
+ function extractOperationOutput(result) {
28776
+ if (!result) {
28777
+ return void 0;
28778
+ }
28779
+ if ("data" in result) {
28780
+ return result.data;
28781
+ }
28782
+ if ("text" in result) {
28783
+ return result.text;
28784
+ }
28785
+ return result;
28786
+ }
28787
+ function metricsFromUsage(usage) {
28788
+ return {
28789
+ ...typeof usage?.input === "number" ? { prompt_tokens: usage.input } : {},
28790
+ ...typeof usage?.output === "number" ? { completion_tokens: usage.output } : {},
28791
+ ...typeof usage?.cacheRead === "number" ? { prompt_cached_tokens: usage.cacheRead } : {},
28792
+ ...typeof usage?.cacheWrite === "number" ? { prompt_cache_creation_tokens: usage.cacheWrite } : {},
28793
+ ...typeof usage?.totalTokens === "number" ? { tokens: usage.totalTokens } : {},
28794
+ ...typeof usage?.cost?.total === "number" ? { estimated_cost: usage.cost.total } : {}
28795
+ };
28796
+ }
28797
+ function buildDurationMetrics3(startTime) {
28798
+ return {
28799
+ duration_ms: Math.max(0, (getCurrentUnixTimestamp() - startTime) * 1e3)
28800
+ };
28801
+ }
28802
+ function durationMsMetrics(durationMs) {
28803
+ return typeof durationMs === "number" ? { duration_ms: durationMs } : {};
28804
+ }
28805
+ function scopeKey(event) {
28806
+ if (event.operationId) {
28807
+ return `operation:${event.operationId}`;
28808
+ }
28809
+ if (event.taskId) {
28810
+ return `task:${event.taskId}`;
28811
+ }
28812
+ if (event.session) {
28813
+ return `session:${event.session}`;
28814
+ }
28815
+ return "flue:unknown";
28816
+ }
28817
+ function toolKey(event) {
28818
+ return `${scopeKey(event)}::tool:${event.toolCallId ?? "unknown"}`;
28819
+ }
28820
+ function toAssistantOutput(text, finishReason, reasoning, toolCalls) {
28821
+ return [
28822
+ {
28823
+ finish_reason: finishReason ?? "stop",
28824
+ index: 0,
28825
+ message: {
28826
+ content: text,
28827
+ ...reasoning ? { reasoning } : {},
28828
+ role: "assistant",
28829
+ ...toolCalls?.length ? {
28830
+ tool_calls: toolCalls.map((toolCall) => ({
28831
+ function: {
28832
+ arguments: toolCall.args === void 0 ? "{}" : JSON.stringify(toolCall.args),
28833
+ name: toolCall.toolName ?? "unknown"
28834
+ },
28835
+ ...toolCall.toolCallId ? { id: toolCall.toolCallId } : {},
28836
+ type: "function"
28837
+ }))
28838
+ } : {}
28839
+ }
28840
+ }
28841
+ ];
28842
+ }
28843
+ function startFlueSpan(parent, args) {
28844
+ return parent ? withCurrent(parent, () => startSpan(args)) : startSpan(args);
28845
+ }
28846
+ function safeLog3(span, event) {
28847
+ try {
28848
+ span.log(event);
28849
+ } catch (error2) {
28850
+ logInstrumentationError3("Flue span log", error2);
28851
+ }
28852
+ }
28853
+ function errorToString(error2) {
28854
+ if (error2 instanceof Error) {
28855
+ return error2.message;
28856
+ }
28857
+ if (typeof error2 === "string") {
28858
+ return error2;
28859
+ }
28860
+ try {
28861
+ return JSON.stringify(error2);
28862
+ } catch {
28863
+ return String(error2);
28864
+ }
28865
+ }
28866
+ function logInstrumentationError3(label, error2) {
28867
+ console.error(`Error in ${label} instrumentation:`, error2);
28868
+ }
28869
+
28870
+ // src/wrappers/langchain/callback-handler.ts
28871
+ var BRAINTRUST_LANGCHAIN_CALLBACK_HANDLER_NAME = "BraintrustCallbackHandler";
28872
+ var BraintrustLangChainCallbackHandler = class {
28873
+ name = BRAINTRUST_LANGCHAIN_CALLBACK_HANDLER_NAME;
28874
+ spans = /* @__PURE__ */ new Map();
28875
+ skippedRuns = /* @__PURE__ */ new Set();
28876
+ parent;
28877
+ rootRunId;
28878
+ options;
28879
+ startTimes = /* @__PURE__ */ new Map();
28880
+ firstTokenTimes = /* @__PURE__ */ new Map();
28881
+ ttftMs = /* @__PURE__ */ new Map();
28882
+ constructor(options) {
28883
+ this.parent = options?.parent;
28884
+ this.options = {
28885
+ debug: options?.debug ?? false,
28886
+ excludeMetadataProps: options?.excludeMetadataProps ?? /^(l[sc]_|langgraph_|__pregel_|checkpoint_ns)/,
28887
+ logger: options?.logger
28888
+ };
28889
+ }
28890
+ startSpan({
28891
+ runId,
28892
+ parentRunId,
28893
+ ...args
28894
+ }) {
28895
+ if (this.spans.has(runId)) {
28896
+ return;
28897
+ }
28898
+ if (!parentRunId) {
28899
+ this.rootRunId = runId;
28900
+ }
28901
+ const tags = args.event?.tags;
28902
+ const spanAttributes = args.spanAttributes || {};
28903
+ spanAttributes.type = args.type || spanAttributes.type || "task";
28904
+ args.type = spanAttributes.type;
28905
+ const currentParent = (typeof this.parent === "function" ? this.parent() : this.parent) ?? currentSpan();
28906
+ let parentSpan;
28907
+ if (parentRunId && this.spans.has(parentRunId)) {
28908
+ parentSpan = this.spans.get(parentRunId);
28909
+ } else if (!Object.is(currentParent, NOOP_SPAN)) {
28910
+ parentSpan = currentParent;
28911
+ } else if (this.options.logger) {
28912
+ parentSpan = this.options.logger;
28913
+ } else {
28914
+ parentSpan = { startSpan };
28915
+ }
28916
+ args.event = {
28917
+ ...args.event,
28918
+ tags: void 0,
28919
+ metadata: {
28920
+ ...tags ? { tags } : {},
28921
+ ...args.event?.metadata,
28922
+ braintrust: {
28923
+ integration_name: "langchain-js",
28924
+ sdk_language: "javascript"
28925
+ },
28926
+ run_id: runId,
28927
+ parent_run_id: parentRunId,
28928
+ ...this.options.debug ? { runId, parentRunId } : {}
28929
+ }
28930
+ };
28931
+ let span = parentSpan.startSpan(args);
28932
+ if (!Object.is(this.options.logger, NOOP_SPAN) && Object.is(span, NOOP_SPAN)) {
28933
+ span = initLogger().startSpan(args);
28934
+ }
28935
+ this.spans.set(runId, span);
28936
+ }
28937
+ endSpan({
28938
+ runId,
28939
+ parentRunId,
28940
+ tags,
28941
+ metadata,
28942
+ ...args
28943
+ }) {
28944
+ if (!this.spans.has(runId)) {
28945
+ return;
28946
+ }
28947
+ if (this.skippedRuns.has(runId)) {
28948
+ this.skippedRuns.delete(runId);
28949
+ return;
28950
+ }
28951
+ const span = this.spans.get(runId);
28952
+ this.spans.delete(runId);
28953
+ if (runId === this.rootRunId) {
28954
+ this.rootRunId = void 0;
28955
+ }
28956
+ span.log({ ...args, metadata: { tags, ...metadata } });
28957
+ span.end();
28958
+ }
28959
+ async handleLLMStart(llm, prompts, runId, parentRunId, extraParams, tags, metadata, runName) {
28960
+ this.startSpan({
28961
+ runId,
28962
+ parentRunId,
28963
+ name: runName ?? getSerializedName(llm) ?? "LLM",
28964
+ type: "llm",
28965
+ event: {
28966
+ input: prompts,
28967
+ tags,
28968
+ metadata: {
28969
+ serialized: llm,
28970
+ name: runName,
28971
+ metadata,
28972
+ ...extraParams
28973
+ }
28974
+ }
28975
+ });
28976
+ }
28977
+ async handleLLMError(err, runId, parentRunId, tags) {
28978
+ this.endSpan({ runId, parentRunId, error: err, tags });
28979
+ }
28980
+ async handleLLMEnd(output, runId, parentRunId, tags) {
28981
+ const metrics = getMetricsFromResponse(output);
28982
+ const modelName2 = getModelNameFromResponse(output);
28983
+ const ttft = this.ttftMs.get(runId);
28984
+ if (ttft !== void 0) {
28985
+ metrics.time_to_first_token = ttft;
28986
+ }
28987
+ this.startTimes.delete(runId);
28988
+ this.firstTokenTimes.delete(runId);
28989
+ this.ttftMs.delete(runId);
28990
+ this.endSpan({
28991
+ runId,
28992
+ parentRunId,
28993
+ output,
28994
+ metrics,
28995
+ tags,
28996
+ metadata: {
28997
+ model: modelName2
28998
+ }
28999
+ });
29000
+ }
29001
+ async handleChatModelStart(llm, messages, runId, parentRunId, extraParams, tags, metadata, runName) {
29002
+ this.startTimes.set(runId, Date.now());
29003
+ this.firstTokenTimes.delete(runId);
29004
+ this.ttftMs.delete(runId);
29005
+ this.startSpan({
29006
+ runId,
29007
+ parentRunId,
29008
+ name: runName ?? getSerializedName(llm) ?? "Chat Model",
29009
+ type: "llm",
29010
+ event: {
29011
+ input: messages,
29012
+ tags,
29013
+ metadata: {
29014
+ serialized: llm,
29015
+ name: runName,
29016
+ metadata,
29017
+ ...extraParams
29018
+ }
29019
+ }
29020
+ });
29021
+ }
29022
+ async handleChainStart(chain, inputs, runId, parentRunId, tags, metadata, runType, runName) {
29023
+ if (tags?.includes("langsmith:hidden")) {
29024
+ this.skippedRuns.add(runId);
29025
+ return;
29026
+ }
29027
+ this.startSpan({
29028
+ runId,
29029
+ parentRunId,
29030
+ name: runName ?? getSerializedName(chain) ?? "Chain",
29031
+ event: {
29032
+ input: inputs,
29033
+ tags,
29034
+ metadata: {
29035
+ serialized: chain,
29036
+ name: runName,
29037
+ metadata,
29038
+ run_type: runType
29039
+ }
29040
+ }
29041
+ });
29042
+ }
29043
+ async handleChainError(err, runId, parentRunId, tags, kwargs) {
29044
+ this.endSpan({ runId, parentRunId, error: err, tags, metadata: kwargs });
29045
+ }
29046
+ async handleChainEnd(outputs, runId, parentRunId, tags, kwargs) {
29047
+ this.endSpan({
29048
+ runId,
29049
+ parentRunId,
29050
+ tags,
29051
+ output: outputs,
29052
+ metadata: { ...kwargs }
29053
+ });
29054
+ }
29055
+ async handleToolStart(tool, input, runId, parentRunId, tags, metadata, runName) {
29056
+ this.startSpan({
29057
+ runId,
29058
+ parentRunId,
29059
+ name: runName ?? getSerializedName(tool) ?? "Tool",
29060
+ type: "llm",
29061
+ event: {
29062
+ input: safeJsonParse(input),
29063
+ tags,
29064
+ metadata: {
29065
+ metadata,
29066
+ serialized: tool,
29067
+ input_str: input,
29068
+ input: safeJsonParse(input),
29069
+ name: runName
29070
+ }
29071
+ }
29072
+ });
29073
+ }
29074
+ async handleToolError(err, runId, parentRunId, tags) {
29075
+ this.endSpan({ runId, parentRunId, error: err, tags });
29076
+ }
29077
+ async handleToolEnd(output, runId, parentRunId, tags) {
29078
+ this.endSpan({ runId, parentRunId, output, tags });
29079
+ }
29080
+ async handleAgentAction(action, runId, parentRunId, tags) {
29081
+ this.startSpan({
29082
+ runId,
29083
+ parentRunId,
29084
+ type: "llm",
29085
+ name: typeof action.tool === "string" ? action.tool : "Agent",
29086
+ event: {
29087
+ input: action,
29088
+ tags
29089
+ }
29090
+ });
29091
+ }
29092
+ async handleAgentEnd(action, runId, parentRunId, tags) {
29093
+ this.endSpan({ runId, parentRunId, output: action, tags });
29094
+ }
29095
+ async handleRetrieverStart(retriever, query, runId, parentRunId, tags, metadata, name) {
29096
+ this.startSpan({
29097
+ runId,
29098
+ parentRunId,
29099
+ name: name ?? getSerializedName(retriever) ?? "Retriever",
29100
+ type: "function",
29101
+ event: {
29102
+ input: query,
29103
+ tags,
29104
+ metadata: {
29105
+ serialized: retriever,
29106
+ metadata,
29107
+ name
29108
+ }
29109
+ }
29110
+ });
29111
+ }
29112
+ async handleRetrieverEnd(documents, runId, parentRunId, tags) {
29113
+ this.endSpan({ runId, parentRunId, output: documents, tags });
29114
+ }
29115
+ async handleRetrieverError(err, runId, parentRunId, tags) {
29116
+ this.endSpan({ runId, parentRunId, error: err, tags });
29117
+ }
29118
+ async handleLLMNewToken(_token, _idx, runId, _parentRunId, _tags) {
29119
+ if (!this.firstTokenTimes.has(runId)) {
29120
+ const now2 = Date.now();
29121
+ this.firstTokenTimes.set(runId, now2);
29122
+ const start = this.startTimes.get(runId);
29123
+ if (start !== void 0) {
29124
+ this.ttftMs.set(runId, (now2 - start) / 1e3);
29125
+ }
29126
+ }
29127
+ }
29128
+ };
29129
+ function getSerializedName(serialized) {
29130
+ if (typeof serialized.name === "string") {
29131
+ return serialized.name;
29132
+ }
29133
+ const lastIdPart = serialized.id?.at(-1);
29134
+ return typeof lastIdPart === "string" ? lastIdPart : void 0;
29135
+ }
29136
+ function cleanObject(obj) {
29137
+ return Object.fromEntries(
29138
+ Object.entries(obj).filter(([, value]) => {
29139
+ if (typeof value !== "number") {
29140
+ return false;
29141
+ }
29142
+ return Number.isFinite(value);
29143
+ })
29144
+ );
29145
+ }
29146
+ function walkGenerations(response) {
29147
+ const result = [];
29148
+ const generations = response.generations || [];
29149
+ for (const batch of generations) {
29150
+ if (Array.isArray(batch)) {
29151
+ for (const generation of batch) {
29152
+ if (isRecord(generation)) {
29153
+ result.push(generation);
29154
+ }
29155
+ }
29156
+ } else if (isRecord(batch)) {
29157
+ result.push(batch);
29158
+ }
29159
+ }
29160
+ return result;
29161
+ }
29162
+ function getModelNameFromResponse(response) {
29163
+ for (const generation of walkGenerations(response)) {
29164
+ const message = generation.message;
29165
+ if (!isRecord(message)) {
29166
+ continue;
29167
+ }
29168
+ const responseMetadata = message.response_metadata;
29169
+ if (!isRecord(responseMetadata)) {
29170
+ continue;
29171
+ }
29172
+ const modelName3 = responseMetadata.model_name ?? responseMetadata.model;
29173
+ if (typeof modelName3 === "string") {
29174
+ return modelName3;
29175
+ }
29176
+ }
29177
+ const llmOutput = response.llmOutput || {};
29178
+ const modelName2 = llmOutput.model_name ?? llmOutput.model;
29179
+ return typeof modelName2 === "string" ? modelName2 : void 0;
29180
+ }
29181
+ function getMetricsFromResponse(response) {
29182
+ for (const generation of walkGenerations(response)) {
29183
+ const message = generation.message;
29184
+ if (!isRecord(message)) {
29185
+ continue;
29186
+ }
29187
+ const usageMetadata = message.usage_metadata;
29188
+ if (!isRecord(usageMetadata)) {
29189
+ continue;
29190
+ }
29191
+ const inputTokenDetails = usageMetadata.input_token_details;
29192
+ return cleanObject({
29193
+ total_tokens: usageMetadata.total_tokens,
29194
+ prompt_tokens: usageMetadata.input_tokens,
29195
+ completion_tokens: usageMetadata.output_tokens,
29196
+ prompt_cache_creation_tokens: isRecord(inputTokenDetails) ? inputTokenDetails.cache_creation : void 0,
29197
+ prompt_cached_tokens: isRecord(inputTokenDetails) ? inputTokenDetails.cache_read : void 0
29198
+ });
29199
+ }
29200
+ const llmOutput = response.llmOutput || {};
29201
+ const tokenUsage = isRecord(llmOutput.tokenUsage) ? llmOutput.tokenUsage : isRecord(llmOutput.estimatedTokens) ? llmOutput.estimatedTokens : {};
29202
+ return cleanObject({
29203
+ total_tokens: tokenUsage.totalTokens,
29204
+ prompt_tokens: tokenUsage.promptTokens,
29205
+ completion_tokens: tokenUsage.completionTokens
29206
+ });
29207
+ }
29208
+ function safeJsonParse(input) {
29209
+ try {
29210
+ return JSON.parse(input);
29211
+ } catch {
29212
+ return input;
29213
+ }
29214
+ }
29215
+ function isRecord(value) {
29216
+ return typeof value === "object" && value !== null && !Array.isArray(value);
29217
+ }
29218
+
29219
+ // src/instrumentation/plugins/langchain-channels.ts
29220
+ var langChainChannels = defineChannels("@langchain/core", {
29221
+ configure: channel({
29222
+ channelName: "CallbackManager.configure",
29223
+ kind: "sync-stream"
29224
+ }),
29225
+ configureSync: channel({
29226
+ channelName: "CallbackManager._configureSync",
29227
+ kind: "sync-stream"
29228
+ })
29229
+ });
29230
+
29231
+ // src/instrumentation/plugins/langchain-plugin.ts
29232
+ var LangChainPlugin = class extends BasePlugin {
29233
+ injectedManagers = /* @__PURE__ */ new WeakSet();
29234
+ onEnable() {
29235
+ this.subscribeToConfigure(langChainChannels.configure);
29236
+ this.subscribeToConfigure(langChainChannels.configureSync);
29237
+ }
29238
+ onDisable() {
29239
+ for (const unsubscribe of this.unsubscribers) {
29240
+ unsubscribe();
29241
+ }
29242
+ this.unsubscribers = [];
29243
+ this.injectedManagers = /* @__PURE__ */ new WeakSet();
29244
+ }
29245
+ subscribeToConfigure(channel2) {
29246
+ const tracingChannel2 = channel2.tracingChannel();
29247
+ const handlers = {
29248
+ start: (event) => {
29249
+ injectHandlerIntoArguments(event.arguments);
29250
+ },
29251
+ end: (event) => {
29252
+ this.injectHandler(event.result);
29253
+ }
29254
+ };
29255
+ tracingChannel2.subscribe(handlers);
29256
+ this.unsubscribers.push(() => {
29257
+ tracingChannel2.unsubscribe(handlers);
29258
+ });
29259
+ }
29260
+ injectHandler(result) {
29261
+ if (!isCallbackManager(result)) {
29262
+ return;
29263
+ }
29264
+ if (this.injectedManagers.has(result) || hasBraintrustHandler(result)) {
29265
+ return;
29266
+ }
29267
+ try {
29268
+ result.addHandler(new BraintrustLangChainCallbackHandler(), true);
29269
+ this.injectedManagers.add(result);
29270
+ } catch {
29271
+ }
29272
+ }
29273
+ };
29274
+ function isCallbackManager(value) {
29275
+ if (typeof value !== "object" || value === null) {
29276
+ return false;
29277
+ }
29278
+ const maybeManager = value;
29279
+ return typeof maybeManager.addHandler === "function";
29280
+ }
29281
+ function hasBraintrustHandler(manager) {
29282
+ return manager.handlers?.some((handler) => {
29283
+ if (typeof handler !== "object" || handler === null) {
29284
+ return false;
29285
+ }
29286
+ const name = Reflect.get(handler, "name");
29287
+ return name === BRAINTRUST_LANGCHAIN_CALLBACK_HANDLER_NAME;
29288
+ }) ?? false;
29289
+ }
29290
+ function injectHandlerIntoArguments(args) {
29291
+ if (!isWritableArgumentsObject(args)) {
29292
+ return;
29293
+ }
29294
+ const inheritedHandlers = Reflect.get(args, "0");
29295
+ const handler = new BraintrustLangChainCallbackHandler();
29296
+ if (inheritedHandlers === void 0 || inheritedHandlers === null) {
29297
+ Reflect.set(args, "0", [handler]);
29298
+ return;
29299
+ }
29300
+ if (Array.isArray(inheritedHandlers)) {
29301
+ if (!inheritedHandlers.some(isBraintrustHandler)) {
29302
+ inheritedHandlers.push(handler);
29303
+ }
29304
+ }
29305
+ }
29306
+ function isWritableArgumentsObject(args) {
29307
+ return typeof args === "object" && args !== null;
29308
+ }
29309
+ function isBraintrustHandler(handler) {
29310
+ if (typeof handler !== "object" || handler === null) {
29311
+ return false;
29312
+ }
29313
+ return Reflect.get(handler, "name") === BRAINTRUST_LANGCHAIN_CALLBACK_HANDLER_NAME;
29314
+ }
29315
+
29316
+ // src/instrumentation/braintrust-plugin.ts
29317
+ function getIntegrationConfig(integrations, key) {
29318
+ return integrations[key];
29319
+ }
29320
+ var BraintrustPlugin = class extends BasePlugin {
29321
+ config;
29322
+ openaiPlugin = null;
29323
+ openAICodexPlugin = null;
29324
+ anthropicPlugin = null;
29325
+ aiSDKPlugin = null;
29326
+ claudeAgentSDKPlugin = null;
27068
29327
  cursorSDKPlugin = null;
29328
+ openAIAgentsPlugin = null;
27069
29329
  googleGenAIPlugin = null;
27070
29330
  huggingFacePlugin = null;
27071
29331
  openRouterPlugin = null;
@@ -27076,6 +29336,8 @@ var BraintrustPlugin = class extends BasePlugin {
27076
29336
  groqPlugin = null;
27077
29337
  genkitPlugin = null;
27078
29338
  gitHubCopilotPlugin = null;
29339
+ fluePlugin = null;
29340
+ langChainPlugin = null;
27079
29341
  constructor(config3 = {}) {
27080
29342
  super();
27081
29343
  this.config = config3;
@@ -27106,6 +29368,10 @@ var BraintrustPlugin = class extends BasePlugin {
27106
29368
  this.cursorSDKPlugin = new CursorSDKPlugin();
27107
29369
  this.cursorSDKPlugin.enable();
27108
29370
  }
29371
+ if (integrations.openAIAgents !== false) {
29372
+ this.openAIAgentsPlugin = new OpenAIAgentsPlugin();
29373
+ this.openAIAgentsPlugin.enable();
29374
+ }
27109
29375
  if (integrations.googleGenAI !== false && integrations.google !== false) {
27110
29376
  this.googleGenAIPlugin = new GoogleGenAIPlugin();
27111
29377
  this.googleGenAIPlugin.enable();
@@ -27146,6 +29412,14 @@ var BraintrustPlugin = class extends BasePlugin {
27146
29412
  this.gitHubCopilotPlugin = new GitHubCopilotPlugin();
27147
29413
  this.gitHubCopilotPlugin.enable();
27148
29414
  }
29415
+ if (getIntegrationConfig(integrations, "flue") !== false) {
29416
+ this.fluePlugin = new FluePlugin();
29417
+ this.fluePlugin.enable();
29418
+ }
29419
+ if (integrations.langchain !== false && integrations.langgraph !== false) {
29420
+ this.langChainPlugin = new LangChainPlugin();
29421
+ this.langChainPlugin.enable();
29422
+ }
27149
29423
  }
27150
29424
  onDisable() {
27151
29425
  if (this.openaiPlugin) {
@@ -27172,6 +29446,10 @@ var BraintrustPlugin = class extends BasePlugin {
27172
29446
  this.cursorSDKPlugin.disable();
27173
29447
  this.cursorSDKPlugin = null;
27174
29448
  }
29449
+ if (this.openAIAgentsPlugin) {
29450
+ this.openAIAgentsPlugin.disable();
29451
+ this.openAIAgentsPlugin = null;
29452
+ }
27175
29453
  if (this.googleGenAIPlugin) {
27176
29454
  this.googleGenAIPlugin.disable();
27177
29455
  this.googleGenAIPlugin = null;
@@ -27212,9 +29490,104 @@ var BraintrustPlugin = class extends BasePlugin {
27212
29490
  this.gitHubCopilotPlugin.disable();
27213
29491
  this.gitHubCopilotPlugin = null;
27214
29492
  }
29493
+ if (this.fluePlugin) {
29494
+ this.fluePlugin.disable();
29495
+ this.fluePlugin = null;
29496
+ }
29497
+ if (this.langChainPlugin) {
29498
+ this.langChainPlugin.disable();
29499
+ this.langChainPlugin = null;
29500
+ }
27215
29501
  }
27216
29502
  };
27217
29503
 
29504
+ // src/instrumentation/config.ts
29505
+ var envIntegrationAliases = {
29506
+ openai: "openai",
29507
+ "openai-codex": "openaiCodexSDK",
29508
+ "openai-codex-sdk": "openaiCodexSDK",
29509
+ openaicodexsdk: "openaiCodexSDK",
29510
+ codex: "openaiCodexSDK",
29511
+ "codex-sdk": "openaiCodexSDK",
29512
+ anthropic: "anthropic",
29513
+ aisdk: "aisdk",
29514
+ "ai-sdk": "aisdk",
29515
+ "vercel-ai": "aisdk",
29516
+ vercel: "vercel",
29517
+ claudeagentsdk: "claudeAgentSDK",
29518
+ "claude-agent-sdk": "claudeAgentSDK",
29519
+ cursor: "cursor",
29520
+ "cursor-sdk": "cursorSDK",
29521
+ cursorsdk: "cursorSDK",
29522
+ flue: "flue",
29523
+ "flue-runtime": "flue",
29524
+ "openai-agents": "openAIAgents",
29525
+ openaiagents: "openAIAgents",
29526
+ "openai-agents-core": "openAIAgents",
29527
+ openaiagentscore: "openAIAgents",
29528
+ google: "google",
29529
+ "google-genai": "googleGenAI",
29530
+ googlegenai: "googleGenAI",
29531
+ huggingface: "huggingface",
29532
+ openrouter: "openrouter",
29533
+ openrouteragent: "openrouterAgent",
29534
+ "openrouter-agent": "openrouterAgent",
29535
+ mistral: "mistral",
29536
+ googleadk: "googleADK",
29537
+ "google-adk": "googleADK",
29538
+ cohere: "cohere",
29539
+ groq: "groq",
29540
+ "groq-sdk": "groq",
29541
+ genkit: "genkit",
29542
+ "firebase-genkit": "genkit",
29543
+ githubcopilot: "gitHubCopilot",
29544
+ "github-copilot": "gitHubCopilot",
29545
+ "copilot-sdk": "gitHubCopilot",
29546
+ langchain: "langchain",
29547
+ "langchain-js": "langchain",
29548
+ "@langchain": "langchain",
29549
+ langgraph: "langgraph"
29550
+ };
29551
+ function getDefaultInstrumentationIntegrations() {
29552
+ return {
29553
+ openai: true,
29554
+ openaiCodexSDK: true,
29555
+ anthropic: true,
29556
+ vercel: true,
29557
+ aisdk: true,
29558
+ google: true,
29559
+ googleGenAI: true,
29560
+ googleADK: true,
29561
+ huggingface: true,
29562
+ claudeAgentSDK: true,
29563
+ cursor: true,
29564
+ cursorSDK: true,
29565
+ flue: true,
29566
+ openAIAgents: true,
29567
+ openrouter: true,
29568
+ openrouterAgent: true,
29569
+ mistral: true,
29570
+ cohere: true,
29571
+ groq: true,
29572
+ genkit: true,
29573
+ gitHubCopilot: true,
29574
+ langchain: true,
29575
+ langgraph: true
29576
+ };
29577
+ }
29578
+ function readDisabledInstrumentationEnvConfig(disabledList) {
29579
+ const integrations = {};
29580
+ if (disabledList) {
29581
+ for (const value of disabledList.split(",")) {
29582
+ const sdk = value.trim().toLowerCase();
29583
+ if (sdk.length > 0) {
29584
+ integrations[envIntegrationAliases[sdk] ?? sdk] = false;
29585
+ }
29586
+ }
29587
+ }
29588
+ return { integrations };
29589
+ }
29590
+
27218
29591
  // src/instrumentation/registry.ts
27219
29592
  var REGISTRY_STATE_KEY = /* @__PURE__ */ Symbol.for("braintrust.registry");
27220
29593
  function getSharedState() {
@@ -27293,60 +29666,75 @@ var PluginRegistry = class {
27293
29666
  * Get default configuration (all integrations enabled).
27294
29667
  */
27295
29668
  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
- };
29669
+ return getDefaultInstrumentationIntegrations();
27317
29670
  }
27318
29671
  /**
27319
29672
  * Read configuration from environment variables.
27320
29673
  * Supports: BRAINTRUST_DISABLE_INSTRUMENTATION=openai,anthropic,...
27321
29674
  */
27322
29675
  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 };
29676
+ return readDisabledInstrumentationEnvConfig(
29677
+ isomorph_default.getEnv("BRAINTRUST_DISABLE_INSTRUMENTATION")
29678
+ );
27340
29679
  }
27341
29680
  };
27342
29681
  var registry = new PluginRegistry();
27343
29682
 
27344
29683
  // src/node/config.ts
29684
+ var BRAINTRUST_ENV_SEARCH_PARENT_LIMIT = 64;
27345
29685
  function configureNode() {
27346
29686
  isomorph_default.buildType = "node";
27347
29687
  isomorph_default.getRepoInfo = getRepoInfo;
27348
29688
  isomorph_default.getPastNAncestors = getPastNAncestors;
27349
- isomorph_default.getEnv = (name) => process.env[name];
29689
+ isomorph_default.getEnv = (name) => {
29690
+ const value = process.env[name];
29691
+ return name === "BRAINTRUST_API_KEY" && !value?.trim() ? void 0 : value;
29692
+ };
29693
+ isomorph_default.getBraintrustApiKey = async () => {
29694
+ const value = process.env.BRAINTRUST_API_KEY;
29695
+ if (value?.trim()) {
29696
+ return value;
29697
+ }
29698
+ const envPaths = [];
29699
+ for (let dir2 = process.cwd(), depth = 0; depth <= BRAINTRUST_ENV_SEARCH_PARENT_LIMIT; dir2 = path.dirname(dir2), depth++) {
29700
+ envPaths.push(path.join(dir2, ".env.braintrust"));
29701
+ if (path.dirname(dir2) === dir2) {
29702
+ break;
29703
+ }
29704
+ }
29705
+ const pending = /* @__PURE__ */ new Map();
29706
+ envPaths.forEach((envPath, index) => {
29707
+ pending.set(
29708
+ index,
29709
+ fs.readFile(envPath, "utf8").then(
29710
+ (contents) => ({ contents, envPath, index }),
29711
+ (error2) => ({ error: error2, envPath, index })
29712
+ )
29713
+ );
29714
+ });
29715
+ const results = [];
29716
+ let nearestUnresolvedIndex = 0;
29717
+ while (pending.size > 0) {
29718
+ const result = await Promise.race(pending.values());
29719
+ pending.delete(result.index);
29720
+ results[result.index] = result;
29721
+ while (results[nearestUnresolvedIndex]) {
29722
+ const nearestResult = results[nearestUnresolvedIndex];
29723
+ if ("contents" in nearestResult) {
29724
+ const parsed = dotenv.parse(nearestResult.contents);
29725
+ const apiKey = parsed.BRAINTRUST_API_KEY;
29726
+ return apiKey?.trim() ? apiKey : void 0;
29727
+ }
29728
+ const e = nearestResult.error;
29729
+ if (typeof e === "object" && e !== null && "code" in e && e.code === "ENOENT") {
29730
+ nearestUnresolvedIndex++;
29731
+ continue;
29732
+ }
29733
+ return void 0;
29734
+ }
29735
+ }
29736
+ return void 0;
29737
+ };
27350
29738
  isomorph_default.getCallerLocation = getCallerLocation;
27351
29739
  isomorph_default.newAsyncLocalStorage = () => new import_node_async_hooks.AsyncLocalStorage();
27352
29740
  isomorph_default.newTracingChannel = (nameOrChannels) => diagnostics_channel.tracingChannel(nameOrChannels);
@@ -28506,7 +30894,7 @@ async function buildBundledFunctionEntry({
28506
30894
 
28507
30895
  // src/cli/util/bundle.ts
28508
30896
  var import_env = require("@next/env");
28509
- var dotenv = __toESM(require("dotenv"));
30897
+ var dotenv2 = __toESM(require("dotenv"));
28510
30898
 
28511
30899
  // src/cli/util/debug-logging.ts
28512
30900
  var VERBOSE_DEPRECATION_MESSAGE = "--verbose is deprecated and will be removed in a future version of braintrust. Use --debug-logging debug to see full stack traces and troubleshooting details.";
@@ -28533,7 +30921,7 @@ async function loadCLIEnv(args) {
28533
30921
  normalizeDebugLoggingArgs(args);
28534
30922
  (0, import_env.loadEnvConfig)(process.cwd(), true);
28535
30923
  if (args.env_file) {
28536
- const loaded = dotenv.config({ path: args.env_file });
30924
+ const loaded = dotenv2.config({ path: args.env_file });
28537
30925
  if (loaded.error) {
28538
30926
  console.error(error(`Error loading ${args.env_file}: ${loaded.error}`));
28539
30927
  process.exit(1);
@@ -30084,7 +32472,7 @@ async function run(args) {
30084
32472
  normalizeDebugLoggingArgs(args);
30085
32473
  (0, import_env2.loadEnvConfig)(process.cwd(), true);
30086
32474
  if (args.env_file) {
30087
- const loaded = dotenv2.config({ path: args.env_file });
32475
+ const loaded = dotenv3.config({ path: args.env_file });
30088
32476
  if (loaded.error) {
30089
32477
  console.error(error(`Error loading ${args.env_file}: ${loaded.error}`));
30090
32478
  process.exit(1);
@@ -30162,7 +32550,7 @@ async function run(args) {
30162
32550
  }
30163
32551
  function addAuthArgs(parser) {
30164
32552
  parser.add_argument("--api-key", {
30165
- help: "Specify a braintrust api key. If the parameter is not specified, the BRAINTRUST_API_KEY environment variable will be used."
32553
+ help: "Specify a braintrust api key. If the parameter is not specified, BRAINTRUST_API_KEY or the nearest .env.braintrust file will be used."
30166
32554
  });
30167
32555
  parser.add_argument("--org-name", {
30168
32556
  help: "The name of a specific organization to connect to. This is useful if you belong to multiple."