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/browser.mjs CHANGED
@@ -92,6 +92,7 @@ var iso = {
92
92
  getRepoInfo: async (_settings) => void 0,
93
93
  getPastNAncestors: async () => [],
94
94
  getEnv: (_name) => void 0,
95
+ getBraintrustApiKey: async () => void 0,
95
96
  getCallerLocation: () => void 0,
96
97
  newAsyncLocalStorage: () => new DefaultAsyncLocalStorage(),
97
98
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -3937,6 +3938,76 @@ var LRUCache = class {
3937
3938
  }
3938
3939
  };
3939
3940
 
3941
+ // src/prompt-cache/cache-config.ts
3942
+ var CACHE_LOCATION_ENV_VAR = "BRAINTRUST_CACHE_LOCATION";
3943
+ var DEFAULT_CACHE_MEMORY_MAX = 1 << 10;
3944
+ var DEFAULT_CACHE_DISK_MAX = 1 << 20;
3945
+ var warnedInvalidCacheModeEnvValue = false;
3946
+ var warnedUnavailableDiskCacheMode = false;
3947
+ function warnInvalidCacheMode(value) {
3948
+ if (warnedInvalidCacheModeEnvValue) {
3949
+ return;
3950
+ }
3951
+ warnedInvalidCacheModeEnvValue = true;
3952
+ debugLogger.warn(
3953
+ `Invalid ${CACHE_LOCATION_ENV_VAR} value "${value}". Expected "mixed", "memory", "disk", or "none". Falling back to "mixed".`
3954
+ );
3955
+ }
3956
+ function warnUnavailableDiskCache() {
3957
+ if (warnedUnavailableDiskCacheMode) {
3958
+ return;
3959
+ }
3960
+ warnedUnavailableDiskCacheMode = true;
3961
+ debugLogger.warn(
3962
+ `Disk cache is not supported on this platform, so ${CACHE_LOCATION_ENV_VAR}="disk" disables prompt and parameters caching.`
3963
+ );
3964
+ }
3965
+ function parseCacheMode() {
3966
+ const value = isomorph_default.getEnv(CACHE_LOCATION_ENV_VAR);
3967
+ const normalized = value?.trim().toLowerCase();
3968
+ if (!normalized) {
3969
+ return "mixed";
3970
+ }
3971
+ if (normalized === "mixed" || normalized === "memory" || normalized === "disk" || normalized === "none") {
3972
+ return normalized;
3973
+ }
3974
+ warnInvalidCacheMode(value ?? "");
3975
+ return "mixed";
3976
+ }
3977
+ function parsePositiveIntegerEnv(envVar, defaultValue) {
3978
+ const value = Number(isomorph_default.getEnv(envVar));
3979
+ return Number.isInteger(value) && value > 0 ? value : defaultValue;
3980
+ }
3981
+ function createCacheLayers({
3982
+ memoryMaxEnvVar,
3983
+ diskCacheDirEnvVar,
3984
+ diskMaxEnvVar,
3985
+ getDefaultDiskCacheDir
3986
+ }) {
3987
+ const mode = parseCacheMode();
3988
+ const memoryCache = mode === "mixed" || mode === "memory" ? new LRUCache({
3989
+ max: parsePositiveIntegerEnv(
3990
+ memoryMaxEnvVar,
3991
+ DEFAULT_CACHE_MEMORY_MAX
3992
+ )
3993
+ }) : void 0;
3994
+ let diskCache;
3995
+ if (mode === "mixed" || mode === "disk") {
3996
+ if (canUseDiskCache()) {
3997
+ diskCache = new DiskCache({
3998
+ cacheDir: isomorph_default.getEnv(diskCacheDirEnvVar) ?? getDefaultDiskCacheDir(),
3999
+ max: parsePositiveIntegerEnv(diskMaxEnvVar, DEFAULT_CACHE_DISK_MAX)
4000
+ });
4001
+ } else if (mode === "disk") {
4002
+ warnUnavailableDiskCache();
4003
+ }
4004
+ }
4005
+ if (diskCache) {
4006
+ return { memoryCache, diskCache };
4007
+ }
4008
+ return { memoryCache };
4009
+ }
4010
+
3940
4011
  // src/prompt-cache/prompt-cache.ts
3941
4012
  function createCacheKey(key) {
3942
4013
  if (key.id) {
@@ -3964,16 +4035,18 @@ var PromptCache = class {
3964
4035
  */
3965
4036
  async get(key) {
3966
4037
  const cacheKey = createCacheKey(key);
3967
- const memoryPrompt = this.memoryCache.get(cacheKey);
3968
- if (memoryPrompt !== void 0) {
3969
- return memoryPrompt;
4038
+ if (this.memoryCache) {
4039
+ const memoryPrompt = this.memoryCache.get(cacheKey);
4040
+ if (memoryPrompt !== void 0) {
4041
+ return memoryPrompt;
4042
+ }
3970
4043
  }
3971
4044
  if (this.diskCache) {
3972
4045
  const diskPrompt = await this.diskCache.get(cacheKey);
3973
4046
  if (!diskPrompt) {
3974
4047
  return void 0;
3975
4048
  }
3976
- this.memoryCache.set(cacheKey, diskPrompt);
4049
+ this.memoryCache?.set(cacheKey, diskPrompt);
3977
4050
  return diskPrompt;
3978
4051
  }
3979
4052
  return void 0;
@@ -3988,7 +4061,7 @@ var PromptCache = class {
3988
4061
  */
3989
4062
  async set(key, value) {
3990
4063
  const cacheKey = createCacheKey(key);
3991
- this.memoryCache.set(cacheKey, value);
4064
+ this.memoryCache?.set(cacheKey, value);
3992
4065
  if (this.diskCache) {
3993
4066
  await this.diskCache.set(cacheKey, value);
3994
4067
  }
@@ -4018,23 +4091,25 @@ var ParametersCache = class {
4018
4091
  }
4019
4092
  async get(key) {
4020
4093
  const cacheKey = createCacheKey2(key);
4021
- const memoryParams = this.memoryCache.get(cacheKey);
4022
- if (memoryParams !== void 0) {
4023
- return memoryParams;
4094
+ if (this.memoryCache) {
4095
+ const memoryParams = this.memoryCache.get(cacheKey);
4096
+ if (memoryParams !== void 0) {
4097
+ return memoryParams;
4098
+ }
4024
4099
  }
4025
4100
  if (this.diskCache) {
4026
4101
  const diskParams = await this.diskCache.get(cacheKey);
4027
4102
  if (!diskParams) {
4028
4103
  return void 0;
4029
4104
  }
4030
- this.memoryCache.set(cacheKey, diskParams);
4105
+ this.memoryCache?.set(cacheKey, diskParams);
4031
4106
  return diskParams;
4032
4107
  }
4033
4108
  return void 0;
4034
4109
  }
4035
4110
  async set(key, value) {
4036
4111
  const cacheKey = createCacheKey2(key);
4037
- this.memoryCache.set(cacheKey, value);
4112
+ this.memoryCache?.set(cacheKey, value);
4038
4113
  if (this.diskCache) {
4039
4114
  await this.diskCache.set(cacheKey, value);
4040
4115
  }
@@ -4566,21 +4641,22 @@ var BraintrustState = class _BraintrustState {
4566
4641
  setGlobalDebugLogLevel(void 0);
4567
4642
  }
4568
4643
  this.resetLoginInfo();
4569
- const memoryCache = new LRUCache({
4570
- max: Number(isomorph_default.getEnv("BRAINTRUST_PROMPT_CACHE_MEMORY_MAX")) ?? 1 << 10
4644
+ const { memoryCache, diskCache } = createCacheLayers({
4645
+ memoryMaxEnvVar: "BRAINTRUST_PROMPT_CACHE_MEMORY_MAX",
4646
+ diskCacheDirEnvVar: "BRAINTRUST_PROMPT_CACHE_DIR",
4647
+ diskMaxEnvVar: "BRAINTRUST_PROMPT_CACHE_DISK_MAX",
4648
+ getDefaultDiskCacheDir: () => `${isomorph_default.getEnv("HOME") ?? isomorph_default.homedir()}/.braintrust/prompt_cache`
4571
4649
  });
4572
- const diskCache = canUseDiskCache() ? new DiskCache({
4573
- cacheDir: isomorph_default.getEnv("BRAINTRUST_PROMPT_CACHE_DIR") ?? `${isomorph_default.getEnv("HOME") ?? isomorph_default.homedir()}/.braintrust/prompt_cache`,
4574
- max: Number(isomorph_default.getEnv("BRAINTRUST_PROMPT_CACHE_DISK_MAX")) ?? 1 << 20
4575
- }) : void 0;
4576
4650
  this.promptCache = new PromptCache({ memoryCache, diskCache });
4577
- const parametersMemoryCache = new LRUCache({
4578
- max: Number(isomorph_default.getEnv("BRAINTRUST_PARAMETERS_CACHE_MEMORY_MAX")) ?? 1 << 10
4651
+ const {
4652
+ memoryCache: parametersMemoryCache,
4653
+ diskCache: parametersDiskCache
4654
+ } = createCacheLayers({
4655
+ memoryMaxEnvVar: "BRAINTRUST_PARAMETERS_CACHE_MEMORY_MAX",
4656
+ diskCacheDirEnvVar: "BRAINTRUST_PARAMETERS_CACHE_DIR",
4657
+ diskMaxEnvVar: "BRAINTRUST_PARAMETERS_CACHE_DISK_MAX",
4658
+ getDefaultDiskCacheDir: () => `${isomorph_default.getEnv("HOME") ?? isomorph_default.homedir()}/.braintrust/parameters_cache`
4579
4659
  });
4580
- const parametersDiskCache = canUseDiskCache() ? new DiskCache({
4581
- cacheDir: isomorph_default.getEnv("BRAINTRUST_PARAMETERS_CACHE_DIR") ?? `${isomorph_default.getEnv("HOME") ?? isomorph_default.homedir()}/.braintrust/parameters_cache`,
4582
- max: Number(isomorph_default.getEnv("BRAINTRUST_PARAMETERS_CACHE_DISK_MAX")) ?? 1 << 20
4583
- }) : void 0;
4584
4660
  this.parametersCache = new ParametersCache({
4585
4661
  memoryCache: parametersMemoryCache,
4586
4662
  diskCache: parametersDiskCache
@@ -5433,6 +5509,19 @@ var JSONAttachment = class extends Attachment {
5433
5509
  */
5434
5510
  constructor(data, options) {
5435
5511
  const { filename = "data.json", pretty = false, state } = options ?? {};
5512
+ const deferredJsonAttachment = globalThis.__BT_DATASET_PIPELINE_DEFER_JSON_ATTACHMENT__;
5513
+ if (deferredJsonAttachment) {
5514
+ super({
5515
+ data: new Blob([]),
5516
+ filename,
5517
+ contentType: "application/json",
5518
+ state
5519
+ });
5520
+ return deferredJsonAttachment(data, {
5521
+ filename,
5522
+ pretty
5523
+ });
5524
+ }
5436
5525
  const jsonString = pretty ? JSON.stringify(data, null, 2) : JSON.stringify(data);
5437
5526
  const blob = new Blob([jsonString], { type: "application/json" });
5438
5527
  super({
@@ -7425,10 +7514,11 @@ async function login(options = {}) {
7425
7514
  async function loginToState(options = {}) {
7426
7515
  const {
7427
7516
  appUrl = isomorph_default.getEnv("BRAINTRUST_APP_URL") || "https://www.braintrust.dev",
7428
- apiKey = isomorph_default.getEnv("BRAINTRUST_API_KEY"),
7517
+ apiKey: apiKeyArg,
7429
7518
  orgName = isomorph_default.getEnv("BRAINTRUST_ORG_NAME"),
7430
7519
  fetch: fetch2 = globalThis.fetch
7431
7520
  } = options || {};
7521
+ const apiKey = apiKeyArg !== void 0 ? apiKeyArg : await isomorph_default.getBraintrustApiKey();
7432
7522
  const appPublicUrl = isomorph_default.getEnv("BRAINTRUST_APP_PUBLIC_URL") || appUrl;
7433
7523
  const state = new BraintrustState(options);
7434
7524
  state.resetLoginInfo();
@@ -8669,9 +8759,15 @@ var SpanImpl = class _SpanImpl {
8669
8759
  const cachedSpan = {
8670
8760
  input: partialRecord.input,
8671
8761
  output: partialRecord.output,
8762
+ expected: partialRecord.expected,
8763
+ error: partialRecord.error,
8764
+ scores: partialRecord.scores,
8765
+ metrics: partialRecord.metrics,
8672
8766
  metadata: partialRecord.metadata,
8767
+ tags: partialRecord.tags,
8673
8768
  span_id: this._spanId,
8674
8769
  span_parents: this._spanParents,
8770
+ is_root: this._spanId === this._rootSpanId,
8675
8771
  span_attributes: partialRecord.span_attributes
8676
8772
  };
8677
8773
  this._state.spanCache.queueWrite(
@@ -9007,6 +9103,7 @@ var Dataset2 = class extends ObjectFetcher {
9007
9103
  metadata,
9008
9104
  tags,
9009
9105
  output,
9106
+ origin,
9010
9107
  isMerge
9011
9108
  }) {
9012
9109
  return new LazyValue(async () => {
@@ -9021,6 +9118,7 @@ var Dataset2 = class extends ObjectFetcher {
9021
9118
  created: !isMerge ? (/* @__PURE__ */ new Date()).toISOString() : void 0,
9022
9119
  //if we're merging/updating an event we will not add this ts
9023
9120
  metadata,
9121
+ origin,
9024
9122
  ...!!isMerge ? {
9025
9123
  [IS_MERGE_FIELD]: true
9026
9124
  } : {}
@@ -9040,6 +9138,7 @@ var Dataset2 = class extends ObjectFetcher {
9040
9138
  * about anything else that's relevant, that you can use to help find and analyze examples later. For example, you could log the
9041
9139
  * `prompt`, example's `id`, or anything else that would be useful to slice/dice later. The values in `metadata` can be any
9042
9140
  * JSON-serializable type, but its keys must be strings.
9141
+ * @param event.origin (Optional) a reference to the source object this dataset record was derived from.
9043
9142
  * @param event.id (Optional) a unique identifier for the event. If you don't provide one, Braintrust will generate one for you.
9044
9143
  * @param event.output: (Deprecated) The output of your application. Use `expected` instead.
9045
9144
  * @returns The `id` of the logged record.
@@ -9050,7 +9149,8 @@ var Dataset2 = class extends ObjectFetcher {
9050
9149
  metadata,
9051
9150
  tags,
9052
9151
  id,
9053
- output
9152
+ output,
9153
+ origin
9054
9154
  }) {
9055
9155
  this.validateEvent({ metadata, expected, output, tags });
9056
9156
  const rowId = id || uuidv42();
@@ -9062,6 +9162,7 @@ var Dataset2 = class extends ObjectFetcher {
9062
9162
  metadata,
9063
9163
  tags,
9064
9164
  output,
9165
+ origin,
9065
9166
  isMerge: false
9066
9167
  })
9067
9168
  );
@@ -25572,7 +25673,7 @@ var BraintrustPlugin = class extends BasePlugin {
25572
25673
  this.config = config;
25573
25674
  }
25574
25675
  onEnable() {
25575
- const integrations = this.config.integrations || {};
25676
+ const integrations = this.config.integrations ?? {};
25576
25677
  if (integrations.openai !== false) {
25577
25678
  this.openaiPlugin = new OpenAIPlugin();
25578
25679
  this.openaiPlugin.enable();
@@ -25637,7 +25738,7 @@ var BraintrustPlugin = class extends BasePlugin {
25637
25738
  this.genkitPlugin = new GenkitPlugin();
25638
25739
  this.genkitPlugin.enable();
25639
25740
  }
25640
- if (getIntegrationConfig(integrations, "gitHubCopilot") !== false) {
25741
+ if (integrations.gitHubCopilot !== false) {
25641
25742
  this.gitHubCopilotPlugin = new GitHubCopilotPlugin();
25642
25743
  this.gitHubCopilotPlugin.enable();
25643
25744
  }
@@ -25750,6 +25851,7 @@ var envIntegrationAliases = {
25750
25851
  cursorsdk: "cursorSDK",
25751
25852
  flue: "flue",
25752
25853
  "flue-runtime": "flue",
25854
+ mastra: "mastra",
25753
25855
  "openai-agents": "openAIAgents",
25754
25856
  openaiagents: "openAIAgents",
25755
25857
  "openai-agents-core": "openAIAgents",
@@ -25792,6 +25894,7 @@ function getDefaultInstrumentationIntegrations() {
25792
25894
  cursor: true,
25793
25895
  cursorSDK: true,
25794
25896
  flue: true,
25897
+ mastra: true,
25795
25898
  openAIAgents: true,
25796
25899
  openrouter: true,
25797
25900
  openrouterAgent: true,
@@ -26019,6 +26122,10 @@ function configureBrowser() {
26019
26122
  }
26020
26123
  return process.env[name];
26021
26124
  };
26125
+ isomorph_default.getBraintrustApiKey = async () => {
26126
+ const value = isomorph_default.getEnv("BRAINTRUST_API_KEY");
26127
+ return value?.trim() ? value : void 0;
26128
+ };
26022
26129
  isomorph_default.hash = (data) => {
26023
26130
  let hash = 0;
26024
26131
  for (let i = 0; i < data.length; i++) {
@@ -26045,6 +26152,7 @@ __export(exports_exports, {
26045
26152
  BaseExperiment: () => BaseExperiment,
26046
26153
  BraintrustLangChainCallbackHandler: () => BraintrustLangChainCallbackHandler,
26047
26154
  BraintrustMiddleware: () => BraintrustMiddleware,
26155
+ BraintrustObservabilityExporter: () => BraintrustObservabilityExporter,
26048
26156
  BraintrustState: () => BraintrustState,
26049
26157
  BraintrustStream: () => BraintrustStream,
26050
26158
  CachedSpanFetcher: () => CachedSpanFetcher,
@@ -26054,6 +26162,7 @@ __export(exports_exports, {
26054
26162
  DEFAULT_FETCH_BATCH_SIZE: () => DEFAULT_FETCH_BATCH_SIZE,
26055
26163
  DEFAULT_MAX_REQUEST_SIZE: () => DEFAULT_MAX_REQUEST_SIZE,
26056
26164
  Dataset: () => Dataset2,
26165
+ DatasetPipeline: () => DatasetPipeline,
26057
26166
  ERR_PERMALINK: () => ERR_PERMALINK,
26058
26167
  Eval: () => Eval,
26059
26168
  EvalResultWithSummary: () => EvalResultWithSummary,
@@ -27660,6 +27769,196 @@ function toolRunnerProxy(toolRunner, anthropic, channel2) {
27660
27769
  }
27661
27770
 
27662
27771
  // src/wrappers/mastra.ts
27772
+ var MASTRA_BRAINTRUST_EXPORTER_NAME = "braintrust";
27773
+ var SPAN_TYPE_MAP = {
27774
+ agent_run: "task" /* TASK */,
27775
+ model_generation: "llm" /* LLM */,
27776
+ model_step: "llm" /* LLM */,
27777
+ model_chunk: "llm" /* LLM */,
27778
+ tool_call: "tool" /* TOOL */,
27779
+ mcp_tool_call: "tool" /* TOOL */,
27780
+ workflow_run: "task" /* TASK */,
27781
+ workflow_step: "function" /* FUNCTION */,
27782
+ workflow_conditional: "function" /* FUNCTION */,
27783
+ workflow_conditional_eval: "function" /* FUNCTION */,
27784
+ workflow_parallel: "function" /* FUNCTION */,
27785
+ workflow_loop: "function" /* FUNCTION */,
27786
+ workflow_sleep: "function" /* FUNCTION */,
27787
+ workflow_wait_event: "function" /* FUNCTION */,
27788
+ memory_operation: "function" /* FUNCTION */,
27789
+ workspace_action: "function" /* FUNCTION */,
27790
+ rag_ingestion: "task" /* TASK */,
27791
+ rag_embedding: "llm" /* LLM */,
27792
+ rag_vector_operation: "function" /* FUNCTION */,
27793
+ rag_action: "function" /* FUNCTION */,
27794
+ graph_action: "function" /* FUNCTION */,
27795
+ scorer_run: "score" /* SCORE */,
27796
+ scorer_step: "score" /* SCORE */,
27797
+ processor_run: "function" /* FUNCTION */,
27798
+ generic: "function" /* FUNCTION */
27799
+ };
27800
+ function spanTypeFor(mastraType) {
27801
+ return SPAN_TYPE_MAP[mastraType] ?? "function" /* FUNCTION */;
27802
+ }
27803
+ function epochSeconds(value) {
27804
+ if (value === void 0) return void 0;
27805
+ const ms = value instanceof Date ? value.getTime() : typeof value === "number" ? value : Date.parse(value);
27806
+ return Number.isFinite(ms) ? ms / 1e3 : void 0;
27807
+ }
27808
+ function modelMetrics(attributes) {
27809
+ if (!isObject(attributes)) return void 0;
27810
+ const usage = isObject(attributes.usage) ? attributes.usage : void 0;
27811
+ if (!usage) return void 0;
27812
+ const out = {};
27813
+ if (typeof usage.inputTokens === "number")
27814
+ out.prompt_tokens = usage.inputTokens;
27815
+ if (typeof usage.outputTokens === "number")
27816
+ out.completion_tokens = usage.outputTokens;
27817
+ if (typeof usage.inputTokens === "number" && typeof usage.outputTokens === "number") {
27818
+ out.tokens = usage.inputTokens + usage.outputTokens;
27819
+ }
27820
+ const inputDetails = isObject(usage.inputDetails) ? usage.inputDetails : void 0;
27821
+ const outputDetails = isObject(usage.outputDetails) ? usage.outputDetails : void 0;
27822
+ if (inputDetails && typeof inputDetails.cacheRead === "number") {
27823
+ out.prompt_cached_tokens = inputDetails.cacheRead;
27824
+ }
27825
+ if (inputDetails && typeof inputDetails.cacheWrite === "number") {
27826
+ out.prompt_cache_creation_tokens = inputDetails.cacheWrite;
27827
+ }
27828
+ if (outputDetails && typeof outputDetails.reasoning === "number") {
27829
+ out.completion_reasoning_tokens = outputDetails.reasoning;
27830
+ }
27831
+ return Object.keys(out).length > 0 ? out : void 0;
27832
+ }
27833
+ function buildMetadata(exported) {
27834
+ const out = {};
27835
+ if (exported.entityId !== void 0) out.entity_id = exported.entityId;
27836
+ if (exported.entityName !== void 0) out.entity_name = exported.entityName;
27837
+ if (exported.entityType !== void 0) out.entity_type = exported.entityType;
27838
+ if (exported.metadata && isObject(exported.metadata)) {
27839
+ Object.assign(out, exported.metadata);
27840
+ }
27841
+ if (exported.attributes && isObject(exported.attributes)) {
27842
+ for (const [key, value] of Object.entries(exported.attributes)) {
27843
+ if (key === "usage") continue;
27844
+ if (value !== void 0) out[key] = value;
27845
+ }
27846
+ }
27847
+ if (exported.tags && exported.tags.length > 0) {
27848
+ out.tags = exported.tags;
27849
+ }
27850
+ if (exported.requestContext && isObject(exported.requestContext)) {
27851
+ out.request_context = exported.requestContext;
27852
+ }
27853
+ return out;
27854
+ }
27855
+ var BraintrustObservabilityExporter = class {
27856
+ name = MASTRA_BRAINTRUST_EXPORTER_NAME;
27857
+ spans = /* @__PURE__ */ new Map();
27858
+ // Captured at the first SPAN_STARTED event. Mastra's observability bus may
27859
+ // dispatch later events outside the user's AsyncLocalStorage context, where
27860
+ // `currentSpan()` returns NOOP_SPAN — which would make our `startSpan()`
27861
+ // calls go to a no-op logger and silently drop. Anchoring on the parent
27862
+ // we observe while still in-context keeps the whole Mastra subtree under
27863
+ // the user's traced scenario.
27864
+ capturedParent;
27865
+ constructor() {
27866
+ _internalSetInitialState();
27867
+ }
27868
+ async exportTracingEvent(event) {
27869
+ const exported = event.exportedSpan;
27870
+ if (exported.isInternal === true) return;
27871
+ try {
27872
+ switch (event.type) {
27873
+ case "span_started":
27874
+ this.onStart(exported);
27875
+ break;
27876
+ case "span_updated":
27877
+ this.onUpdate(exported);
27878
+ break;
27879
+ case "span_ended":
27880
+ this.onEnd(exported);
27881
+ break;
27882
+ }
27883
+ } catch (err) {
27884
+ logExporterError(err);
27885
+ }
27886
+ }
27887
+ async flush() {
27888
+ const state = _internalGetGlobalState();
27889
+ if (state) {
27890
+ await state.bgLogger().flush();
27891
+ }
27892
+ }
27893
+ async shutdown() {
27894
+ await this.flush();
27895
+ this.spans.clear();
27896
+ }
27897
+ onStart(exported) {
27898
+ if (this.spans.has(exported.id)) return;
27899
+ const args = {
27900
+ name: exported.name,
27901
+ spanAttributes: { type: spanTypeFor(exported.type) },
27902
+ startTime: epochSeconds(exported.startTime)
27903
+ };
27904
+ const parentRecord = exported.parentSpanId ? this.spans.get(exported.parentSpanId) : void 0;
27905
+ if (!this.capturedParent) {
27906
+ const probe = currentSpan();
27907
+ if (probe && probe.spanId) {
27908
+ this.capturedParent = probe;
27909
+ }
27910
+ }
27911
+ const span = parentRecord ? parentRecord.span.startSpan(args) : this.capturedParent ? this.capturedParent.startSpan(args) : startSpan(args);
27912
+ const record = { span, hasLoggedInput: false };
27913
+ this.logPayload(record, exported);
27914
+ this.spans.set(exported.id, record);
27915
+ if (exported.isEvent === true) {
27916
+ span.end({ endTime: args.startTime });
27917
+ this.spans.delete(exported.id);
27918
+ }
27919
+ }
27920
+ onUpdate(exported) {
27921
+ const record = this.spans.get(exported.id);
27922
+ if (!record) return;
27923
+ this.logPayload(record, exported);
27924
+ }
27925
+ onEnd(exported) {
27926
+ const record = this.spans.get(exported.id);
27927
+ if (!record) return;
27928
+ this.logPayload(record, exported);
27929
+ if (exported.errorInfo) {
27930
+ record.span.log({
27931
+ error: exported.errorInfo.message || exported.errorInfo.name || "Unknown Mastra error"
27932
+ });
27933
+ }
27934
+ record.span.end({ endTime: epochSeconds(exported.endTime) });
27935
+ this.spans.delete(exported.id);
27936
+ }
27937
+ logPayload(record, exported) {
27938
+ const event = {};
27939
+ if (exported.input !== void 0) {
27940
+ event.input = exported.input;
27941
+ record.hasLoggedInput = true;
27942
+ }
27943
+ if (exported.output !== void 0) {
27944
+ event.output = exported.output;
27945
+ }
27946
+ const metadata = buildMetadata(exported);
27947
+ if (Object.keys(metadata).length > 0) {
27948
+ event.metadata = metadata;
27949
+ }
27950
+ const metrics = modelMetrics(exported.attributes);
27951
+ if (metrics) {
27952
+ event.metrics = metrics;
27953
+ }
27954
+ if (Object.keys(event).length > 0) {
27955
+ record.span.log(event);
27956
+ }
27957
+ }
27958
+ };
27959
+ function logExporterError(err) {
27960
+ debugLogger.warn("Mastra exporter failure:", err);
27961
+ }
27663
27962
  function wrapMastraAgent(agent, _options) {
27664
27963
  return agent;
27665
27964
  }
@@ -29312,10 +29611,12 @@ function formatExperimentSummary(summary) {
29312
29611
  // src/wrappers/shared/flush.ts
29313
29612
  async function summarizeAndFlush(experiment, options) {
29314
29613
  const shouldDisplay = options.displaySummary ?? true;
29315
- const summary = await experiment.summarize();
29316
- if (shouldDisplay) {
29317
- console.log(formatExperimentSummary(summary));
29614
+ if (!shouldDisplay) {
29615
+ await experiment.flush();
29616
+ return;
29318
29617
  }
29618
+ const summary = await experiment.summarize();
29619
+ console.log(formatExperimentSummary(summary));
29319
29620
  }
29320
29621
 
29321
29622
  // src/wrappers/vitest/flush-manager.ts
@@ -31179,8 +31480,12 @@ var waterfall$1 = awaitify(waterfall);
31179
31480
 
31180
31481
  // src/trace.ts
31181
31482
  var SpanFetcher = class _SpanFetcher extends ObjectFetcher {
31182
- constructor(objectType, _objectId, rootSpanId, _state, spanTypeFilter) {
31183
- const filterExpr = _SpanFetcher.buildFilter(rootSpanId, spanTypeFilter);
31483
+ constructor(objectType, _objectId, rootSpanId, _state, spanTypeFilter, includeScorers = false) {
31484
+ const filterExpr = _SpanFetcher.buildFilter(
31485
+ rootSpanId,
31486
+ spanTypeFilter,
31487
+ includeScorers
31488
+ );
31184
31489
  super(objectType, void 0, void 0, {
31185
31490
  filter: filterExpr
31186
31491
  });
@@ -31189,16 +31494,17 @@ var SpanFetcher = class _SpanFetcher extends ObjectFetcher {
31189
31494
  this._state = _state;
31190
31495
  this.spanTypeFilter = spanTypeFilter;
31191
31496
  }
31192
- static buildFilter(rootSpanId, spanTypeFilter) {
31497
+ static buildFilter(rootSpanId, spanTypeFilter, includeScorers = false) {
31193
31498
  const children = [
31194
31499
  // Base filter: root_span_id = 'value'
31195
31500
  {
31196
31501
  op: "eq",
31197
31502
  left: { op: "ident", name: ["root_span_id"] },
31198
31503
  right: { op: "literal", value: rootSpanId }
31199
- },
31200
- // Exclude span_attributes.purpose = 'score'
31201
- {
31504
+ }
31505
+ ];
31506
+ if (!includeScorers) {
31507
+ children.push({
31202
31508
  op: "or",
31203
31509
  children: [
31204
31510
  {
@@ -31211,8 +31517,8 @@ var SpanFetcher = class _SpanFetcher extends ObjectFetcher {
31211
31517
  right: { op: "literal", value: "scorer" }
31212
31518
  }
31213
31519
  ]
31214
- }
31215
- ];
31520
+ });
31521
+ }
31216
31522
  if (spanTypeFilter && spanTypeFilter.length > 0) {
31217
31523
  children.push({
31218
31524
  op: "in",
@@ -31238,35 +31544,49 @@ var CachedSpanFetcher = class {
31238
31544
  fetchFn;
31239
31545
  constructor(objectTypeOrFetchFn, objectId, rootSpanId, getState) {
31240
31546
  if (typeof objectTypeOrFetchFn === "function") {
31241
- this.fetchFn = objectTypeOrFetchFn;
31547
+ this.fetchFn = (spanType) => objectTypeOrFetchFn(spanType);
31242
31548
  } else {
31243
31549
  const objectType = objectTypeOrFetchFn;
31244
- this.fetchFn = async (spanType) => {
31550
+ this.fetchFn = async (spanType, includeScorers) => {
31245
31551
  const state = await getState();
31246
31552
  const fetcher = new SpanFetcher(
31247
31553
  objectType,
31248
31554
  objectId,
31249
31555
  rootSpanId,
31250
31556
  state,
31251
- spanType
31557
+ spanType,
31558
+ includeScorers
31252
31559
  );
31253
31560
  const rows = await fetcher.fetchedData();
31254
- return rows.filter((row) => row.span_attributes?.purpose !== "scorer").map((row) => ({
31561
+ return rows.map((row) => ({
31255
31562
  input: row.input,
31256
31563
  output: row.output,
31564
+ expected: row.expected,
31565
+ error: row.error,
31566
+ scores: row.scores,
31567
+ metrics: row.metrics,
31257
31568
  metadata: row.metadata,
31258
31569
  span_id: row.span_id,
31259
31570
  span_parents: row.span_parents,
31571
+ is_root: row.is_root,
31260
31572
  span_attributes: row.span_attributes,
31261
31573
  id: row.id,
31262
31574
  _xact_id: row._xact_id,
31263
31575
  _pagination_key: row._pagination_key,
31264
- root_span_id: row.root_span_id
31576
+ root_span_id: row.root_span_id,
31577
+ created: row.created,
31578
+ tags: row.tags
31265
31579
  }));
31266
31580
  };
31267
31581
  }
31268
31582
  }
31269
- async getSpans({ spanType } = {}) {
31583
+ async getSpans({
31584
+ spanType,
31585
+ includeScorers = false
31586
+ } = {}) {
31587
+ if (includeScorers) {
31588
+ return this.fetchFn(spanType, true);
31589
+ }
31270
31590
  if (this.allFetched) {
31271
31591
  return this.getFromCache(spanType);
31272
31592
  }
@@ -31283,7 +31603,7 @@ var CachedSpanFetcher = class {
31283
31603
  return this.getFromCache(spanType);
31284
31604
  }
31285
31605
  async fetchSpans(spanType) {
31286
- const spans = await this.fetchFn(spanType);
31606
+ const spans = await this.fetchFn(spanType, false);
31287
31607
  for (const span of spans) {
31288
31608
  const type = span.span_attributes?.type ?? "";
31289
31609
  const existing = this.spanCache.get(type) ?? [];
@@ -31361,10 +31681,13 @@ var LocalTrace = class {
31361
31681
  * First checks the local span cache for recently logged spans, then falls
31362
31682
  * back to CachedSpanFetcher which handles BTQL fetching and caching.
31363
31683
  */
31364
- async getSpans({ spanType } = {}) {
31684
+ async getSpans({
31685
+ spanType,
31686
+ includeScorers = false
31687
+ } = {}) {
31365
31688
  const cachedSpans = this.state.spanCache.getByRootSpanId(this.rootSpanId);
31366
31689
  if (cachedSpans && cachedSpans.length > 0) {
31367
- let spans = cachedSpans.filter(
31690
+ let spans = includeScorers ? cachedSpans : cachedSpans.filter(
31368
31691
  (span) => span.span_attributes?.purpose !== "scorer"
31369
31692
  );
31370
31693
  if (spanType && spanType.length > 0) {
@@ -31375,13 +31698,19 @@ var LocalTrace = class {
31375
31698
  return spans.map((span) => ({
31376
31699
  input: span.input,
31377
31700
  output: span.output,
31701
+ expected: span.expected,
31702
+ error: span.error,
31703
+ scores: span.scores,
31704
+ metrics: span.metrics,
31378
31705
  metadata: span.metadata,
31379
31706
  span_id: span.span_id,
31380
31707
  span_parents: span.span_parents,
31381
- span_attributes: span.span_attributes
31708
+ is_root: span.is_root,
31709
+ span_attributes: span.span_attributes,
31710
+ tags: span.tags
31382
31711
  }));
31383
31712
  }
31384
- return this.cachedFetcher.getSpans({ spanType });
31713
+ return this.cachedFetcher.getSpans({ spanType, includeScorers });
31385
31714
  }
31386
31715
  /**
31387
31716
  * Get the thread (preprocessed messages) for this trace.
@@ -32570,6 +32899,34 @@ var defaultReporter = {
32570
32899
  }
32571
32900
  };
32572
32901
 
32902
+ // src/dataset-pipeline.ts
32903
+ function DatasetPipeline(definition) {
32904
+ if (!globalThis.__braintrust_dataset_pipelines) {
32905
+ globalThis.__braintrust_dataset_pipelines = [];
32906
+ }
32907
+ const storedDefinition = {
32908
+ name: definition.name,
32909
+ source: {
32910
+ projectId: definition.source.projectId,
32911
+ projectName: definition.source.projectName,
32912
+ orgName: definition.source.orgName,
32913
+ filter: definition.source.filter,
32914
+ scope: definition.source.scope ?? "span"
32915
+ },
32916
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions, @typescript-eslint/no-explicit-any
32917
+ transform: definition.transform,
32918
+ target: {
32919
+ projectId: definition.target.projectId,
32920
+ projectName: definition.target.projectName,
32921
+ orgName: definition.target.orgName,
32922
+ datasetName: definition.target.datasetName,
32923
+ description: definition.target.description,
32924
+ metadata: definition.target.metadata
32925
+ }
32926
+ };
32927
+ globalThis.__braintrust_dataset_pipelines.push(storedDefinition);
32928
+ }
32929
+
32573
32930
  // src/framework2.ts
32574
32931
  import { z as z12 } from "zod/v3";
32575
32932
  var currentFilename = typeof __filename !== "undefined" ? __filename : "unknown";
@@ -33100,6 +33457,7 @@ export {
33100
33457
  BaseExperiment,
33101
33458
  BraintrustLangChainCallbackHandler,
33102
33459
  BraintrustMiddleware,
33460
+ BraintrustObservabilityExporter,
33103
33461
  BraintrustState,
33104
33462
  BraintrustStream,
33105
33463
  CachedSpanFetcher,
@@ -33109,6 +33467,7 @@ export {
33109
33467
  DEFAULT_FETCH_BATCH_SIZE,
33110
33468
  DEFAULT_MAX_REQUEST_SIZE,
33111
33469
  Dataset2 as Dataset,
33470
+ DatasetPipeline,
33112
33471
  ERR_PERMALINK,
33113
33472
  Eval,
33114
33473
  EvalResultWithSummary,