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
package/dist/index.mjs CHANGED
@@ -14,6 +14,8 @@ import {
14
14
  googleGenAIChannels,
15
15
  groqChannels,
16
16
  huggingFaceChannels,
17
+ installMastraExporterFactory,
18
+ isInstrumentationIntegrationDisabled,
17
19
  isomorph_default,
18
20
  langChainChannels,
19
21
  mistralChannels,
@@ -24,7 +26,7 @@ import {
24
26
  openRouterChannels,
25
27
  patchTracingChannel,
26
28
  readDisabledInstrumentationEnvConfig
27
- } from "./chunk-MSLBGITU.mjs";
29
+ } from "./chunk-NU2GSPHX.mjs";
28
30
 
29
31
  // src/node/config.ts
30
32
  import { AsyncLocalStorage } from "node:async_hooks";
@@ -36,6 +38,7 @@ import * as fsSync from "node:fs";
36
38
  import * as crypto from "node:crypto";
37
39
  import { promisify } from "node:util";
38
40
  import * as zlib from "node:zlib";
41
+ import * as dotenv from "dotenv";
39
42
 
40
43
  // src/debug-logger.ts
41
44
  var PREFIX = "[braintrust]";
@@ -4084,6 +4087,76 @@ var LRUCache = class {
4084
4087
  }
4085
4088
  };
4086
4089
 
4090
+ // src/prompt-cache/cache-config.ts
4091
+ var CACHE_LOCATION_ENV_VAR = "BRAINTRUST_CACHE_LOCATION";
4092
+ var DEFAULT_CACHE_MEMORY_MAX = 1 << 10;
4093
+ var DEFAULT_CACHE_DISK_MAX = 1 << 20;
4094
+ var warnedInvalidCacheModeEnvValue = false;
4095
+ var warnedUnavailableDiskCacheMode = false;
4096
+ function warnInvalidCacheMode(value) {
4097
+ if (warnedInvalidCacheModeEnvValue) {
4098
+ return;
4099
+ }
4100
+ warnedInvalidCacheModeEnvValue = true;
4101
+ debugLogger.warn(
4102
+ `Invalid ${CACHE_LOCATION_ENV_VAR} value "${value}". Expected "mixed", "memory", "disk", or "none". Falling back to "mixed".`
4103
+ );
4104
+ }
4105
+ function warnUnavailableDiskCache() {
4106
+ if (warnedUnavailableDiskCacheMode) {
4107
+ return;
4108
+ }
4109
+ warnedUnavailableDiskCacheMode = true;
4110
+ debugLogger.warn(
4111
+ `Disk cache is not supported on this platform, so ${CACHE_LOCATION_ENV_VAR}="disk" disables prompt and parameters caching.`
4112
+ );
4113
+ }
4114
+ function parseCacheMode() {
4115
+ const value = isomorph_default.getEnv(CACHE_LOCATION_ENV_VAR);
4116
+ const normalized = value?.trim().toLowerCase();
4117
+ if (!normalized) {
4118
+ return "mixed";
4119
+ }
4120
+ if (normalized === "mixed" || normalized === "memory" || normalized === "disk" || normalized === "none") {
4121
+ return normalized;
4122
+ }
4123
+ warnInvalidCacheMode(value ?? "");
4124
+ return "mixed";
4125
+ }
4126
+ function parsePositiveIntegerEnv(envVar, defaultValue) {
4127
+ const value = Number(isomorph_default.getEnv(envVar));
4128
+ return Number.isInteger(value) && value > 0 ? value : defaultValue;
4129
+ }
4130
+ function createCacheLayers({
4131
+ memoryMaxEnvVar,
4132
+ diskCacheDirEnvVar,
4133
+ diskMaxEnvVar,
4134
+ getDefaultDiskCacheDir
4135
+ }) {
4136
+ const mode = parseCacheMode();
4137
+ const memoryCache = mode === "mixed" || mode === "memory" ? new LRUCache({
4138
+ max: parsePositiveIntegerEnv(
4139
+ memoryMaxEnvVar,
4140
+ DEFAULT_CACHE_MEMORY_MAX
4141
+ )
4142
+ }) : void 0;
4143
+ let diskCache;
4144
+ if (mode === "mixed" || mode === "disk") {
4145
+ if (canUseDiskCache()) {
4146
+ diskCache = new DiskCache({
4147
+ cacheDir: isomorph_default.getEnv(diskCacheDirEnvVar) ?? getDefaultDiskCacheDir(),
4148
+ max: parsePositiveIntegerEnv(diskMaxEnvVar, DEFAULT_CACHE_DISK_MAX)
4149
+ });
4150
+ } else if (mode === "disk") {
4151
+ warnUnavailableDiskCache();
4152
+ }
4153
+ }
4154
+ if (diskCache) {
4155
+ return { memoryCache, diskCache };
4156
+ }
4157
+ return { memoryCache };
4158
+ }
4159
+
4087
4160
  // src/prompt-cache/prompt-cache.ts
4088
4161
  function createCacheKey(key) {
4089
4162
  if (key.id) {
@@ -4111,16 +4184,18 @@ var PromptCache = class {
4111
4184
  */
4112
4185
  async get(key) {
4113
4186
  const cacheKey = createCacheKey(key);
4114
- const memoryPrompt = this.memoryCache.get(cacheKey);
4115
- if (memoryPrompt !== void 0) {
4116
- return memoryPrompt;
4187
+ if (this.memoryCache) {
4188
+ const memoryPrompt = this.memoryCache.get(cacheKey);
4189
+ if (memoryPrompt !== void 0) {
4190
+ return memoryPrompt;
4191
+ }
4117
4192
  }
4118
4193
  if (this.diskCache) {
4119
4194
  const diskPrompt = await this.diskCache.get(cacheKey);
4120
4195
  if (!diskPrompt) {
4121
4196
  return void 0;
4122
4197
  }
4123
- this.memoryCache.set(cacheKey, diskPrompt);
4198
+ this.memoryCache?.set(cacheKey, diskPrompt);
4124
4199
  return diskPrompt;
4125
4200
  }
4126
4201
  return void 0;
@@ -4135,7 +4210,7 @@ var PromptCache = class {
4135
4210
  */
4136
4211
  async set(key, value) {
4137
4212
  const cacheKey = createCacheKey(key);
4138
- this.memoryCache.set(cacheKey, value);
4213
+ this.memoryCache?.set(cacheKey, value);
4139
4214
  if (this.diskCache) {
4140
4215
  await this.diskCache.set(cacheKey, value);
4141
4216
  }
@@ -4165,23 +4240,25 @@ var ParametersCache = class {
4165
4240
  }
4166
4241
  async get(key) {
4167
4242
  const cacheKey = createCacheKey2(key);
4168
- const memoryParams = this.memoryCache.get(cacheKey);
4169
- if (memoryParams !== void 0) {
4170
- return memoryParams;
4243
+ if (this.memoryCache) {
4244
+ const memoryParams = this.memoryCache.get(cacheKey);
4245
+ if (memoryParams !== void 0) {
4246
+ return memoryParams;
4247
+ }
4171
4248
  }
4172
4249
  if (this.diskCache) {
4173
4250
  const diskParams = await this.diskCache.get(cacheKey);
4174
4251
  if (!diskParams) {
4175
4252
  return void 0;
4176
4253
  }
4177
- this.memoryCache.set(cacheKey, diskParams);
4254
+ this.memoryCache?.set(cacheKey, diskParams);
4178
4255
  return diskParams;
4179
4256
  }
4180
4257
  return void 0;
4181
4258
  }
4182
4259
  async set(key, value) {
4183
4260
  const cacheKey = createCacheKey2(key);
4184
- this.memoryCache.set(cacheKey, value);
4261
+ this.memoryCache?.set(cacheKey, value);
4185
4262
  if (this.diskCache) {
4186
4263
  await this.diskCache.set(cacheKey, value);
4187
4264
  }
@@ -4713,21 +4790,22 @@ var BraintrustState = class _BraintrustState {
4713
4790
  setGlobalDebugLogLevel(void 0);
4714
4791
  }
4715
4792
  this.resetLoginInfo();
4716
- const memoryCache = new LRUCache({
4717
- max: Number(isomorph_default.getEnv("BRAINTRUST_PROMPT_CACHE_MEMORY_MAX")) ?? 1 << 10
4793
+ const { memoryCache, diskCache } = createCacheLayers({
4794
+ memoryMaxEnvVar: "BRAINTRUST_PROMPT_CACHE_MEMORY_MAX",
4795
+ diskCacheDirEnvVar: "BRAINTRUST_PROMPT_CACHE_DIR",
4796
+ diskMaxEnvVar: "BRAINTRUST_PROMPT_CACHE_DISK_MAX",
4797
+ getDefaultDiskCacheDir: () => `${isomorph_default.getEnv("HOME") ?? isomorph_default.homedir()}/.braintrust/prompt_cache`
4718
4798
  });
4719
- const diskCache = canUseDiskCache() ? new DiskCache({
4720
- cacheDir: isomorph_default.getEnv("BRAINTRUST_PROMPT_CACHE_DIR") ?? `${isomorph_default.getEnv("HOME") ?? isomorph_default.homedir()}/.braintrust/prompt_cache`,
4721
- max: Number(isomorph_default.getEnv("BRAINTRUST_PROMPT_CACHE_DISK_MAX")) ?? 1 << 20
4722
- }) : void 0;
4723
4799
  this.promptCache = new PromptCache({ memoryCache, diskCache });
4724
- const parametersMemoryCache = new LRUCache({
4725
- max: Number(isomorph_default.getEnv("BRAINTRUST_PARAMETERS_CACHE_MEMORY_MAX")) ?? 1 << 10
4800
+ const {
4801
+ memoryCache: parametersMemoryCache,
4802
+ diskCache: parametersDiskCache
4803
+ } = createCacheLayers({
4804
+ memoryMaxEnvVar: "BRAINTRUST_PARAMETERS_CACHE_MEMORY_MAX",
4805
+ diskCacheDirEnvVar: "BRAINTRUST_PARAMETERS_CACHE_DIR",
4806
+ diskMaxEnvVar: "BRAINTRUST_PARAMETERS_CACHE_DISK_MAX",
4807
+ getDefaultDiskCacheDir: () => `${isomorph_default.getEnv("HOME") ?? isomorph_default.homedir()}/.braintrust/parameters_cache`
4726
4808
  });
4727
- const parametersDiskCache = canUseDiskCache() ? new DiskCache({
4728
- cacheDir: isomorph_default.getEnv("BRAINTRUST_PARAMETERS_CACHE_DIR") ?? `${isomorph_default.getEnv("HOME") ?? isomorph_default.homedir()}/.braintrust/parameters_cache`,
4729
- max: Number(isomorph_default.getEnv("BRAINTRUST_PARAMETERS_CACHE_DISK_MAX")) ?? 1 << 20
4730
- }) : void 0;
4731
4809
  this.parametersCache = new ParametersCache({
4732
4810
  memoryCache: parametersMemoryCache,
4733
4811
  diskCache: parametersDiskCache
@@ -5580,6 +5658,19 @@ var JSONAttachment = class extends Attachment {
5580
5658
  */
5581
5659
  constructor(data, options) {
5582
5660
  const { filename = "data.json", pretty = false, state } = options ?? {};
5661
+ const deferredJsonAttachment = globalThis.__BT_DATASET_PIPELINE_DEFER_JSON_ATTACHMENT__;
5662
+ if (deferredJsonAttachment) {
5663
+ super({
5664
+ data: new Blob([]),
5665
+ filename,
5666
+ contentType: "application/json",
5667
+ state
5668
+ });
5669
+ return deferredJsonAttachment(data, {
5670
+ filename,
5671
+ pretty
5672
+ });
5673
+ }
5583
5674
  const jsonString = pretty ? JSON.stringify(data, null, 2) : JSON.stringify(data);
5584
5675
  const blob = new Blob([jsonString], { type: "application/json" });
5585
5676
  super({
@@ -7572,10 +7663,11 @@ async function login(options = {}) {
7572
7663
  async function loginToState(options = {}) {
7573
7664
  const {
7574
7665
  appUrl = isomorph_default.getEnv("BRAINTRUST_APP_URL") || "https://www.braintrust.dev",
7575
- apiKey = isomorph_default.getEnv("BRAINTRUST_API_KEY"),
7666
+ apiKey: apiKeyArg,
7576
7667
  orgName = isomorph_default.getEnv("BRAINTRUST_ORG_NAME"),
7577
7668
  fetch: fetch2 = globalThis.fetch
7578
7669
  } = options || {};
7670
+ const apiKey = apiKeyArg !== void 0 ? apiKeyArg : await isomorph_default.getBraintrustApiKey();
7579
7671
  const appPublicUrl = isomorph_default.getEnv("BRAINTRUST_APP_PUBLIC_URL") || appUrl;
7580
7672
  const state = new BraintrustState(options);
7581
7673
  state.resetLoginInfo();
@@ -8816,9 +8908,15 @@ var SpanImpl = class _SpanImpl {
8816
8908
  const cachedSpan = {
8817
8909
  input: partialRecord.input,
8818
8910
  output: partialRecord.output,
8911
+ expected: partialRecord.expected,
8912
+ error: partialRecord.error,
8913
+ scores: partialRecord.scores,
8914
+ metrics: partialRecord.metrics,
8819
8915
  metadata: partialRecord.metadata,
8916
+ tags: partialRecord.tags,
8820
8917
  span_id: this._spanId,
8821
8918
  span_parents: this._spanParents,
8919
+ is_root: this._spanId === this._rootSpanId,
8822
8920
  span_attributes: partialRecord.span_attributes
8823
8921
  };
8824
8922
  this._state.spanCache.queueWrite(
@@ -9154,6 +9252,7 @@ var Dataset2 = class extends ObjectFetcher {
9154
9252
  metadata,
9155
9253
  tags,
9156
9254
  output,
9255
+ origin,
9157
9256
  isMerge
9158
9257
  }) {
9159
9258
  return new LazyValue(async () => {
@@ -9168,6 +9267,7 @@ var Dataset2 = class extends ObjectFetcher {
9168
9267
  created: !isMerge ? (/* @__PURE__ */ new Date()).toISOString() : void 0,
9169
9268
  //if we're merging/updating an event we will not add this ts
9170
9269
  metadata,
9270
+ origin,
9171
9271
  ...!!isMerge ? {
9172
9272
  [IS_MERGE_FIELD]: true
9173
9273
  } : {}
@@ -9187,6 +9287,7 @@ var Dataset2 = class extends ObjectFetcher {
9187
9287
  * about anything else that's relevant, that you can use to help find and analyze examples later. For example, you could log the
9188
9288
  * `prompt`, example's `id`, or anything else that would be useful to slice/dice later. The values in `metadata` can be any
9189
9289
  * JSON-serializable type, but its keys must be strings.
9290
+ * @param event.origin (Optional) a reference to the source object this dataset record was derived from.
9190
9291
  * @param event.id (Optional) a unique identifier for the event. If you don't provide one, Braintrust will generate one for you.
9191
9292
  * @param event.output: (Deprecated) The output of your application. Use `expected` instead.
9192
9293
  * @returns The `id` of the logged record.
@@ -9197,7 +9298,8 @@ var Dataset2 = class extends ObjectFetcher {
9197
9298
  metadata,
9198
9299
  tags,
9199
9300
  id,
9200
- output
9301
+ output,
9302
+ origin
9201
9303
  }) {
9202
9304
  this.validateEvent({ metadata, expected, output, tags });
9203
9305
  const rowId = id || uuidv42();
@@ -9209,6 +9311,7 @@ var Dataset2 = class extends ObjectFetcher {
9209
9311
  metadata,
9210
9312
  tags,
9211
9313
  output,
9314
+ origin,
9212
9315
  isMerge: false
9213
9316
  })
9214
9317
  );
@@ -25210,7 +25313,7 @@ var BraintrustPlugin = class extends BasePlugin {
25210
25313
  this.config = config;
25211
25314
  }
25212
25315
  onEnable() {
25213
- const integrations = this.config.integrations || {};
25316
+ const integrations = this.config.integrations ?? {};
25214
25317
  if (integrations.openai !== false) {
25215
25318
  this.openaiPlugin = new OpenAIPlugin();
25216
25319
  this.openaiPlugin.enable();
@@ -25275,7 +25378,7 @@ var BraintrustPlugin = class extends BasePlugin {
25275
25378
  this.genkitPlugin = new GenkitPlugin();
25276
25379
  this.genkitPlugin.enable();
25277
25380
  }
25278
- if (getIntegrationConfig(integrations, "gitHubCopilot") !== false) {
25381
+ if (integrations.gitHubCopilot !== false) {
25279
25382
  this.gitHubCopilotPlugin = new GitHubCopilotPlugin();
25280
25383
  this.gitHubCopilotPlugin.enable();
25281
25384
  }
@@ -25463,12 +25566,256 @@ function configureInstrumentation(config) {
25463
25566
  registry.configure(config);
25464
25567
  }
25465
25568
 
25569
+ // src/wrappers/mastra.ts
25570
+ var MASTRA_BRAINTRUST_EXPORTER_NAME = "braintrust";
25571
+ var SPAN_TYPE_MAP = {
25572
+ agent_run: "task" /* TASK */,
25573
+ model_generation: "llm" /* LLM */,
25574
+ model_step: "llm" /* LLM */,
25575
+ model_chunk: "llm" /* LLM */,
25576
+ tool_call: "tool" /* TOOL */,
25577
+ mcp_tool_call: "tool" /* TOOL */,
25578
+ workflow_run: "task" /* TASK */,
25579
+ workflow_step: "function" /* FUNCTION */,
25580
+ workflow_conditional: "function" /* FUNCTION */,
25581
+ workflow_conditional_eval: "function" /* FUNCTION */,
25582
+ workflow_parallel: "function" /* FUNCTION */,
25583
+ workflow_loop: "function" /* FUNCTION */,
25584
+ workflow_sleep: "function" /* FUNCTION */,
25585
+ workflow_wait_event: "function" /* FUNCTION */,
25586
+ memory_operation: "function" /* FUNCTION */,
25587
+ workspace_action: "function" /* FUNCTION */,
25588
+ rag_ingestion: "task" /* TASK */,
25589
+ rag_embedding: "llm" /* LLM */,
25590
+ rag_vector_operation: "function" /* FUNCTION */,
25591
+ rag_action: "function" /* FUNCTION */,
25592
+ graph_action: "function" /* FUNCTION */,
25593
+ scorer_run: "score" /* SCORE */,
25594
+ scorer_step: "score" /* SCORE */,
25595
+ processor_run: "function" /* FUNCTION */,
25596
+ generic: "function" /* FUNCTION */
25597
+ };
25598
+ function spanTypeFor(mastraType) {
25599
+ return SPAN_TYPE_MAP[mastraType] ?? "function" /* FUNCTION */;
25600
+ }
25601
+ function epochSeconds(value) {
25602
+ if (value === void 0) return void 0;
25603
+ const ms = value instanceof Date ? value.getTime() : typeof value === "number" ? value : Date.parse(value);
25604
+ return Number.isFinite(ms) ? ms / 1e3 : void 0;
25605
+ }
25606
+ function modelMetrics(attributes) {
25607
+ if (!isObject(attributes)) return void 0;
25608
+ const usage = isObject(attributes.usage) ? attributes.usage : void 0;
25609
+ if (!usage) return void 0;
25610
+ const out = {};
25611
+ if (typeof usage.inputTokens === "number")
25612
+ out.prompt_tokens = usage.inputTokens;
25613
+ if (typeof usage.outputTokens === "number")
25614
+ out.completion_tokens = usage.outputTokens;
25615
+ if (typeof usage.inputTokens === "number" && typeof usage.outputTokens === "number") {
25616
+ out.tokens = usage.inputTokens + usage.outputTokens;
25617
+ }
25618
+ const inputDetails = isObject(usage.inputDetails) ? usage.inputDetails : void 0;
25619
+ const outputDetails = isObject(usage.outputDetails) ? usage.outputDetails : void 0;
25620
+ if (inputDetails && typeof inputDetails.cacheRead === "number") {
25621
+ out.prompt_cached_tokens = inputDetails.cacheRead;
25622
+ }
25623
+ if (inputDetails && typeof inputDetails.cacheWrite === "number") {
25624
+ out.prompt_cache_creation_tokens = inputDetails.cacheWrite;
25625
+ }
25626
+ if (outputDetails && typeof outputDetails.reasoning === "number") {
25627
+ out.completion_reasoning_tokens = outputDetails.reasoning;
25628
+ }
25629
+ return Object.keys(out).length > 0 ? out : void 0;
25630
+ }
25631
+ function buildMetadata(exported) {
25632
+ const out = {};
25633
+ if (exported.entityId !== void 0) out.entity_id = exported.entityId;
25634
+ if (exported.entityName !== void 0) out.entity_name = exported.entityName;
25635
+ if (exported.entityType !== void 0) out.entity_type = exported.entityType;
25636
+ if (exported.metadata && isObject(exported.metadata)) {
25637
+ Object.assign(out, exported.metadata);
25638
+ }
25639
+ if (exported.attributes && isObject(exported.attributes)) {
25640
+ for (const [key, value] of Object.entries(exported.attributes)) {
25641
+ if (key === "usage") continue;
25642
+ if (value !== void 0) out[key] = value;
25643
+ }
25644
+ }
25645
+ if (exported.tags && exported.tags.length > 0) {
25646
+ out.tags = exported.tags;
25647
+ }
25648
+ if (exported.requestContext && isObject(exported.requestContext)) {
25649
+ out.request_context = exported.requestContext;
25650
+ }
25651
+ return out;
25652
+ }
25653
+ var BraintrustObservabilityExporter = class {
25654
+ name = MASTRA_BRAINTRUST_EXPORTER_NAME;
25655
+ spans = /* @__PURE__ */ new Map();
25656
+ // Captured at the first SPAN_STARTED event. Mastra's observability bus may
25657
+ // dispatch later events outside the user's AsyncLocalStorage context, where
25658
+ // `currentSpan()` returns NOOP_SPAN — which would make our `startSpan()`
25659
+ // calls go to a no-op logger and silently drop. Anchoring on the parent
25660
+ // we observe while still in-context keeps the whole Mastra subtree under
25661
+ // the user's traced scenario.
25662
+ capturedParent;
25663
+ constructor() {
25664
+ _internalSetInitialState();
25665
+ }
25666
+ async exportTracingEvent(event) {
25667
+ const exported = event.exportedSpan;
25668
+ if (exported.isInternal === true) return;
25669
+ try {
25670
+ switch (event.type) {
25671
+ case "span_started":
25672
+ this.onStart(exported);
25673
+ break;
25674
+ case "span_updated":
25675
+ this.onUpdate(exported);
25676
+ break;
25677
+ case "span_ended":
25678
+ this.onEnd(exported);
25679
+ break;
25680
+ }
25681
+ } catch (err) {
25682
+ logExporterError(err);
25683
+ }
25684
+ }
25685
+ async flush() {
25686
+ const state = _internalGetGlobalState();
25687
+ if (state) {
25688
+ await state.bgLogger().flush();
25689
+ }
25690
+ }
25691
+ async shutdown() {
25692
+ await this.flush();
25693
+ this.spans.clear();
25694
+ }
25695
+ onStart(exported) {
25696
+ if (this.spans.has(exported.id)) return;
25697
+ const args = {
25698
+ name: exported.name,
25699
+ spanAttributes: { type: spanTypeFor(exported.type) },
25700
+ startTime: epochSeconds(exported.startTime)
25701
+ };
25702
+ const parentRecord = exported.parentSpanId ? this.spans.get(exported.parentSpanId) : void 0;
25703
+ if (!this.capturedParent) {
25704
+ const probe = currentSpan();
25705
+ if (probe && probe.spanId) {
25706
+ this.capturedParent = probe;
25707
+ }
25708
+ }
25709
+ const span = parentRecord ? parentRecord.span.startSpan(args) : this.capturedParent ? this.capturedParent.startSpan(args) : startSpan(args);
25710
+ const record = { span, hasLoggedInput: false };
25711
+ this.logPayload(record, exported);
25712
+ this.spans.set(exported.id, record);
25713
+ if (exported.isEvent === true) {
25714
+ span.end({ endTime: args.startTime });
25715
+ this.spans.delete(exported.id);
25716
+ }
25717
+ }
25718
+ onUpdate(exported) {
25719
+ const record = this.spans.get(exported.id);
25720
+ if (!record) return;
25721
+ this.logPayload(record, exported);
25722
+ }
25723
+ onEnd(exported) {
25724
+ const record = this.spans.get(exported.id);
25725
+ if (!record) return;
25726
+ this.logPayload(record, exported);
25727
+ if (exported.errorInfo) {
25728
+ record.span.log({
25729
+ error: exported.errorInfo.message || exported.errorInfo.name || "Unknown Mastra error"
25730
+ });
25731
+ }
25732
+ record.span.end({ endTime: epochSeconds(exported.endTime) });
25733
+ this.spans.delete(exported.id);
25734
+ }
25735
+ logPayload(record, exported) {
25736
+ const event = {};
25737
+ if (exported.input !== void 0) {
25738
+ event.input = exported.input;
25739
+ record.hasLoggedInput = true;
25740
+ }
25741
+ if (exported.output !== void 0) {
25742
+ event.output = exported.output;
25743
+ }
25744
+ const metadata = buildMetadata(exported);
25745
+ if (Object.keys(metadata).length > 0) {
25746
+ event.metadata = metadata;
25747
+ }
25748
+ const metrics = modelMetrics(exported.attributes);
25749
+ if (metrics) {
25750
+ event.metrics = metrics;
25751
+ }
25752
+ if (Object.keys(event).length > 0) {
25753
+ record.span.log(event);
25754
+ }
25755
+ }
25756
+ };
25757
+ function logExporterError(err) {
25758
+ debugLogger.warn("Mastra exporter failure:", err);
25759
+ }
25760
+ function wrapMastraAgent(agent, _options) {
25761
+ return agent;
25762
+ }
25763
+
25466
25764
  // src/node/config.ts
25765
+ var BRAINTRUST_ENV_SEARCH_PARENT_LIMIT = 64;
25467
25766
  function configureNode() {
25468
25767
  isomorph_default.buildType = "node";
25469
25768
  isomorph_default.getRepoInfo = getRepoInfo;
25470
25769
  isomorph_default.getPastNAncestors = getPastNAncestors;
25471
- 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
+ };
25472
25819
  isomorph_default.getCallerLocation = getCallerLocation;
25473
25820
  isomorph_default.newAsyncLocalStorage = () => new AsyncLocalStorage();
25474
25821
  isomorph_default.newTracingChannel = (nameOrChannels) => diagnostics_channel.tracingChannel(nameOrChannels);
@@ -25499,6 +25846,12 @@ function configureNode() {
25499
25846
  isomorph_default.gunzip = promisify(zlib.gunzip);
25500
25847
  isomorph_default.hash = (data) => crypto.createHash("sha256").update(data).digest("hex");
25501
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
+ }
25502
25855
  registry.enable();
25503
25856
  }
25504
25857
 
@@ -25513,6 +25866,7 @@ __export(exports_exports, {
25513
25866
  BaseExperiment: () => BaseExperiment,
25514
25867
  BraintrustLangChainCallbackHandler: () => BraintrustLangChainCallbackHandler,
25515
25868
  BraintrustMiddleware: () => BraintrustMiddleware,
25869
+ BraintrustObservabilityExporter: () => BraintrustObservabilityExporter,
25516
25870
  BraintrustState: () => BraintrustState,
25517
25871
  BraintrustStream: () => BraintrustStream,
25518
25872
  CachedSpanFetcher: () => CachedSpanFetcher,
@@ -25522,6 +25876,7 @@ __export(exports_exports, {
25522
25876
  DEFAULT_FETCH_BATCH_SIZE: () => DEFAULT_FETCH_BATCH_SIZE,
25523
25877
  DEFAULT_MAX_REQUEST_SIZE: () => DEFAULT_MAX_REQUEST_SIZE,
25524
25878
  Dataset: () => Dataset2,
25879
+ DatasetPipeline: () => DatasetPipeline,
25525
25880
  ERR_PERMALINK: () => ERR_PERMALINK,
25526
25881
  Eval: () => Eval,
25527
25882
  EvalResultWithSummary: () => EvalResultWithSummary,
@@ -27127,11 +27482,6 @@ function toolRunnerProxy(toolRunner, anthropic, channel) {
27127
27482
  });
27128
27483
  }
27129
27484
 
27130
- // src/wrappers/mastra.ts
27131
- function wrapMastraAgent(agent, _options) {
27132
- return agent;
27133
- }
27134
-
27135
27485
  // src/wrappers/claude-agent-sdk/claude-agent-sdk.ts
27136
27486
  function wrapClaudeAgentSDK(sdk) {
27137
27487
  const s = sdk;
@@ -28780,10 +29130,12 @@ function formatExperimentSummary(summary) {
28780
29130
  // src/wrappers/shared/flush.ts
28781
29131
  async function summarizeAndFlush(experiment, options) {
28782
29132
  const shouldDisplay = options.displaySummary ?? true;
28783
- const summary = await experiment.summarize();
28784
- if (shouldDisplay) {
28785
- console.log(formatExperimentSummary(summary));
29133
+ if (!shouldDisplay) {
29134
+ await experiment.flush();
29135
+ return;
28786
29136
  }
29137
+ const summary = await experiment.summarize();
29138
+ console.log(formatExperimentSummary(summary));
28787
29139
  }
28788
29140
 
28789
29141
  // src/wrappers/vitest/flush-manager.ts
@@ -30647,8 +30999,12 @@ var waterfall$1 = awaitify(waterfall);
30647
30999
 
30648
31000
  // src/trace.ts
30649
31001
  var SpanFetcher = class _SpanFetcher extends ObjectFetcher {
30650
- constructor(objectType, _objectId, rootSpanId, _state, spanTypeFilter) {
30651
- const filterExpr = _SpanFetcher.buildFilter(rootSpanId, spanTypeFilter);
31002
+ constructor(objectType, _objectId, rootSpanId, _state, spanTypeFilter, includeScorers = false) {
31003
+ const filterExpr = _SpanFetcher.buildFilter(
31004
+ rootSpanId,
31005
+ spanTypeFilter,
31006
+ includeScorers
31007
+ );
30652
31008
  super(objectType, void 0, void 0, {
30653
31009
  filter: filterExpr
30654
31010
  });
@@ -30657,16 +31013,17 @@ var SpanFetcher = class _SpanFetcher extends ObjectFetcher {
30657
31013
  this._state = _state;
30658
31014
  this.spanTypeFilter = spanTypeFilter;
30659
31015
  }
30660
- static buildFilter(rootSpanId, spanTypeFilter) {
31016
+ static buildFilter(rootSpanId, spanTypeFilter, includeScorers = false) {
30661
31017
  const children = [
30662
31018
  // Base filter: root_span_id = 'value'
30663
31019
  {
30664
31020
  op: "eq",
30665
31021
  left: { op: "ident", name: ["root_span_id"] },
30666
31022
  right: { op: "literal", value: rootSpanId }
30667
- },
30668
- // Exclude span_attributes.purpose = 'score'
30669
- {
31023
+ }
31024
+ ];
31025
+ if (!includeScorers) {
31026
+ children.push({
30670
31027
  op: "or",
30671
31028
  children: [
30672
31029
  {
@@ -30679,8 +31036,8 @@ var SpanFetcher = class _SpanFetcher extends ObjectFetcher {
30679
31036
  right: { op: "literal", value: "scorer" }
30680
31037
  }
30681
31038
  ]
30682
- }
30683
- ];
31039
+ });
31040
+ }
30684
31041
  if (spanTypeFilter && spanTypeFilter.length > 0) {
30685
31042
  children.push({
30686
31043
  op: "in",
@@ -30706,35 +31063,49 @@ var CachedSpanFetcher = class {
30706
31063
  fetchFn;
30707
31064
  constructor(objectTypeOrFetchFn, objectId, rootSpanId, getState) {
30708
31065
  if (typeof objectTypeOrFetchFn === "function") {
30709
- this.fetchFn = objectTypeOrFetchFn;
31066
+ this.fetchFn = (spanType) => objectTypeOrFetchFn(spanType);
30710
31067
  } else {
30711
31068
  const objectType = objectTypeOrFetchFn;
30712
- this.fetchFn = async (spanType) => {
31069
+ this.fetchFn = async (spanType, includeScorers) => {
30713
31070
  const state = await getState();
30714
31071
  const fetcher = new SpanFetcher(
30715
31072
  objectType,
30716
31073
  objectId,
30717
31074
  rootSpanId,
30718
31075
  state,
30719
- spanType
31076
+ spanType,
31077
+ includeScorers
30720
31078
  );
30721
31079
  const rows = await fetcher.fetchedData();
30722
- return rows.filter((row) => row.span_attributes?.purpose !== "scorer").map((row) => ({
31080
+ return rows.map((row) => ({
30723
31081
  input: row.input,
30724
31082
  output: row.output,
31083
+ expected: row.expected,
31084
+ error: row.error,
31085
+ scores: row.scores,
31086
+ metrics: row.metrics,
30725
31087
  metadata: row.metadata,
30726
31088
  span_id: row.span_id,
30727
31089
  span_parents: row.span_parents,
31090
+ is_root: row.is_root,
30728
31091
  span_attributes: row.span_attributes,
30729
31092
  id: row.id,
30730
31093
  _xact_id: row._xact_id,
30731
31094
  _pagination_key: row._pagination_key,
30732
- root_span_id: row.root_span_id
31095
+ root_span_id: row.root_span_id,
31096
+ created: row.created,
31097
+ tags: row.tags
30733
31098
  }));
30734
31099
  };
30735
31100
  }
30736
31101
  }
30737
- async getSpans({ spanType } = {}) {
31102
+ async getSpans({
31103
+ spanType,
31104
+ includeScorers = false
31105
+ } = {}) {
31106
+ if (includeScorers) {
31107
+ return this.fetchFn(spanType, true);
31108
+ }
30738
31109
  if (this.allFetched) {
30739
31110
  return this.getFromCache(spanType);
30740
31111
  }
@@ -30751,7 +31122,7 @@ var CachedSpanFetcher = class {
30751
31122
  return this.getFromCache(spanType);
30752
31123
  }
30753
31124
  async fetchSpans(spanType) {
30754
- const spans = await this.fetchFn(spanType);
31125
+ const spans = await this.fetchFn(spanType, false);
30755
31126
  for (const span of spans) {
30756
31127
  const type = span.span_attributes?.type ?? "";
30757
31128
  const existing = this.spanCache.get(type) ?? [];
@@ -30829,10 +31200,13 @@ var LocalTrace = class {
30829
31200
  * First checks the local span cache for recently logged spans, then falls
30830
31201
  * back to CachedSpanFetcher which handles BTQL fetching and caching.
30831
31202
  */
30832
- async getSpans({ spanType } = {}) {
31203
+ async getSpans({
31204
+ spanType,
31205
+ includeScorers = false
31206
+ } = {}) {
30833
31207
  const cachedSpans = this.state.spanCache.getByRootSpanId(this.rootSpanId);
30834
31208
  if (cachedSpans && cachedSpans.length > 0) {
30835
- let spans = cachedSpans.filter(
31209
+ let spans = includeScorers ? cachedSpans : cachedSpans.filter(
30836
31210
  (span) => span.span_attributes?.purpose !== "scorer"
30837
31211
  );
30838
31212
  if (spanType && spanType.length > 0) {
@@ -30843,13 +31217,19 @@ var LocalTrace = class {
30843
31217
  return spans.map((span) => ({
30844
31218
  input: span.input,
30845
31219
  output: span.output,
31220
+ expected: span.expected,
31221
+ error: span.error,
31222
+ scores: span.scores,
31223
+ metrics: span.metrics,
30846
31224
  metadata: span.metadata,
30847
31225
  span_id: span.span_id,
30848
31226
  span_parents: span.span_parents,
30849
- span_attributes: span.span_attributes
31227
+ is_root: span.is_root,
31228
+ span_attributes: span.span_attributes,
31229
+ tags: span.tags
30850
31230
  }));
30851
31231
  }
30852
- return this.cachedFetcher.getSpans({ spanType });
31232
+ return this.cachedFetcher.getSpans({ spanType, includeScorers });
30853
31233
  }
30854
31234
  /**
30855
31235
  * Get the thread (preprocessed messages) for this trace.
@@ -32038,6 +32418,34 @@ var defaultReporter = {
32038
32418
  }
32039
32419
  };
32040
32420
 
32421
+ // src/dataset-pipeline.ts
32422
+ function DatasetPipeline(definition) {
32423
+ if (!globalThis.__braintrust_dataset_pipelines) {
32424
+ globalThis.__braintrust_dataset_pipelines = [];
32425
+ }
32426
+ const storedDefinition = {
32427
+ name: definition.name,
32428
+ source: {
32429
+ projectId: definition.source.projectId,
32430
+ projectName: definition.source.projectName,
32431
+ orgName: definition.source.orgName,
32432
+ filter: definition.source.filter,
32433
+ scope: definition.source.scope ?? "span"
32434
+ },
32435
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions, @typescript-eslint/no-explicit-any
32436
+ transform: definition.transform,
32437
+ target: {
32438
+ projectId: definition.target.projectId,
32439
+ projectName: definition.target.projectName,
32440
+ orgName: definition.target.orgName,
32441
+ datasetName: definition.target.datasetName,
32442
+ description: definition.target.description,
32443
+ metadata: definition.target.metadata
32444
+ }
32445
+ };
32446
+ globalThis.__braintrust_dataset_pipelines.push(storedDefinition);
32447
+ }
32448
+
32041
32449
  // src/framework2.ts
32042
32450
  import { z as z12 } from "zod/v3";
32043
32451
  var currentFilename = typeof __filename !== "undefined" ? __filename : "unknown";
@@ -32568,6 +32976,7 @@ export {
32568
32976
  BaseExperiment,
32569
32977
  BraintrustLangChainCallbackHandler,
32570
32978
  BraintrustMiddleware,
32979
+ BraintrustObservabilityExporter,
32571
32980
  BraintrustState,
32572
32981
  BraintrustStream,
32573
32982
  CachedSpanFetcher,
@@ -32577,6 +32986,7 @@ export {
32577
32986
  DEFAULT_FETCH_BATCH_SIZE,
32578
32987
  DEFAULT_MAX_REQUEST_SIZE,
32579
32988
  Dataset2 as Dataset,
32989
+ DatasetPipeline,
32580
32990
  ERR_PERMALINK,
32581
32991
  Eval,
32582
32992
  EvalResultWithSummary,