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/workerd.mjs CHANGED
@@ -89,6 +89,7 @@ var iso = {
89
89
  getRepoInfo: async (_settings) => void 0,
90
90
  getPastNAncestors: async () => [],
91
91
  getEnv: (_name) => void 0,
92
+ getBraintrustApiKey: async () => void 0,
92
93
  getCallerLocation: () => void 0,
93
94
  newAsyncLocalStorage: () => new DefaultAsyncLocalStorage(),
94
95
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -3934,6 +3935,76 @@ var LRUCache = class {
3934
3935
  }
3935
3936
  };
3936
3937
 
3938
+ // src/prompt-cache/cache-config.ts
3939
+ var CACHE_LOCATION_ENV_VAR = "BRAINTRUST_CACHE_LOCATION";
3940
+ var DEFAULT_CACHE_MEMORY_MAX = 1 << 10;
3941
+ var DEFAULT_CACHE_DISK_MAX = 1 << 20;
3942
+ var warnedInvalidCacheModeEnvValue = false;
3943
+ var warnedUnavailableDiskCacheMode = false;
3944
+ function warnInvalidCacheMode(value) {
3945
+ if (warnedInvalidCacheModeEnvValue) {
3946
+ return;
3947
+ }
3948
+ warnedInvalidCacheModeEnvValue = true;
3949
+ debugLogger.warn(
3950
+ `Invalid ${CACHE_LOCATION_ENV_VAR} value "${value}". Expected "mixed", "memory", "disk", or "none". Falling back to "mixed".`
3951
+ );
3952
+ }
3953
+ function warnUnavailableDiskCache() {
3954
+ if (warnedUnavailableDiskCacheMode) {
3955
+ return;
3956
+ }
3957
+ warnedUnavailableDiskCacheMode = true;
3958
+ debugLogger.warn(
3959
+ `Disk cache is not supported on this platform, so ${CACHE_LOCATION_ENV_VAR}="disk" disables prompt and parameters caching.`
3960
+ );
3961
+ }
3962
+ function parseCacheMode() {
3963
+ const value = isomorph_default.getEnv(CACHE_LOCATION_ENV_VAR);
3964
+ const normalized = value?.trim().toLowerCase();
3965
+ if (!normalized) {
3966
+ return "mixed";
3967
+ }
3968
+ if (normalized === "mixed" || normalized === "memory" || normalized === "disk" || normalized === "none") {
3969
+ return normalized;
3970
+ }
3971
+ warnInvalidCacheMode(value ?? "");
3972
+ return "mixed";
3973
+ }
3974
+ function parsePositiveIntegerEnv(envVar, defaultValue) {
3975
+ const value = Number(isomorph_default.getEnv(envVar));
3976
+ return Number.isInteger(value) && value > 0 ? value : defaultValue;
3977
+ }
3978
+ function createCacheLayers({
3979
+ memoryMaxEnvVar,
3980
+ diskCacheDirEnvVar,
3981
+ diskMaxEnvVar,
3982
+ getDefaultDiskCacheDir
3983
+ }) {
3984
+ const mode = parseCacheMode();
3985
+ const memoryCache = mode === "mixed" || mode === "memory" ? new LRUCache({
3986
+ max: parsePositiveIntegerEnv(
3987
+ memoryMaxEnvVar,
3988
+ DEFAULT_CACHE_MEMORY_MAX
3989
+ )
3990
+ }) : void 0;
3991
+ let diskCache;
3992
+ if (mode === "mixed" || mode === "disk") {
3993
+ if (canUseDiskCache()) {
3994
+ diskCache = new DiskCache({
3995
+ cacheDir: isomorph_default.getEnv(diskCacheDirEnvVar) ?? getDefaultDiskCacheDir(),
3996
+ max: parsePositiveIntegerEnv(diskMaxEnvVar, DEFAULT_CACHE_DISK_MAX)
3997
+ });
3998
+ } else if (mode === "disk") {
3999
+ warnUnavailableDiskCache();
4000
+ }
4001
+ }
4002
+ if (diskCache) {
4003
+ return { memoryCache, diskCache };
4004
+ }
4005
+ return { memoryCache };
4006
+ }
4007
+
3937
4008
  // src/prompt-cache/prompt-cache.ts
3938
4009
  function createCacheKey(key) {
3939
4010
  if (key.id) {
@@ -3961,16 +4032,18 @@ var PromptCache = class {
3961
4032
  */
3962
4033
  async get(key) {
3963
4034
  const cacheKey = createCacheKey(key);
3964
- const memoryPrompt = this.memoryCache.get(cacheKey);
3965
- if (memoryPrompt !== void 0) {
3966
- return memoryPrompt;
4035
+ if (this.memoryCache) {
4036
+ const memoryPrompt = this.memoryCache.get(cacheKey);
4037
+ if (memoryPrompt !== void 0) {
4038
+ return memoryPrompt;
4039
+ }
3967
4040
  }
3968
4041
  if (this.diskCache) {
3969
4042
  const diskPrompt = await this.diskCache.get(cacheKey);
3970
4043
  if (!diskPrompt) {
3971
4044
  return void 0;
3972
4045
  }
3973
- this.memoryCache.set(cacheKey, diskPrompt);
4046
+ this.memoryCache?.set(cacheKey, diskPrompt);
3974
4047
  return diskPrompt;
3975
4048
  }
3976
4049
  return void 0;
@@ -3985,7 +4058,7 @@ var PromptCache = class {
3985
4058
  */
3986
4059
  async set(key, value) {
3987
4060
  const cacheKey = createCacheKey(key);
3988
- this.memoryCache.set(cacheKey, value);
4061
+ this.memoryCache?.set(cacheKey, value);
3989
4062
  if (this.diskCache) {
3990
4063
  await this.diskCache.set(cacheKey, value);
3991
4064
  }
@@ -4015,23 +4088,25 @@ var ParametersCache = class {
4015
4088
  }
4016
4089
  async get(key) {
4017
4090
  const cacheKey = createCacheKey2(key);
4018
- const memoryParams = this.memoryCache.get(cacheKey);
4019
- if (memoryParams !== void 0) {
4020
- return memoryParams;
4091
+ if (this.memoryCache) {
4092
+ const memoryParams = this.memoryCache.get(cacheKey);
4093
+ if (memoryParams !== void 0) {
4094
+ return memoryParams;
4095
+ }
4021
4096
  }
4022
4097
  if (this.diskCache) {
4023
4098
  const diskParams = await this.diskCache.get(cacheKey);
4024
4099
  if (!diskParams) {
4025
4100
  return void 0;
4026
4101
  }
4027
- this.memoryCache.set(cacheKey, diskParams);
4102
+ this.memoryCache?.set(cacheKey, diskParams);
4028
4103
  return diskParams;
4029
4104
  }
4030
4105
  return void 0;
4031
4106
  }
4032
4107
  async set(key, value) {
4033
4108
  const cacheKey = createCacheKey2(key);
4034
- this.memoryCache.set(cacheKey, value);
4109
+ this.memoryCache?.set(cacheKey, value);
4035
4110
  if (this.diskCache) {
4036
4111
  await this.diskCache.set(cacheKey, value);
4037
4112
  }
@@ -4563,21 +4638,22 @@ var BraintrustState = class _BraintrustState {
4563
4638
  setGlobalDebugLogLevel(void 0);
4564
4639
  }
4565
4640
  this.resetLoginInfo();
4566
- const memoryCache = new LRUCache({
4567
- max: Number(isomorph_default.getEnv("BRAINTRUST_PROMPT_CACHE_MEMORY_MAX")) ?? 1 << 10
4641
+ const { memoryCache, diskCache } = createCacheLayers({
4642
+ memoryMaxEnvVar: "BRAINTRUST_PROMPT_CACHE_MEMORY_MAX",
4643
+ diskCacheDirEnvVar: "BRAINTRUST_PROMPT_CACHE_DIR",
4644
+ diskMaxEnvVar: "BRAINTRUST_PROMPT_CACHE_DISK_MAX",
4645
+ getDefaultDiskCacheDir: () => `${isomorph_default.getEnv("HOME") ?? isomorph_default.homedir()}/.braintrust/prompt_cache`
4568
4646
  });
4569
- const diskCache = canUseDiskCache() ? new DiskCache({
4570
- cacheDir: isomorph_default.getEnv("BRAINTRUST_PROMPT_CACHE_DIR") ?? `${isomorph_default.getEnv("HOME") ?? isomorph_default.homedir()}/.braintrust/prompt_cache`,
4571
- max: Number(isomorph_default.getEnv("BRAINTRUST_PROMPT_CACHE_DISK_MAX")) ?? 1 << 20
4572
- }) : void 0;
4573
4647
  this.promptCache = new PromptCache({ memoryCache, diskCache });
4574
- const parametersMemoryCache = new LRUCache({
4575
- max: Number(isomorph_default.getEnv("BRAINTRUST_PARAMETERS_CACHE_MEMORY_MAX")) ?? 1 << 10
4648
+ const {
4649
+ memoryCache: parametersMemoryCache,
4650
+ diskCache: parametersDiskCache
4651
+ } = createCacheLayers({
4652
+ memoryMaxEnvVar: "BRAINTRUST_PARAMETERS_CACHE_MEMORY_MAX",
4653
+ diskCacheDirEnvVar: "BRAINTRUST_PARAMETERS_CACHE_DIR",
4654
+ diskMaxEnvVar: "BRAINTRUST_PARAMETERS_CACHE_DISK_MAX",
4655
+ getDefaultDiskCacheDir: () => `${isomorph_default.getEnv("HOME") ?? isomorph_default.homedir()}/.braintrust/parameters_cache`
4576
4656
  });
4577
- const parametersDiskCache = canUseDiskCache() ? new DiskCache({
4578
- cacheDir: isomorph_default.getEnv("BRAINTRUST_PARAMETERS_CACHE_DIR") ?? `${isomorph_default.getEnv("HOME") ?? isomorph_default.homedir()}/.braintrust/parameters_cache`,
4579
- max: Number(isomorph_default.getEnv("BRAINTRUST_PARAMETERS_CACHE_DISK_MAX")) ?? 1 << 20
4580
- }) : void 0;
4581
4657
  this.parametersCache = new ParametersCache({
4582
4658
  memoryCache: parametersMemoryCache,
4583
4659
  diskCache: parametersDiskCache
@@ -5430,6 +5506,19 @@ var JSONAttachment = class extends Attachment {
5430
5506
  */
5431
5507
  constructor(data, options) {
5432
5508
  const { filename = "data.json", pretty = false, state } = options ?? {};
5509
+ const deferredJsonAttachment = globalThis.__BT_DATASET_PIPELINE_DEFER_JSON_ATTACHMENT__;
5510
+ if (deferredJsonAttachment) {
5511
+ super({
5512
+ data: new Blob([]),
5513
+ filename,
5514
+ contentType: "application/json",
5515
+ state
5516
+ });
5517
+ return deferredJsonAttachment(data, {
5518
+ filename,
5519
+ pretty
5520
+ });
5521
+ }
5433
5522
  const jsonString = pretty ? JSON.stringify(data, null, 2) : JSON.stringify(data);
5434
5523
  const blob = new Blob([jsonString], { type: "application/json" });
5435
5524
  super({
@@ -7422,10 +7511,11 @@ async function login(options = {}) {
7422
7511
  async function loginToState(options = {}) {
7423
7512
  const {
7424
7513
  appUrl = isomorph_default.getEnv("BRAINTRUST_APP_URL") || "https://www.braintrust.dev",
7425
- apiKey = isomorph_default.getEnv("BRAINTRUST_API_KEY"),
7514
+ apiKey: apiKeyArg,
7426
7515
  orgName = isomorph_default.getEnv("BRAINTRUST_ORG_NAME"),
7427
7516
  fetch: fetch2 = globalThis.fetch
7428
7517
  } = options || {};
7518
+ const apiKey = apiKeyArg !== void 0 ? apiKeyArg : await isomorph_default.getBraintrustApiKey();
7429
7519
  const appPublicUrl = isomorph_default.getEnv("BRAINTRUST_APP_PUBLIC_URL") || appUrl;
7430
7520
  const state = new BraintrustState(options);
7431
7521
  state.resetLoginInfo();
@@ -8666,9 +8756,15 @@ var SpanImpl = class _SpanImpl {
8666
8756
  const cachedSpan = {
8667
8757
  input: partialRecord.input,
8668
8758
  output: partialRecord.output,
8759
+ expected: partialRecord.expected,
8760
+ error: partialRecord.error,
8761
+ scores: partialRecord.scores,
8762
+ metrics: partialRecord.metrics,
8669
8763
  metadata: partialRecord.metadata,
8764
+ tags: partialRecord.tags,
8670
8765
  span_id: this._spanId,
8671
8766
  span_parents: this._spanParents,
8767
+ is_root: this._spanId === this._rootSpanId,
8672
8768
  span_attributes: partialRecord.span_attributes
8673
8769
  };
8674
8770
  this._state.spanCache.queueWrite(
@@ -9004,6 +9100,7 @@ var Dataset2 = class extends ObjectFetcher {
9004
9100
  metadata,
9005
9101
  tags,
9006
9102
  output,
9103
+ origin,
9007
9104
  isMerge
9008
9105
  }) {
9009
9106
  return new LazyValue(async () => {
@@ -9018,6 +9115,7 @@ var Dataset2 = class extends ObjectFetcher {
9018
9115
  created: !isMerge ? (/* @__PURE__ */ new Date()).toISOString() : void 0,
9019
9116
  //if we're merging/updating an event we will not add this ts
9020
9117
  metadata,
9118
+ origin,
9021
9119
  ...!!isMerge ? {
9022
9120
  [IS_MERGE_FIELD]: true
9023
9121
  } : {}
@@ -9037,6 +9135,7 @@ var Dataset2 = class extends ObjectFetcher {
9037
9135
  * about anything else that's relevant, that you can use to help find and analyze examples later. For example, you could log the
9038
9136
  * `prompt`, example's `id`, or anything else that would be useful to slice/dice later. The values in `metadata` can be any
9039
9137
  * JSON-serializable type, but its keys must be strings.
9138
+ * @param event.origin (Optional) a reference to the source object this dataset record was derived from.
9040
9139
  * @param event.id (Optional) a unique identifier for the event. If you don't provide one, Braintrust will generate one for you.
9041
9140
  * @param event.output: (Deprecated) The output of your application. Use `expected` instead.
9042
9141
  * @returns The `id` of the logged record.
@@ -9047,7 +9146,8 @@ var Dataset2 = class extends ObjectFetcher {
9047
9146
  metadata,
9048
9147
  tags,
9049
9148
  id,
9050
- output
9149
+ output,
9150
+ origin
9051
9151
  }) {
9052
9152
  this.validateEvent({ metadata, expected, output, tags });
9053
9153
  const rowId = id || uuidv42();
@@ -9059,6 +9159,7 @@ var Dataset2 = class extends ObjectFetcher {
9059
9159
  metadata,
9060
9160
  tags,
9061
9161
  output,
9162
+ origin,
9062
9163
  isMerge: false
9063
9164
  })
9064
9165
  );
@@ -25692,7 +25793,7 @@ var BraintrustPlugin = class extends BasePlugin {
25692
25793
  this.config = config;
25693
25794
  }
25694
25795
  onEnable() {
25695
- const integrations = this.config.integrations || {};
25796
+ const integrations = this.config.integrations ?? {};
25696
25797
  if (integrations.openai !== false) {
25697
25798
  this.openaiPlugin = new OpenAIPlugin();
25698
25799
  this.openaiPlugin.enable();
@@ -25757,7 +25858,7 @@ var BraintrustPlugin = class extends BasePlugin {
25757
25858
  this.genkitPlugin = new GenkitPlugin();
25758
25859
  this.genkitPlugin.enable();
25759
25860
  }
25760
- if (getIntegrationConfig(integrations, "gitHubCopilot") !== false) {
25861
+ if (integrations.gitHubCopilot !== false) {
25761
25862
  this.gitHubCopilotPlugin = new GitHubCopilotPlugin();
25762
25863
  this.gitHubCopilotPlugin.enable();
25763
25864
  }
@@ -25870,6 +25971,7 @@ var envIntegrationAliases = {
25870
25971
  cursorsdk: "cursorSDK",
25871
25972
  flue: "flue",
25872
25973
  "flue-runtime": "flue",
25974
+ mastra: "mastra",
25873
25975
  "openai-agents": "openAIAgents",
25874
25976
  openaiagents: "openAIAgents",
25875
25977
  "openai-agents-core": "openAIAgents",
@@ -25912,6 +26014,7 @@ function getDefaultInstrumentationIntegrations() {
25912
26014
  cursor: true,
25913
26015
  cursorSDK: true,
25914
26016
  flue: true,
26017
+ mastra: true,
25915
26018
  openAIAgents: true,
25916
26019
  openrouter: true,
25917
26020
  openrouterAgent: true,
@@ -26054,6 +26157,10 @@ function configureWorkerd() {
26054
26157
  }
26055
26158
  return process.env[name];
26056
26159
  };
26160
+ isomorph_default.getBraintrustApiKey = async () => {
26161
+ const value = isomorph_default.getEnv("BRAINTRUST_API_KEY");
26162
+ return value?.trim() ? value : void 0;
26163
+ };
26057
26164
  isomorph_default.hash = (data) => {
26058
26165
  let hash = 0;
26059
26166
  for (let i = 0; i < data.length; i++) {
@@ -26080,6 +26187,7 @@ __export(exports_exports, {
26080
26187
  BaseExperiment: () => BaseExperiment,
26081
26188
  BraintrustLangChainCallbackHandler: () => BraintrustLangChainCallbackHandler,
26082
26189
  BraintrustMiddleware: () => BraintrustMiddleware,
26190
+ BraintrustObservabilityExporter: () => BraintrustObservabilityExporter,
26083
26191
  BraintrustState: () => BraintrustState,
26084
26192
  BraintrustStream: () => BraintrustStream,
26085
26193
  CachedSpanFetcher: () => CachedSpanFetcher,
@@ -26089,6 +26197,7 @@ __export(exports_exports, {
26089
26197
  DEFAULT_FETCH_BATCH_SIZE: () => DEFAULT_FETCH_BATCH_SIZE,
26090
26198
  DEFAULT_MAX_REQUEST_SIZE: () => DEFAULT_MAX_REQUEST_SIZE,
26091
26199
  Dataset: () => Dataset2,
26200
+ DatasetPipeline: () => DatasetPipeline,
26092
26201
  ERR_PERMALINK: () => ERR_PERMALINK,
26093
26202
  Eval: () => Eval,
26094
26203
  EvalResultWithSummary: () => EvalResultWithSummary,
@@ -27695,6 +27804,196 @@ function toolRunnerProxy(toolRunner, anthropic, channel2) {
27695
27804
  }
27696
27805
 
27697
27806
  // src/wrappers/mastra.ts
27807
+ var MASTRA_BRAINTRUST_EXPORTER_NAME = "braintrust";
27808
+ var SPAN_TYPE_MAP = {
27809
+ agent_run: "task" /* TASK */,
27810
+ model_generation: "llm" /* LLM */,
27811
+ model_step: "llm" /* LLM */,
27812
+ model_chunk: "llm" /* LLM */,
27813
+ tool_call: "tool" /* TOOL */,
27814
+ mcp_tool_call: "tool" /* TOOL */,
27815
+ workflow_run: "task" /* TASK */,
27816
+ workflow_step: "function" /* FUNCTION */,
27817
+ workflow_conditional: "function" /* FUNCTION */,
27818
+ workflow_conditional_eval: "function" /* FUNCTION */,
27819
+ workflow_parallel: "function" /* FUNCTION */,
27820
+ workflow_loop: "function" /* FUNCTION */,
27821
+ workflow_sleep: "function" /* FUNCTION */,
27822
+ workflow_wait_event: "function" /* FUNCTION */,
27823
+ memory_operation: "function" /* FUNCTION */,
27824
+ workspace_action: "function" /* FUNCTION */,
27825
+ rag_ingestion: "task" /* TASK */,
27826
+ rag_embedding: "llm" /* LLM */,
27827
+ rag_vector_operation: "function" /* FUNCTION */,
27828
+ rag_action: "function" /* FUNCTION */,
27829
+ graph_action: "function" /* FUNCTION */,
27830
+ scorer_run: "score" /* SCORE */,
27831
+ scorer_step: "score" /* SCORE */,
27832
+ processor_run: "function" /* FUNCTION */,
27833
+ generic: "function" /* FUNCTION */
27834
+ };
27835
+ function spanTypeFor(mastraType) {
27836
+ return SPAN_TYPE_MAP[mastraType] ?? "function" /* FUNCTION */;
27837
+ }
27838
+ function epochSeconds(value) {
27839
+ if (value === void 0) return void 0;
27840
+ const ms = value instanceof Date ? value.getTime() : typeof value === "number" ? value : Date.parse(value);
27841
+ return Number.isFinite(ms) ? ms / 1e3 : void 0;
27842
+ }
27843
+ function modelMetrics(attributes) {
27844
+ if (!isObject(attributes)) return void 0;
27845
+ const usage = isObject(attributes.usage) ? attributes.usage : void 0;
27846
+ if (!usage) return void 0;
27847
+ const out = {};
27848
+ if (typeof usage.inputTokens === "number")
27849
+ out.prompt_tokens = usage.inputTokens;
27850
+ if (typeof usage.outputTokens === "number")
27851
+ out.completion_tokens = usage.outputTokens;
27852
+ if (typeof usage.inputTokens === "number" && typeof usage.outputTokens === "number") {
27853
+ out.tokens = usage.inputTokens + usage.outputTokens;
27854
+ }
27855
+ const inputDetails = isObject(usage.inputDetails) ? usage.inputDetails : void 0;
27856
+ const outputDetails = isObject(usage.outputDetails) ? usage.outputDetails : void 0;
27857
+ if (inputDetails && typeof inputDetails.cacheRead === "number") {
27858
+ out.prompt_cached_tokens = inputDetails.cacheRead;
27859
+ }
27860
+ if (inputDetails && typeof inputDetails.cacheWrite === "number") {
27861
+ out.prompt_cache_creation_tokens = inputDetails.cacheWrite;
27862
+ }
27863
+ if (outputDetails && typeof outputDetails.reasoning === "number") {
27864
+ out.completion_reasoning_tokens = outputDetails.reasoning;
27865
+ }
27866
+ return Object.keys(out).length > 0 ? out : void 0;
27867
+ }
27868
+ function buildMetadata(exported) {
27869
+ const out = {};
27870
+ if (exported.entityId !== void 0) out.entity_id = exported.entityId;
27871
+ if (exported.entityName !== void 0) out.entity_name = exported.entityName;
27872
+ if (exported.entityType !== void 0) out.entity_type = exported.entityType;
27873
+ if (exported.metadata && isObject(exported.metadata)) {
27874
+ Object.assign(out, exported.metadata);
27875
+ }
27876
+ if (exported.attributes && isObject(exported.attributes)) {
27877
+ for (const [key, value] of Object.entries(exported.attributes)) {
27878
+ if (key === "usage") continue;
27879
+ if (value !== void 0) out[key] = value;
27880
+ }
27881
+ }
27882
+ if (exported.tags && exported.tags.length > 0) {
27883
+ out.tags = exported.tags;
27884
+ }
27885
+ if (exported.requestContext && isObject(exported.requestContext)) {
27886
+ out.request_context = exported.requestContext;
27887
+ }
27888
+ return out;
27889
+ }
27890
+ var BraintrustObservabilityExporter = class {
27891
+ name = MASTRA_BRAINTRUST_EXPORTER_NAME;
27892
+ spans = /* @__PURE__ */ new Map();
27893
+ // Captured at the first SPAN_STARTED event. Mastra's observability bus may
27894
+ // dispatch later events outside the user's AsyncLocalStorage context, where
27895
+ // `currentSpan()` returns NOOP_SPAN — which would make our `startSpan()`
27896
+ // calls go to a no-op logger and silently drop. Anchoring on the parent
27897
+ // we observe while still in-context keeps the whole Mastra subtree under
27898
+ // the user's traced scenario.
27899
+ capturedParent;
27900
+ constructor() {
27901
+ _internalSetInitialState();
27902
+ }
27903
+ async exportTracingEvent(event) {
27904
+ const exported = event.exportedSpan;
27905
+ if (exported.isInternal === true) return;
27906
+ try {
27907
+ switch (event.type) {
27908
+ case "span_started":
27909
+ this.onStart(exported);
27910
+ break;
27911
+ case "span_updated":
27912
+ this.onUpdate(exported);
27913
+ break;
27914
+ case "span_ended":
27915
+ this.onEnd(exported);
27916
+ break;
27917
+ }
27918
+ } catch (err) {
27919
+ logExporterError(err);
27920
+ }
27921
+ }
27922
+ async flush() {
27923
+ const state = _internalGetGlobalState();
27924
+ if (state) {
27925
+ await state.bgLogger().flush();
27926
+ }
27927
+ }
27928
+ async shutdown() {
27929
+ await this.flush();
27930
+ this.spans.clear();
27931
+ }
27932
+ onStart(exported) {
27933
+ if (this.spans.has(exported.id)) return;
27934
+ const args = {
27935
+ name: exported.name,
27936
+ spanAttributes: { type: spanTypeFor(exported.type) },
27937
+ startTime: epochSeconds(exported.startTime)
27938
+ };
27939
+ const parentRecord = exported.parentSpanId ? this.spans.get(exported.parentSpanId) : void 0;
27940
+ if (!this.capturedParent) {
27941
+ const probe = currentSpan();
27942
+ if (probe && probe.spanId) {
27943
+ this.capturedParent = probe;
27944
+ }
27945
+ }
27946
+ const span = parentRecord ? parentRecord.span.startSpan(args) : this.capturedParent ? this.capturedParent.startSpan(args) : startSpan(args);
27947
+ const record = { span, hasLoggedInput: false };
27948
+ this.logPayload(record, exported);
27949
+ this.spans.set(exported.id, record);
27950
+ if (exported.isEvent === true) {
27951
+ span.end({ endTime: args.startTime });
27952
+ this.spans.delete(exported.id);
27953
+ }
27954
+ }
27955
+ onUpdate(exported) {
27956
+ const record = this.spans.get(exported.id);
27957
+ if (!record) return;
27958
+ this.logPayload(record, exported);
27959
+ }
27960
+ onEnd(exported) {
27961
+ const record = this.spans.get(exported.id);
27962
+ if (!record) return;
27963
+ this.logPayload(record, exported);
27964
+ if (exported.errorInfo) {
27965
+ record.span.log({
27966
+ error: exported.errorInfo.message || exported.errorInfo.name || "Unknown Mastra error"
27967
+ });
27968
+ }
27969
+ record.span.end({ endTime: epochSeconds(exported.endTime) });
27970
+ this.spans.delete(exported.id);
27971
+ }
27972
+ logPayload(record, exported) {
27973
+ const event = {};
27974
+ if (exported.input !== void 0) {
27975
+ event.input = exported.input;
27976
+ record.hasLoggedInput = true;
27977
+ }
27978
+ if (exported.output !== void 0) {
27979
+ event.output = exported.output;
27980
+ }
27981
+ const metadata = buildMetadata(exported);
27982
+ if (Object.keys(metadata).length > 0) {
27983
+ event.metadata = metadata;
27984
+ }
27985
+ const metrics = modelMetrics(exported.attributes);
27986
+ if (metrics) {
27987
+ event.metrics = metrics;
27988
+ }
27989
+ if (Object.keys(event).length > 0) {
27990
+ record.span.log(event);
27991
+ }
27992
+ }
27993
+ };
27994
+ function logExporterError(err) {
27995
+ debugLogger.warn("Mastra exporter failure:", err);
27996
+ }
27698
27997
  function wrapMastraAgent(agent, _options) {
27699
27998
  return agent;
27700
27999
  }
@@ -29347,10 +29646,12 @@ function formatExperimentSummary(summary) {
29347
29646
  // src/wrappers/shared/flush.ts
29348
29647
  async function summarizeAndFlush(experiment, options) {
29349
29648
  const shouldDisplay = options.displaySummary ?? true;
29350
- const summary = await experiment.summarize();
29351
- if (shouldDisplay) {
29352
- console.log(formatExperimentSummary(summary));
29649
+ if (!shouldDisplay) {
29650
+ await experiment.flush();
29651
+ return;
29353
29652
  }
29653
+ const summary = await experiment.summarize();
29654
+ console.log(formatExperimentSummary(summary));
29354
29655
  }
29355
29656
 
29356
29657
  // src/wrappers/vitest/flush-manager.ts
@@ -31214,8 +31515,12 @@ var waterfall$1 = awaitify(waterfall);
31214
31515
 
31215
31516
  // src/trace.ts
31216
31517
  var SpanFetcher = class _SpanFetcher extends ObjectFetcher {
31217
- constructor(objectType, _objectId, rootSpanId, _state, spanTypeFilter) {
31218
- const filterExpr = _SpanFetcher.buildFilter(rootSpanId, spanTypeFilter);
31518
+ constructor(objectType, _objectId, rootSpanId, _state, spanTypeFilter, includeScorers = false) {
31519
+ const filterExpr = _SpanFetcher.buildFilter(
31520
+ rootSpanId,
31521
+ spanTypeFilter,
31522
+ includeScorers
31523
+ );
31219
31524
  super(objectType, void 0, void 0, {
31220
31525
  filter: filterExpr
31221
31526
  });
@@ -31224,16 +31529,17 @@ var SpanFetcher = class _SpanFetcher extends ObjectFetcher {
31224
31529
  this._state = _state;
31225
31530
  this.spanTypeFilter = spanTypeFilter;
31226
31531
  }
31227
- static buildFilter(rootSpanId, spanTypeFilter) {
31532
+ static buildFilter(rootSpanId, spanTypeFilter, includeScorers = false) {
31228
31533
  const children = [
31229
31534
  // Base filter: root_span_id = 'value'
31230
31535
  {
31231
31536
  op: "eq",
31232
31537
  left: { op: "ident", name: ["root_span_id"] },
31233
31538
  right: { op: "literal", value: rootSpanId }
31234
- },
31235
- // Exclude span_attributes.purpose = 'score'
31236
- {
31539
+ }
31540
+ ];
31541
+ if (!includeScorers) {
31542
+ children.push({
31237
31543
  op: "or",
31238
31544
  children: [
31239
31545
  {
@@ -31246,8 +31552,8 @@ var SpanFetcher = class _SpanFetcher extends ObjectFetcher {
31246
31552
  right: { op: "literal", value: "scorer" }
31247
31553
  }
31248
31554
  ]
31249
- }
31250
- ];
31555
+ });
31556
+ }
31251
31557
  if (spanTypeFilter && spanTypeFilter.length > 0) {
31252
31558
  children.push({
31253
31559
  op: "in",
@@ -31273,35 +31579,49 @@ var CachedSpanFetcher = class {
31273
31579
  fetchFn;
31274
31580
  constructor(objectTypeOrFetchFn, objectId, rootSpanId, getState) {
31275
31581
  if (typeof objectTypeOrFetchFn === "function") {
31276
- this.fetchFn = objectTypeOrFetchFn;
31582
+ this.fetchFn = (spanType) => objectTypeOrFetchFn(spanType);
31277
31583
  } else {
31278
31584
  const objectType = objectTypeOrFetchFn;
31279
- this.fetchFn = async (spanType) => {
31585
+ this.fetchFn = async (spanType, includeScorers) => {
31280
31586
  const state = await getState();
31281
31587
  const fetcher = new SpanFetcher(
31282
31588
  objectType,
31283
31589
  objectId,
31284
31590
  rootSpanId,
31285
31591
  state,
31286
- spanType
31592
+ spanType,
31593
+ includeScorers
31287
31594
  );
31288
31595
  const rows = await fetcher.fetchedData();
31289
- return rows.filter((row) => row.span_attributes?.purpose !== "scorer").map((row) => ({
31596
+ return rows.map((row) => ({
31290
31597
  input: row.input,
31291
31598
  output: row.output,
31599
+ expected: row.expected,
31600
+ error: row.error,
31601
+ scores: row.scores,
31602
+ metrics: row.metrics,
31292
31603
  metadata: row.metadata,
31293
31604
  span_id: row.span_id,
31294
31605
  span_parents: row.span_parents,
31606
+ is_root: row.is_root,
31295
31607
  span_attributes: row.span_attributes,
31296
31608
  id: row.id,
31297
31609
  _xact_id: row._xact_id,
31298
31610
  _pagination_key: row._pagination_key,
31299
- root_span_id: row.root_span_id
31611
+ root_span_id: row.root_span_id,
31612
+ created: row.created,
31613
+ tags: row.tags
31300
31614
  }));
31301
31615
  };
31302
31616
  }
31303
31617
  }
31304
- async getSpans({ spanType } = {}) {
31618
+ async getSpans({
31619
+ spanType,
31620
+ includeScorers = false
31621
+ } = {}) {
31622
+ if (includeScorers) {
31623
+ return this.fetchFn(spanType, true);
31624
+ }
31305
31625
  if (this.allFetched) {
31306
31626
  return this.getFromCache(spanType);
31307
31627
  }
@@ -31318,7 +31638,7 @@ var CachedSpanFetcher = class {
31318
31638
  return this.getFromCache(spanType);
31319
31639
  }
31320
31640
  async fetchSpans(spanType) {
31321
- const spans = await this.fetchFn(spanType);
31641
+ const spans = await this.fetchFn(spanType, false);
31322
31642
  for (const span of spans) {
31323
31643
  const type = span.span_attributes?.type ?? "";
31324
31644
  const existing = this.spanCache.get(type) ?? [];
@@ -31396,10 +31716,13 @@ var LocalTrace = class {
31396
31716
  * First checks the local span cache for recently logged spans, then falls
31397
31717
  * back to CachedSpanFetcher which handles BTQL fetching and caching.
31398
31718
  */
31399
- async getSpans({ spanType } = {}) {
31719
+ async getSpans({
31720
+ spanType,
31721
+ includeScorers = false
31722
+ } = {}) {
31400
31723
  const cachedSpans = this.state.spanCache.getByRootSpanId(this.rootSpanId);
31401
31724
  if (cachedSpans && cachedSpans.length > 0) {
31402
- let spans = cachedSpans.filter(
31725
+ let spans = includeScorers ? cachedSpans : cachedSpans.filter(
31403
31726
  (span) => span.span_attributes?.purpose !== "scorer"
31404
31727
  );
31405
31728
  if (spanType && spanType.length > 0) {
@@ -31410,13 +31733,19 @@ var LocalTrace = class {
31410
31733
  return spans.map((span) => ({
31411
31734
  input: span.input,
31412
31735
  output: span.output,
31736
+ expected: span.expected,
31737
+ error: span.error,
31738
+ scores: span.scores,
31739
+ metrics: span.metrics,
31413
31740
  metadata: span.metadata,
31414
31741
  span_id: span.span_id,
31415
31742
  span_parents: span.span_parents,
31416
- span_attributes: span.span_attributes
31743
+ is_root: span.is_root,
31744
+ span_attributes: span.span_attributes,
31745
+ tags: span.tags
31417
31746
  }));
31418
31747
  }
31419
- return this.cachedFetcher.getSpans({ spanType });
31748
+ return this.cachedFetcher.getSpans({ spanType, includeScorers });
31420
31749
  }
31421
31750
  /**
31422
31751
  * Get the thread (preprocessed messages) for this trace.
@@ -32605,6 +32934,34 @@ var defaultReporter = {
32605
32934
  }
32606
32935
  };
32607
32936
 
32937
+ // src/dataset-pipeline.ts
32938
+ function DatasetPipeline(definition) {
32939
+ if (!globalThis.__braintrust_dataset_pipelines) {
32940
+ globalThis.__braintrust_dataset_pipelines = [];
32941
+ }
32942
+ const storedDefinition = {
32943
+ name: definition.name,
32944
+ source: {
32945
+ projectId: definition.source.projectId,
32946
+ projectName: definition.source.projectName,
32947
+ orgName: definition.source.orgName,
32948
+ filter: definition.source.filter,
32949
+ scope: definition.source.scope ?? "span"
32950
+ },
32951
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions, @typescript-eslint/no-explicit-any
32952
+ transform: definition.transform,
32953
+ target: {
32954
+ projectId: definition.target.projectId,
32955
+ projectName: definition.target.projectName,
32956
+ orgName: definition.target.orgName,
32957
+ datasetName: definition.target.datasetName,
32958
+ description: definition.target.description,
32959
+ metadata: definition.target.metadata
32960
+ }
32961
+ };
32962
+ globalThis.__braintrust_dataset_pipelines.push(storedDefinition);
32963
+ }
32964
+
32608
32965
  // src/framework2.ts
32609
32966
  import { z as z12 } from "zod/v3";
32610
32967
  var currentFilename = typeof __filename !== "undefined" ? __filename : "unknown";
@@ -33135,6 +33492,7 @@ export {
33135
33492
  BaseExperiment,
33136
33493
  BraintrustLangChainCallbackHandler,
33137
33494
  BraintrustMiddleware,
33495
+ BraintrustObservabilityExporter,
33138
33496
  BraintrustState,
33139
33497
  BraintrustStream,
33140
33498
  CachedSpanFetcher,
@@ -33144,6 +33502,7 @@ export {
33144
33502
  DEFAULT_FETCH_BATCH_SIZE,
33145
33503
  DEFAULT_MAX_REQUEST_SIZE,
33146
33504
  Dataset2 as Dataset,
33505
+ DatasetPipeline,
33147
33506
  ERR_PERMALINK,
33148
33507
  Eval,
33149
33508
  EvalResultWithSummary,