braintrust 3.12.0 → 3.14.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 (55) hide show
  1. package/dev/dist/index.d.mts +31 -14
  2. package/dev/dist/index.d.ts +31 -14
  3. package/dev/dist/index.js +919 -485
  4. package/dev/dist/index.mjs +480 -46
  5. package/dist/apply-auto-instrumentation.js +204 -174
  6. package/dist/apply-auto-instrumentation.mjs +35 -5
  7. package/dist/auto-instrumentations/bundler/esbuild.cjs +226 -1
  8. package/dist/auto-instrumentations/bundler/esbuild.mjs +3 -2
  9. package/dist/auto-instrumentations/bundler/next.cjs +226 -1
  10. package/dist/auto-instrumentations/bundler/next.mjs +4 -3
  11. package/dist/auto-instrumentations/bundler/rollup.cjs +226 -1
  12. package/dist/auto-instrumentations/bundler/rollup.mjs +3 -2
  13. package/dist/auto-instrumentations/bundler/vite.cjs +226 -1
  14. package/dist/auto-instrumentations/bundler/vite.mjs +3 -2
  15. package/dist/auto-instrumentations/bundler/webpack-loader.cjs +9 -0
  16. package/dist/auto-instrumentations/bundler/webpack.cjs +226 -1
  17. package/dist/auto-instrumentations/bundler/webpack.mjs +4 -3
  18. package/dist/auto-instrumentations/{chunk-2DPA74KK.mjs → chunk-E5DUYJWK.mjs} +1 -0
  19. package/dist/auto-instrumentations/chunk-J57YF7WS.mjs +208 -0
  20. package/dist/auto-instrumentations/{chunk-AFXRW7I7.mjs → chunk-OTUQ7KH5.mjs} +1 -1
  21. package/dist/auto-instrumentations/chunk-QFMACSOL.mjs +280 -0
  22. package/dist/auto-instrumentations/{chunk-73BZUKVI.mjs → chunk-XKAAVWT6.mjs} +24 -2
  23. package/dist/auto-instrumentations/hook.mjs +7981 -7
  24. package/dist/auto-instrumentations/index.cjs +1 -0
  25. package/dist/auto-instrumentations/index.mjs +1 -1
  26. package/dist/auto-instrumentations/loader/cjs-patch.cjs +194 -4
  27. package/dist/auto-instrumentations/loader/cjs-patch.mjs +13 -27
  28. package/dist/auto-instrumentations/loader/esm-hook.mjs +24 -10
  29. package/dist/browser.d.mts +274 -30
  30. package/dist/browser.d.ts +274 -30
  31. package/dist/browser.js +407 -48
  32. package/dist/browser.mjs +407 -48
  33. package/dist/{chunk-BW4DF4CY.js → chunk-NKD77KGB.js} +180 -1
  34. package/dist/{chunk-MSLBGITU.mjs → chunk-NU2GSPHX.mjs} +180 -1
  35. package/dist/cli.js +494 -94
  36. package/dist/edge-light.d.mts +1 -1
  37. package/dist/edge-light.d.ts +1 -1
  38. package/dist/edge-light.js +407 -48
  39. package/dist/edge-light.mjs +407 -48
  40. package/dist/index.d.mts +274 -30
  41. package/dist/index.d.ts +274 -30
  42. package/dist/index.js +1267 -857
  43. package/dist/index.mjs +465 -55
  44. package/dist/instrumentation/index.d.mts +47 -11
  45. package/dist/instrumentation/index.d.ts +47 -11
  46. package/dist/instrumentation/index.js +116 -26
  47. package/dist/instrumentation/index.mjs +116 -26
  48. package/dist/workerd.d.mts +1 -1
  49. package/dist/workerd.d.ts +1 -1
  50. package/dist/workerd.js +407 -48
  51. package/dist/workerd.mjs +407 -48
  52. package/package.json +3 -23
  53. package/util/dist/index.d.mts +3 -1
  54. package/util/dist/index.d.ts +3 -1
  55. package/dist/auto-instrumentations/chunk-MWZXZQUO.mjs +0 -81
@@ -96,6 +96,7 @@ import * as fsSync from "node:fs";
96
96
  import * as crypto from "node:crypto";
97
97
  import { promisify } from "node:util";
98
98
  import * as zlib from "node:zlib";
99
+ import * as dotenv from "dotenv";
99
100
 
100
101
  // src/isomorph.ts
101
102
  var DefaultAsyncLocalStorage = class {
@@ -182,6 +183,7 @@ var iso = {
182
183
  getRepoInfo: async (_settings) => void 0,
183
184
  getPastNAncestors: async () => [],
184
185
  getEnv: (_name) => void 0,
186
+ getBraintrustApiKey: async () => void 0,
185
187
  getCallerLocation: () => void 0,
186
188
  newAsyncLocalStorage: () => new DefaultAsyncLocalStorage(),
187
189
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -4252,6 +4254,76 @@ var LRUCache = class {
4252
4254
  }
4253
4255
  };
4254
4256
 
4257
+ // src/prompt-cache/cache-config.ts
4258
+ var CACHE_LOCATION_ENV_VAR = "BRAINTRUST_CACHE_LOCATION";
4259
+ var DEFAULT_CACHE_MEMORY_MAX = 1 << 10;
4260
+ var DEFAULT_CACHE_DISK_MAX = 1 << 20;
4261
+ var warnedInvalidCacheModeEnvValue = false;
4262
+ var warnedUnavailableDiskCacheMode = false;
4263
+ function warnInvalidCacheMode(value) {
4264
+ if (warnedInvalidCacheModeEnvValue) {
4265
+ return;
4266
+ }
4267
+ warnedInvalidCacheModeEnvValue = true;
4268
+ debugLogger.warn(
4269
+ `Invalid ${CACHE_LOCATION_ENV_VAR} value "${value}". Expected "mixed", "memory", "disk", or "none". Falling back to "mixed".`
4270
+ );
4271
+ }
4272
+ function warnUnavailableDiskCache() {
4273
+ if (warnedUnavailableDiskCacheMode) {
4274
+ return;
4275
+ }
4276
+ warnedUnavailableDiskCacheMode = true;
4277
+ debugLogger.warn(
4278
+ `Disk cache is not supported on this platform, so ${CACHE_LOCATION_ENV_VAR}="disk" disables prompt and parameters caching.`
4279
+ );
4280
+ }
4281
+ function parseCacheMode() {
4282
+ const value = isomorph_default.getEnv(CACHE_LOCATION_ENV_VAR);
4283
+ const normalized = value?.trim().toLowerCase();
4284
+ if (!normalized) {
4285
+ return "mixed";
4286
+ }
4287
+ if (normalized === "mixed" || normalized === "memory" || normalized === "disk" || normalized === "none") {
4288
+ return normalized;
4289
+ }
4290
+ warnInvalidCacheMode(value ?? "");
4291
+ return "mixed";
4292
+ }
4293
+ function parsePositiveIntegerEnv(envVar, defaultValue) {
4294
+ const value = Number(isomorph_default.getEnv(envVar));
4295
+ return Number.isInteger(value) && value > 0 ? value : defaultValue;
4296
+ }
4297
+ function createCacheLayers({
4298
+ memoryMaxEnvVar,
4299
+ diskCacheDirEnvVar,
4300
+ diskMaxEnvVar,
4301
+ getDefaultDiskCacheDir
4302
+ }) {
4303
+ const mode = parseCacheMode();
4304
+ const memoryCache = mode === "mixed" || mode === "memory" ? new LRUCache({
4305
+ max: parsePositiveIntegerEnv(
4306
+ memoryMaxEnvVar,
4307
+ DEFAULT_CACHE_MEMORY_MAX
4308
+ )
4309
+ }) : void 0;
4310
+ let diskCache;
4311
+ if (mode === "mixed" || mode === "disk") {
4312
+ if (canUseDiskCache()) {
4313
+ diskCache = new DiskCache({
4314
+ cacheDir: isomorph_default.getEnv(diskCacheDirEnvVar) ?? getDefaultDiskCacheDir(),
4315
+ max: parsePositiveIntegerEnv(diskMaxEnvVar, DEFAULT_CACHE_DISK_MAX)
4316
+ });
4317
+ } else if (mode === "disk") {
4318
+ warnUnavailableDiskCache();
4319
+ }
4320
+ }
4321
+ if (diskCache) {
4322
+ return { memoryCache, diskCache };
4323
+ }
4324
+ return { memoryCache };
4325
+ }
4326
+
4255
4327
  // src/prompt-cache/prompt-cache.ts
4256
4328
  function createCacheKey(key) {
4257
4329
  if (key.id) {
@@ -4279,16 +4351,18 @@ var PromptCache = class {
4279
4351
  */
4280
4352
  async get(key) {
4281
4353
  const cacheKey = createCacheKey(key);
4282
- const memoryPrompt = this.memoryCache.get(cacheKey);
4283
- if (memoryPrompt !== void 0) {
4284
- return memoryPrompt;
4354
+ if (this.memoryCache) {
4355
+ const memoryPrompt = this.memoryCache.get(cacheKey);
4356
+ if (memoryPrompt !== void 0) {
4357
+ return memoryPrompt;
4358
+ }
4285
4359
  }
4286
4360
  if (this.diskCache) {
4287
4361
  const diskPrompt = await this.diskCache.get(cacheKey);
4288
4362
  if (!diskPrompt) {
4289
4363
  return void 0;
4290
4364
  }
4291
- this.memoryCache.set(cacheKey, diskPrompt);
4365
+ this.memoryCache?.set(cacheKey, diskPrompt);
4292
4366
  return diskPrompt;
4293
4367
  }
4294
4368
  return void 0;
@@ -4303,7 +4377,7 @@ var PromptCache = class {
4303
4377
  */
4304
4378
  async set(key, value) {
4305
4379
  const cacheKey = createCacheKey(key);
4306
- this.memoryCache.set(cacheKey, value);
4380
+ this.memoryCache?.set(cacheKey, value);
4307
4381
  if (this.diskCache) {
4308
4382
  await this.diskCache.set(cacheKey, value);
4309
4383
  }
@@ -4333,23 +4407,25 @@ var ParametersCache = class {
4333
4407
  }
4334
4408
  async get(key) {
4335
4409
  const cacheKey = createCacheKey2(key);
4336
- const memoryParams = this.memoryCache.get(cacheKey);
4337
- if (memoryParams !== void 0) {
4338
- return memoryParams;
4410
+ if (this.memoryCache) {
4411
+ const memoryParams = this.memoryCache.get(cacheKey);
4412
+ if (memoryParams !== void 0) {
4413
+ return memoryParams;
4414
+ }
4339
4415
  }
4340
4416
  if (this.diskCache) {
4341
4417
  const diskParams = await this.diskCache.get(cacheKey);
4342
4418
  if (!diskParams) {
4343
4419
  return void 0;
4344
4420
  }
4345
- this.memoryCache.set(cacheKey, diskParams);
4421
+ this.memoryCache?.set(cacheKey, diskParams);
4346
4422
  return diskParams;
4347
4423
  }
4348
4424
  return void 0;
4349
4425
  }
4350
4426
  async set(key, value) {
4351
4427
  const cacheKey = createCacheKey2(key);
4352
- this.memoryCache.set(cacheKey, value);
4428
+ this.memoryCache?.set(cacheKey, value);
4353
4429
  if (this.diskCache) {
4354
4430
  await this.diskCache.set(cacheKey, value);
4355
4431
  }
@@ -4881,21 +4957,22 @@ var BraintrustState = class _BraintrustState {
4881
4957
  setGlobalDebugLogLevel(void 0);
4882
4958
  }
4883
4959
  this.resetLoginInfo();
4884
- const memoryCache = new LRUCache({
4885
- max: Number(isomorph_default.getEnv("BRAINTRUST_PROMPT_CACHE_MEMORY_MAX")) ?? 1 << 10
4960
+ const { memoryCache, diskCache } = createCacheLayers({
4961
+ memoryMaxEnvVar: "BRAINTRUST_PROMPT_CACHE_MEMORY_MAX",
4962
+ diskCacheDirEnvVar: "BRAINTRUST_PROMPT_CACHE_DIR",
4963
+ diskMaxEnvVar: "BRAINTRUST_PROMPT_CACHE_DISK_MAX",
4964
+ getDefaultDiskCacheDir: () => `${isomorph_default.getEnv("HOME") ?? isomorph_default.homedir()}/.braintrust/prompt_cache`
4886
4965
  });
4887
- const diskCache = canUseDiskCache() ? new DiskCache({
4888
- cacheDir: isomorph_default.getEnv("BRAINTRUST_PROMPT_CACHE_DIR") ?? `${isomorph_default.getEnv("HOME") ?? isomorph_default.homedir()}/.braintrust/prompt_cache`,
4889
- max: Number(isomorph_default.getEnv("BRAINTRUST_PROMPT_CACHE_DISK_MAX")) ?? 1 << 20
4890
- }) : void 0;
4891
4966
  this.promptCache = new PromptCache({ memoryCache, diskCache });
4892
- const parametersMemoryCache = new LRUCache({
4893
- max: Number(isomorph_default.getEnv("BRAINTRUST_PARAMETERS_CACHE_MEMORY_MAX")) ?? 1 << 10
4967
+ const {
4968
+ memoryCache: parametersMemoryCache,
4969
+ diskCache: parametersDiskCache
4970
+ } = createCacheLayers({
4971
+ memoryMaxEnvVar: "BRAINTRUST_PARAMETERS_CACHE_MEMORY_MAX",
4972
+ diskCacheDirEnvVar: "BRAINTRUST_PARAMETERS_CACHE_DIR",
4973
+ diskMaxEnvVar: "BRAINTRUST_PARAMETERS_CACHE_DISK_MAX",
4974
+ getDefaultDiskCacheDir: () => `${isomorph_default.getEnv("HOME") ?? isomorph_default.homedir()}/.braintrust/parameters_cache`
4894
4975
  });
4895
- const parametersDiskCache = canUseDiskCache() ? new DiskCache({
4896
- cacheDir: isomorph_default.getEnv("BRAINTRUST_PARAMETERS_CACHE_DIR") ?? `${isomorph_default.getEnv("HOME") ?? isomorph_default.homedir()}/.braintrust/parameters_cache`,
4897
- max: Number(isomorph_default.getEnv("BRAINTRUST_PARAMETERS_CACHE_DISK_MAX")) ?? 1 << 20
4898
- }) : void 0;
4899
4976
  this.parametersCache = new ParametersCache({
4900
4977
  memoryCache: parametersMemoryCache,
4901
4978
  diskCache: parametersDiskCache
@@ -7266,10 +7343,11 @@ async function login(options = {}) {
7266
7343
  async function loginToState(options = {}) {
7267
7344
  const {
7268
7345
  appUrl = isomorph_default.getEnv("BRAINTRUST_APP_URL") || "https://www.braintrust.dev",
7269
- apiKey = isomorph_default.getEnv("BRAINTRUST_API_KEY"),
7346
+ apiKey: apiKeyArg,
7270
7347
  orgName = isomorph_default.getEnv("BRAINTRUST_ORG_NAME"),
7271
7348
  fetch: fetch2 = globalThis.fetch
7272
7349
  } = options || {};
7350
+ const apiKey = apiKeyArg !== void 0 ? apiKeyArg : await isomorph_default.getBraintrustApiKey();
7273
7351
  const appPublicUrl = isomorph_default.getEnv("BRAINTRUST_APP_PUBLIC_URL") || appUrl;
7274
7352
  const state = new BraintrustState(options);
7275
7353
  state.resetLoginInfo();
@@ -8288,9 +8366,15 @@ var SpanImpl = class _SpanImpl {
8288
8366
  const cachedSpan = {
8289
8367
  input: partialRecord.input,
8290
8368
  output: partialRecord.output,
8369
+ expected: partialRecord.expected,
8370
+ error: partialRecord.error,
8371
+ scores: partialRecord.scores,
8372
+ metrics: partialRecord.metrics,
8291
8373
  metadata: partialRecord.metadata,
8374
+ tags: partialRecord.tags,
8292
8375
  span_id: this._spanId,
8293
8376
  span_parents: this._spanParents,
8377
+ is_root: this._spanId === this._rootSpanId,
8294
8378
  span_attributes: partialRecord.span_attributes
8295
8379
  };
8296
8380
  this._state.spanCache.queueWrite(
@@ -8626,6 +8710,7 @@ var Dataset2 = class extends ObjectFetcher {
8626
8710
  metadata,
8627
8711
  tags,
8628
8712
  output,
8713
+ origin,
8629
8714
  isMerge
8630
8715
  }) {
8631
8716
  return new LazyValue(async () => {
@@ -8640,6 +8725,7 @@ var Dataset2 = class extends ObjectFetcher {
8640
8725
  created: !isMerge ? (/* @__PURE__ */ new Date()).toISOString() : void 0,
8641
8726
  //if we're merging/updating an event we will not add this ts
8642
8727
  metadata,
8728
+ origin,
8643
8729
  ...!!isMerge ? {
8644
8730
  [IS_MERGE_FIELD]: true
8645
8731
  } : {}
@@ -8659,6 +8745,7 @@ var Dataset2 = class extends ObjectFetcher {
8659
8745
  * about anything else that's relevant, that you can use to help find and analyze examples later. For example, you could log the
8660
8746
  * `prompt`, example's `id`, or anything else that would be useful to slice/dice later. The values in `metadata` can be any
8661
8747
  * JSON-serializable type, but its keys must be strings.
8748
+ * @param event.origin (Optional) a reference to the source object this dataset record was derived from.
8662
8749
  * @param event.id (Optional) a unique identifier for the event. If you don't provide one, Braintrust will generate one for you.
8663
8750
  * @param event.output: (Deprecated) The output of your application. Use `expected` instead.
8664
8751
  * @returns The `id` of the logged record.
@@ -8669,7 +8756,8 @@ var Dataset2 = class extends ObjectFetcher {
8669
8756
  metadata,
8670
8757
  tags,
8671
8758
  id,
8672
- output
8759
+ output,
8760
+ origin
8673
8761
  }) {
8674
8762
  this.validateEvent({ metadata, expected, output, tags });
8675
8763
  const rowId = id || uuidv42();
@@ -8681,6 +8769,7 @@ var Dataset2 = class extends ObjectFetcher {
8681
8769
  metadata,
8682
8770
  tags,
8683
8771
  output,
8772
+ origin,
8684
8773
  isMerge: false
8685
8774
  })
8686
8775
  );
@@ -25073,7 +25162,7 @@ var BraintrustPlugin = class extends BasePlugin {
25073
25162
  this.config = config;
25074
25163
  }
25075
25164
  onEnable() {
25076
- const integrations = this.config.integrations || {};
25165
+ const integrations = this.config.integrations ?? {};
25077
25166
  if (integrations.openai !== false) {
25078
25167
  this.openaiPlugin = new OpenAIPlugin();
25079
25168
  this.openaiPlugin.enable();
@@ -25138,7 +25227,7 @@ var BraintrustPlugin = class extends BasePlugin {
25138
25227
  this.genkitPlugin = new GenkitPlugin();
25139
25228
  this.genkitPlugin.enable();
25140
25229
  }
25141
- if (getIntegrationConfig(integrations, "gitHubCopilot") !== false) {
25230
+ if (integrations.gitHubCopilot !== false) {
25142
25231
  this.gitHubCopilotPlugin = new GitHubCopilotPlugin();
25143
25232
  this.gitHubCopilotPlugin.enable();
25144
25233
  }
@@ -25251,6 +25340,7 @@ var envIntegrationAliases = {
25251
25340
  cursorsdk: "cursorSDK",
25252
25341
  flue: "flue",
25253
25342
  "flue-runtime": "flue",
25343
+ mastra: "mastra",
25254
25344
  "openai-agents": "openAIAgents",
25255
25345
  openaiagents: "openAIAgents",
25256
25346
  "openai-agents-core": "openAIAgents",
@@ -25293,6 +25383,7 @@ function getDefaultInstrumentationIntegrations() {
25293
25383
  cursor: true,
25294
25384
  cursorSDK: true,
25295
25385
  flue: true,
25386
+ mastra: true,
25296
25387
  openAIAgents: true,
25297
25388
  openrouter: true,
25298
25389
  openrouterAgent: true,
@@ -25317,6 +25408,9 @@ function readDisabledInstrumentationEnvConfig(disabledList) {
25317
25408
  }
25318
25409
  return { integrations };
25319
25410
  }
25411
+ function isInstrumentationIntegrationDisabled(integrations, ...names) {
25412
+ return names.some((name) => integrations?.[name] === false);
25413
+ }
25320
25414
 
25321
25415
  // src/instrumentation/registry.ts
25322
25416
  var REGISTRY_STATE_KEY = /* @__PURE__ */ Symbol.for("braintrust.registry");
@@ -25410,12 +25504,318 @@ var PluginRegistry = class {
25410
25504
  };
25411
25505
  var registry = new PluginRegistry();
25412
25506
 
25507
+ // src/auto-instrumentations/loader/mastra-observability-patch.ts
25508
+ var MASTRA_EXPORTER_FACTORY_GLOBAL = "__braintrustMastraExporterFactory";
25509
+ function installMastraExporterFactory(factory) {
25510
+ const globals = globalThis;
25511
+ globals[MASTRA_EXPORTER_FACTORY_GLOBAL] ??= factory;
25512
+ }
25513
+ var EXPORTER_FACTORY_KEY = JSON.stringify(MASTRA_EXPORTER_FACTORY_GLOBAL);
25514
+ var OBSERVABILITY_APPEND_BODY = `
25515
+ ;(function __braintrustWrapObservability() {
25516
+ // Top-level so we can both read and reassign the var binding the original
25517
+ // entry declared.
25518
+ if (typeof Observability === "undefined") return;
25519
+ if (Observability.__braintrustWrapped) return;
25520
+ function __braintrustEnsureExporter(rawConfig) {
25521
+ try {
25522
+ var factory = globalThis[${EXPORTER_FACTORY_KEY}];
25523
+ if (typeof factory !== "function") return rawConfig;
25524
+ var config = rawConfig && typeof rawConfig === "object" ? rawConfig : {};
25525
+ var configsIn = config.configs && typeof config.configs === "object" ? config.configs : null;
25526
+ var configsOut = {};
25527
+ var hadEntries = false;
25528
+ if (configsIn) {
25529
+ for (var name in configsIn) {
25530
+ if (!Object.prototype.hasOwnProperty.call(configsIn, name)) continue;
25531
+ hadEntries = true;
25532
+ var inst = configsIn[name] || {};
25533
+ var existing = Array.isArray(inst.exporters) ? inst.exporters : [];
25534
+ var hasOurs = existing.some(function (e) { return e && e.name === "braintrust"; });
25535
+ configsOut[name] = Object.assign({}, inst, {
25536
+ exporters: hasOurs ? existing : existing.concat([factory()]),
25537
+ });
25538
+ }
25539
+ }
25540
+ if (!hadEntries) {
25541
+ configsOut.default = {
25542
+ serviceName: "mastra",
25543
+ exporters: [factory()],
25544
+ };
25545
+ }
25546
+ return Object.assign({}, config, { configs: configsOut });
25547
+ } catch (e) {
25548
+ return rawConfig;
25549
+ }
25550
+ }
25551
+ var __OriginalObservability = Observability;
25552
+ Observability = new Proxy(__OriginalObservability, {
25553
+ construct: function (target, args, newTarget) {
25554
+ var nextArgs = args.slice();
25555
+ nextArgs[0] = __braintrustEnsureExporter(nextArgs[0]);
25556
+ return Reflect.construct(target, nextArgs, newTarget);
25557
+ },
25558
+ });
25559
+ Observability.__braintrustWrapped = true;
25560
+ if (typeof exports !== "undefined" && exports && typeof exports === "object") {
25561
+ try {
25562
+ Object.defineProperty(exports, "Observability", {
25563
+ enumerable: true,
25564
+ configurable: true,
25565
+ get: function () { return Observability; },
25566
+ });
25567
+ } catch (e) {}
25568
+ }
25569
+ })();
25570
+ `;
25571
+
25572
+ // src/wrappers/mastra.ts
25573
+ var MASTRA_BRAINTRUST_EXPORTER_NAME = "braintrust";
25574
+ var SPAN_TYPE_MAP = {
25575
+ agent_run: "task" /* TASK */,
25576
+ model_generation: "llm" /* LLM */,
25577
+ model_step: "llm" /* LLM */,
25578
+ model_chunk: "llm" /* LLM */,
25579
+ tool_call: "tool" /* TOOL */,
25580
+ mcp_tool_call: "tool" /* TOOL */,
25581
+ workflow_run: "task" /* TASK */,
25582
+ workflow_step: "function" /* FUNCTION */,
25583
+ workflow_conditional: "function" /* FUNCTION */,
25584
+ workflow_conditional_eval: "function" /* FUNCTION */,
25585
+ workflow_parallel: "function" /* FUNCTION */,
25586
+ workflow_loop: "function" /* FUNCTION */,
25587
+ workflow_sleep: "function" /* FUNCTION */,
25588
+ workflow_wait_event: "function" /* FUNCTION */,
25589
+ memory_operation: "function" /* FUNCTION */,
25590
+ workspace_action: "function" /* FUNCTION */,
25591
+ rag_ingestion: "task" /* TASK */,
25592
+ rag_embedding: "llm" /* LLM */,
25593
+ rag_vector_operation: "function" /* FUNCTION */,
25594
+ rag_action: "function" /* FUNCTION */,
25595
+ graph_action: "function" /* FUNCTION */,
25596
+ scorer_run: "score" /* SCORE */,
25597
+ scorer_step: "score" /* SCORE */,
25598
+ processor_run: "function" /* FUNCTION */,
25599
+ generic: "function" /* FUNCTION */
25600
+ };
25601
+ function spanTypeFor(mastraType) {
25602
+ return SPAN_TYPE_MAP[mastraType] ?? "function" /* FUNCTION */;
25603
+ }
25604
+ function epochSeconds(value) {
25605
+ if (value === void 0) return void 0;
25606
+ const ms = value instanceof Date ? value.getTime() : typeof value === "number" ? value : Date.parse(value);
25607
+ return Number.isFinite(ms) ? ms / 1e3 : void 0;
25608
+ }
25609
+ function modelMetrics(attributes) {
25610
+ if (!isObject(attributes)) return void 0;
25611
+ const usage = isObject(attributes.usage) ? attributes.usage : void 0;
25612
+ if (!usage) return void 0;
25613
+ const out = {};
25614
+ if (typeof usage.inputTokens === "number")
25615
+ out.prompt_tokens = usage.inputTokens;
25616
+ if (typeof usage.outputTokens === "number")
25617
+ out.completion_tokens = usage.outputTokens;
25618
+ if (typeof usage.inputTokens === "number" && typeof usage.outputTokens === "number") {
25619
+ out.tokens = usage.inputTokens + usage.outputTokens;
25620
+ }
25621
+ const inputDetails = isObject(usage.inputDetails) ? usage.inputDetails : void 0;
25622
+ const outputDetails = isObject(usage.outputDetails) ? usage.outputDetails : void 0;
25623
+ if (inputDetails && typeof inputDetails.cacheRead === "number") {
25624
+ out.prompt_cached_tokens = inputDetails.cacheRead;
25625
+ }
25626
+ if (inputDetails && typeof inputDetails.cacheWrite === "number") {
25627
+ out.prompt_cache_creation_tokens = inputDetails.cacheWrite;
25628
+ }
25629
+ if (outputDetails && typeof outputDetails.reasoning === "number") {
25630
+ out.completion_reasoning_tokens = outputDetails.reasoning;
25631
+ }
25632
+ return Object.keys(out).length > 0 ? out : void 0;
25633
+ }
25634
+ function buildMetadata(exported) {
25635
+ const out = {};
25636
+ if (exported.entityId !== void 0) out.entity_id = exported.entityId;
25637
+ if (exported.entityName !== void 0) out.entity_name = exported.entityName;
25638
+ if (exported.entityType !== void 0) out.entity_type = exported.entityType;
25639
+ if (exported.metadata && isObject(exported.metadata)) {
25640
+ Object.assign(out, exported.metadata);
25641
+ }
25642
+ if (exported.attributes && isObject(exported.attributes)) {
25643
+ for (const [key, value] of Object.entries(exported.attributes)) {
25644
+ if (key === "usage") continue;
25645
+ if (value !== void 0) out[key] = value;
25646
+ }
25647
+ }
25648
+ if (exported.tags && exported.tags.length > 0) {
25649
+ out.tags = exported.tags;
25650
+ }
25651
+ if (exported.requestContext && isObject(exported.requestContext)) {
25652
+ out.request_context = exported.requestContext;
25653
+ }
25654
+ return out;
25655
+ }
25656
+ var BraintrustObservabilityExporter = class {
25657
+ name = MASTRA_BRAINTRUST_EXPORTER_NAME;
25658
+ spans = /* @__PURE__ */ new Map();
25659
+ // Captured at the first SPAN_STARTED event. Mastra's observability bus may
25660
+ // dispatch later events outside the user's AsyncLocalStorage context, where
25661
+ // `currentSpan()` returns NOOP_SPAN — which would make our `startSpan()`
25662
+ // calls go to a no-op logger and silently drop. Anchoring on the parent
25663
+ // we observe while still in-context keeps the whole Mastra subtree under
25664
+ // the user's traced scenario.
25665
+ capturedParent;
25666
+ constructor() {
25667
+ _internalSetInitialState();
25668
+ }
25669
+ async exportTracingEvent(event) {
25670
+ const exported = event.exportedSpan;
25671
+ if (exported.isInternal === true) return;
25672
+ try {
25673
+ switch (event.type) {
25674
+ case "span_started":
25675
+ this.onStart(exported);
25676
+ break;
25677
+ case "span_updated":
25678
+ this.onUpdate(exported);
25679
+ break;
25680
+ case "span_ended":
25681
+ this.onEnd(exported);
25682
+ break;
25683
+ }
25684
+ } catch (err) {
25685
+ logExporterError(err);
25686
+ }
25687
+ }
25688
+ async flush() {
25689
+ const state = _internalGetGlobalState();
25690
+ if (state) {
25691
+ await state.bgLogger().flush();
25692
+ }
25693
+ }
25694
+ async shutdown() {
25695
+ await this.flush();
25696
+ this.spans.clear();
25697
+ }
25698
+ onStart(exported) {
25699
+ if (this.spans.has(exported.id)) return;
25700
+ const args = {
25701
+ name: exported.name,
25702
+ spanAttributes: { type: spanTypeFor(exported.type) },
25703
+ startTime: epochSeconds(exported.startTime)
25704
+ };
25705
+ const parentRecord = exported.parentSpanId ? this.spans.get(exported.parentSpanId) : void 0;
25706
+ if (!this.capturedParent) {
25707
+ const probe = currentSpan();
25708
+ if (probe && probe.spanId) {
25709
+ this.capturedParent = probe;
25710
+ }
25711
+ }
25712
+ const span = parentRecord ? parentRecord.span.startSpan(args) : this.capturedParent ? this.capturedParent.startSpan(args) : startSpan(args);
25713
+ const record = { span, hasLoggedInput: false };
25714
+ this.logPayload(record, exported);
25715
+ this.spans.set(exported.id, record);
25716
+ if (exported.isEvent === true) {
25717
+ span.end({ endTime: args.startTime });
25718
+ this.spans.delete(exported.id);
25719
+ }
25720
+ }
25721
+ onUpdate(exported) {
25722
+ const record = this.spans.get(exported.id);
25723
+ if (!record) return;
25724
+ this.logPayload(record, exported);
25725
+ }
25726
+ onEnd(exported) {
25727
+ const record = this.spans.get(exported.id);
25728
+ if (!record) return;
25729
+ this.logPayload(record, exported);
25730
+ if (exported.errorInfo) {
25731
+ record.span.log({
25732
+ error: exported.errorInfo.message || exported.errorInfo.name || "Unknown Mastra error"
25733
+ });
25734
+ }
25735
+ record.span.end({ endTime: epochSeconds(exported.endTime) });
25736
+ this.spans.delete(exported.id);
25737
+ }
25738
+ logPayload(record, exported) {
25739
+ const event = {};
25740
+ if (exported.input !== void 0) {
25741
+ event.input = exported.input;
25742
+ record.hasLoggedInput = true;
25743
+ }
25744
+ if (exported.output !== void 0) {
25745
+ event.output = exported.output;
25746
+ }
25747
+ const metadata = buildMetadata(exported);
25748
+ if (Object.keys(metadata).length > 0) {
25749
+ event.metadata = metadata;
25750
+ }
25751
+ const metrics = modelMetrics(exported.attributes);
25752
+ if (metrics) {
25753
+ event.metrics = metrics;
25754
+ }
25755
+ if (Object.keys(event).length > 0) {
25756
+ record.span.log(event);
25757
+ }
25758
+ }
25759
+ };
25760
+ function logExporterError(err) {
25761
+ debugLogger.warn("Mastra exporter failure:", err);
25762
+ }
25763
+
25413
25764
  // src/node/config.ts
25765
+ var BRAINTRUST_ENV_SEARCH_PARENT_LIMIT = 64;
25414
25766
  function configureNode() {
25415
25767
  isomorph_default.buildType = "node";
25416
25768
  isomorph_default.getRepoInfo = getRepoInfo;
25417
25769
  isomorph_default.getPastNAncestors = getPastNAncestors;
25418
- isomorph_default.getEnv = (name) => process.env[name];
25770
+ isomorph_default.getEnv = (name) => {
25771
+ const value = process.env[name];
25772
+ return name === "BRAINTRUST_API_KEY" && !value?.trim() ? void 0 : value;
25773
+ };
25774
+ isomorph_default.getBraintrustApiKey = async () => {
25775
+ const value = process.env.BRAINTRUST_API_KEY;
25776
+ if (value?.trim()) {
25777
+ return value;
25778
+ }
25779
+ const envPaths = [];
25780
+ for (let dir2 = process.cwd(), depth = 0; depth <= BRAINTRUST_ENV_SEARCH_PARENT_LIMIT; dir2 = path.dirname(dir2), depth++) {
25781
+ envPaths.push(path.join(dir2, ".env.braintrust"));
25782
+ if (path.dirname(dir2) === dir2) {
25783
+ break;
25784
+ }
25785
+ }
25786
+ const pending = /* @__PURE__ */ new Map();
25787
+ envPaths.forEach((envPath, index) => {
25788
+ pending.set(
25789
+ index,
25790
+ fs.readFile(envPath, "utf8").then(
25791
+ (contents) => ({ contents, envPath, index }),
25792
+ (error) => ({ error, envPath, index })
25793
+ )
25794
+ );
25795
+ });
25796
+ const results = [];
25797
+ let nearestUnresolvedIndex = 0;
25798
+ while (pending.size > 0) {
25799
+ const result = await Promise.race(pending.values());
25800
+ pending.delete(result.index);
25801
+ results[result.index] = result;
25802
+ while (results[nearestUnresolvedIndex]) {
25803
+ const nearestResult = results[nearestUnresolvedIndex];
25804
+ if ("contents" in nearestResult) {
25805
+ const parsed = dotenv.parse(nearestResult.contents);
25806
+ const apiKey = parsed.BRAINTRUST_API_KEY;
25807
+ return apiKey?.trim() ? apiKey : void 0;
25808
+ }
25809
+ const e = nearestResult.error;
25810
+ if (typeof e === "object" && e !== null && "code" in e && e.code === "ENOENT") {
25811
+ nearestUnresolvedIndex++;
25812
+ continue;
25813
+ }
25814
+ return void 0;
25815
+ }
25816
+ }
25817
+ return void 0;
25818
+ };
25419
25819
  isomorph_default.getCallerLocation = getCallerLocation;
25420
25820
  isomorph_default.newAsyncLocalStorage = () => new AsyncLocalStorage();
25421
25821
  isomorph_default.newTracingChannel = (nameOrChannels) => diagnostics_channel.tracingChannel(nameOrChannels);
@@ -25446,6 +25846,12 @@ function configureNode() {
25446
25846
  isomorph_default.gunzip = promisify(zlib.gunzip);
25447
25847
  isomorph_default.hash = (data) => crypto.createHash("sha256").update(data).digest("hex");
25448
25848
  _internalSetInitialState();
25849
+ const disabled = readDisabledInstrumentationEnvConfig(
25850
+ isomorph_default.getEnv("BRAINTRUST_DISABLE_INSTRUMENTATION")
25851
+ ).integrations;
25852
+ if (!isInstrumentationIntegrationDisabled(disabled, "mastra")) {
25853
+ installMastraExporterFactory(() => new BraintrustObservabilityExporter());
25854
+ }
25449
25855
  registry.enable();
25450
25856
  }
25451
25857
 
@@ -26570,8 +26976,12 @@ async function invoke(args) {
26570
26976
 
26571
26977
  // src/trace.ts
26572
26978
  var SpanFetcher = class _SpanFetcher extends ObjectFetcher {
26573
- constructor(objectType, _objectId, rootSpanId, _state, spanTypeFilter) {
26574
- const filterExpr = _SpanFetcher.buildFilter(rootSpanId, spanTypeFilter);
26979
+ constructor(objectType, _objectId, rootSpanId, _state, spanTypeFilter, includeScorers = false) {
26980
+ const filterExpr = _SpanFetcher.buildFilter(
26981
+ rootSpanId,
26982
+ spanTypeFilter,
26983
+ includeScorers
26984
+ );
26575
26985
  super(objectType, void 0, void 0, {
26576
26986
  filter: filterExpr
26577
26987
  });
@@ -26580,16 +26990,17 @@ var SpanFetcher = class _SpanFetcher extends ObjectFetcher {
26580
26990
  this._state = _state;
26581
26991
  this.spanTypeFilter = spanTypeFilter;
26582
26992
  }
26583
- static buildFilter(rootSpanId, spanTypeFilter) {
26993
+ static buildFilter(rootSpanId, spanTypeFilter, includeScorers = false) {
26584
26994
  const children = [
26585
26995
  // Base filter: root_span_id = 'value'
26586
26996
  {
26587
26997
  op: "eq",
26588
26998
  left: { op: "ident", name: ["root_span_id"] },
26589
26999
  right: { op: "literal", value: rootSpanId }
26590
- },
26591
- // Exclude span_attributes.purpose = 'score'
26592
- {
27000
+ }
27001
+ ];
27002
+ if (!includeScorers) {
27003
+ children.push({
26593
27004
  op: "or",
26594
27005
  children: [
26595
27006
  {
@@ -26602,8 +27013,8 @@ var SpanFetcher = class _SpanFetcher extends ObjectFetcher {
26602
27013
  right: { op: "literal", value: "scorer" }
26603
27014
  }
26604
27015
  ]
26605
- }
26606
- ];
27016
+ });
27017
+ }
26607
27018
  if (spanTypeFilter && spanTypeFilter.length > 0) {
26608
27019
  children.push({
26609
27020
  op: "in",
@@ -26629,35 +27040,49 @@ var CachedSpanFetcher = class {
26629
27040
  fetchFn;
26630
27041
  constructor(objectTypeOrFetchFn, objectId, rootSpanId, getState) {
26631
27042
  if (typeof objectTypeOrFetchFn === "function") {
26632
- this.fetchFn = objectTypeOrFetchFn;
27043
+ this.fetchFn = (spanType) => objectTypeOrFetchFn(spanType);
26633
27044
  } else {
26634
27045
  const objectType = objectTypeOrFetchFn;
26635
- this.fetchFn = async (spanType) => {
27046
+ this.fetchFn = async (spanType, includeScorers) => {
26636
27047
  const state = await getState();
26637
27048
  const fetcher = new SpanFetcher(
26638
27049
  objectType,
26639
27050
  objectId,
26640
27051
  rootSpanId,
26641
27052
  state,
26642
- spanType
27053
+ spanType,
27054
+ includeScorers
26643
27055
  );
26644
27056
  const rows = await fetcher.fetchedData();
26645
- return rows.filter((row) => row.span_attributes?.purpose !== "scorer").map((row) => ({
27057
+ return rows.map((row) => ({
26646
27058
  input: row.input,
26647
27059
  output: row.output,
27060
+ expected: row.expected,
27061
+ error: row.error,
27062
+ scores: row.scores,
27063
+ metrics: row.metrics,
26648
27064
  metadata: row.metadata,
26649
27065
  span_id: row.span_id,
26650
27066
  span_parents: row.span_parents,
27067
+ is_root: row.is_root,
26651
27068
  span_attributes: row.span_attributes,
26652
27069
  id: row.id,
26653
27070
  _xact_id: row._xact_id,
26654
27071
  _pagination_key: row._pagination_key,
26655
- root_span_id: row.root_span_id
27072
+ root_span_id: row.root_span_id,
27073
+ created: row.created,
27074
+ tags: row.tags
26656
27075
  }));
26657
27076
  };
26658
27077
  }
26659
27078
  }
26660
- async getSpans({ spanType } = {}) {
27079
+ async getSpans({
27080
+ spanType,
27081
+ includeScorers = false
27082
+ } = {}) {
27083
+ if (includeScorers) {
27084
+ return this.fetchFn(spanType, true);
27085
+ }
26661
27086
  if (this.allFetched) {
26662
27087
  return this.getFromCache(spanType);
26663
27088
  }
@@ -26674,7 +27099,7 @@ var CachedSpanFetcher = class {
26674
27099
  return this.getFromCache(spanType);
26675
27100
  }
26676
27101
  async fetchSpans(spanType) {
26677
- const spans = await this.fetchFn(spanType);
27102
+ const spans = await this.fetchFn(spanType, false);
26678
27103
  for (const span of spans) {
26679
27104
  const type = span.span_attributes?.type ?? "";
26680
27105
  const existing = this.spanCache.get(type) ?? [];
@@ -26752,10 +27177,13 @@ var LocalTrace = class {
26752
27177
  * First checks the local span cache for recently logged spans, then falls
26753
27178
  * back to CachedSpanFetcher which handles BTQL fetching and caching.
26754
27179
  */
26755
- async getSpans({ spanType } = {}) {
27180
+ async getSpans({
27181
+ spanType,
27182
+ includeScorers = false
27183
+ } = {}) {
26756
27184
  const cachedSpans = this.state.spanCache.getByRootSpanId(this.rootSpanId);
26757
27185
  if (cachedSpans && cachedSpans.length > 0) {
26758
- let spans = cachedSpans.filter(
27186
+ let spans = includeScorers ? cachedSpans : cachedSpans.filter(
26759
27187
  (span) => span.span_attributes?.purpose !== "scorer"
26760
27188
  );
26761
27189
  if (spanType && spanType.length > 0) {
@@ -26766,13 +27194,19 @@ var LocalTrace = class {
26766
27194
  return spans.map((span) => ({
26767
27195
  input: span.input,
26768
27196
  output: span.output,
27197
+ expected: span.expected,
27198
+ error: span.error,
27199
+ scores: span.scores,
27200
+ metrics: span.metrics,
26769
27201
  metadata: span.metadata,
26770
27202
  span_id: span.span_id,
26771
27203
  span_parents: span.span_parents,
26772
- span_attributes: span.span_attributes
27204
+ is_root: span.is_root,
27205
+ span_attributes: span.span_attributes,
27206
+ tags: span.tags
26773
27207
  }));
26774
27208
  }
26775
- return this.cachedFetcher.getSpans({ spanType });
27209
+ return this.cachedFetcher.getSpans({ spanType, includeScorers });
26776
27210
  }
26777
27211
  /**
26778
27212
  * Get the thread (preprocessed messages) for this trace.